Перейти к содержанию
Авторизация  
pvpgate

Создание инстанс зоны

Рекомендуемые сообщения

7 часов назад, pvpgate сказал:

интересно получается при логировании. getId() не подходит, т.к. дает Id рефлекта а не инстанс зоны.

int izId = reflection.getInstancedZoneId();

  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
В 08.06.2018 в 06:30, Gaikotsu сказал:

int izId = reflection.getInstancedZoneId();

Привет, это снова я, и опять же, чтобы не создавать новую тему, есть вопрос по инстансам.

Как можно обрабатывать покидание инстанс зоны? Например по выходу из инстанс зоны (СОЕ, "в город" после смерти и т.д.) 

При входе я пробую причислить игроков к одной из 2 команд, а сразу при выходе хочу удалять игрока из списка команды.
И второй вопрос, сложнее, можно ли имея списки игроков для 1 и 2 команды настроить, скажем, чтобы все игроки второй команды были варами для игрока первой команды. Или что-то типа такого, но не используя уродские RED и BLUE которые во всех ивентах и дуелях используются.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
19 минут назад, pvpgate сказал:

Привет, это снова я, и опять же, чтобы не создавать новую тему, есть вопрос по инстансам.

Как можно обрабатывать покидание инстанс зоны? Например по выходу из инстанс зоны (СОЕ, "в город" после смерти и т.д.) 

При входе я пробую причислить игроков к одной из 2 команд, а сразу при выходе хочу удалять игрока из списка команды.
И второй вопрос, сложнее, можно ли имея списки игроков для 1 и 2 команды настроить, скажем, чтобы все игроки второй команды были варами для игрока первой команды. Или что-то типа такого, но не используя уродские RED и BLUE которые во всех ивентах и дуелях используются.

добавляете метод onLeave листинг при выходе и туда все условия нужные

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
30 минут назад, Demoncool сказал:

добавляете метод onLeave листинг при выходе и туда все условия нужные

Извини, не понимаю. Я инстанс зону начал пробовать делать всего пару дней назад. а джаву и ооп вцелом начал осваивать незадолго до этого. В каком классе этот метод onLeave? Я так понимаю это в нем по умолчанию описано что у персонаж еще минуту после выхода будет принадлежать покинутой инстанс зоне?

//upd кажется понял, это минуту живет зона. Если бы она жила час после вхыхода, то час игрок к ней бы и принадлежал... но все же, как удалить игрока из списка, в который он добавлен при входе в зону?

 

Изменено пользователем pvpgate

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

объявить для своего инстанса наследный класс от Reflection и делать в нем что хочется - там есть методы onPlayerEnter и onPlayerExit, вызывающиеся при входе и выходе игрока в инстанс.

пример инстанса, имеющего свой особый класс - в нем при входе игроку показывают сценку на дивжке игры

package instances;

import l2p.gameserver.enums.Scene;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.entity.Reflection;

/**
 * @author Gaikotsu
 */
public class AdventOfDelusion extends Reflection
{
	@Override
	public void onPlayerEnter(Player player)
	{
		super.onPlayerEnter(player);

		player.showScene(Scene.BLOODVEIN_OPENING);
	}
}

ну и естественно создавать и входить в инстанс с этим самым наследным классом, а не с базовым Reflection, т.е. так к примеру

ReflectionUtils.simpleEnterInstancedZone(player, new AdventOfDelusion(), izId);

ну а для того, чтобы сразу же при выходе из инстанса убрать игрока из списка посетивших его - надо его удалить из списка _visitors в этом самом методе onPlayerExit

_visitors.remove(player.getObjectId());

 

  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а по причислению игроков к разным отрядам без стандартного setTeam - это можно, но только с модифицированием ядра сервера, если хочется чтобы полноценно обрабатывались все ситуации, связанные с взаимодействием игроков в одной и в разных командах.

надо просто во всех местах, где проверяются стандартная принадлежность командам, добавить и проверку своей реализации причисления к командам.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
42 минуты назад, Gaikotsu сказал:

 


ReflectionUtils.simpleEnterInstancedZone(player, new AdventOfDelusion(), izId);

 

Слушай, а я же не смогу вызывать эту функцию прямо в классе своей инстанс зоны?
Просто с одной стороны я в классе инстанс зоны должен удалять игроков из списка. А с другой стороны я в другом классе проверяю есть ли инстанс зона с таким названием, и если нет - создаю ее, а если да - телепортирую в существующую. И именно в этом месте, в байпасе, я должен решать в какую команду записывать игрока. Как я могу делать это в 2 классах?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

дык запоминай в классе непися, через которого входишь - созданный инстанс и сверяйся с ним - есть он еще или нет и действуй по обстоятельствам

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
3 часа назад, Gaikotsu сказал:

дык запоминай в классе непися, через которого входишь - созданный инстанс и сверяйся с ним - есть он еще или нет и действуй по обстоятельствам

да, так и делаю, но ведь onPlayerEnter() я буду в классе инстанса допиливать и в нем нужно удалять из списка игроков
Что-то типа
 

public class L2Arena extends Reflection
{
	
	ArrayList<Player> arenaTeam1 = new ArrayList<Player>();
	ArrayList<Player> arenaTeam2 = new ArrayList<Player>();
	@Override
	public void onPlayerExit(Player player)
	{
		super.onPlayerExit(player);
		player.sendMessage("Leave instance");
		_visitors.remove(player.getObjectId());
		arenaTeam1.remove(player);
		arenaTeam2.remove(player);
	}	

А добавлять в ту или иную команду мне нужно в классе НПЦ

Я попробовал сделать костыль, и распределять по командам после входа на арену, а потом телепортировать в нужную точку арены:
 

public class L2Arena extends Reflection
{
	
	ArrayList<Player> arenaTeam1 = new ArrayList<Player>();
	ArrayList<Player> arenaTeam2 = new ArrayList<Player>();
	
	
	@Override
	public void onPlayerEnter(Player player)
	{
		super.onPlayerEnter(player);
		player.sendMessage("Enter instance");
		if(arenaTeam1.size()>arenaTeam2.size())
		{
			player.teleToLocation(84696, -16824, -1824, player.getActiveReflection());
			arenaTeam2.add(player);
			player.sendMessage("add to team 2");
		}
		else
		{
			player.teleToLocation(83304, -16024, -1888, player.getActiveReflection());	
			arenaTeam1.add(player);	
			player.sendMessage("add to team 1");			
		}
	}	

добавил логирование, все происходит нормально, только вот улетаю я всегда на точку телепорта в xml инстанса и больше никуда не лечу, т.е. доп. телоепорты в IF-е ну срабатывают

Изменено пользователем pvpgate

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

это происходит из-за того, что onPlayerEnter вызывается как раз в процессе телепорта в инстанс и само собой в то же время еще раз телепортироваться нельзя.

можешь раскидывать по командам и перемещать на требуемые координаты с определенной задержкой, запуская задачу с этим в onPlayerEnter

к примеру так - действия через 5 секунд после входа

ThreadPoolManager.getInstance().schedule(new RunnableImpl()
{
	@Override
	public void runImpl() throws Exception
	{
		// здесь назначаем команду и делаем телепорт
	}
}, 5000);

но вобще по уму надо сделать так как я выше писал - для телепортирующего в инстанс непися объявить свой инстанс и в нем обрабатывая байпас на вход перед самим входом обрабатывать игроков - давать им нужный отряд и задавать куда их телепортировать, в какие координаты.

Изменено пользователем Gaikotsu
  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
47 минут назад, Gaikotsu сказал:

но вобще по уму надо сделать так как я выше писал - для телепортирующего в инстанс непися объявить свой инстанс и в нем обрабатывая байпас на вход перед самим входом обрабатывать игроков - давать им нужный отряд и задавать куда их телепортировать, в какие координаты.

Спасибо. А нет случайно примера где объявляется инстанса классе НПС? Я не совсем понимаю что это значит. Класс НПЦ должен наследовать класс моей инсты? Или просто надо импортировать класс моей инсты? и Как объявлять новый экземпляр класса моей инсты в классе нпс?
Сори за глупые вопросы, только начинаю разбираться с java и ооп вообще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в датапаке, в scripts/npc/model/ есть целая куча персональных классов-инстансов для определенных неписей, так что примеров тебе там целую кучу найти можно

  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
В 10.06.2018 в 14:23, Gaikotsu сказал:

в датапаке, в scripts/npc/model/ есть целая куча персональных классов-инстансов для определенных неписей, так что примеров тебе там целую кучу найти можно

спасибо.
Еще один вопрос есть, можно ли точку респауна задавать динамически? Т.е. по сути я делаю некоторую модификацию ТВТ ивента, хочу чтобы при нажатии "в город" игроки ресались на своей стороне арены. Или же появлялась дополнительная кнопка, по аналогии "к флагу" на осаде, не важно, что можно что проще..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

добавить свою обработку воскрешения и перемещения в пакет RequestRestartPoint

ну или сделать проще - если игрок в режиме участия в пвп-эвенте, то вобще игнорировать от него запросы на воскрешение, а просто ресать самому с определенной задержкой.

вот к примеру у меня в эвенте Team DeathMatch так сделано

	@Override
	public void onKill(Creature actor, Creature victim)
	{
		if (actor == null || victim == null || getStatus() != EventStatus.BATTLE || actor.getPlayer() == null || !victim.isPlayer())
			return;

		EventMember killer = getMember(actor.getPlayer());
		EventMember killed = getMember(victim.getPlayer());

		if (killer == null || killed == null || killer == killed || killer.getPlayer() == null || killed.getPlayer() == null || killer.getTeam() == killed.getTeam())
			return;

		if (killer.getTeam() == TeamType.RED)
		{
			incScore(TeamType.RED, getConfig().getPointsGive());
			decScore(TeamType.BLUE, getConfig().getPointsLose());
		}
		else
		{
			incScore(TeamType.BLUE, getConfig().getPointsGive());
			decScore(TeamType.RED, getConfig().getPointsLose());
		}

		addRewards(killer.getPlayer(), ActionType.KILL);
		ThreadPoolManager.getInstance().schedule(new PvPEventTasks.ActionTask(this, killed.getPlayer(), ActionTaskType.REVIVE_AND_BUFF), getConfig().getTimeToRevive() * 1000L);
		showMessage(killed.getPlayer(), "Вас убили. Через несколько секунд вы будете возрождены.");

		if (getConfig().getPointsCount() > 0 && (getScore(TeamType.RED) >= getConfig().getPointsCount() || getScore(TeamType.BLUE) >= getConfig().getPointsCount()))
			endBattle();
	}

вот эта строчка

ThreadPoolManager.getInstance().schedule(new PvPEventTasks.ActionTask(this, killed.getPlayer(), ActionTaskType.REVIVE_AND_BUFF), getConfig().getTimeToRevive() * 1000L);
		

указывает что надо через определенное время после смерти воскресить (с перемещением в заданную точку) и бафнуть

З.Ы. onKill - это из листенера OnKillListener, так что само собой надо этот листенер объявлять и регистрировать у участников в начале боя, а в конце убирать обратно.

Изменено пользователем Gaikotsu
  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
В 12.06.2018 в 09:27, Gaikotsu сказал:

добавить свою обработку воскрешения и перемещения в пакет RequestRestartPoint

Добавил в RequestRestartPoint условия
 

			default:
				if(activeChar.isInL2ArenaMode()==true)
				{
					if(activeChar.getL2ArenaSide()==1)
					{	
						activeChar.setPendingRevive(true);
						activeChar.teleToLocation(81992, -16040, -1888, activeChar.getActiveReflection());
					}
					if(activeChar.getL2ArenaSide()==2)
					{
						activeChar.setPendingRevive(true);
						activeChar.teleToLocation(84232, -16696, -1840, activeChar.getActiveReflection());
					}
				}

но это не дело так хардкодить. Подскажи плз, как правильно в классе моей инсты задать 2 точки телепортации ?
пробовал так:
 

private static Location _blueloc = null;
private static Location _redloc = null;

_blueloc.set(81992, -16040, -1888);
_blueloc.set(84232, -16696, -1840);

Но ничего хорошего не получилось.
Как задать их так, чтоб потом можно было обращаться к какому нибудь методу, возвращающему локацию по типу

ctiveChar.teleToLocation(L2Arena.getBlueLoc(), activeChar.getActiveReflection());

?
 

Изменено пользователем pvpgate

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

если ты объявляешь их в датапаке, то из ядра будет достаточно сложно к ним обратиться.

вобще, можешь сделать листенер на запрос воскрешения, зарегать в своем эвенте и дергать его в RequestRestartPoint

т.е. первым делом дергается листенер и если он не отработал (обработка должна возвращать к примеру true/false как признак того что что-то сделано/не сделано), то только тогда обрабатываются стандартные варианты воскрешения.

 

еще как вариант, заведи в классе Player сессионные переменные, в которых можно будет хранить любые данные до перезахода в игру - чисто в памяти, без сохранения в бд. т.е. по сути аналог кукисов в вебе - таким образом можно будет обмениваться любыми данными между датапаком и ядром.

сделать это в виде обычной мапы <String, String> или <String, Object> к примеру.

и вот туда можешь к примеру положить координаты, а потом в любое время взять обратно по ключу мапы.

 

для примера, моя реализация сессионных переменных

	/**
	 * --------------------------------------------------
	 * Работа с временными переменными, хранящимися в памяти и удаляющимися при выходе игрока из игры 
	 * --------------------------------------------------
	 */

	private final Map<String, String> _sessionVars = new ConcurrentHashMap<>();

	public Map<String, String> getSessionVars()
	{
		return _sessionVars;
	}

	public String getSessionVar(String name)
	{
		return _sessionVars.get(name);
	}

	public String getSessionVar(String name, String def)
	{
		String val = getSessionVar(name);
		return val != null && !val.isEmpty() ? val : def;
	}

	public int getSessionVar(String name, int def)
	{
		String val = getSessionVar(name, null);
		return val != null ? Integer.parseInt(val) : def;
	}

	public long getSessionVar(String name, long def)
	{
		String val = getSessionVar(name, null);
		return val != null ? Long.parseLong(val) : def;
	}

	public double getSessionVar(String name, double def)
	{
		String val = getSessionVar(name, null);
		return val != null ? Double.parseDouble(val) : def;
	}

	public boolean getSessionVar(String name, boolean def)
	{
		String val = getSessionVar(name, null);
		return val != null ? !val.equalsIgnoreCase("false") : def;
	}

	public void setSessionVar(String name, String val)
	{
		_sessionVars.put(name, val);
	}

	public void setSessionVar(String name, int val)
	{
		setSessionVar(name, Integer.toString(val));
	}

	public void setSessionVar(String name, long val)
	{
		setSessionVar(name, Long.toString(val));
	}

	public void setSessionVar(String name, double val)
	{
		setSessionVar(name, Double.toString(val));
	}

	public void setSessionVar(String name, boolean val)
	{
		setSessionVar(name, Boolean.toString(val));
	}

	public void unsetSessionVar(String... names)
	{
		for (String name : names)
			_sessionVars.remove(name);
	}

вобщем по сути аналог стандартных setVar/getVar, просто без работы с бд.

Изменено пользователем Gaikotsu
  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Извиняюсь что наверно не в теме есть инст фреи как из него выпилить проверку на командный канал ( тоесть что бы в инст можно было залазить 1й группой) и если не в коде то где можно это убрать. Заранее благодарен.  
public class FreyaNormal extends Reflection
{
	private static final int FreyaThrone = 29177;
	private static final int FreyaStandNormal = 29179;
	private static final int IceKnightNormal = 18855; //state 1 - in ice, state 2 - ice shattering, then normal state
	private static final int IceKnightLeaderNormal = 25699;
	private static final int IceCastleBreath = 18854;
	private static final int Glacier = 18853; // state 1 - falling, state 2 - waiting
	private static final int IceCastleController = 18932; // state 1-7
	private static final int Sirra = 32762;
	private static final int Jinia = 18850;
	private static final int Kegor = 18851;

	private static final int[] _eventTriggers = {
			23140202,
			23140204,
			23140206,
			23140208,
			23140212,
			23140214,
			23140216
	};

	private Zone damagezone, attackUp, pcbuff, pcbuff2;

	private ScheduledFuture<?> firstStageGuardSpawn;
	private ScheduledFuture<?> secondStageGuardSpawn;
	private ScheduledFuture<?> thirdStageGuardSpawn;

	private ZoneListener _epicZoneListener = new ZoneListener();
	private ZoneListenerL _landingZoneListener = new ZoneListenerL();
	private DeathListener _deathListener = new DeathListener();
	private CurrentHpListener _currentHpListener = new CurrentHpListener();

	private boolean _entryLocked = false;
	private boolean _startLaunched = false;
	private boolean _freyaSlayed = false;

	private AtomicInteger raidplayers = new AtomicInteger();

	private static Territory centralRoom = new Territory().add(new Polygon().add(114264, -113672).add(113640, -114344).add(113640, -115240).add(114264, -115912).add(115176, -115912).add(115800, -115272).add(115800, -114328).add(115192, -113672).setZmax(-11225).setZmin(-11225));

	@Override
	protected void onCreate()
	{
		super.onCreate();

		attackUp = getZone("[freya_attack_up]");
		pcbuff = getZone("[freya_pc_buff1]");
		pcbuff2 = getZone("[freya_pc_buff2]");
		getZone("[freya_normal_epic]").addListener(_epicZoneListener);
		getZone("[freya_landing_room_epic]").addListener(_landingZoneListener);
	}

	private void manageDamageZone(int level, boolean disable)
	{
		if(disable)
		{
			damagezone.setActive(false);
			return;
		}
		if(damagezone != null)
		{
			damagezone.setActive(false);
		}

		switch(level)
		{
			case 1:
				damagezone = getZone("[freya_normal_freezing_01]");
				break;
			case 2:
				damagezone = getZone("[freya_normal_freezing_02]");
				break;
			case 3:
				damagezone = getZone("[freya_normal_freezing_03]");
				break;
			case 4:
				damagezone = getZone("[freya_normal_freezing_04]");
				break;
			case 5:
				damagezone = getZone("[freya_normal_freezing_05]");
				break;
			case 6:
				damagezone = getZone("[freya_normal_freezing_06]");
				break;
			case 7:
				damagezone = getZone("[freya_normal_freezing_07]");
				break;
			default:
				break;
		}
		if(damagezone != null)
		{
			damagezone.setActive(true);
		}
	}

	private void manageAttackUpZone(boolean disable)
	{
		if(attackUp != null && disable)
		{
			attackUp.setActive(false);
			return;
		}
		if(attackUp != null)
		{
			attackUp.setActive(true);
		}
	}

	private void managePcBuffZone(boolean disable)
	{
		if(pcbuff != null && pcbuff2 != null && disable)
		{
			pcbuff.setActive(false);
			pcbuff2.setActive(false);
			return;
		}
		if(pcbuff != null)
		{
			pcbuff.setActive(true);
		}
		if(pcbuff2 != null)
		{
			pcbuff2.setActive(true);
		}
	}

	private void manageCastleController(int state)
	{
		// 1-7 enabled, 8 - disabled
		for(NpcInstance n : getNpcs())
		{
			if(n.getNpcId() == IceCastleController)
			{
				n.setNpcState(state);
			}
		}
	}

	private void manageStorm(boolean active)
	{
		for(Player p : getPlayers())
		{
			for(int _eventTrigger : _eventTriggers)
			{
				p.sendPacket(new EventTriggerPacket(_eventTrigger, active));
			}
		}
	}

	private class StartNormalFreya extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			_entryLocked = true;
			closeDoor(23140101);
			for(Player player : getPlayers())
			{
				QuestState qs = player.getQuestState(10286);
				if(qs != null && qs.getCond() == 5)
				{
					qs.setCond(6);
				}
				player.startScenePlayer(SceneMovie.FREYA_OPENING);
			}
			ThreadPoolManager.getInstance().schedule(new PreStage(), 55000L); // 53.5sec for movie
		}
	}

	private class PreStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			manageDamageZone(1, false);
			//screen message
			for(Player player : getPlayers())
			{
				player.sendPacket(new ExShowScreenMessage(NpcString.BEGIN_STAGE_1_FREYA, 6000, ScreenMessageAlign.TOP_CENTER, true, 1, -1, true));
			}
			//spawning few guards
			for(int i = 0; i < 10; i++)
			{
				addSpawnWithoutRespawn(IceKnightNormal, Territory.getRandomLoc(centralRoom, getGeoIndex()), 0);
			}
			ThreadPoolManager.getInstance().schedule(new FirstStage(), 40000L);
		}
	}

	private class FirstStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			manageCastleController(1);
			manageDamageZone(2, false);
			for(Player player : getPlayers())
			{
				player.sendPacket(new ExShowScreenMessage(NpcString.FREYA_HAS_STARTED_TO_MOVE, 4000, ScreenMessageAlign.MIDDLE_CENTER, true));
			}
			//Spawning Freya Throne
			NpcInstance freyaTrhone = addSpawnWithoutRespawn(FreyaThrone, new Location(114720, -117085, -11088, 15956), 0);
			freyaTrhone.addListener(_deathListener);
			firstStageGuardSpawn = ThreadPoolManager.getInstance().scheduleAtFixedRate(new GuardSpawnTask(1), 2000L, 30000L);
		}
	}

	private class GuardSpawnTask extends RunnableImpl
	{
		int _mode, _knightsMin, _knightsMax, _breathMin, _breathMax;

		public GuardSpawnTask(int mode) // 1 - light, 2 - normal, 3 - hard, 4 - extreme
		{
			_mode = mode;
			if(_mode < 1 || _mode > 4)
			{
				_mode = 1;
			}
		}

		@Override
		public void runImpl() throws Exception
		{
			switch(_mode)
			{
				case 1:
					_knightsMin = 2;
					_knightsMax = 3;
					_breathMin = 1;
					_breathMax = 2;
					break;
				case 2:
					_knightsMin = 2;
					_knightsMax = 4;
					_breathMin = 1;
					_breathMax = 3;
					break;
				case 3:
					_knightsMin = 3;
					_knightsMax = 8;
					_breathMin = 2;
					_breathMax = 4;
					break;
				case 4:
					_knightsMin = 6;
					_knightsMax = 10;
					_breathMin = 3;
					_breathMax = 7;
					break;
				default:
					break;
			}
			for(int i = 0; i < Rnd.get(_knightsMin, _knightsMax); i++)
			{
				addSpawnWithoutRespawn(IceKnightNormal, Territory.getRandomLoc(centralRoom, getGeoIndex()), 0);
			}
			for(int i = 0; i < Rnd.get(_breathMin, _breathMax); i++)
			{
				addSpawnWithoutRespawn(IceCastleBreath, Territory.getRandomLoc(centralRoom, getGeoIndex()), 0);
			}
			if(Rnd.chance(60))
			{
				for(int i = 0; i < Rnd.get(1, 3); i++)
				{
					addSpawnWithoutRespawn(Glacier, Territory.getRandomLoc(centralRoom, getGeoIndex()), 0);
				}
			}
		}
	}

	private class PreSecondStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			firstStageGuardSpawn.cancel(true);
			for(NpcInstance n : getNpcs())
			{
				if(n.getNpcId() != Sirra && n.getNpcId() != IceCastleController)
				{
					n.deleteMe();
				}
			}

			for(Player p : getPlayers())
			{
				p.startScenePlayer(SceneMovie.FREYA_PHASE_CHANGE_A);
			}
			ThreadPoolManager.getInstance().schedule(new TimerToSecondStage(), 22000L); // 22.1 secs for movie
		}
	}

	private class TimerToSecondStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			for(Player p : getPlayers())
			{
				p.sendPacket(new ExSendUIEventPacket(p, 0, 0, 60, 0, NpcString.TIME_REMAINING_UNTIL_NEXT_BATTLE));
			}
			ThreadPoolManager.getInstance().schedule(new SecondStage(), 60000L);
		}
	}

	private class SecondStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			manageCastleController(3);
			manageDamageZone(3, false);
			for(Player p : getPlayers())
			{
				p.sendPacket(new ExShowScreenMessage(NpcString.BEGIN_STAGE_2_FREYA, 6000, ScreenMessageAlign.TOP_CENTER, true, 1, -1, true));
			}
			secondStageGuardSpawn = ThreadPoolManager.getInstance().scheduleAtFixedRate(new GuardSpawnTask(2), 2000L, 30000L);
			ThreadPoolManager.getInstance().schedule(new KnightCaptainSpawnMovie(), 60000L);
		}
	}

	private class KnightCaptainSpawnMovie extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			for(NpcInstance n : getNpcs())
			{
				n.block();
			}
			for(Player p : getPlayers())
			{
				p.startScenePlayer(SceneMovie.ICE_HEAVY_KNIGHT_SPAWN);
			}
			ThreadPoolManager.getInstance().schedule(new KnightCaptainSpawn(), 7500L);
		}
	}

	private class KnightCaptainSpawn extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			manageDamageZone(4, false);
			for(NpcInstance n : getNpcs())
			{
				n.unblock();
			}
			NpcInstance knightLeader = addSpawnWithoutRespawn(IceKnightLeaderNormal, new Location(114707, -114799, -11199, 15956), 0);
			knightLeader.addListener(_deathListener);
		}
	}

	private class PreThirdStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			for(Player p : getPlayers())
			{
				p.sendPacket(new ExSendUIEventPacket(p, 0, 0, 60, 0, NpcString.TIME_REMAINING_UNTIL_NEXT_BATTLE));
			}
			secondStageGuardSpawn.cancel(true);
			for(NpcInstance n : getNpcs())
			{
				if(n.getNpcId() != Sirra && n.getNpcId() != IceCastleController)
				{
					n.deleteMe();
				}
			}
			ThreadPoolManager.getInstance().schedule(new PreThirdStageM(), 60000L);
		}
	}

	private class PreThirdStageM extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			for(Player p : getPlayers())
			{
				p.startScenePlayer(SceneMovie.FREYA_PHASE_CHANGE_B);
			}
			ThreadPoolManager.getInstance().schedule(new ThirdStage(), 22000L); // 21.5 secs for movie
		}
	}

	private class ThirdStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			manageCastleController(4);
			manageAttackUpZone(false);
			manageDamageZone(5, false);
			manageStorm(true);
			for(Player p : getPlayers())
			{
				p.sendPacket(new ExShowScreenMessage(NpcString.BEGIN_STAGE_3_FREYA, 6000, ScreenMessageAlign.TOP_CENTER, true, 1, -1, true));
				p.sendPacket(new ExChangeClientEffectInfo(2));
			}
			thirdStageGuardSpawn = ThreadPoolManager.getInstance().scheduleAtFixedRate(new GuardSpawnTask(3), 2000L, 30000L);
			NpcInstance freyaStand = addSpawnWithoutRespawn(FreyaStandNormal, new Location(114720, -117085, -11088, 15956), 0);
			freyaStand.addListener(_currentHpListener);
			freyaStand.addListener(_deathListener);
		}
	}

	private class PreForthStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			for(NpcInstance n : getNpcs())
			{
				n.block();
			}
			for(Player p : getPlayers())
			{
				p.block();
				p.startScenePlayer(SceneMovie.KEGOR_INTRUSION);
			}
			ThreadPoolManager.getInstance().schedule(new ForthStage(), 28000L); // 27 secs for movie
		}
	}

	private class ForthStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			for(NpcInstance n : getNpcs())
			{
				n.unblock();
			}
			for(Player p : getPlayers())
			{
				p.unblock();
				p.sendPacket(new ExShowScreenMessage(NpcString.BEGIN_STAGE_4_FREYA, 6000, ScreenMessageAlign.TOP_CENTER, true, 1, -1, true));
			}
			addSpawnWithoutRespawn(Jinia, new Location(114727, -114700, -11200, -16260), 0);
			addSpawnWithoutRespawn(Kegor, new Location(114690, -114700, -11200, -16260), 0);
			managePcBuffZone(false);
		}
	}

	private class FreyaDeathStage extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			setReenterTime(System.currentTimeMillis());
			//Guard spawn task cancellation
			thirdStageGuardSpawn.cancel(true);
			//switching off zones
			manageDamageZone(1, true);
			manageAttackUpZone(true);
			managePcBuffZone(true);
			//Deleting all NPCs + Freya corpse
			for(NpcInstance n : getNpcs())
			{
				n.deleteMe();
			}
			//Movie + quest update
			for(Player p : getPlayers())
			{
				QuestState qs = p.getQuestState(10286);
				if(qs != null && qs.getCond() == 6)
				{
					qs.setCond(7);
				}
				p.startScenePlayer(SceneMovie.FREYA_ENDING_A);
			}
			ThreadPoolManager.getInstance().schedule(new ConclusionMovie(), 16200L); // 16 secs for movie
		}
	}

	private class ConclusionMovie extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			for(Player p : getPlayers())
			{
				p.startScenePlayer(SceneMovie.FREYA_ENDING_B);
			}
			ThreadPoolManager.getInstance().schedule(new InstanceConclusion(), 57000L); // 56 secs for movie
		}
	}

	private class InstanceConclusion extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			startCollapseTimer(5 * 60 * 1000L);
			doCleanup();
			for(Player p : getPlayers())
			{
				p.sendPacket(new SystemMessage(SystemMessage.THIS_DUNGEON_WILL_EXPIRE_IN_S1_MINUTES).addNumber(5));
			}
		}
	}

	private class DeathListener implements OnDeathListener
	{
		@Override
		public void onDeath(Creature self, Creature killer)
		{
			if(self.isNpc() && self.getNpcId() == FreyaThrone)
			{
				ThreadPoolManager.getInstance().schedule(new PreSecondStage(), 10);
				self.deleteMe();
			}
			else if(self.isNpc() && self.getNpcId() == IceKnightLeaderNormal)
			{
				ThreadPoolManager.getInstance().schedule(new PreThirdStage(), 10);
			}
			else if(self.isNpc() && self.getNpcId() == FreyaStandNormal)
			{
				ThreadPoolManager.getInstance().schedule(new FreyaDeathStage(), 10);
			}
		}
	}

	public class CurrentHpListener implements OnCurrentHpDamageListener
	{
		@Override
		public void onCurrentHpDamage(Creature actor, double damage, Creature attacker, Skill skill)
		{
			if(actor == null || actor.isDead() || actor.getNpcId() != FreyaStandNormal)
			{
				return;
			}
			double newHp = actor.getCurrentHp() - damage;
			double maxHp = actor.getMaxHp();
			if(!_freyaSlayed && newHp <= 0.2 * maxHp)
			{
				_freyaSlayed = true;
				ThreadPoolManager.getInstance().schedule(new PreForthStage(), 10);
				actor.removeListener(_currentHpListener);
			}
		}
	}

	public class ZoneListener implements OnZoneEnterLeaveListener
	{
		@Override
		public void onZoneEnter(Zone zone, Creature cha)
		{
			if(_entryLocked)
			{
				return;
			}

			Player player = cha.getPlayer();
			if(player == null || !cha.isPlayer())
			{
				return;
			}

			if(checkstartCond(raidplayers.incrementAndGet()))
			{
				ThreadPoolManager.getInstance().schedule(new StartNormalFreya(), 30000L);
				_startLaunched = true;
			}
		}

		@Override
		public void onZoneLeave(Zone zone, Creature cha)
		{
		}
	}

	public class ZoneListenerL implements OnZoneEnterLeaveListener
	{
		@Override
		public void onZoneEnter(Zone zone, Creature cha)
		{
			if(cha.isPlayer())
			{
				cha.sendPacket(new ExChangeClientEffectInfo(1));
			}
		}

		@Override
		public void onZoneLeave(Zone zone, Creature cha)
		{
		}
	}

	private boolean checkstartCond(int raidplayers)
	{
		return !(raidplayers < getInstancedZone().getMinParty() || _startLaunched);
	}

	private void doCleanup()
	{
		if(firstStageGuardSpawn != null)
		{
			firstStageGuardSpawn.cancel(true);
		}
		if(secondStageGuardSpawn != null)
		{
			secondStageGuardSpawn.cancel(true);
		}
		if(thirdStageGuardSpawn != null)
		{
			thirdStageGuardSpawn.cancel(true);
		}
	}

	@Override
	protected void onCollapse()
	{
		super.onCollapse();
		doCleanup();
	}
}

 

Hide  

 

Изменено пользователем darkseed

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
17 часов назад, Gaikotsu сказал:

еще как вариант, заведи в классе Player сессионные переменные, в которых можно будет хранить любые данные до перезахода в игру - чисто в памяти, без сохранения в бд. т.е. по сути аналог кукисов в вебе - таким образом можно будет обмениваться любыми данными между датапаком и ядром.

сделать это в виде обычной мапы <String, String> или <String, Object> к примеру.

и вот туда можешь к примеру положить координаты, а потом в любое время взять обратно по ключу мапы.

Кажется я что-то подобное сделал чтобы хранить принадлежность к командам в классе Player:
 

private int _l2arenaSide = -1;
public void setL2ArenaSide(final int i)
{
	_l2arenaSide = i;
}

public int getL2ArenaSide()
{
	return _l2arenaSide;
}

Впринципе сюда же можно сохранять координаты, в зависимости от тимы, вот только я не понял что такое map?
Я так понимаю есть класс Location, у которого есть метод set(int x, int y, int z);
Сейчас будет совсем глупый вопрос, а не могу ли я создать 2 объекта класса Location в классе Player, на подобии как я создал интовые _l2atenaSide, а потом сделать методы set() и get() для них?
Если да, то как правильно создать объект типа Location и как правильно настроить set() и get() для него по аналогии с моей _l2arenaSide ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
20 часов назад, darkseed сказал:
Извиняюсь что наверно не в теме есть инст фреи как из него выпилить проверку на командный канал ( тоесть что бы в инст можно было залазить 1й группой) и если не в коде то где можно это убрать. Заранее благодарен.

...

Скрыть

ну к примеру в стандартном овере/лосте тип инстанса определяется по количеству игроков что могут в него войти, т.е. по данным из хмлки, описывающей свойства этого инстанса - так что обычно достаточно там просто убавить количество до одной пати.

но к примеру я у себя давно доработал работу с инстансами в этом плане и у меня инстанс может быть одновременно как для пати, так и для кк, или к примеру для одиночного игрока или пати

хотя я вобще хорошо так перелопатил оригинальный оверовский формат хмлок с данными по инстансам :) 
--------------------------------------------------------------------------------
--- Описание структуры файлов, описывающих инстансы
---
--- Местонахождение: data/instances/*.xml
--------------------------------------------------------------------------------

Нода instance:
	id - идентификатор инстанса.
	name - название инстанса.

Так же может содержать в себе следующие субноды: params, return, teleport, spawns, doors, zones.

Субнода params:
	Содержит в себе субноды param, с атрибутами name и value - название параметра и его значение.

Допустимые параметры и их значения:
	entryType - тип инстанса. Допустимые значения: SOLO - для одного игрока, PARTY - для группы, COMMAND_CHANNEL -
		для командного канала. Можно перечислить несколько типов через точку с запятой. Если параметр не задан, то
		он определяется автоматически по параметру "players". Если перечисляется несколько типов входа, то для корректной
		работы желательно перечислять типы в следующем порядке: COMMAND_CHANNEL, PARTY, SOLO.
	levels - лимит уровней игроков. Строка вида "minLevel;maxLevel". Если не задан максимальный уровень, то он равен
		максимально достижимому уровню.
		Значение по умолчанию - 1;110.
	players - лимит количества игроков. Строка вида "minCount;maxCount". Если не задано максимальное количество, то
		оно равно минимальному количеству. Если не задан явно параметр "entryType", то именно от значения этого 
		параметра зависит то, какой тип выставится инстансу (соло, для пати, для КК): минимальное количество 
		равно 1 - соло; минимальное количество от 2 до 7 включительно и максимальное количество не больше 7 - для пати;
		максимальное количество больше 7 - для КК.
		Значение по умолчанию - 1;1.
	timeLimit - лимит времени инстанса, в минутах. Если значение больше 0, то при создании инстанса активируется задача, 
		закрывающая этот инстанс через заданное время.
		Значение по умолчанию - 0.
	maxChannels - лимит одновременно существующих инстансов данного вида. Указывает, сколько инстансов этого вида может
		существовать одновременно на сервере.
		Значение по умолчанию - 20.
	collapseIfEmpty - через сколько минут закрыть инстанс, если его покинули все игроки. При значении равном -1 функция 
		отключается.
		Значение по умолчанию - 0.
	collapseIfPartyDismiss - через сколько минут закрыть инстанс, если группа игроков, находящаяся в нем, была распущена.
		При значении равном 0 функция отключается.
		Значение по умолчанию - 1.
	collapseIfCommandChannelDismiss - через сколько минут закрыть инстанс, если командный канал игроков, находящихся в нем,
		был распущен. При значении равном 0 функция отключается.
		Значение по умолчанию - 0.
	kickIfDead - через сколько минут выбросить мертвого игрока из инстанса, если его никто за это время не воскресил.
		При значении равном 0 функция отключается.
		Значение по умолчанию - 1.
	dispelBuffs - снимать или нет все баффы с игроков при заходе в инстанс.
		Значение по умолчанию - false.
	timerMode - режим показа таймера, находящимся в инстансе игрокам. Допустимые значения: NONE - не показывать время,
		ELAPSED - прошло времени, REMAINING - осталось времени.
		Значение по умолчанию - NONE.
	timerTime - с какого значения, в секундах, начать отсчет времени на таймере.
		Значение по умолчанию - timeLimit * 60.
	removeItem - предметы, проверяемые у игроков при попытке входа в инстанс и удаляемые при успешном входе в него.
		Строка вида "itemId,itemId ... itemId;count;removeType". Если задано несколько разных предметов, то необходимо 
		наличие хотя бы одного из них. Если количество предметов не задано, то оно равно 1. Значение removeType отвечает
		за то, у кого будут удалены требуемые предметы: 0 - у всех входящих в инстанс; 1 - только у лидера группы/КК.
		Если значение removeType не задано, то оно равно 0. 
		Значение по умолчанию - 0;0;0.
	requiredItem - предметы, проверяемые у игроков при попытке входа в инстанс и не удаляемые при входе в него.
		Строка вида "itemId,itemId ... itemId;count". Если задано несколько разных предметов, то необходимо наличие
		хотя бы одного из них. Если количество предметов не задано, то оно равно 1.
		Значение по умолчанию - 0;0.
	giveItem - предметы, выдаваемые игрокам при входе в инстанс. Строка вида "itemId,itemId ... itemId;count". 
		Если количество предметов не задано, то оно равно 1.
		Значение по умолчанию - 0;0.
	geodata - сектор геодаты, в котором находится инстанс. Необходим в инстансах с дверями, т.к. без указания сектора
		в таком инстансе будут проблемы с проходом через открытые двери.
		Значение по умолчанию - сектор не задан.
	requiredQuestId - идентификатор начатого или выполненного квеста, который должен быть у игрока для входа в инстанс.
		При значении равном 0 наличие квеста не проверяется.
		Значение по умолчанию - 0.
	onlyStartedQuest - дополнительное условие для предыдущего параметра. Если равно true, то проверяются только начатые
		квесты.
		Значение по умолчанию - true.
	resetReuse - ближайшее время, в которое сбрасывается ограничение на вход в инстанс. Задается строкой в формате Cron.
		Значение по умолчанию - "* * * * *" (можно сразу же повторно зайти в инстанс).
	setReuseUponEntry - устанавливать или нет реюз при входе в инстанс. Если значение равно false, то реюз по необходимости
		необходимо выставлять игрокам вручную.
		Значение по умолчанию - true.
	sharedReuseGroup - общая группа реюза. У всех инстансов с одинаковой группой, со значением больше 0, будет выставляться
		одинаковый реюз.
		Значение по умолчанию - 0.
	removeVisitor - Удалять или нет вышедшего из инстанса игрока из списка посетивших этот инстанс. Может пригодиться для
		статичных инстансов, которые существуют после создания до выключения сервера.
		Значение по умолчанию - false.

Кроме того, можно задавать и свои параметры, читая их потом через метод getParams() инстанса.

Для параметров removeItem и requiredItem, кроме обычных предметов можно так же указывать очки PC Cafe (-100), славу (-300) и
рейдовые очки (-500) - в скобках указаны их идентификаторы.

Субнода return:
	loc - координаты, в которые перемещаются игроки при закрытии инстанса или выходе через SOE/смерть.

Субнода teleport (можно задавать несколько таких субнод):
	loc - координаты, в которые перемещаются игроки при телепорте в инстанс.

Субнода spawns:
	Может содержать в себе субноды group и spawn.

	Субнода group может иметь следующие атрибуты:
		name - название группы спавна.
		spawned - должна ли группа спавнится сразу же после создания инстанса. Значение по умолчанию - false.

	Субнода spawn может иметь следующие атрибуты:
		id - идентификаторы нпс. Строка вида "npcId;npcId ... npcId".
		count - количество нпс для спавна.
			Значение по умолчанию - 1.
		respawn - время респавна в секундах. При значении равном 0 респавн отключается.
			Значение по умолчанию - 0.
		respawnRnd - разброс времени респавна в секундах.
			Значение по умолчанию - 0.
		type - тип спавна. Может принимать следующие значения: 0 - точечный, в каждой указанной точке; 1 - один точечный 
			спаун в рандомной точке; 2 - локационный.
			Значение по умолчанию - 0.

	Так же данная субнода имеет субноды coords, в которых описываются точки спавна или территория, внутри которой будут 
	заспавлены нпс.

Субнода doors:
	Может содержать в себе субноды door, описывающие двери в инстансе.

	Субнода door может иметь следующие атрибуты:
		id - идентификатор двери.
		opened - начальное состояние двери. При значении равном true - открыта.
			Значение по умолчанию - false.
		invul - неуязвима или нет дверь.
			Значение по умолчанию - true.

Субнода zones:
	Может содержать в себе субноды zone, описывающие зоны в инстансе.

	Субнода zone может иметь следующие атрибуты:
		name - название зоны.
		active - начальное состояние зоны.
			Значение по умолчанию - false.

 

Скрыть  

 

Изменено пользователем Gaikotsu
  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
6 часов назад, pvpgate сказал:

Впринципе сюда же можно сохранять координаты, в зависимости от тимы, вот только я не понял что такое map?
Я так понимаю есть класс Location, у которого есть метод set(int x, int y, int z);
Сейчас будет совсем глупый вопрос, а не могу ли я создать 2 объекта класса Location в классе Player, на подобии как я создал интовые _l2atenaSide, а потом сделать методы set() и get() для них?
Если да, то как правильно создать объект типа Location и как правильно настроить set() и get() для него по аналогии с моей _l2arenaSide ?

1. Map/HashMap и т.п.

2. есть

3. можешь

4. да как хочешь, к примеру

private Location _loc;

public void setLoc(Location loc)
{
	_loc = loc;
}

public Location getLoc()
{
	return _loc;
}

и не забывай проверять на null значение возвращаемое getLoc, т.к. по умолчанию новосозданный объект равен null.

  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация  

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...