com.l2jfree.gameserver.instancemanager.AutoChatManager.java Source code

Java tutorial

Introduction

Here is the source code for com.l2jfree.gameserver.instancemanager.AutoChatManager.java

Source

/*
 * 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.l2jfree.gameserver.instancemanager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.concurrent.ScheduledFuture;

import javolution.util.FastList;
import javolution.util.FastMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.l2jfree.Config;
import com.l2jfree.L2DatabaseFactory;
import com.l2jfree.gameserver.ThreadPoolManager;
import com.l2jfree.gameserver.gameobjects.L2Creature;
import com.l2jfree.gameserver.gameobjects.L2Npc;
import com.l2jfree.gameserver.gameobjects.L2Player;
import com.l2jfree.gameserver.model.sevensigns.SevenSigns;
import com.l2jfree.gameserver.model.world.spawn.L2Spawn;
import com.l2jfree.gameserver.model.world.spawn.SpawnListener;
import com.l2jfree.gameserver.network.SystemChatChannelId;
import com.l2jfree.gameserver.network.packets.server.CreatureSay;
import com.l2jfree.tools.random.Rnd;

/**
 * Auto Chat Handler
 * 
 * Allows NPCs to automatically send messages to nearby players
 * at a set time interval.
 * 
 * @author Tempy
 */
public class AutoChatManager implements SpawnListener {
    protected static Log _log = LogFactory.getLog(AutoChatManager.class);

    private static final int DEFAULT_CHAT_RANGE = 1500;

    protected final FastMap<Integer, AutoChatInstance> _registeredChats;

    private AutoChatManager() {
        _registeredChats = new FastMap<Integer, AutoChatInstance>();
        restoreChatData();
        L2Spawn.addSpawnListener(this);
        _log.info("AutoChatHandler: Loaded " + size() + " handlers in total.");
    }

    private void restoreChatData() {
        int numLoaded = 0;
        Connection con = null;
        PreparedStatement statement = null;
        PreparedStatement statement2 = null;
        ResultSet rs = null;
        ResultSet rs2 = null;

        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);

            statement = con.prepareStatement("SELECT * FROM auto_chat ORDER BY groupId ASC");
            rs = statement.executeQuery();

            while (rs.next()) {
                int groupId = rs.getInt("groupId");
                int npcId = rs.getInt("npcId");
                long chatDelay = rs.getLong("chatDelay") * 1000;
                int chatRange = rs.getInt("chatRange");
                boolean chatRandom = rs.getBoolean("chatRandom");

                numLoaded++;

                statement2 = con.prepareStatement("SELECT * FROM auto_chat_text WHERE groupId=?");
                statement2.setInt(1, groupId);
                rs2 = statement2.executeQuery();

                ArrayList<String> chatTexts = new ArrayList<String>();

                while (rs2.next())
                    chatTexts.add(rs2.getString("chatText"));

                if (!chatTexts.isEmpty())
                    registerGlobalChat(npcId, chatTexts.toArray(new String[chatTexts.size()]), chatDelay, chatRange,
                            chatRandom);
                else
                    _log.warn("AutoChatHandler: Chat group " + groupId + " is empty.");

                statement2.close();
            }

            statement.close();

            if (_log.isDebugEnabled())
                _log.info("AutoChatHandler: Loaded " + numLoaded + " chat group(s) from the database.");
        } catch (Exception e) {
            _log.warn("AutoSpawnHandler: Could not restore chat data: ", e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    public void reload() {
        // unregister all registered spawns
        for (AutoChatInstance aci : _registeredChats.values()) {
            if (aci != null) {
                // clear timer
                if (aci._chatTask != null)
                    aci._chatTask.cancel(true);
                removeChat(aci);
            }
        }

        // create clean list
        _registeredChats.clear();

        // load
        restoreChatData();
    }

    public static AutoChatManager getInstance() {
        return SingletonHolder._instance;
    }

    public int size() {
        return _registeredChats.size();
    }

    /**
     * Registers a globally active auto chat for ALL instances of the given NPC ID.
     * <BR>
     * Returns the associated auto chat instance.
     * 
     * @param npcId
     * @param chatTexts
     * @param chatDelay (-1 = default delay)
     * @return AutoChatInstance chatInst
     */
    public AutoChatInstance registerGlobalChat(int npcId, String[] chatTexts, long chatDelay, int chatRange,
            boolean chatRandom) {
        return registerChat(npcId, null, chatTexts, chatDelay, chatRange, chatRandom);
    }

    /**
     * Registers a NON globally-active auto chat for the given NPC instance, and adds to the currently
     * assigned chat instance for this NPC ID, otherwise creates a new instance if
     * a previous one is not found.
     * <BR>
     * Returns the associated auto chat instance.
     * 
     * @param npcInst
     * @param chatTexts
     * @param chatDelay (-1 = default delay)
     * @return AutoChatInstance chatInst
     */
    public AutoChatInstance registerChat(L2Npc npcInst, String[] chatTexts, long chatDelay) {
        return registerChat(npcInst.getNpcId(), npcInst, chatTexts, chatDelay, DEFAULT_CHAT_RANGE, false);
    }

    public AutoChatInstance registerChat(L2Npc npcInst, String[] chatTexts, long chatDelay, int chatRange,
            boolean chatRandom) {
        return registerChat(npcInst.getNpcId(), npcInst, chatTexts, chatDelay, chatRange, chatRandom);
    }

    private final AutoChatInstance registerChat(int npcId, L2Npc npcInst, String[] chatTexts, long chatDelay,
            int chatRange, boolean chatRandom) {
        AutoChatInstance chatInst = null;

        if (chatDelay < 0)
            chatDelay = Config.ALT_AUTOCHAT_DELAY;
        if (chatRange < 0)
            chatRange = DEFAULT_CHAT_RANGE;

        if (_registeredChats.containsKey(npcId))
            chatInst = _registeredChats.get(npcId);
        else
            chatInst = new AutoChatInstance(npcId, chatTexts, chatDelay, chatRange, chatRandom, (npcInst == null));

        if (npcInst != null)
            chatInst.addChatDefinition(npcInst);

        _registeredChats.put(npcId, chatInst);

        return chatInst;
    }

    /**
     * Removes and cancels ALL auto chat definition for the given NPC ID,
     * and removes its chat instance if it exists.
     * 
     * @param npcId
     * @return boolean removedSuccessfully
     */
    public boolean removeChat(int npcId) {
        AutoChatInstance chatInst = _registeredChats.get(npcId);

        return removeChat(chatInst);
    }

    /**
     * Removes and cancels ALL auto chats for the given chat instance.
     * 
     * @param chatInst
     * @return boolean removedSuccessfully
     */
    public boolean removeChat(AutoChatInstance chatInst) {
        if (chatInst == null)
            return false;

        _registeredChats.remove(chatInst.getNPCId());
        chatInst.setActive(false);

        if (_log.isDebugEnabled())
            _log.info("AutoChatHandler: Removed auto chat for NPC ID " + chatInst.getNPCId());

        return true;
    }

    /**
     * Returns the associated auto chat instance either by the given NPC ID
     * or object ID.
     * 
     * @param id
     * @param byObjectId
     * @return AutoChatInstance chatInst
     */
    public AutoChatInstance getAutoChatInstance(int id, boolean byObjectId) {
        if (!byObjectId)
            return _registeredChats.get(id);
        for (AutoChatInstance chatInst : _registeredChats.values())
            if (chatInst.getChatDefinition(id) != null)
                return chatInst;

        return null;
    }

    /**
     * Sets the active state of all auto chat instances to that specified,
     * and cancels the scheduled chat task if necessary.
     * 
     * @param isActive
     */
    public void setAutoChatActive(boolean isActive) {
        for (AutoChatInstance chatInst : _registeredChats.values())
            chatInst.setActive(isActive);
    }

    /**
     * Sets the active state of all auto chat instances of specified NPC ID
     * 
     * @param npcId
     * @param isActive
     */
    public void setAutoChatActive(int npcId, boolean isActive) {
        for (AutoChatInstance chatInst : _registeredChats.values())
            if (chatInst.getNPCId() == npcId)
                chatInst.setActive(isActive);
    }

    /**
     * Used in conjunction with a SpawnListener, this method is called every time
     * an NPC is spawned in the world.
     * <BR><BR>
     * If an auto chat instance is set to be "global", all instances matching the registered
     * NPC ID will be added to that chat instance.
     */
    @Override
    public void npcSpawned(L2Npc npc) {
        synchronized (_registeredChats) {
            if (npc == null)
                return;

            int npcId = npc.getNpcId();

            if (_registeredChats.containsKey(npcId)) {
                AutoChatInstance chatInst = _registeredChats.get(npcId);

                if (chatInst != null && chatInst.isGlobal())
                    chatInst.addChatDefinition(npc);
            }
        }
    }

    /**
     * Auto Chat Instance
     * <BR><BR>
     * Manages the auto chat instances for a specific registered NPC ID.
     * 
     * @author Tempy
     */
    public class AutoChatInstance {
        protected int _npcId;
        private long _defaultDelay = Config.ALT_AUTOCHAT_DELAY;
        private int _defaultRange = DEFAULT_CHAT_RANGE;
        private String[] _defaultTexts;
        private boolean _defaultRandom;

        private boolean _globalChat = false;
        private boolean _isActive;

        private final FastMap<Integer, AutoChatDefinition> _chatDefinitions = new FastMap<Integer, AutoChatDefinition>();
        protected ScheduledFuture<?> _chatTask;

        protected AutoChatInstance(int npcId, String[] chatTexts, long chatDelay, int chatRange, boolean chatRandom,
                boolean isGlobal) {
            _defaultTexts = chatTexts;
            _npcId = npcId;
            _defaultDelay = (chatDelay <= 0 ? Config.ALT_AUTOCHAT_DELAY : chatDelay);
            _defaultRange = chatRange;
            _defaultRandom = chatRandom;
            _globalChat = isGlobal;

            if (_log.isDebugEnabled())
                _log.info("AutoChatHandler: Registered auto chat for NPC ID " + _npcId + " (Global Chat = "
                        + _globalChat + ").");

            setActive(true);
        }

        protected AutoChatDefinition getChatDefinition(int objectId) {
            return _chatDefinitions.get(objectId);
        }

        protected AutoChatDefinition[] getChatDefinitions() {
            return _chatDefinitions.values().toArray(new AutoChatDefinition[_chatDefinitions.values().size()]);
        }

        /**
         * Defines an auto chat for an instance matching this auto chat instance's registered NPC ID,
         * and launches the scheduled chat task.
         * <BR>
         * Returns the object ID for the NPC instance, with which to refer
         * to the created chat definition.
         * <BR>
         * <B>Note</B>: Uses pre-defined default values for texts and chat delays from the chat instance.
         * 
         * @param npcInst
         * @return int objectId
         */
        public int addChatDefinition(L2Npc npcInst) {
            return addChatDefinition(npcInst, null, 0);
        }

        /**
         * Defines an auto chat for an instance matching this auto chat instance's registered NPC ID,
         * and launches the scheduled chat task.
         * <BR>
         * Returns the object ID for the NPC instance, with which to refer
         * to the created chat definition.
         * 
         * @param npcInst
         * @param chatTexts
         * @param chatDelay
         * @return int objectId
         */
        public int addChatDefinition(L2Npc npcInst, String[] chatTexts, long chatDelay) {
            int objectId = npcInst.getObjectId();
            AutoChatDefinition chatDef = new AutoChatDefinition(this, npcInst, chatTexts, chatDelay);

            _chatDefinitions.put(objectId, chatDef);
            return objectId;
        }

        /**
         * Removes a chat definition specified by the given object ID.
         * 
         * @param objectId
         * @return boolean removedSuccessfully
         */
        public boolean removeChatDefinition(int objectId) {
            if (!_chatDefinitions.containsKey(objectId))
                return false;

            AutoChatDefinition chatDefinition = _chatDefinitions.get(objectId);
            chatDefinition.setActive(false);

            _chatDefinitions.remove(objectId);

            return true;
        }

        /**
         * Tests if this auto chat instance is active.
         * 
         * @return boolean isActive
         */
        public boolean isActive() {
            return _isActive;
        }

        /**
         * Tests if this auto chat instance applies to
         * ALL currently spawned instances of the registered NPC ID.
         * 
         * @return boolean isGlobal
         */
        public boolean isGlobal() {
            return _globalChat;
        }

        /**
         * Tests if random order is the DEFAULT for new chat definitions.
         * 
         * @return boolean isRandom
         */
        public boolean isDefaultRandom() {
            return _defaultRandom;
        }

        /**
         * Tests if the auto chat definition given by its object ID is set to be random.
         * 
         * @return boolean isRandom
         */
        public boolean isRandomChat(int objectId) {
            if (!_chatDefinitions.containsKey(objectId))
                return false;

            return _chatDefinitions.get(objectId).isRandomChat();
        }

        /**
         * Returns the ID of the NPC type managed by this auto chat instance.
         *
         * @return int npcId
         */
        public int getNPCId() {
            return _npcId;
        }

        /**
         * Returns the number of auto chat definitions stored for this instance.
         * 
         * @return int definitionCount
         */
        public int getDefinitionCount() {
            return _chatDefinitions.size();
        }

        /**
         * Returns a list of all NPC instances handled by this auto chat instance.
         * 
         * @return L2Npc[] npcInsts
         */
        public L2Npc[] getNPCInstanceList() {
            FastList<L2Npc> npcInsts = new FastList<L2Npc>();

            for (AutoChatDefinition chatDefinition : _chatDefinitions.values())
                npcInsts.add(chatDefinition._npcInstance);

            return npcInsts.toArray(new L2Npc[npcInsts.size()]);
        }

        /**
         * A series of methods used to get and set default values for new chat definitions.
         */
        public long getDefaultDelay() {
            return _defaultDelay;
        }

        public String[] getDefaultTexts() {
            return _defaultTexts;
        }

        public int getDefaultRange() {
            return _defaultRange;
        }

        public void setDefaultChatDelay(long delayValue) {
            _defaultDelay = delayValue;
        }

        public void setDefaultChatTexts(String[] textsValue) {
            _defaultTexts = textsValue;
        }

        public void setDefaultRange(int rangeValue) {
            _defaultRange = rangeValue;
        }

        public void setDefaultRandom(boolean randValue) {
            _defaultRandom = randValue;
        }

        /**
         * Sets a specific chat delay for the specified auto chat definition given by its object ID.
         * 
         * @param objectId
         * @param delayValue
         */
        public void setChatDelay(int objectId, long delayValue) {
            AutoChatDefinition chatDef = getChatDefinition(objectId);

            if (chatDef != null)
                chatDef.setChatDelay(delayValue);
        }

        /**
         * Sets a specific set of chat texts for the specified auto chat definition given by its object ID.
         * 
         * @param objectId
         * @param textsValue
         */
        public void setChatTexts(int objectId, String[] textsValue) {
            AutoChatDefinition chatDef = getChatDefinition(objectId);

            if (chatDef != null)
                chatDef.setChatTexts(textsValue);
        }

        /**
         * Sets specifically to use random chat order for the auto chat definition given by its object ID.
         * 
         * @param objectId
         * @param randValue
         */
        public void setRandomChat(int objectId, boolean randValue) {
            AutoChatDefinition chatDef = getChatDefinition(objectId);

            if (chatDef != null)
                chatDef.setRandomChat(randValue);
        }

        /**
         * Sets specifically to use chat range for the auto chat definition given by its object ID.
         * 
         * @param objectId
         * @param randValue
         */
        public void setChatRange(int objectId, int rangeValue) {
            AutoChatDefinition chatDef = getChatDefinition(objectId);

            if (chatDef != null)
                chatDef.setChatRange(rangeValue);
        }

        /**
         * Sets the activity of ALL auto chat definitions handled by this chat instance.
         * 
         * @param isActive
         */
        public void setActive(boolean activeValue) {
            if (_isActive == activeValue)
                return;

            _isActive = activeValue;

            if (!isGlobal()) {
                for (AutoChatDefinition chatDefinition : _chatDefinitions.values())
                    chatDefinition.setActive(activeValue);

                return;
            }

            if (isActive()) {
                AutoChatRunner acr = new AutoChatRunner(_npcId, -1);
                _chatTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(acr, _defaultDelay,
                        _defaultDelay);
            } else {
                _chatTask.cancel(false);
            }
        }

        /**
         * Auto Chat Definition
         * <BR><BR>
         * Stores information about specific chat data for an instance of the NPC ID
         * specified by the containing auto chat instance.
         * <BR>
         * Each NPC instance of this type should be stored in a subsequent AutoChatDefinition class.
         * 
         * @author Tempy
         */
        private class AutoChatDefinition {
            protected int _chatIndex = 0;
            protected L2Npc _npcInstance;

            protected AutoChatInstance _chatInstance;

            private long _chatDelay = Config.ALT_AUTOCHAT_DELAY;
            private int _chatRange = DEFAULT_CHAT_RANGE;
            private String[] _chatTexts = null;
            private boolean _isActiveDefinition;
            private boolean _randomChat;

            protected AutoChatDefinition(AutoChatInstance chatInst, L2Npc npcInst, String[] chatTexts,
                    long chatDelay) {
                _npcInstance = npcInst;

                _chatInstance = chatInst;
                _randomChat = chatInst.isDefaultRandom();

                _chatDelay = (chatDelay <= 0 ? Config.ALT_AUTOCHAT_DELAY : chatDelay);
                _chatRange = chatInst.getDefaultRange();
                _chatTexts = chatTexts;

                if (_log.isDebugEnabled())
                    _log.info("AutoChatHandler: Chat definition added for NPC ID " + _npcInstance.getNpcId()
                            + " (Object ID = " + _npcInstance.getObjectId() + ").");

                // If global chat isn't enabled for the parent instance,
                // then handle the chat task locally.
                if (!chatInst.isGlobal())
                    setActive(true);
            }

            //         protected AutoChatDefinition(AutoChatInstance chatInst, L2Npc npcInst)
            //         {
            //            this(chatInst, npcInst, null, -1);
            //         }

            protected String[] getChatTexts() {
                if (_chatTexts != null)
                    return _chatTexts;
                return _chatInstance.getDefaultTexts();
            }

            private long getChatDelay() {
                if (_chatDelay > 0)
                    return _chatDelay;
                return _chatInstance.getDefaultDelay();
            }

            private boolean isActive() {
                return _isActiveDefinition;
            }

            boolean isRandomChat() {
                return _randomChat;
            }

            void setRandomChat(boolean randValue) {
                _randomChat = randValue;
            }

            void setChatDelay(long delayValue) {
                _chatDelay = delayValue;
            }

            void setChatRange(int rangeValue) {
                _chatRange = rangeValue;
            }

            void setChatTexts(String[] textsValue) {
                _chatTexts = textsValue;
            }

            void setActive(boolean activeValue) {
                if (isActive() == activeValue)
                    return;

                if (activeValue) {
                    AutoChatRunner acr = new AutoChatRunner(_npcId, _npcInstance.getObjectId());
                    _chatTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(acr, getChatDelay(),
                            getChatDelay());
                } else {
                    _chatTask.cancel(false);
                }

                _isActiveDefinition = activeValue;
            }
        }

        /**
         * Auto Chat Runner
         * <BR><BR>
         * Represents the auto chat scheduled task for each chat instance.
         * 
         * @author Tempy
         */
        private class AutoChatRunner implements Runnable {
            private final int _runnerNpcId;
            private final int _objectId;

            protected AutoChatRunner(int pNpcId, int pObjectId) {
                _runnerNpcId = pNpcId;
                _objectId = pObjectId;
            }

            @Override
            public synchronized void run() {
                AutoChatInstance chatInst = _registeredChats.get(_runnerNpcId);
                AutoChatDefinition[] chatDefinitions;

                if (chatInst.isGlobal()) {
                    chatDefinitions = chatInst.getChatDefinitions();
                } else {
                    AutoChatDefinition chatDef = chatInst.getChatDefinition(_objectId);

                    if (chatDef == null) {
                        _log.warn("AutoChatHandler: Auto chat definition is NULL for NPC ID " + _npcId + ".");
                        return;
                    }

                    chatDefinitions = new AutoChatDefinition[] { chatDef };
                }

                if (_log.isDebugEnabled())
                    _log.info("AutoChatHandler: Running auto chat for " + chatDefinitions.length
                            + " instances of NPC ID " + _npcId + "." + " (Global Chat = " + chatInst.isGlobal()
                            + ")");

                for (AutoChatDefinition chatDef : chatDefinitions) {
                    try {
                        L2Npc chatNpc = chatDef._npcInstance;
                        FastList<L2Player> nearbyPlayers = new FastList<L2Player>();

                        for (L2Creature player : chatNpc.getKnownList()
                                .getKnownCharactersInRadius(chatDef._chatRange))
                            if (player instanceof L2Player && !((L2Player) player).isGM())
                                nearbyPlayers.add((L2Player) player);

                        int maxIndex = chatDef.getChatTexts().length;
                        int lastIndex = Rnd.nextInt(maxIndex);

                        String creatureName = chatNpc.getName();
                        String text;

                        if (!chatDef.isRandomChat()) {
                            lastIndex = chatDef._chatIndex;
                            if (lastIndex == maxIndex)
                                lastIndex = 0;
                            chatDef._chatIndex = lastIndex + 1;
                        }

                        text = chatDef.getChatTexts()[lastIndex];

                        if (text == null)
                            return;

                        if (!nearbyPlayers.isEmpty()) {
                            final int winningCabal = SevenSigns.getInstance().getCabalHighestScore();
                            int losingCabal = SevenSigns.CABAL_NULL;

                            if (winningCabal == SevenSigns.CABAL_DAWN)
                                losingCabal = SevenSigns.CABAL_DUSK;
                            else if (winningCabal == SevenSigns.CABAL_DUSK)
                                losingCabal = SevenSigns.CABAL_DAWN;

                            if (text.indexOf("%player_") > -1) {
                                ArrayList<Integer> karmaPlayers = new ArrayList<Integer>();
                                ArrayList<Integer> winningCabals = new ArrayList<Integer>();
                                ArrayList<Integer> losingCabals = new ArrayList<Integer>();

                                for (int i = 0; i < nearbyPlayers.size(); i++) {
                                    L2Player nearbyPlayer = nearbyPlayers.get(i);

                                    // Get all nearby players with karma
                                    if (nearbyPlayer.getKarma() > 0)
                                        karmaPlayers.add(i);

                                    // Get all nearby Seven Signs winners and loosers
                                    if (SevenSigns.getInstance().getPlayerCabal(nearbyPlayer) == winningCabal)
                                        winningCabals.add(i);
                                    else if (SevenSigns.getInstance().getPlayerCabal(nearbyPlayer) == losingCabal)
                                        losingCabals.add(i);
                                }

                                if (text.indexOf("%player_random%") > -1) {
                                    int randomPlayerIndex = Rnd.nextInt(nearbyPlayers.size());
                                    L2Player randomPlayer = nearbyPlayers.get(randomPlayerIndex);
                                    text = text.replaceAll("%player_random%", randomPlayer.getName());
                                } else if (text.indexOf("%player_killer%") > -1 && !karmaPlayers.isEmpty()) {
                                    int randomPlayerIndex = karmaPlayers.get(Rnd.nextInt(karmaPlayers.size()));
                                    L2Player randomPlayer = nearbyPlayers.get(randomPlayerIndex);
                                    text = text.replaceAll("%player_killer%", randomPlayer.getName());
                                } else if (text.indexOf("%player_cabal_winner%") > -1 && !winningCabals.isEmpty()) {
                                    int randomPlayerIndex = winningCabals.get(Rnd.nextInt(winningCabals.size()));
                                    L2Player randomPlayer = nearbyPlayers.get(randomPlayerIndex);
                                    text = text.replaceAll("%player_cabal_winner%", randomPlayer.getName());
                                } else if (text.indexOf("%player_cabal_loser%") > -1 && !losingCabals.isEmpty()) {
                                    int randomPlayerIndex = losingCabals.get(Rnd.nextInt(losingCabals.size()));
                                    L2Player randomPlayer = nearbyPlayers.get(randomPlayerIndex);
                                    text = text.replaceAll("%player_cabal_loser%", randomPlayer.getName());
                                }
                            }
                        }

                        if (text == null)
                            return;

                        if (text.contains("%player_"))
                            return;

                        chatNpc.broadcastPacket(new CreatureSay(chatNpc.getObjectId(),
                                SystemChatChannelId.Chat_Normal, creatureName, text));

                        if (_log.isDebugEnabled())
                            _log.info("AutoChatHandler: Chat propogation for object ID " + chatNpc.getObjectId()
                                    + " (" + creatureName + ") with text '" + text + "' sent to "
                                    + nearbyPlayers.size() + " nearby players.");
                    } catch (Exception e) {
                        _log.error(e.getMessage(), e);
                        return;
                    }
                }
            }
        }
    }

    @SuppressWarnings("synthetic-access")
    private static class SingletonHolder {
        protected static final AutoChatManager _instance = new AutoChatManager();
    }
}