l2j_mobius/trunk/java/com/l2jmobius/gameserver/model/ceremonyofchaos/CeremonyOfChaosEvent.java
2016-06-12 01:34:09 +00:00

524 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.model.ceremonyofchaos;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.l2jmobius.gameserver.enums.CeremonyOfChaosResult;
import com.l2jmobius.gameserver.instancemanager.CeremonyOfChaosManager;
import com.l2jmobius.gameserver.instancemanager.InstanceManager;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2Party.MessageType;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.appearance.PcAppearance;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.eventengine.AbstractEvent;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.ListenerRegisterType;
import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import com.l2jmobius.gameserver.model.events.annotations.RegisterType;
import com.l2jmobius.gameserver.model.events.impl.ceremonyofchaos.OnCeremonyOfChaosMatchResult;
import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureDeath;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.instancezone.Instance;
import com.l2jmobius.gameserver.model.instancezone.InstanceTemplate;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
import com.l2jmobius.gameserver.network.serverpackets.ExUserInfoAbnormalVisualEffect;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.SkillCoolTime;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.appearance.ExCuriousHouseMemberUpdate;
import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseEnter;
import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseLeave;
import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseMemberList;
import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseObserveMode;
import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseRemainTime;
import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseResult;
/**
* @author UnAfraid
*/
public class CeremonyOfChaosEvent extends AbstractEvent<CeremonyOfChaosMember>
{
private static final Logger LOGGER = Logger.getLogger(CeremonyOfChaosEvent.class.getName());
private final int _id;
private final Instance _instance;
private final Set<L2MonsterInstance> _monsters = ConcurrentHashMap.newKeySet();
private long _battleStartTime = 0;
public CeremonyOfChaosEvent(int id, InstanceTemplate template)
{
_id = id;
_instance = InstanceManager.getInstance().createInstance(template, null);
if (_instance.getEnterLocations().size() < CeremonyOfChaosManager.getInstance().getMaxPlayersInArena())
{
LOGGER.warning("There are more member slots: " + _instance.getEnterLocations().size() + " then instance entrance positions: " + CeremonyOfChaosManager.getInstance().getMaxPlayersInArena() + "!");
}
}
public int getId()
{
return _id;
}
public int getInstanceId()
{
return _instance.getId();
}
public Instance getInstance()
{
return _instance;
}
public Set<L2MonsterInstance> getMonsters()
{
return _monsters;
}
public void preparePlayers()
{
final ExCuriousHouseMemberList membersList = new ExCuriousHouseMemberList(_id, CeremonyOfChaosManager.getInstance().getMaxPlayersInArena(), getMembers().values());
final NpcHtmlMessage msg = new NpcHtmlMessage(0);
int index = 0;
for (CeremonyOfChaosMember member : getMembers().values())
{
final L2PcInstance player = member.getPlayer();
if (player.inObserverMode())
{
player.leaveObserverMode();
}
if (player.isInDuel())
{
player.setIsInDuel(0);
}
// Remember player's last location
player.setLastLocation();
// Hide player information
final PcAppearance app = player.getAppearance();
app.setVisibleName("Challenger" + member.getPosition());
app.setVisibleTitle("");
app.setVisibleClanData(0, 0, 0, 0, 0);
// Register the event instance
player.registerOnEvent(this);
// Load the html
msg.setFile(player.getHtmlPrefix(), "data/html/CeremonyOfChaos/started.htm");
// Remove buffs
player.stopAllEffectsExceptThoseThatLastThroughDeath();
// Player shouldn't be able to move and is hidden
player.setIsImmobilized(true);
player.setInvisible(true);
// Same goes for summon
player.getServitors().values().forEach(s ->
{
s.stopAllEffectsExceptThoseThatLastThroughDeath();
s.setInvisible(true);
s.setIsImmobilized(true);
});
if (player.isFlyingMounted())
{
player.untransform();
}
// If player is dead, revive it
if (player.isDead())
{
player.doRevive();
}
// If player is sitting, stand up
if (player.isSitting())
{
player.standUp();
}
// If player in party, leave it
final L2Party party = player.getParty();
if (party != null)
{
party.removePartyMember(player, MessageType.EXPELLED);
}
// Cancel any started action
player.abortAttack();
player.abortCast();
player.stopMove(null);
player.setTarget(null);
// Unsummon pet
final L2Summon pet = player.getPet();
if (pet != null)
{
pet.unSummon(player);
}
// Unsummon agathion
if (player.getAgathionId() > 0)
{
player.setAgathionId(0);
}
// The character’s HP, MP, and CP are fully recovered.
player.setCurrentHp(player.getMaxHp());
player.setCurrentMp(player.getMaxMp());
player.setCurrentCp(player.getMaxCp());
// Skill reuse timers for all skills that have less than 15 minutes of cooldown time are reset.
for (Skill skill : player.getAllSkills())
{
if (skill.getReuseDelay() <= 900000)
{
player.enableSkill(skill);
}
}
player.sendSkillList();
player.sendPacket(new SkillCoolTime(player));
// Apply the Energy of Chaos skill
for (SkillHolder holder : CeremonyOfChaosManager.getInstance().getVariables().getList(CeremonyOfChaosManager.INITIAL_BUFF_KEY, SkillHolder.class))
{
holder.getSkill().activateSkill(player, player);
}
// Send Enter packet
player.sendPacket(ExCuriousHouseEnter.STATIC_PACKET);
// Send all members
player.sendPacket(membersList);
// Send the entrance html
player.sendPacket(msg);
// Send support items to player
for (ItemHolder holder : CeremonyOfChaosManager.getInstance().getRewards(CeremonyOfChaosManager.INITIAL_ITEMS_KEY).calculateDrops())
{
player.addItem("CoC", holder, null, true);
}
// Teleport player to the arena
player.teleToLocation(_instance.getEnterLocations().get(index++), 0, _instance);
}
getTimers().addTimer("match_start_countdown", StatsSet.valueOf("time", 60), 100, null, null);
getTimers().addTimer("teleport_message1", 10000, null, null);
getTimers().addTimer("teleport_message2", 14000, null, null);
getTimers().addTimer("teleport_message3", 18000, null, null);
}
public void startFight()
{
for (CeremonyOfChaosMember member : getMembers().values())
{
final L2PcInstance player = member.getPlayer();
if (player != null)
{
player.sendPacket(SystemMessageId.THE_MATCH_HAS_STARTED_FIGHT);
player.setIsImmobilized(false);
player.setInvisible(false);
player.broadcastInfo();
player.sendPacket(new ExUserInfoAbnormalVisualEffect(player));
player.getServitors().values().forEach(s ->
{
s.setInvisible(false);
s.setIsImmobilized(false);
s.broadcastInfo();
});
}
}
_battleStartTime = System.currentTimeMillis();
getTimers().addRepeatingTimer("update", 1000, null, null);
}
public void stopFight()
{
getMembers().values().stream().filter(p -> p.getLifeTime() == 0).forEach(this::updateLifeTime);
validateWinner();
final List<CeremonyOfChaosMember> winners = getWinners();
final List<CeremonyOfChaosMember> members = new ArrayList<>(getMembers().size());
final SystemMessage msg;
if (winners.isEmpty() || (winners.size() > 1))
{
msg = SystemMessage.getSystemMessage(SystemMessageId.THERE_IS_NO_VICTOR_THE_MATCH_ENDS_IN_A_TIE);
}
else
{
msg = SystemMessage.getSystemMessage(SystemMessageId.CONGRATULATIONS_C1_YOU_WIN_THE_MATCH);
msg.addCharName(winners.get(0).getPlayer());
}
for (CeremonyOfChaosMember member : getMembers().values())
{
final L2PcInstance player = member.getPlayer();
if (player != null)
{
// Send winner message
player.sendPacket(msg);
// Send result
player.sendPacket(new ExCuriousHouseResult(member.getResultType(), this));
members.add(member);
}
}
getTimers().cancelTimer("update", null, null);
getTimers().addTimer("match_end_countdown", StatsSet.valueOf("time", 30), 30 * 1000, null, null);
EventDispatcher.getInstance().notifyEvent(new OnCeremonyOfChaosMatchResult(winners, members));
}
private void teleportPlayersOut()
{
for (CeremonyOfChaosMember member : getMembers().values())
{
final L2PcInstance player = member.getPlayer();
if (player != null)
{
// Leaves observer mode
if (player.inObserverMode())
{
player.setObserving(false);
}
// Revive the player
player.doRevive();
// Remove Energy of Chaos
for (SkillHolder holder : CeremonyOfChaosManager.getInstance().getVariables().getList(CeremonyOfChaosManager.INITIAL_BUFF_KEY, SkillHolder.class))
{
player.stopSkillEffects(holder.getSkill());
}
// Apply buffs on players
for (SkillHolder holder : CeremonyOfChaosManager.getInstance().getVariables().getList(CeremonyOfChaosManager.END_BUFFS_KEYH, SkillHolder.class))
{
holder.getSkill().activateSkill(player, player);
}
// Remove quit button
player.sendPacket(ExCuriousHouseLeave.STATIC_PACKET);
// Remove spectator mode
player.setObserving(false);
player.sendPacket(ExCuriousHouseObserveMode.STATIC_DISABLED);
// Teleport player back
player.teleToLocation(player.getLastLocation(), null);
// Restore player information
final PcAppearance app = player.getAppearance();
app.setVisibleName(null);
app.setVisibleTitle(null);
app.setVisibleClanData(-1, -1, -1, -1, -1);
// Remove player from event
player.removeFromEvent(this);
}
}
getMembers().clear();
_instance.destroy();
}
private void updateLifeTime(CeremonyOfChaosMember member)
{
member.setLifeTime(((int) (System.currentTimeMillis() - _battleStartTime) / 1000));
}
public List<CeremonyOfChaosMember> getWinners()
{
final List<CeremonyOfChaosMember> winners = new ArrayList<>();
//@formatter:off
final OptionalInt winnerLifeTime = getMembers().values().stream()
.mapToInt(CeremonyOfChaosMember::getLifeTime)
.max();
if(winnerLifeTime.isPresent())
{
getMembers().values().stream()
.sorted(Comparator.comparingLong(CeremonyOfChaosMember::getLifeTime)
.reversed()
.thenComparingInt(CeremonyOfChaosMember::getScore)
.reversed())
.filter(member -> member.getLifeTime() == winnerLifeTime.getAsInt())
.collect(Collectors.toCollection(() -> winners));
}
//@formatter:on
return winners;
}
private void validateWinner()
{
final List<CeremonyOfChaosMember> winners = getWinners();
winners.forEach(winner -> winner.setResultType(winners.size() > 1 ? CeremonyOfChaosResult.TIE : CeremonyOfChaosResult.WIN));
}
@Override
public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "update":
{
final int time = (int) CeremonyOfChaosManager.getInstance().getScheduler("stopFight").getRemainingTime(TimeUnit.SECONDS);
broadcastPacket(new ExCuriousHouseRemainTime(time));
getMembers().values().forEach(p -> broadcastPacket(new ExCuriousHouseMemberUpdate(p)));
// Validate winner
if (getMembers().values().stream().filter(member -> !member.isDefeated()).count() <= 1)
{
stopFight();
}
break;
}
case "teleport_message1":
{
broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.PROVE_YOUR_ABILITIES));
break;
}
case "teleport_message2":
{
broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.THERE_ARE_NO_ALLIES_HERE_EVERYONE_IS_AN_ENEMY));
break;
}
case "teleport_message3":
{
broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.IT_WILL_BE_A_LONELY_BATTLE_BUT_I_WISH_YOU_VICTORY));
break;
}
case "match_start_countdown":
{
final int time = params.getInt("time", 0);
final SystemMessage countdown = SystemMessage.getSystemMessage(SystemMessageId.THE_MATCH_WILL_START_IN_S1_SECOND_S);
countdown.addByte(time);
broadcastPacket(countdown);
// Reschedule
if (time == 60)
{
getTimers().addTimer(event, params.set("time", 30), 30 * 1000, null, null);
}
else if ((time == 30) || (time == 20))
{
getTimers().addTimer(event, params.set("time", time - 10), 10 * 1000, null, null);
}
else if (time == 10)
{
getTimers().addTimer(event, params.set("time", 5), 5 * 1000, null, null);
}
else if ((time > 1) && (time <= 5))
{
getTimers().addTimer(event, params.set("time", time - 1), 1000, null, null);
}
break;
}
case "match_end_countdown":
{
final int time = params.getInt("time", 0);
final SystemMessage countdown = SystemMessage.getSystemMessage(SystemMessageId.IN_S1_SECOND_S_YOU_WILL_BE_MOVED_TO_WHERE_YOU_WERE_BEFORE_PARTICIPATING_IN_THE_CEREMONY_OF_CHAOS);
countdown.addByte(time);
broadcastPacket(countdown);
// Reschedule
if ((time == 30) || (time == 20))
{
getTimers().addTimer(event, params.set("time", time - 10), 10 * 1000, null, null);
}
else if ((time > 0) && (time <= 10))
{
getTimers().addTimer(event, params.set("time", time - 1), 1000, null, null);
}
else if (time == 0)
{
teleportPlayersOut();
}
break;
}
}
}
@RegisterEvent(EventType.ON_CREATURE_DEATH)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onPlayerDeath(OnCreatureDeath event)
{
if (event.getAttacker().isPlayer() && event.getTarget().isPlayer())
{
final L2PcInstance attackerPlayer = event.getAttacker().getActingPlayer();
final L2PcInstance targetPlayer = event.getTarget().getActingPlayer();
final CeremonyOfChaosMember attackerMember = getMembers().get(attackerPlayer.getObjectId());
final CeremonyOfChaosMember targetMember = getMembers().get(targetPlayer.getObjectId());
final DeleteObject deleteObject = new DeleteObject(targetPlayer);
if ((attackerMember != null) && (targetMember != null))
{
attackerMember.incrementScore();
updateLifeTime(targetMember);
// Mark player as defeated
targetMember.setDefeated(true);
// Delete target player
//@formatter:off
getMembers().values().stream()
.filter(member -> member.getObjectId() != targetPlayer.getObjectId())
.map(CeremonyOfChaosMember::getPlayer)
.forEach(deleteObject::sendTo);
//@formatter:on
// Make the target observer
targetPlayer.setObserving(true);
// Make the target spectator
targetPlayer.sendPacket(ExCuriousHouseObserveMode.STATIC_ENABLED);
}
}
}
}