Browse Source

BETA: Implementing retail-like clan leader changes:
* Note: In retail clan leader change requests are applied during maintenance here we'll schedule this to Tuesday (Or any other day you set in config).
* Instant clan leader changes are still possible but disabled by default.
* You can apply pending clan leader changes before Tuesday via admin command: '''!//clan_show_pending''' .

* Reviewed by: Zoey76, Tryskell
* Requires: [DP9492]

Rumen Nikiforov 12 years ago
parent
commit
2b942b8a45

+ 21 - 0
L2J_Server_BETA/dist/game/config/Character.properties

@@ -528,6 +528,27 @@ StoreRecipeShopList = False
 # Clan
 # ---------------------------------------------------------------------------
 
+# Day on which all pending clan leader requests will be applied:
+# Possible values:
+# 1 - Sunday
+# 2 - Monday
+# 3 - Tuesday
+# 4 - Wednesday
+# 5 - Thursday
+# 6 - Friday
+# 7 - Saturday
+# Default: 3
+AltClanLeaderDateChange = 3
+
+# Hour on which all pending data requests will be applied:
+# Format: Hour:Minute:Second
+# Default: 00:00:00
+AltClanLeaderHourChange = 00:00:00
+
+# When enabled all clan leader requests will be performed instantly.
+# Default: False
+AltClanLeaderInstantActivation = False
+
 # Number of days you have to wait before joining another clan.
 # Default: 1
 DaysBeforeJoinAClan = 1

+ 11 - 0
L2J_Server_BETA/java/com/l2jserver/Config.java

@@ -203,6 +203,9 @@ public final class Config
 	public static double ALT_GAME_CREATION_RARE_XPSP_RATE;
 	public static double ALT_GAME_CREATION_SP_RATE;
 	public static boolean ALT_BLACKSMITH_USE_RECIPES;
+	public static int ALT_CLAN_LEADER_DATE_CHANGE;
+	public static String ALT_CLAN_LEADER_HOUR_CHANGE;
+	public static boolean ALT_CLAN_LEADER_INSTANT_ACTIVATION;
 	public static int ALT_CLAN_JOIN_DAYS;
 	public static int ALT_CLAN_CREATE_DAYS;
 	public static int ALT_CLAN_DISSOLVE_DAYS;
@@ -1665,6 +1668,14 @@ public final class Config
 			ALT_GAME_CREATION_SP_RATE = Double.parseDouble(Character.getProperty("AltGameCreationSpRate", "1"));
 			ALT_GAME_CREATION_RARE_XPSP_RATE = Double.parseDouble(Character.getProperty("AltGameCreationRareXpSpRate", "2"));
 			ALT_BLACKSMITH_USE_RECIPES = Boolean.parseBoolean(Character.getProperty("AltBlacksmithUseRecipes", "true"));
+			ALT_CLAN_LEADER_DATE_CHANGE = Integer.parseInt(Character.getProperty("AltClanLeaderDateChange", "3"));
+			if ((ALT_CLAN_LEADER_DATE_CHANGE < 1) || (ALT_CLAN_LEADER_DATE_CHANGE > 7))
+			{
+				_log.log(Level.WARNING, "Wrong value specified for AltClanLeaderDateChange: " + ALT_CLAN_LEADER_DATE_CHANGE);
+				ALT_CLAN_LEADER_DATE_CHANGE = 3;
+			}
+			ALT_CLAN_LEADER_HOUR_CHANGE = Character.getProperty("AltClanLeaderHourChange", "00:00:00");
+			ALT_CLAN_LEADER_INSTANT_ACTIVATION = Boolean.parseBoolean(Character.getProperty("AltClanLeaderInstantActivation", "false"));
 			ALT_CLAN_JOIN_DAYS = Integer.parseInt(Character.getProperty("DaysBeforeJoinAClan", "1"));
 			ALT_CLAN_CREATE_DAYS = Integer.parseInt(Character.getProperty("DaysBeforeCreateAClan", "10"));
 			ALT_CLAN_DISSOLVE_DAYS = Integer.parseInt(Character.getProperty("DaysToPassToDissolveAClan", "7"));

+ 1 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/idfactory/IdFactory.java

@@ -286,6 +286,7 @@ public abstract class IdFactory
 			
 			// Update needed items after cleaning has taken place.
 			stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
+			stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
 			stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
 			stmt.executeUpdate("UPDATE castle SET taxpercent=0 WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
 			stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");

+ 104 - 52
L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2Clan.java

@@ -36,6 +36,7 @@ import com.l2jserver.L2DatabaseFactory;
 import com.l2jserver.gameserver.cache.CrestCache;
 import com.l2jserver.gameserver.communitybbs.BB.Forum;
 import com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager;
+import com.l2jserver.gameserver.datatables.CharNameTable;
 import com.l2jserver.gameserver.datatables.ClanTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
 import com.l2jserver.gameserver.instancemanager.CastleManager;
@@ -64,7 +65,6 @@ import com.l2jserver.gameserver.network.serverpackets.PledgeShowMemberListUpdate
 import com.l2jserver.gameserver.network.serverpackets.PledgeSkillList;
 import com.l2jserver.gameserver.network.serverpackets.PledgeSkillList.SubPledgeSkill;
 import com.l2jserver.gameserver.network.serverpackets.PledgeSkillListAdd;
-import com.l2jserver.gameserver.network.serverpackets.SkillCoolTime;
 import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
 import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
 import com.l2jserver.gameserver.network.serverpackets.UserInfo;
@@ -82,8 +82,8 @@ public class L2Clan
 	private static final Logger _log = Logger.getLogger(L2Clan.class.getName());
 	
 	// SQL queries
-	private static final String INSERT_CLAN_DATA = "INSERT INTO clan_data (clan_id,clan_name,clan_level,hasCastle,blood_alliance_count,blood_oath_count,ally_id,ally_name,leader_id,crest_id,crest_large_id,ally_crest_id) values (?,?,?,?,?,?,?,?,?,?,?,?)";
-	private static final String SELECT_CLAN_DATA = "SELECT clan_name,clan_level,hasCastle,blood_alliance_count,blood_oath_count,ally_id,ally_name,leader_id,crest_id,crest_large_id,ally_crest_id,reputation_score,auction_bid_at,ally_penalty_expiry_time,ally_penalty_type,char_penalty_expiry_time,dissolving_expiry_time FROM clan_data where clan_id=?";
+	private static final String INSERT_CLAN_DATA = "INSERT INTO clan_data (clan_id,clan_name,clan_level,hasCastle,blood_alliance_count,blood_oath_count,ally_id,ally_name,leader_id,crest_id,crest_large_id,ally_crest_id,new_leader_id) values (?,?,?,?,?,?,?,?,?,?,?,?,?)";
+	private static final String SELECT_CLAN_DATA = "SELECT * FROM clan_data where clan_id=?";
 	
 	// Ally Penalty Types
 	/** Clan leaved ally */
@@ -188,6 +188,7 @@ public class L2Clan
 	private String _notice;
 	private boolean _noticeEnabled = false;
 	private static final int MAX_NOTICE_LENGTH = 8192;
+	private int _newLeaderId;
 	
 	/**
 	 * Called if a clan is referenced only by id. In this case all other data needs to be fetched from db
@@ -257,68 +258,92 @@ public class L2Clan
 	
 	public void setNewLeader(L2ClanMember member)
 	{
-		if (!getLeader().isOnline())
+		final L2PcInstance newLeader = member.getPlayerInstance();
+		final L2ClanMember exMember = getLeader();
+		final L2PcInstance exLeader = exMember.getPlayerInstance();
+		
+		if (!fireClanLeaderChangeListeners(newLeader, exLeader))
 		{
 			return;
 		}
-		if (member == null)
+		
+		if (exLeader != null)
 		{
-			return;
+			if (exLeader.isFlying())
+			{
+				exLeader.dismount();
+			}
+			
+			if (getLevel() >= SiegeManager.getInstance().getSiegeClanMinLevel())
+			{
+				SiegeManager.getInstance().removeSiegeSkills(exLeader);
+			}
+			exLeader.setClanPrivileges(L2Clan.CP_NOTHING);
+			exLeader.broadcastUserInfo();
+			
 		}
-		if (!member.isOnline())
+		else
 		{
-			return;
+			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+				PreparedStatement statement = con.prepareStatement("UPDATE characters SET clan_privs = ? WHERE charId = ?"))
+			{
+				statement.setInt(1, L2Clan.CP_NOTHING);
+				statement.setInt(2, getLeaderId());
+				statement.execute();
+			}
+			catch (Exception e)
+			{
+				_log.log(Level.WARNING, "Couldn't update clan privs for old clan leader", e);
+			}
 		}
 		
-		L2PcInstance exLeader = getLeader().getPlayerInstance();
-		L2PcInstance newLeader = member.getPlayerInstance();
-		if (!fireClanLeaderChangeListeners(newLeader, exLeader))
+		setLeader(member);
+		if (getNewLeaderId() != 0)
 		{
-			return;
+			setNewLeaderId(0, true);
 		}
-		
-		SiegeManager.getInstance().removeSiegeSkills(exLeader);
-		exLeader.setClan(this);
-		exLeader.setClanPrivileges(L2Clan.CP_NOTHING);
-		exLeader.broadcastUserInfo();
-		
-		setLeader(member);
 		updateClanInDB();
 		
-		exLeader.setPledgeClass(L2ClanMember.calculatePledgeClass(exLeader));
-		exLeader.broadcastUserInfo();
-		exLeader.checkItemRestriction();
-		newLeader.setClan(this);
-		newLeader.setPledgeClass(L2ClanMember.calculatePledgeClass(newLeader));
-		newLeader.setClanPrivileges(L2Clan.CP_ALL);
-		if (getLevel() >= SiegeManager.getInstance().getSiegeClanMinLevel())
+		if (exLeader != null)
+		{
+			exLeader.setPledgeClass(L2ClanMember.calculatePledgeClass(exLeader));
+			exLeader.broadcastUserInfo();
+			exLeader.checkItemRestriction();
+		}
+		
+		if (newLeader != null)
 		{
-			SiegeManager.getInstance().addSiegeSkills(newLeader);
+			newLeader.setPledgeClass(L2ClanMember.calculatePledgeClass(newLeader));
+			newLeader.setClanPrivileges(L2Clan.CP_ALL);
 			
-			// Transferring siege skills TimeStamps from old leader to new leader to prevent unlimited headquarters
-			if (!exLeader.getSkillReuseTimeStamps().isEmpty())
+			if (getLevel() >= SiegeManager.getInstance().getSiegeClanMinLevel())
 			{
-				TimeStamp t;
-				for (L2Skill sk : SkillTable.getInstance().getSiegeSkills(newLeader.isNoble(), getCastleId() > 0))
-				{
-					if (exLeader.hasSkillReuse(sk.getReuseHashCode()))
-					{
-						t = exLeader.getSkillReuseTimeStamp(sk.getReuseHashCode());
-						newLeader.addTimeStamp(sk, t.getReuse(), t.getStamp());
-					}
-				}
-				newLeader.sendPacket(new SkillCoolTime(newLeader));
+				SiegeManager.getInstance().addSiegeSkills(newLeader);
+			}
+			newLeader.broadcastUserInfo();
+		}
+		else
+		{
+			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+				PreparedStatement statement = con.prepareStatement("UPDATE characters SET clan_privs = ? WHERE charId = ?"))
+			{
+				statement.setInt(1, L2Clan.CP_ALL);
+				statement.setInt(2, getLeaderId());
+				statement.execute();
+			}
+			catch (Exception e)
+			{
+				_log.log(Level.WARNING, "Couldn't update clan privs for new clan leader", e);
 			}
 		}
-		newLeader.broadcastUserInfo();
 		
 		broadcastClanStatus();
-		
-		SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.CLAN_LEADER_PRIVILEGES_HAVE_BEEN_TRANSFERRED_TO_C1);
-		sm.addString(newLeader.getName());
-		broadcastToOnlineMembers(sm);
-		sm = null;
-		CommunityServerThread.getInstance().sendPacket(new WorldInfo(null, this, WorldInfo.TYPE_UPDATE_CLAN_DATA));
+		broadcastToOnlineMembers(SystemMessage.getSystemMessage(SystemMessageId.CLAN_LEADER_PRIVILEGES_HAVE_BEEN_TRANSFERRED_TO_C1).addString(member.getName()));
+		if (CommunityServerThread.getInstance() != null)
+		{
+			CommunityServerThread.getInstance().sendPacket(new WorldInfo(null, this, WorldInfo.TYPE_UPDATE_CLAN_DATA));
+		}
+		_log.log(Level.INFO, "Leader of Clan: " + getName() + " changed to: " + member.getName() + " ex leader: " + exMember.getName());
 	}
 	
 	/**
@@ -418,12 +443,12 @@ public class L2Clan
 	}
 	
 	/**
-	 * @param objectID the required clan member object Id.
-	 * @return the clan member for a given {@code objectID}.
+	 * @param objectId the required clan member object Id.
+	 * @return the clan member for a given {@code objectId}.
 	 */
-	public L2ClanMember getClanMember(int objectID)
+	public L2ClanMember getClanMember(int objectId)
 	{
-		return _members.get(objectID);
+		return _members.get(objectId);
 	}
 	
 	/**
@@ -959,7 +984,7 @@ public class L2Clan
 	{
 		try (Connection con = L2DatabaseFactory.getInstance().getConnection())
 		{
-			final PreparedStatement statement = con.prepareStatement("UPDATE clan_data SET leader_id=?,ally_id=?,ally_name=?,reputation_score=?,ally_penalty_expiry_time=?,ally_penalty_type=?,char_penalty_expiry_time=?,dissolving_expiry_time=? WHERE clan_id=?");
+			final PreparedStatement statement = con.prepareStatement("UPDATE clan_data SET leader_id=?,ally_id=?,ally_name=?,reputation_score=?,ally_penalty_expiry_time=?,ally_penalty_type=?,char_penalty_expiry_time=?,dissolving_expiry_time=?,new_leader_id=? WHERE clan_id=?");
 			statement.setInt(1, getLeaderId());
 			statement.setInt(2, getAllyId());
 			statement.setString(3, getAllyName());
@@ -968,7 +993,8 @@ public class L2Clan
 			statement.setInt(6, getAllyPenaltyType());
 			statement.setLong(7, getCharPenaltyExpiryTime());
 			statement.setLong(8, getDissolvingExpiryTime());
-			statement.setInt(9, getClanId());
+			statement.setInt(9, getNewLeaderId());
+			statement.setInt(10, getClanId());
 			statement.execute();
 			statement.close();
 			if (Config.DEBUG)
@@ -1014,6 +1040,7 @@ public class L2Clan
 			ps.setInt(10, getCrestId());
 			ps.setInt(11, getCrestLargeId());
 			ps.setInt(12, getAllyCrestId());
+			ps.setInt(13, getNewLeaderId());
 			ps.execute();
 			if (Config.DEBUG)
 			{
@@ -1114,6 +1141,7 @@ public class L2Clan
 					
 					setReputationScore(clanData.getInt("reputation_score"), false);
 					setAuctionBiddedAt(clanData.getInt("auction_bid_at"), false);
+					setNewLeaderId(clanData.getInt("new_leader_id"), false);
 					
 					final int leaderId = (clanData.getInt("leader_id"));
 					
@@ -3091,6 +3119,30 @@ public class L2Clan
 		return result;
 	}
 	
+	public void setNewLeaderId(int objectId, boolean storeInDb)
+	{
+		_newLeaderId = objectId;
+		if (storeInDb)
+		{
+			updateClanInDB();
+		}
+	}
+	
+	public int getNewLeaderId()
+	{
+		return _newLeaderId;
+	}
+	
+	public L2PcInstance getNewLeader()
+	{
+		return L2World.getInstance().getPlayer(_newLeaderId);
+	}
+	
+	public String getNewLeaderName()
+	{
+		return CharNameTable.getInstance().getNameById(_newLeaderId);
+	}
+	
 	// Listeners
 	/**
 	 * Fires the clan creation listeners, if any.

+ 74 - 44
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2VillageMasterInstance.java

@@ -203,7 +203,80 @@ public class L2VillageMasterInstance extends L2NpcInstance
 				return;
 			}
 			
-			changeClanLeader(player, cmdParams);
+			if (!player.isClanLeader())
+			{
+				player.sendPacket(SystemMessageId.YOU_ARE_NOT_AUTHORIZED_TO_DO_THAT);
+				return;
+			}
+			
+			if (player.getName().equalsIgnoreCase(cmdParams))
+			{
+				return;
+			}
+			
+			final L2Clan clan = player.getClan();
+			final L2ClanMember member = clan.getClanMember(cmdParams);
+			if (member == null)
+			{
+				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DOES_NOT_EXIST);
+				sm.addString(cmdParams);
+				player.sendPacket(sm);
+				return;
+			}
+			
+			if (!member.isOnline())
+			{
+				player.sendPacket(SystemMessageId.INVITED_USER_NOT_ONLINE);
+				return;
+			}
+			
+			// To avoid clans with null clan leader, academy members shouldn't be eligible for clan leader.
+			if (member.getPlayerInstance().isAcademyMember())
+			{
+				player.sendPacket(SystemMessageId.RIGHT_CANT_TRANSFERRED_TO_ACADEMY_MEMBER);
+				return;
+			}
+			
+			if (Config.ALT_CLAN_LEADER_INSTANT_ACTIVATION)
+			{
+				clan.setNewLeader(member);
+			}
+			else
+			{
+				final NpcHtmlMessage msg = new NpcHtmlMessage(getObjectId());
+				if (clan.getNewLeaderId() == 0)
+				{
+					clan.setNewLeaderId(member.getObjectId(), true);
+					msg.setFile(player.getHtmlPrefix(), "data/scripts/village_master/Clan/9000-07-success.htm");
+				}
+				else
+				{
+					msg.setFile(player.getHtmlPrefix(), "data/scripts/village_master/Clan/9000-07-in-progress.htm");
+				}
+				player.sendPacket(msg);
+			}
+		}
+		else if (actualCommand.equalsIgnoreCase("cancel_clan_leader_change"))
+		{
+			if (!player.isClanLeader())
+			{
+				player.sendPacket(SystemMessageId.YOU_ARE_NOT_AUTHORIZED_TO_DO_THAT);
+				return;
+			}
+			
+			final L2Clan clan = player.getClan();
+			final NpcHtmlMessage msg = new NpcHtmlMessage(getObjectId());
+			if (clan.getNewLeaderId() != 0)
+			{
+				clan.setNewLeaderId(0, true);
+				msg.setFile(player.getHtmlPrefix(), "data/scripts/village_master/Clan/9000-07-canceled.htm");
+			}
+			else
+			{
+				msg.setHtml("<html><body>You don't have clan leader delegation applications submitted yet!</body></html>");
+			}
+			
+			player.sendPacket(msg);
 		}
 		else if (actualCommand.equalsIgnoreCase("recover_clan"))
 		{
@@ -888,49 +961,6 @@ public class L2VillageMasterInstance extends L2NpcInstance
 		clan.updateClanInDB();
 	}
 	
-	private static final void changeClanLeader(L2PcInstance player, String target)
-	{
-		if (!player.isClanLeader())
-		{
-			player.sendPacket(SystemMessageId.YOU_ARE_NOT_AUTHORIZED_TO_DO_THAT);
-			return;
-		}
-		if (player.getName().equalsIgnoreCase(target))
-		{
-			return;
-		}
-		/*
-		 * Until proper clan leader change support is done, this is a little exploit fix (leader, while fliying wyvern changes clan leader and the new leader can ride the wyvern too) DrHouse
-		 */
-		if (player.isFlying())
-		{
-			player.sendMessage("Please, stop flying");
-			return;
-		}
-		
-		final L2Clan clan = player.getClan();
-		final L2ClanMember member = clan.getClanMember(target);
-		if (member == null)
-		{
-			SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DOES_NOT_EXIST);
-			sm.addString(target);
-			player.sendPacket(sm);
-			return;
-		}
-		if (!member.isOnline())
-		{
-			player.sendPacket(SystemMessageId.INVITED_USER_NOT_ONLINE);
-			return;
-		}
-		// To avoid clans with null clan leader, academy members shouldn't be eligible for clan leader.
-		if (member.getPlayerInstance().isAcademyMember())
-		{
-			player.sendPacket(SystemMessageId.RIGHT_CANT_TRANSFERRED_TO_ACADEMY_MEMBER);
-			return;
-		}
-		clan.setNewLeader(member);
-	}
-	
 	private static final void createSubPledge(L2PcInstance player, String clanName, String leaderName, int pledgeType, int minClanLvl)
 	{
 		if (!player.isClanLeader())

+ 2 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/taskmanager/TaskManager.java

@@ -38,6 +38,7 @@ import java.util.logging.Logger;
 import com.l2jserver.L2DatabaseFactory;
 import com.l2jserver.gameserver.ThreadPoolManager;
 import com.l2jserver.gameserver.taskmanager.tasks.TaskBirthday;
+import com.l2jserver.gameserver.taskmanager.tasks.TaskClanLeaderApply;
 import com.l2jserver.gameserver.taskmanager.tasks.TaskCleanUp;
 import com.l2jserver.gameserver.taskmanager.tasks.TaskDailySkillReuseClean;
 import com.l2jserver.gameserver.taskmanager.tasks.TaskGlobalVariablesSave;
@@ -185,6 +186,7 @@ public final class TaskManager
 	private void initializate()
 	{
 		registerTask(new TaskBirthday());
+		registerTask(new TaskClanLeaderApply());
 		registerTask(new TaskCleanUp());
 		registerTask(new TaskDailySkillReuseClean());
 		registerTask(new TaskGlobalVariablesSave());

+ 73 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/taskmanager/tasks/TaskClanLeaderApply.java

@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2004-2013 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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.
+ * 
+ * L2J Server 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.l2jserver.gameserver.taskmanager.tasks;
+
+import java.util.Calendar;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.datatables.ClanTable;
+import com.l2jserver.gameserver.model.L2Clan;
+import com.l2jserver.gameserver.model.L2ClanMember;
+import com.l2jserver.gameserver.taskmanager.Task;
+import com.l2jserver.gameserver.taskmanager.TaskManager;
+import com.l2jserver.gameserver.taskmanager.TaskManager.ExecutedTask;
+import com.l2jserver.gameserver.taskmanager.TaskTypes;
+
+/**
+ * @author UnAfraid
+ */
+public class TaskClanLeaderApply extends Task
+{
+	private static final String NAME = "clanleaderapply";
+	
+	@Override
+	public String getName()
+	{
+		return NAME;
+	}
+	
+	@Override
+	public void onTimeElapsed(ExecutedTask task)
+	{
+		Calendar cal = Calendar.getInstance();
+		if (cal.get(Calendar.DAY_OF_WEEK) == Config.ALT_CLAN_LEADER_DATE_CHANGE)
+		{
+			for (L2Clan clan : ClanTable.getInstance().getClans())
+			{
+				if (clan.getNewLeaderId() != 0)
+				{
+					final L2ClanMember member = clan.getClanMember(clan.getNewLeaderId());
+					if (member == null)
+					{
+						continue;
+					}
+					
+					clan.setNewLeader(member);
+				}
+			}
+			_log.info(getClass().getSimpleName() + ": launched.");
+		}
+	}
+	
+	@Override
+	public void initializate()
+	{
+		TaskManager.addUniqueTask(NAME, TaskTypes.TYPE_GLOBAL_TASK, "1", Config.ALT_CLAN_LEADER_HOUR_CHANGE, "");
+	}
+}