Noticias:

No tienes permiso para ver los enlaces. Para poder verlos Registrate o Conectate.

Menú Principal

Evento Deathmatch Engine by Intrepid

Iniciado por Swarlog, Jun 29, 2025, 12:08 AM

Tema anterior - Siguiente tema

Swarlog

/*
 * 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.azaria.events;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.Logger;

import javolution.util.FastMap;

import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.Announcements;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.instance.L2CubicInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.util.Broadcast;
import com.l2jserver.tools.random.Rnd;

/**
 * @author Intrepid
 *
 */
public class DeathMatch
{
	// declare logger
	private static final Logger _log = Logger.getLogger(DeathMatch.class.getName());
	
	// event name
	private static final String _eventName = "DeathMatch";
	
	// event finished and not started yet
	private static final int STATUS_NOT_IN_PROGRESS = 0;
	
	// event registration allowed
	private static final int STATUS_REGISTRATION = 1;
	
	// event registration ended and combat not started yet
	private static final int STATUS_PREPARATION = 2;
	
	// event players teleported to the event and combat starter
	private static final int STATUS_COMBAT = 3;
	
	// event combat ended wait setup for next event
	private static final int STATUS_NEXT_EVENT = 4;
	
	private static final String REMOVE_DISCONNECTED = "UPDATE characters SET heading=?,x=?,y=?,z=? WHERE charId=?";
	
	/**
	 * Initialize new/Returns the one and only instance<br><br>
	 *
	 * @return DeathMatch<br>
	 */
	public static DeathMatch getInstance()
	{
		return SingletonHolder._instance;
	}
	
	private static class SingletonHolder
	{
		protected static final DeathMatch _instance = new DeathMatch();
	}
	
	private final ThreadPoolManager				tpm;
	
	private final autoEventTask					task;
	private final reviveTask					taskDuring;
	private ScheduledFuture<?>					reviver;
	private ScheduledFuture<?>					event;
	private int									announced;
	
	private static FastMap<Integer,L2PcInstance>	players;
	
	private volatile int						status;
	private volatile boolean					active;
	
	/**
	 * private constructor
	 */
	private DeathMatch()
	{
		tpm = ThreadPoolManager.getInstance();
		status = STATUS_NOT_IN_PROGRESS;
		announced = 0;
		players = new FastMap<Integer,L2PcInstance>(Config.DM_MAX_PARTICIPANT);
		task = new autoEventTask();
		taskDuring = new reviveTask();
		reviver = null;
		active = Config.DM_ALLOWED;
		if (active)
		{
			tpm.scheduleGeneral(task, Config.DM_DELAY_INITIAL_REGISTRATION);
			_log.info("DeathMatch: Initialized event enabled.");
		}
		else
			_log.info("DeathMatch: Initialized but not enabled.");
	}
	
	private class autoEventTask implements Runnable
	{
		@Override
		public void run()
		{
			switch (status)
			{
				case STATUS_NOT_IN_PROGRESS:
					if (Config.DM_ALLOWED)
						registrationStart();
					else
						active = false;
					break;
				case STATUS_REGISTRATION:
					if (announced < (Config.DM_REGISTRATION_ANNOUNCEMENT_COUNT + 2))
						registrationAnnounce();
					else
						registrationEnd();
					break;
				case STATUS_PREPARATION:
					startEvent();
					break;
				case STATUS_COMBAT:
					endEvent();
					break;
				case STATUS_NEXT_EVENT:
					status = STATUS_NOT_IN_PROGRESS;
					tpm.scheduleGeneral(task, Config.DM_DELAY_BETWEEN_EVENTS);
					break;
				default:
					_log.severe("Incorrect status set in Automated " + _eventName + ", terminating the event!");
			}
		}
	}
	
	private class reviveTask implements Runnable
	{
		@Override
		public void run()
		{
			L2PcInstance player;
			for (L2PcInstance p : players.values())
			{
				player = p.getActingPlayer();
				if (player != null && player.isDead())
					revive(player);
			}
		}
	}
	

	public void registerPlayer(L2PcInstance player)
	{
		if (!active)
			return;
		
		if (status != STATUS_REGISTRATION || players.size() >= Config.DM_MAX_PARTICIPANT)
			player.sendPacket(SystemMessageId.REGISTRATION_PERIOD_OVER);
		else if(!players.containsValue(player))
		{
			if (!canJoin(player))
			{
				player.sendMessage("You can't join to the" + _eventName + " because you dont meet with the requirements!");
				return;
			}
			players.put(player.getObjectId(), player);
			player.sendMessage("You are successfully registered to: " + _eventName);
			if (Config.DM_REG_CANCEL)
				player.sendMessage("If you decide to cancel your registration use .leavedm!");
		}
		else
			player.sendMessage("You are alredy registered");
	}
	
	public void cancelRegistration(L2PcInstance player)
	{
		if (!active)
			return;
		
		if (status != STATUS_REGISTRATION)
			player.sendPacket(SystemMessageId.REGISTRATION_PERIOD_OVER);
		else if (players.containsValue(player))
		{
			players.remove(player);
			player.sendMessage("You successfully cancelled your registration in " + _eventName);
		}
		else
			player.sendMessage("You are not a participant in" + _eventName);
	}

	public void registrationStart()
	{
		status = STATUS_REGISTRATION;
		Announcements.getInstance().announceToAll(new SystemMessage(SystemMessageId.REGISTRATION_PERIOD));
		SystemMessage time = new SystemMessage(SystemMessageId.REGISTRATION_TIME_S1_S2_S3);
		long timeLeft = Config.DM_REGISTRATION_LENGHT/ 1000;
		time.addNumber((int) (timeLeft / 3600));
		time.addNumber((int) (timeLeft % 3600 / 60));
		time.addNumber((int) (timeLeft % 3600 % 60));
		Broadcast.toAllOnlinePlayers(time);
		Announcements.getInstance().announceToAll("To join the " + _eventName + " you must type .joindm");
		tpm.scheduleGeneral(task, Config.DM_REGISTRATION_LENGHT / (Config.DM_REGISTRATION_ANNOUNCEMENT_COUNT + 2));
	}

	public void registrationAnnounce()
	{
		SystemMessage time = new SystemMessage(SystemMessageId.REGISTRATION_TIME_S1_S2_S3);
		long timeLeft = Config.DM_REGISTRATION_LENGHT;
		long elapsed = timeLeft / (Config.DM_REGISTRATION_ANNOUNCEMENT_COUNT + 2) * announced;
		timeLeft -= elapsed;
		timeLeft /= 1000;
		time.addNumber((int) (timeLeft / 3600));
		time.addNumber((int) (timeLeft % 3600 / 60));
		time.addNumber((int) (timeLeft % 3600 % 60));
		Broadcast.toAllOnlinePlayers(time);
		Announcements.getInstance().announceToAll("To join the " + _eventName + " you must type .joindm");
		announced++;
		tpm.scheduleGeneral(task, Config.DM_REGISTRATION_LENGHT / (Config.DM_REGISTRATION_ANNOUNCEMENT_COUNT + 2));
	}
	
	public void registrationEnd()
	{
		announced = 0;
		status = STATUS_PREPARATION;
		
		for (L2PcInstance p : players.values())
		{
			if (p == null)
				continue;
			if (!canJoin(p))
			{
				p.sendMessage("You can't join to the" + _eventName + " because you dont meet with the requirements!");
				players.remove(p);
			}
		}
		
		if (players.size() <= Config.DM_MIN_PLAYER)
		{
			Announcements.getInstance().announceToAll(_eventName + "aborted not enough players!");
			players.clear();
			status = STATUS_NOT_IN_PROGRESS;
			tpm.scheduleGeneral(task, Config.DM_DELAY_BETWEEN_EVENTS);
			return;
		}
		
		SystemMessage time = new SystemMessage(SystemMessageId.BATTLE_BEGINS_S1_S2_S3);
		long timeLeft = Config.DM_PREPARATION_LENGHT / 1000;
		time.addNumber((int) (timeLeft / 3600));
		time.addNumber((int) (timeLeft % 3600 / 60));
		time.addNumber((int) (timeLeft % 3600 % 60));
		
		for (L2PcInstance p : players.values())
		{
			if (p == null)
				continue;
			
			p.setIsParalyzed(true);
			p.sendPacket(time);
			checkEquipment(p);
			if (Config.DM_CANCEL_PARTY_ONSTART && p.getParty() != null)
				p.getParty().removePartyMember(p);
			if (Config.DM_CANCEL_BUFF_ONSTART)
				p.stopAllEffects();
			if (Config.DM_CANCEL_CUBIC_ONSTART && !p.getCubics().isEmpty())
			{
				for (L2CubicInstance cubic : p.getCubics().values())
				{
					cubic.stopAction();
					cubic.cancelDisappear();
				}
				p.getCubics().clear();
			}
			if (Config.DM_UNSUMMON_PET_ONSTART && p.getPet() != null)
				p.getPet().unSummon(p);
			if (Config.DM_CANCEL_TRANSFORM_ONSTART && p.isTransformed())
				p.untransform();
			if (p.isDead())
				p.setIsPendingRevive(true);
			
			int spawn = Rnd.get(2);
			if (spawn == 0)
				p.teleToLocation(Config.DM_LOCX1,Config.DM_LOCY1,Config.DM_LOCZ1);
			if (spawn == 1)
				p.teleToLocation(Config.DM_LOCX2,Config.DM_LOCY2,Config.DM_LOCZ2);
			
			if (Config.DM_RECOVER_ONSTART && p.getCurrentCp() != p.getMaxCp() || p.getCurrentHp() != p.getMaxHp() || p.getCurrentMp() != p.getMaxMp())
			{
				p.getStatus().setCurrentCp(p.getMaxCp());
				p.getStatus().setCurrentHpMp(p.getMaxHp(), p.getMaxMp());
			}
		}
		tpm.scheduleGeneral(task, Config.DM_PREPARATION_LENGHT);
	}
	
	public void startEvent()
	{
		status = STATUS_COMBAT;
		SystemMessage time = new SystemMessage(SystemMessageId.BATTLE_ENDS_S1_S2_S3);
		long timeLeft = Config.DM_EVENT_LENGHT / 1000;
		time.addNumber((int) (timeLeft / 3600));
		time.addNumber((int) (timeLeft % 3600 / 60));
		time.addNumber((int) (timeLeft % 3600 % 60));
		L2PcInstance player;
		for (L2PcInstance p : players.values())
		{
			player = p.getActingPlayer();
			if (player == null)
				continue;
			player.setIsParalyzed(false);
			player.sendPacket(time);
		}
		reviver = tpm.scheduleGeneralAtFixedRate(taskDuring, Config.DM_REVIVE_DELAY, Config.DM_REVIVE_DELAY);
		event = tpm.scheduleGeneral(task, Config.DM_EVENT_LENGHT);
	}
	
	public void endEvent()
	{
		if (status != STATUS_COMBAT)
			return;
		status = STATUS_NEXT_EVENT;
		reviver.cancel(true);
		if (!event.cancel(false))
			return;
		
		Announcements.getInstance().announceToAll(_eventName + " is finished!");
		
		L2PcInstance player;
		for (L2PcInstance p : players.values())
		{
			player = p.getActingPlayer();
			if (player == null)
			{
				removeDisconnected(p.getObjectId(), p);
				continue;
			}
			removeFromEvent(player);
		}
		players.clear();
		tpm.scheduleGeneral(task, Config.DM_ENDING_LENGHT);
	}
	
	private void revive(L2PcInstance player)
	{
		player.setIsPendingRevive(true);
		int teleTo = Rnd.get(1);
		if (teleTo == 1)
			player.teleToLocation(Config.DM_RANDOM_RESPAWN1_X, Config.DM_RANDOM_RESPAWN1_Y, Config.DM_RANDOM_RESPAWN1_Z);
		if (teleTo == 2)
			player.teleToLocation(Config.DM_RANDOM_RESPAWN2_X, Config.DM_RANDOM_RESPAWN2_Y, Config.DM_RANDOM_RESPAWN2_Z);
	}
	
	private boolean canJoin(L2PcInstance player)
	{
		// level restriction
		boolean can = player.getLevel() <= Config.DM_MAX_LVL;
		can &= player.getLevel() >= Config.DM_MIN_LVL;
		// hero restriction
		if (!Config.DM_HERO_JOIN)
			can &= !player.isHero();
		// cw owner restriction
		if (Config.DM_CWOWNER_JOIN)
			can &= !player.isCursedWeaponEquipped();
		return can;
	}
	
	private final void checkEquipment(L2PcInstance player)
	{
		L2ItemInstance item;
		for (int i = 0; i < 25; i++)
		{
			synchronized (player.getInventory())
			{
				item = player.getInventory().getPaperdollItem(i);
				if (item != null && !canUse(item.getItemId()))
					player.useEquippableItem(item, true);
			}
		}
	}
	
	public static final boolean canUse(int itemId)
	{
		for (int id : Config.DM_DISALLOWED_ITEMS)
			if (itemId == id)
				return false;
		return true;
	}
	
	private void removeFromEvent(L2PcInstance player)
	{
		if (!player.isDead())
		{
			player.getStatus().setCurrentCp(player.getMaxCp());
			player.getStatus().setCurrentHpMp(player.getMaxHp(), player.getMaxMp());
		}
		else
			player.setIsPendingRevive(true);
		player.teleToLocation(Config.DM_TELE_BACK_X, Config.DM_TELE_BACK_Y, Config.DM_TELE_BACK_Z);
	}
	
	public final void removeDisconnected(int objID,L2PcInstance player)
	{
		Connection con = null;
		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement ps = con.prepareStatement(REMOVE_DISCONNECTED);
			ps.setInt(1, player.getHeading());
			ps.setInt(2, Config.DM_TELE_BACK_X);
			ps.setInt(3, Config.DM_TELE_BACK_Y);
			ps.setInt(4, Config.DM_TELE_BACK_Z);
			ps.setInt(5, objID);
			ps.executeUpdate();
			ps.close();
		}
		catch (SQLException e)
		{
			_log.log(Level.WARNING,"Could not remove a disconnected DM player!", e);
		}
		finally
		{
			L2DatabaseFactory.close(con);
		}
	}
	
	public final void addDisconnected(L2PcInstance participant)
	{
		switch (status)
		{
			case STATUS_REGISTRATION:
				if (Config.DM_REGISTER_AFTER_RELOG && !players.containsValue(participant))
					registerPlayer(participant);
				break;
			case STATUS_COMBAT:
				L2PcInstance p = players.get(participant.getObjectId());
				if (p == null)
					break;
				players.put(participant.getObjectId(), participant);
				checkEquipment(participant);
				int spawn = Rnd.get(2);
				if (spawn == 0)
					participant.teleToLocation(Config.DM_LOCX1,Config.DM_LOCY1,Config.DM_LOCZ1);
				if (spawn == 1)
					participant.teleToLocation(Config.DM_LOCX2,Config.DM_LOCY2,Config.DM_LOCZ2);
				break;
		}
	}
	
	public final void onKill(L2Character killer,L2PcInstance killed)
	{
		if (status != STATUS_COMBAT)
			return;
		
		((L2PcInstance) killer).addItem("DEATHMACH", Config.DM_REWARD_ID, Config.DM_REWARD_COUNT, killer, false);
		killer.sendMessage(killer + "killed: " + killed);
		killed.sendMessage(killed + "killed by: " + killer);
	}
	
	
	public static final boolean isInProgress()
	{
		switch (getInstance().status)
		{
		case STATUS_PREPARATION:
		case STATUS_COMBAT:
			return true;
		default:
			return false;
		}
	}
	
	public static final boolean isPlaying(L2PcInstance player)
	{
		return isInProgress() && isMember(player);
	}
	
	public static final boolean isMember(L2PcInstance player)
	{
		if (player == null)
			return false;
		
		switch (getInstance().status)
		{
			case STATUS_NOT_IN_PROGRESS:
				return false;
			case STATUS_REGISTRATION:
				return players.containsValue(player);
			case STATUS_PREPARATION:
				return players.containsValue(player) || isMember(player.getObjectId());
			case STATUS_COMBAT:
			case STATUS_NEXT_EVENT:
				return isMember(player.getObjectId());
			default:
				return false;
		}
	}
	
	private final static boolean isMember(int oID)
	{
		return players.get(oID) != null;
	}
}