Package com.l2jfrozen.gameserver.managers

Source Code of com.l2jfrozen.gameserver.managers.MercTicketManager$SingletonHolder

/* 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 2, 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* http://www.gnu.org/copyleft/gpl.html
*/
package com.l2jfrozen.gameserver.managers;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.logging.Logger;

import javolution.util.FastList;

import com.l2jfrozen.gameserver.datatables.sql.NpcTable;
import com.l2jfrozen.gameserver.handler.AutoChatHandler;
import com.l2jfrozen.gameserver.idfactory.IdFactory;
import com.l2jfrozen.gameserver.model.L2World;
import com.l2jfrozen.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2PcInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2SiegeGuardInstance;
import com.l2jfrozen.gameserver.model.entity.siege.Castle;
import com.l2jfrozen.gameserver.templates.L2NpcTemplate;
import com.l2jfrozen.gameserver.thread.ThreadPoolManager;
import com.l2jfrozen.util.CloseUtil;
import com.l2jfrozen.util.database.L2DatabaseFactory;

/**
* @author yellowperil & Fulminus This class is similar to the SiegeGuardManager, except it handles the loading of the
*         mercenary tickets that are dropped on castle floors by the castle lords. These tickets (aka badges) need to
*         be readded after each server reboot except when the server crashed in the middle of an ongoig siege. In
*         addition, this class keeps track of the added tickets, in order to properly limit the number of mercenaries
*         in each castle and the number of mercenaries from each mercenary type. Finally, we provide auxilary functions
*         to identify the castle in which each item (and its corresponding NPC) belong to, in order to help avoid
*         mixing them up.
*/
public class MercTicketManager
{
  protected static Logger _log = Logger.getLogger(MercTicketManager.class.getName());

  // =========================================================

  // =========================================================
  // Data Field
  private List<L2ItemInstance> _droppedTickets = new FastList<L2ItemInstance>();

   
  public static final MercTicketManager getInstance()
  {
    return SingletonHolder._instance;
  }
 
  public MercTicketManager(){
    _log.info("Initializing MercTicketManager");
    _droppedTickets.clear();
    load();
  }

  //TODO move all these values into siege.properties
  // max tickets per merc type = 10 + (castleid * 2)?
  // max ticker per castle = 40 + (castleid * 20)?
  private static final int[] MAX_MERC_PER_TYPE =
  {
      10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, // Gludio
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15,
      15, // Dion
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10, // Giran
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10,
      10, // Oren
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20, // Aden
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20, // Innadril
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20, // Goddard
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20, // Rune
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20,
      20
  // Schuttgart
  };
  private static final int[] MERCS_MAX_PER_CASTLE =
  {
      100, // Gludio
      150, // Dion
      200, // Giran
      300, // Oren
      400, // Aden
      400, // Innadril
      400, // Goddard
      400, // Rune
      400
  // Schuttgart
  };

  private static final int[] ITEM_IDS =
  {
      3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 6038, 6039, 6040, 6041, 6042, 6043, 6044, 6045, 6046, 6047, // Gludio
      3973,
      3974,
      3975,
      3976,
      3977,
      3978,
      3979,
      3980,
      3981,
      3982,
      6051,
      6052,
      6053,
      6054,
      6055,
      6056,
      6057,
      6058,
      6059,
      6060, // Dion
      3986,
      3987,
      3988,
      3989,
      3990,
      3991,
      3992,
      3993,
      3994,
      3995,
      6064,
      6065,
      6066,
      6067,
      6068,
      6069,
      6070,
      6071,
      6072,
      6073, // Giran
      3999,
      4000,
      4001,
      4002,
      4003,
      4004,
      4005,
      4006,
      4007,
      4008,
      6077,
      6078,
      6079,
      6080,
      6081,
      6082,
      6083,
      6084,
      6085,
      6086, // Oren
      4012,
      4013,
      4014,
      4015,
      4016,
      4017,
      4018,
      4019,
      4020,
      4021,
      6090,
      6091,
      6092,
      6093,
      6094,
      6095,
      6096,
      6097,
      6098,
      6099, // Aden
      5205,
      5206,
      5207,
      5208,
      5209,
      5210,
      5211,
      5212,
      5213,
      5214,
      6105,
      6106,
      6107,
      6108,
      6109,
      6110,
      6111,
      6112,
      6113,
      6114, // Innadril
      6779,
      6780,
      6781,
      6782,
      6783,
      6784,
      6785,
      6786,
      6787,
      6788,
      6792,
      6793,
      6794,
      6795,
      6796,
      6797,
      6798,
      6799,
      6800,
      6801, // Goddard
      7973,
      7974,
      7975,
      7976,
      7977,
      7978,
      7979,
      7980,
      7981,
      7982,
      7988,
      7989,
      7990,
      7991,
      7992,
      7993,
      7994,
      7995,
      7996,
      7997, // Rune
      7918,
      7919,
      7920,
      7921,
      7922,
      7923,
      7924,
      7925,
      7926,
      7927,
      7931,
      7932,
      7933,
      7934,
      7935,
      7936,
      7937,
      7938,
      7939,
      7940
  // Schuttgart
  };

  private static final int[] NPC_IDS =
  {
      35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35030, 35031, 35032, 35033, 35034, 35035, 35036, 35037, 35038, 35039, // Gludio
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039, // Dion
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039, // Giran
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039, // Oren
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039, // Aden
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039, // Innadril
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039, // Goddard
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039, // Rune
      35010,
      35011,
      35012,
      35013,
      35014,
      35015,
      35016,
      35017,
      35018,
      35019,
      35030,
      35031,
      35032,
      35033,
      35034,
      35035,
      35036,
      35037,
      35038,
      35039
  // Schuttgart
  };

  // =========================================================
  // Method - Public
  // returns the castleId for the passed ticket item id
  public int getTicketCastleId(int itemId)
  {
    if(itemId >= ITEM_IDS[0] && itemId <= ITEM_IDS[9] || itemId >= ITEM_IDS[10] && itemId <= ITEM_IDS[19])
      return 1; // Gludio
    if(itemId >= ITEM_IDS[20] && itemId <= ITEM_IDS[29] || itemId >= ITEM_IDS[30] && itemId <= ITEM_IDS[39])
      return 2; // Dion
    if(itemId >= ITEM_IDS[40] && itemId <= ITEM_IDS[49] || itemId >= ITEM_IDS[50] && itemId <= ITEM_IDS[59])
      return 3; // Giran
    if(itemId >= ITEM_IDS[60] && itemId <= ITEM_IDS[69] || itemId >= ITEM_IDS[70] && itemId <= ITEM_IDS[79])
      return 4; // Oren
    if(itemId >= ITEM_IDS[80] && itemId <= ITEM_IDS[89] || itemId >= ITEM_IDS[90] && itemId <= ITEM_IDS[99])
      return 5; // Aden
    if(itemId >= ITEM_IDS[100] && itemId <= ITEM_IDS[109] || itemId >= ITEM_IDS[110] && itemId <= ITEM_IDS[119])
      return 6; // Innadril
    if(itemId >= ITEM_IDS[120] && itemId <= ITEM_IDS[129] || itemId >= ITEM_IDS[130] && itemId <= ITEM_IDS[139])
      return 7; // Goddard
    if(itemId >= ITEM_IDS[140] && itemId <= ITEM_IDS[149] || itemId >= ITEM_IDS[150] && itemId <= ITEM_IDS[159])
      return 8; // Rune
    if(itemId >= ITEM_IDS[160] && itemId <= ITEM_IDS[169] || itemId >= ITEM_IDS[170] && itemId <= ITEM_IDS[179])
      return 9; // Schuttgart
    return -1;
  }

  public void reload()
  {
    getDroppedTickets().clear();
    load();
  }

  // =========================================================
  // Method - Private
  private final void load()
  {
    Connection con = null;
    // load merc tickets into the world
    try
    {
      PreparedStatement statement;
      ResultSet rs;

      con = L2DatabaseFactory.getInstance().getConnection(false);
      statement = con.prepareStatement("SELECT * FROM castle_siege_guards Where isHired = 1");
      rs = statement.executeQuery();

      int npcId;
      int itemId;
      int x, y, z;
      // start index to begin the search for the itemId corresponding to this NPC
      // this will help with:
      //    a) skip unnecessary iterations in the search loop
      //    b) avoid finding the wrong itemId whenever tickets of different spawn the same npc!
      int startindex = 0;

      while(rs.next())
      {
        npcId = rs.getInt("npcId");
        x = rs.getInt("x");
        y = rs.getInt("y");
        z = rs.getInt("z");
        Castle castle = CastleManager.getInstance().getCastle(x, y, z);
        if(castle != null)
        {
          startindex = 10*(castle.getCastleId() - 1);
        }

        // find the FIRST ticket itemId with spawns the saved NPC in the saved location
        for(int i = startindex; i < NPC_IDS.length; i++)
          if(NPC_IDS[i] == npcId) // Find the index of the item used
          {
            // only handle tickets if a siege is not ongoing in this npc's castle

            if(castle != null && !castle.getSiege().getIsInProgress())
            {
              itemId = ITEM_IDS[i];
              // create the ticket in the gameworld
              L2ItemInstance dropticket = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
              dropticket.setLocation(L2ItemInstance.ItemLocation.VOID);
              dropticket.dropMe(null, x, y, z);
              dropticket.setDropTime(0); //avoids it from beeing removed by the auto item destroyer
              L2World.getInstance().storeObject(dropticket);
              getDroppedTickets().add(dropticket);
              dropticket = null;
            }
            break;
          }
        castle = null;
      }
      statement.close();
      statement = null;
      rs.close();
      rs = null;

      _log.info("Loaded: " + getDroppedTickets().size() + " Mercenary Tickets");
    }
    catch(Exception e)
    {
      _log.info("Exception: loadMercenaryData(): " + e.getMessage());
      e.printStackTrace();
    }
    finally
    {
      CloseUtil.close(con);
    }
  }

  // =========================================================
  // Property - Public
  /**
   * Checks if the passed item has reached the limit of number of dropped tickets that this SPECIFIC item may have in
   * its castle
   * @param itemId
   * @return
   */
  public boolean isAtTypeLimit(int itemId)
  {
    int limit = -1;
    // find the max value for this item
    for(int i = 0; i < ITEM_IDS.length; i++)
      if(ITEM_IDS[i] == itemId) // Find the index of the item used
      {
        limit = MAX_MERC_PER_TYPE[i];
        break;
      }

    if(limit <= 0)
      return true;

    int count = 0;
    L2ItemInstance ticket;
    for(int i = 0; i < getDroppedTickets().size(); i++)
    {
      ticket = getDroppedTickets().get(i);
      if(ticket != null && ticket.getItemId() == itemId)
      {
        count++;
      }
    }
    ticket = null;
    if(count >= limit)
      return true;

    return false;
  }

  /**
   * Checks if the passed item belongs to a castle which has reached its limit of number of dropped tickets.
   * @param itemId
   * @return
   */
  public boolean isAtCasleLimit(int itemId)
  {
    int castleId = getTicketCastleId(itemId);
    if(castleId <= 0)
      return true;

    int limit = MERCS_MAX_PER_CASTLE[castleId - 1];
    if(limit <= 0)
      return true;

    int count = 0;
    L2ItemInstance ticket;
    for(int i = 0; i < getDroppedTickets().size(); i++)
    {
      ticket = getDroppedTickets().get(i);
      if(ticket != null && getTicketCastleId(ticket.getItemId()) == castleId)
      {
        count++;
      }
    }
    ticket = null;
    if(count >= limit)
      return true;

    return false;
  }

  /**
   * addTicket actions 1) find the npc that needs to be saved in the mercenary spawns, given this item 2) Use the
   * passed character's location info to add the spawn 3) create a copy of the item to drop in the world returns the
   * id of the mercenary npc that was added to the spawn returns -1 if this fails.
   * @param itemId
   * @param activeChar
   * @param messages
   * @return
   */
  public int addTicket(int itemId, L2PcInstance activeChar, String[] messages)
  {
    int x = activeChar.getX();
    int y = activeChar.getY();
    int z = activeChar.getZ();
    int heading = activeChar.getHeading();

    Castle castle = CastleManager.getInstance().getCastle(activeChar);
    if(castle == null) //this should never happen at this point
      return -1;

    //check if this item can be added here
    for(int i = 0; i < ITEM_IDS.length; i++)
    {
      if(ITEM_IDS[i] == itemId) // Find the index of the item used
      {
        spawnMercenary(NPC_IDS[i], x, y, z, 3000, messages, 0);

        // Hire merc for this caslte.  NpcId is at the same index as the item used.
        castle.getSiege().getSiegeGuardManager().hireMerc(x, y, z, heading, NPC_IDS[i]);

        // create the ticket in the gameworld
        L2ItemInstance dropticket = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
        dropticket.setLocation(L2ItemInstance.ItemLocation.INVENTORY);
        dropticket.dropMe(null, x, y, z);
        dropticket.setDropTime(0); //avoids it from beeing removed by the auto item destroyer
        L2World.getInstance().storeObject(dropticket); //add to the world
        // and keep track of this ticket in the list
        _droppedTickets.add(dropticket);

        dropticket = null;

        return NPC_IDS[i];
      }
    }
    castle = null;
    return -1;
  }

  private void spawnMercenary(int npcId, int x, int y, int z, int despawnDelay, String[] messages, int chatDelay)
  {
    L2NpcTemplate template = NpcTable.getInstance().getTemplate(npcId);
    if(template != null)
    {
      final L2SiegeGuardInstance npc = new L2SiegeGuardInstance(IdFactory.getInstance().getNextId(), template);
      npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp());
      npc.setDecayed(false);
      npc.spawnMe(x, y, (z + 20));

      if(messages != null && messages.length > 0)
      {
        AutoChatHandler.getInstance().registerChat(npc, messages, chatDelay);
      }

      if(despawnDelay > 0)
      {
        ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() {
          @Override
          public void run()
          {
            npc.deleteMe();
          }
        }, despawnDelay);
      }
    }
    template = null;
  }

  /**
   * Delete all tickets from a castle; remove the items from the world and remove references to them from this class
   * @param castleId
   */
  public void deleteTickets(int castleId)
  {
    int i = 0;
    while(i < getDroppedTickets().size())
    {
      L2ItemInstance item = getDroppedTickets().get(i);
      if(item != null && getTicketCastleId(item.getItemId()) == castleId)
      {
        item.decayMe();
        L2World.getInstance().removeObject(item);

        // remove from the list
        getDroppedTickets().remove(i);
      }
      else
      {
        i++;
      }

      item = null;
    }
  }

  /**
   * remove a single ticket and its associated spawn from the world (used when the castle lord picks up a ticket, for
   * example)
   * @param item
   */
  public void removeTicket(L2ItemInstance item)
  {
    int itemId = item.getItemId();
    int npcId = -1;

    // find the FIRST ticket itemId with spawns the saved NPC in the saved location
    for(int i = 0; i < ITEM_IDS.length; i++)
      if(ITEM_IDS[i] == itemId) // Find the index of the item used
      {
        npcId = NPC_IDS[i];
        break;
      }
    // find the castle where this item is
    Castle castle = CastleManager.getInstance().getCastleById(getTicketCastleId(itemId));

    if(npcId > 0 && castle != null)
    {
      new SiegeGuardManager(castle).removeMerc(npcId, item.getX(), item.getY(), item.getZ());
    }

    castle = null;

    getDroppedTickets().remove(item);
  }

  public int[] getItemIds()
  {
    return ITEM_IDS;
  }

  public final List<L2ItemInstance> getDroppedTickets()
  {
    return _droppedTickets;
  }
 
  private static class SingletonHolder
  {
    protected static final MercTicketManager _instance = new MercTicketManager();
  }
}
TOP

Related Classes of com.l2jfrozen.gameserver.managers.MercTicketManager$SingletonHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.