Interlude branch.

This commit is contained in:
MobiusDev
2018-03-03 00:51:38 +00:00
parent ae7660220a
commit e013196428
17475 changed files with 1039393 additions and 0 deletions

View File

@@ -0,0 +1,652 @@
/*
* 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;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.Server;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.crypt.nProtect;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.mmocore.NetcoreConfig;
import com.l2jmobius.commons.mmocore.SelectorConfig;
import com.l2jmobius.commons.mmocore.SelectorThread;
import com.l2jmobius.commons.util.IPv4Filter;
import com.l2jmobius.commons.util.Memory;
import com.l2jmobius.commons.util.Util;
import com.l2jmobius.gameserver.cache.CrestCache;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.communitybbs.Manager.ForumsBBSManager;
import com.l2jmobius.gameserver.datatables.BufferTable;
import com.l2jmobius.gameserver.datatables.GmListTable;
import com.l2jmobius.gameserver.datatables.HeroSkillTable;
import com.l2jmobius.gameserver.datatables.NobleSkillTable;
import com.l2jmobius.gameserver.datatables.OfflineTradeTable;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.datatables.csv.DoorTable;
import com.l2jmobius.gameserver.datatables.csv.ExtractableItemsData;
import com.l2jmobius.gameserver.datatables.csv.FishTable;
import com.l2jmobius.gameserver.datatables.csv.HennaTable;
import com.l2jmobius.gameserver.datatables.csv.MapRegionTable;
import com.l2jmobius.gameserver.datatables.csv.NpcWalkerRoutesTable;
import com.l2jmobius.gameserver.datatables.csv.RecipeTable;
import com.l2jmobius.gameserver.datatables.csv.StaticObjects;
import com.l2jmobius.gameserver.datatables.csv.SummonItemsData;
import com.l2jmobius.gameserver.datatables.sql.AccessLevels;
import com.l2jmobius.gameserver.datatables.sql.AdminCommandAccessRights;
import com.l2jmobius.gameserver.datatables.sql.ArmorSetsTable;
import com.l2jmobius.gameserver.datatables.sql.CharNameTable;
import com.l2jmobius.gameserver.datatables.sql.CharTemplateTable;
import com.l2jmobius.gameserver.datatables.sql.ClanTable;
import com.l2jmobius.gameserver.datatables.sql.CustomArmorSetsTable;
import com.l2jmobius.gameserver.datatables.sql.HelperBuffTable;
import com.l2jmobius.gameserver.datatables.sql.HennaTreeTable;
import com.l2jmobius.gameserver.datatables.sql.L2PetDataTable;
import com.l2jmobius.gameserver.datatables.sql.LevelUpData;
import com.l2jmobius.gameserver.datatables.sql.NpcTable;
import com.l2jmobius.gameserver.datatables.sql.SkillSpellbookTable;
import com.l2jmobius.gameserver.datatables.sql.SkillTreeTable;
import com.l2jmobius.gameserver.datatables.sql.SpawnTable;
import com.l2jmobius.gameserver.datatables.sql.TeleportLocationTable;
import com.l2jmobius.gameserver.datatables.xml.AugmentationData;
import com.l2jmobius.gameserver.datatables.xml.ExperienceData;
import com.l2jmobius.gameserver.datatables.xml.ItemTable;
import com.l2jmobius.gameserver.datatables.xml.ZoneData;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.geodata.geoeditorcon.GeoEditorListener;
import com.l2jmobius.gameserver.geodata.pathfinding.PathFinding;
import com.l2jmobius.gameserver.handler.AdminCommandHandler;
import com.l2jmobius.gameserver.handler.AutoAnnouncementHandler;
import com.l2jmobius.gameserver.handler.AutoChatHandler;
import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.handler.SkillHandler;
import com.l2jmobius.gameserver.handler.UserCommandHandler;
import com.l2jmobius.gameserver.handler.VoicedCommandHandler;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.AuctionManager;
import com.l2jmobius.gameserver.instancemanager.AutoSaveManager;
import com.l2jmobius.gameserver.instancemanager.AwayManager;
import com.l2jmobius.gameserver.instancemanager.BoatManager;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
import com.l2jmobius.gameserver.instancemanager.CastleManorManager;
import com.l2jmobius.gameserver.instancemanager.ClanHallManager;
import com.l2jmobius.gameserver.instancemanager.ClassDamageManager;
import com.l2jmobius.gameserver.instancemanager.CoupleManager;
import com.l2jmobius.gameserver.instancemanager.CrownManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager;
import com.l2jmobius.gameserver.instancemanager.DuelManager;
import com.l2jmobius.gameserver.instancemanager.FishingChampionshipManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.FourSepulchersManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.instancemanager.MercTicketManager;
import com.l2jmobius.gameserver.instancemanager.PetitionManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.RaidBossPointsManager;
import com.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
import com.l2jmobius.gameserver.instancemanager.SiegeManager;
import com.l2jmobius.gameserver.model.L2Manor;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.PartyMatchRoomList;
import com.l2jmobius.gameserver.model.PartyMatchWaitingList;
import com.l2jmobius.gameserver.model.entity.Announcements;
import com.l2jmobius.gameserver.model.entity.Hero;
import com.l2jmobius.gameserver.model.entity.MonsterRace;
import com.l2jmobius.gameserver.model.entity.event.manager.EventManager;
import com.l2jmobius.gameserver.model.entity.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.entity.sevensigns.SevenSigns;
import com.l2jmobius.gameserver.model.entity.sevensigns.SevenSignsFestival;
import com.l2jmobius.gameserver.model.entity.siege.clanhalls.BanditStrongholdSiege;
import com.l2jmobius.gameserver.model.entity.siege.clanhalls.DevastatedCastle;
import com.l2jmobius.gameserver.model.entity.siege.clanhalls.FortressOfResistance;
import com.l2jmobius.gameserver.model.multisell.L2Multisell;
import com.l2jmobius.gameserver.model.spawn.AutoSpawn;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.L2GamePacketHandler;
import com.l2jmobius.gameserver.script.EventDroplist;
import com.l2jmobius.gameserver.script.faenor.FaenorScriptEngine;
import com.l2jmobius.gameserver.scripting.CompiledScriptCache;
import com.l2jmobius.gameserver.scripting.L2ScriptEngineManager;
import com.l2jmobius.gameserver.taskmanager.TaskManager;
import com.l2jmobius.gameserver.thread.LoginServerThread;
import com.l2jmobius.gameserver.thread.daemons.DeadlockDetector;
import com.l2jmobius.gameserver.thread.daemons.ItemsAutoDestroy;
import com.l2jmobius.gameserver.thread.daemons.PcPoint;
import com.l2jmobius.gameserver.util.DynamicExtension;
import com.l2jmobius.status.Status;
public class GameServer
{
private static Logger LOGGER = Logger.getLogger(GameServer.class.getName());
// Local Constants
private static final String LOG_FOLDER = "log"; // Name of folder for log file
private static final String LOG_NAME = "./config/others/log.cfg"; // Name of log file
private static SelectorThread<L2GameClient> _selectorThread;
private static LoginServerThread _loginThread;
private static L2GamePacketHandler _gamePacketHandler;
private static Status _statusServer;
public static final Calendar dateTimeServerStarted = Calendar.getInstance();
public static void main(String[] args) throws Exception
{
Server.serverMode = Server.MODE_GAMESERVER;
// Create log folder
final File logFolder = new File(Config.DATAPACK_ROOT, LOG_FOLDER);
logFolder.mkdir();
// Create input stream for log file -- or store file data into memory
try (InputStream is = new FileInputStream(new File(LOG_NAME)))
{
LogManager.getLogManager().readConfiguration(is);
}
final long serverLoadStart = System.currentTimeMillis();
// Load GameServer Configs
Config.load();
Util.printSection("Database");
DatabaseFactory.getInstance();
LOGGER.info("L2DatabaseFactory: loaded.");
Util.printSection("Threads");
ThreadPoolManager.init();
if (Config.DEADLOCKCHECK_INTIAL_TIME > 0)
{
ThreadPoolManager.scheduleAtFixedRate(DeadlockDetector.getInstance(), Config.DEADLOCKCHECK_INTIAL_TIME, Config.DEADLOCKCHECK_DELAY_TIME);
}
new File(Config.DATAPACK_ROOT, "data/clans").mkdirs();
new File(Config.DATAPACK_ROOT, "data/crests").mkdirs();
new File(Config.DATAPACK_ROOT, "data/pathnode").mkdirs();
new File(Config.DATAPACK_ROOT, "data/geodata").mkdirs();
HtmCache.getInstance();
CrestCache.getInstance();
L2ScriptEngineManager.getInstance();
nProtect.getInstance();
if (nProtect.isEnabled())
{
LOGGER.info("nProtect System Enabled");
}
Util.printSection("World");
L2World.getInstance();
MapRegionTable.getInstance();
Announcements.getInstance();
AutoAnnouncementHandler.getInstance();
if (!IdFactory.getInstance().isInitialized())
{
LOGGER.info("Could not read object IDs from DB. Please Check Your Data.");
throw new Exception("Could not initialize the ID factory");
}
GlobalVariablesManager.getInstance();
StaticObjects.getInstance();
TeleportLocationTable.getInstance();
PartyMatchWaitingList.getInstance();
PartyMatchRoomList.getInstance();
GameTimeController.getInstance();
CharNameTable.getInstance();
ExperienceData.getInstance();
DuelManager.getInstance();
if (Config.ENABLE_CLASS_DAMAGES)
{
ClassDamageManager.loadConfig();
}
if (Config.AUTOSAVE_DELAY_TIME > 0)
{
AutoSaveManager.getInstance().startAutoSaveManager();
}
Util.printSection("Skills");
if (!SkillTable.getInstance().isInitialized())
{
LOGGER.info("Could not find the extraced files. Please Check Your Data.");
throw new Exception("Could not initialize the skill table");
}
SkillTreeTable.getInstance();
SkillSpellbookTable.getInstance();
NobleSkillTable.getInstance();
HeroSkillTable.getInstance();
LOGGER.info("Skills: All skills loaded.");
Util.printSection("Items");
ItemTable.getInstance();
ArmorSetsTable.getInstance();
if (Config.CUSTOM_ARMORSETS_TABLE)
{
CustomArmorSetsTable.getInstance();
}
ExtractableItemsData.getInstance();
SummonItemsData.getInstance();
if (Config.ALLOWFISHING)
{
FishTable.getInstance();
}
Util.printSection("Npc");
BufferTable.getInstance();
NpcWalkerRoutesTable.getInstance().load();
if (!NpcTable.getInstance().isInitialized())
{
LOGGER.info("Could not find the extracted files. Please Check Your Data.");
throw new Exception("Could not initialize the npc table");
}
Util.printSection("Characters");
if (Config.ENABLE_COMMUNITY_BOARD)
{
ForumsBBSManager.getInstance().initRoot();
}
ClanTable.getInstance();
CharTemplateTable.getInstance();
LevelUpData.getInstance();
if (!HennaTable.getInstance().isInitialized())
{
throw new Exception("Could not initialize the Henna Table");
}
if (!HennaTreeTable.getInstance().isInitialized())
{
throw new Exception("Could not initialize the Henna Tree Table");
}
if (!HelperBuffTable.getInstance().isInitialized())
{
throw new Exception("Could not initialize the Helper Buff Table");
}
Util.printSection("Geodata");
GeoData.getInstance();
if (Config.PATHFINDING > 0)
{
PathFinding.getInstance();
}
Util.printSection("Economy");
TradeController.getInstance();
L2Multisell.getInstance();
LOGGER.info("Multisell: loaded.");
Util.printSection("Clan Halls");
ClanHallManager.getInstance();
FortressOfResistance.getInstance();
DevastatedCastle.getInstance();
BanditStrongholdSiege.getInstance();
AuctionManager.getInstance();
Util.printSection("Zone");
ZoneData.getInstance();
Util.printSection("Spawnlist");
if (!Config.ALT_DEV_NO_SPAWNS)
{
SpawnTable.getInstance();
}
else
{
LOGGER.info("Spawn: disable load.");
}
if (!Config.ALT_DEV_NO_RB)
{
RaidBossSpawnManager.getInstance();
GrandBossManager.getInstance();
RaidBossPointsManager.init();
}
else
{
LOGGER.info("RaidBoss: disable load.");
}
DayNightSpawnManager.getInstance().notifyChangeMode();
Util.printSection("Dimensional Rift");
DimensionalRiftManager.getInstance();
Util.printSection("Misc");
RecipeTable.getInstance();
RecipeController.getInstance();
EventDroplist.getInstance();
AugmentationData.getInstance();
MonsterRace.getInstance();
MercTicketManager.getInstance();
PetitionManager.getInstance();
CursedWeaponsManager.getInstance();
TaskManager.getInstance();
L2PetDataTable.getInstance().loadPetsData();
if (Config.ACCEPT_GEOEDITOR_CONN)
{
GeoEditorListener.getInstance();
}
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance();
}
if ((Config.AUTODESTROY_ITEM_AFTER > 0) || (Config.HERB_AUTO_DESTROY_TIME > 0))
{
ItemsAutoDestroy.getInstance();
}
Util.printSection("Manor");
L2Manor.getInstance();
CastleManorManager.getInstance();
Util.printSection("Castles");
CastleManager.getInstance();
SiegeManager.getInstance();
FortManager.getInstance();
FortSiegeManager.getInstance();
CrownManager.getInstance();
Util.printSection("Boat");
BoatManager.getInstance();
Util.printSection("Doors");
DoorTable.getInstance().parseData();
Util.printSection("Four Sepulchers");
FourSepulchersManager.getInstance();
Util.printSection("Seven Signs");
SevenSigns.getInstance();
SevenSignsFestival.getInstance();
AutoSpawn.getInstance();
AutoChatHandler.getInstance();
Util.printSection("Olympiad System");
Olympiad.getInstance();
Hero.getInstance();
Util.printSection("Access Levels");
AccessLevels.getInstance();
AdminCommandAccessRights.getInstance();
GmListTable.getInstance();
Util.printSection("Handlers");
ItemHandler.getInstance();
SkillHandler.getInstance();
AdminCommandHandler.getInstance();
UserCommandHandler.getInstance();
VoicedCommandHandler.getInstance();
LOGGER.info("AutoChatHandler : Loaded " + AutoChatHandler.getInstance().size() + " handlers in total.");
LOGGER.info("AutoSpawnHandler : Loaded " + AutoSpawn.getInstance().size() + " handlers in total.");
Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
try
{
DoorTable doorTable = DoorTable.getInstance();
// Opened by players like L2OFF
// doorTable.getDoor(19160010).openMe();
// doorTable.getDoor(19160011).openMe();
doorTable.getDoor(19160012).openMe();
doorTable.getDoor(19160013).openMe();
doorTable.getDoor(19160014).openMe();
doorTable.getDoor(19160015).openMe();
doorTable.getDoor(19160016).openMe();
doorTable.getDoor(19160017).openMe();
doorTable.getDoor(24190001).openMe();
doorTable.getDoor(24190002).openMe();
doorTable.getDoor(24190003).openMe();
doorTable.getDoor(24190004).openMe();
doorTable.getDoor(23180001).openMe();
doorTable.getDoor(23180002).openMe();
doorTable.getDoor(23180003).openMe();
doorTable.getDoor(23180004).openMe();
doorTable.getDoor(23180005).openMe();
doorTable.getDoor(23180006).openMe();
doorTable.checkAutoOpen();
}
catch (NullPointerException e)
{
LOGGER.info("There is errors in your Door.csv file. Update door.csv");
}
Util.printSection("Scripts");
if (!Config.ALT_DEV_NO_SCRIPT)
{
final File scripts = new File(Config.DATAPACK_ROOT, "data/scripts.cfg");
L2ScriptEngineManager.getInstance().executeScriptsList(scripts);
final CompiledScriptCache compiledScriptCache = L2ScriptEngineManager.getInstance().getCompiledScriptCache();
if (compiledScriptCache == null)
{
LOGGER.info("Compiled Scripts Cache is disabled.");
}
else
{
compiledScriptCache.purge();
if (compiledScriptCache.isModified())
{
compiledScriptCache.save();
LOGGER.info("Compiled Scripts Cache was saved.");
}
else
{
LOGGER.info("Compiled Scripts Cache is up-to-date.");
}
}
FaenorScriptEngine.getInstance();
}
else
{
LOGGER.info("Script: disable load.");
}
if (Config.ALT_FISH_CHAMPIONSHIP_ENABLED)
{
FishingChampionshipManager.getInstance();
}
/* QUESTS */
Util.printSection("Quests");
if (!Config.ALT_DEV_NO_QUESTS)
{
if (QuestManager.getInstance().getQuests().size() == 0)
{
QuestManager.getInstance().reloadAllQuests();
}
else
{
QuestManager.getInstance().report();
}
}
else
{
QuestManager.getInstance().unloadAllQuests();
}
Util.printSection("Game Server");
LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size());
try
{
DynamicExtension.getInstance();
}
catch (Exception ex)
{
LOGGER.info("DynamicExtension could not be loaded and initialized" + ex);
}
Util.printSection("Custom Mods");
if (Config.L2JMOD_ALLOW_WEDDING || Config.ALLOW_AWAY_STATUS || Config.PCB_ENABLE)
{
if (Config.L2JMOD_ALLOW_WEDDING)
{
CoupleManager.getInstance();
}
if (Config.ALLOW_AWAY_STATUS)
{
AwayManager.getInstance();
}
if (Config.PCB_ENABLE)
{
ThreadPoolManager.scheduleAtFixedRate(PcPoint.getInstance(), Config.PCB_INTERVAL * 1000, Config.PCB_INTERVAL * 1000);
}
}
else
{
LOGGER.info("All custom mods are Disabled.");
}
Util.printSection("EventManager");
EventManager.getInstance().startEventRegistration();
if (EventManager.TVT_EVENT_ENABLED || EventManager.CTF_EVENT_ENABLED || EventManager.DM_EVENT_ENABLED)
{
if (EventManager.TVT_EVENT_ENABLED)
{
LOGGER.info("TVT Event is Enabled.");
}
if (EventManager.CTF_EVENT_ENABLED)
{
LOGGER.info("CTF Event is Enabled.");
}
if (EventManager.DM_EVENT_ENABLED)
{
LOGGER.info("DM Event is Enabled.");
}
}
else
{
LOGGER.info("All events are Disabled.");
}
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{
OfflineTradeTable.restoreOfflineTraders();
}
Util.printSection("Protection");
if (Config.CHECK_SKILLS_ON_ENTER)
{
LOGGER.info("Check skills on enter actived.");
}
if (Config.CHECK_NAME_ON_LOGIN)
{
LOGGER.info("Check bad name on enter actived.");
}
if (Config.PROTECTED_ENCHANT)
{
LOGGER.info("Check OverEnchant items on enter actived.");
}
if (Config.BYPASS_VALIDATION)
{
LOGGER.info("Bypass Validation actived.");
}
if (Config.L2WALKER_PROTEC)
{
LOGGER.info("L2Walker protection actived.");
}
Util.printSection("Info");
LOGGER.info("Maximum Numbers of Connected Players: " + Config.MAXIMUM_ONLINE_USERS);
LOGGER.info("GameServer Started, free memory " + Memory.getFreeMemory() + " Mb of " + Memory.getTotalMemory() + " Mb");
LOGGER.info("Used memory: " + Memory.getUsedMemory() + " MB");
Util.printSection("Status");
System.gc();
LOGGER.info("Server Loaded in " + ((System.currentTimeMillis() - serverLoadStart) / 1000) + " seconds");
ServerStatus.getInstance();
// Load telnet status
Util.printSection("Telnet");
if (Config.IS_TELNET_ENABLED)
{
_statusServer = new Status(Server.serverMode);
_statusServer.start();
}
else
{
LOGGER.info("Telnet server is disabled.");
}
Util.printSection("Login");
_loginThread = LoginServerThread.getInstance();
_loginThread.start();
final SelectorConfig sc = new SelectorConfig();
sc.setMaxReadPerPass(NetcoreConfig.getInstance().MMO_MAX_READ_PER_PASS);
sc.setMaxSendPerPass(NetcoreConfig.getInstance().MMO_MAX_SEND_PER_PASS);
sc.setSleepTime(NetcoreConfig.getInstance().MMO_SELECTOR_SLEEP_TIME);
sc.setHelperBufferCount(NetcoreConfig.getInstance().MMO_HELPER_BUFFER_COUNT);
_gamePacketHandler = new L2GamePacketHandler();
_selectorThread = new SelectorThread<>(sc, _gamePacketHandler, _gamePacketHandler, _gamePacketHandler, new IPv4Filter());
InetAddress bindAddress = null;
if (!Config.GAMESERVER_HOSTNAME.equals("*"))
{
try
{
bindAddress = InetAddress.getByName(Config.GAMESERVER_HOSTNAME);
}
catch (UnknownHostException e1)
{
LOGGER.warning("The GameServer bind address is invalid, using all avaliable IPs. Reason: " + e1);
}
}
try
{
_selectorThread.openServerSocket(bindAddress, Config.PORT_GAME);
}
catch (IOException e)
{
LOGGER.severe("Failed to open server socket. Reason: " + e);
System.exit(1);
}
_selectorThread.start();
}
public static SelectorThread<L2GameClient> getSelectorThread()
{
return _selectorThread;
}
}

View File

@@ -0,0 +1,283 @@
/*
* 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;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Logger;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jmobius.gameserver.model.actor.L2Character;
/**
* This class ...
* @version $Revision: 1.1.4.8 $ $Date: 2005/04/06 16:13:24 $
*/
public class GameTimeController
{
static final Logger LOGGER = Logger.getLogger(GameTimeController.class.getName());
public static final int TICKS_PER_SECOND = 10;
public static final int MILLIS_IN_TICK = 1000 / TICKS_PER_SECOND;
private static GameTimeController _instance = new GameTimeController();
protected static int _gameTicks;
protected static long _gameStartTime;
protected static boolean _isNight = false;
private static List<L2Character> _movingObjects = new ArrayList<>();
protected static TimerThread _timer;
private final ScheduledFuture<?> _timerWatcher;
/**
* one ingame day is 240 real minutes
* @return
*/
public static GameTimeController getInstance()
{
return _instance;
}
private GameTimeController()
{
_gameStartTime = System.currentTimeMillis() - 3600000; // offset so that the server starts a day begin
_gameTicks = 3600000 / MILLIS_IN_TICK; // offset so that the server starts a day begin
_timer = new TimerThread();
_timer.start();
_timerWatcher = ThreadPoolManager.scheduleAtFixedRate(new TimerWatcher(), 0, 1000);
ThreadPoolManager.scheduleAtFixedRate(new BroadcastSunState(), 0, 600000);
}
public boolean isNowNight()
{
return _isNight;
}
public int getGameTime()
{
return _gameTicks / (TICKS_PER_SECOND * 10);
}
public static int getGameTicks()
{
return _gameTicks;
}
/**
* Add a L2Character to movingObjects of GameTimeController.<BR>
* <BR>
* <B><U> Concept</U> :</B><BR>
* <BR>
* All L2Character in movement are identified in <B>movingObjects</B> of GameTimeController.<BR>
* <BR>
* @param cha The L2Character to add to movingObjects of GameTimeController
*/
public synchronized void registerMovingObject(L2Character cha)
{
if (cha == null)
{
return;
}
if (!_movingObjects.contains(cha))
{
_movingObjects.add(cha);
}
}
/**
* Move all L2Characters contained in movingObjects of GameTimeController.<BR>
* <BR>
* <B><U> Concept</U> :</B><BR>
* <BR>
* All L2Character in movement are identified in <B>movingObjects</B> of GameTimeController.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update the position of each L2Character</li>
* <li>If movement is finished, the L2Character is removed from movingObjects</li>
* <li>Create a task to update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object then notify AI with EVT_ARRIVED</li><BR>
* <BR>
*/
protected synchronized void moveObjects()
{
// Get all L2Character from the ArrayList movingObjects and put them into a table
final L2Character[] chars = _movingObjects.toArray(new L2Character[_movingObjects.size()]);
// Create an ArrayList to contain all L2Character that are arrived to destination
List<L2Character> ended = null;
// Go throw the table containing L2Character in movement
for (L2Character cha : chars)
{
// Update the position of the L2Character and return True if the movement is finished
final boolean end = cha.updatePosition(_gameTicks);
// If movement is finished, the L2Character is removed from movingObjects and added to the ArrayList ended
if (end)
{
_movingObjects.remove(cha);
if (ended == null)
{
ended = new ArrayList<>();
}
ended.add(cha);
}
}
// Create a task to update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object
// then notify AI with EVT_ARRIVED
// TODO: maybe a general TP is needed for that kinda stuff (all knownlist updates should be done in a TP anyway).
if (ended != null)
{
ThreadPoolManager.execute(new MovingObjectArrived(ended));
}
}
public void stopTimer()
{
_timerWatcher.cancel(true);
_timer.interrupt();
}
class TimerThread extends Thread
{
protected Exception _error;
public TimerThread()
{
super("GameTimeController");
setDaemon(true);
setPriority(MAX_PRIORITY);
}
@Override
public void run()
{
for (;;)
{
final int _oldTicks = _gameTicks; // save old ticks value to avoid moving objects 2x in same tick
long runtime = System.currentTimeMillis() - _gameStartTime; // from server boot to now
_gameTicks = (int) (runtime / MILLIS_IN_TICK); // new ticks value (ticks now)
if (_oldTicks != _gameTicks)
{
moveObjects(); // XXX: if this makes objects go slower, remove it
// but I think it can't make that effect. is it better to call moveObjects() twice in same
// tick to make-up for missed tick ? or is it better to ignore missed tick ?
// (will happen very rarely but it will happen ... on garbage collection definitely)
}
runtime = System.currentTimeMillis() - _gameStartTime - runtime;
// calculate sleep time... time needed to next tick minus time it takes to call moveObjects()
final int sleepTime = (1 + MILLIS_IN_TICK) - ((int) runtime % MILLIS_IN_TICK);
// LOGGER.finest("TICK: "+_gameTicks);
try
{
sleep(sleepTime); // hope other threads will have much more cpu time available now
}
catch (InterruptedException ie)
{
// nothing
}
// SelectorThread most of all
}
}
}
class TimerWatcher implements Runnable
{
@Override
public void run()
{
if (!_timer.isAlive())
{
final String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
LOGGER.warning(time + " TimerThread stop with following error. restart it.");
if (_timer._error != null)
{
_timer._error.printStackTrace();
}
_timer = new TimerThread();
_timer.start();
}
}
}
/**
* Update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object then notify AI with EVT_ARRIVED.<BR>
* <BR>
*/
class MovingObjectArrived implements Runnable
{
private final List<L2Character> _ended;
MovingObjectArrived(List<L2Character> ended)
{
_ended = ended;
}
@Override
public void run()
{
for (L2Character cha : _ended)
{
try
{
cha.getKnownList().updateKnownObjects();
cha.getAI().notifyEvent(CtrlEvent.EVT_ARRIVED);
}
catch (NullPointerException e)
{
}
}
}
}
class BroadcastSunState implements Runnable
{
@Override
public void run()
{
final int h = (getGameTime() / 60) % 24; // Time in hour
final boolean tempIsNight = h < 6;
// If diff day/night state
if (tempIsNight != _isNight)
{
// Set current day/night varible to value of temp varible
_isNight = tempIsNight;
DayNightSpawnManager.getInstance().notifyChangeMode();
}
}
}
}

View File

@@ -0,0 +1,733 @@
/*
* 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.datatables.csv.RecipeTable;
import com.l2jmobius.gameserver.model.Inventory;
import com.l2jmobius.gameserver.model.L2ManufactureItem;
import com.l2jmobius.gameserver.model.L2RecipeList;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2RecipeInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ItemList;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.RecipeBookItemList;
import com.l2jmobius.gameserver.network.serverpackets.RecipeItemMakeInfo;
import com.l2jmobius.gameserver.network.serverpackets.RecipeShopItemInfo;
import com.l2jmobius.gameserver.network.serverpackets.SetupGauge;
import com.l2jmobius.gameserver.network.serverpackets.StatusUpdate;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.skills.Stats;
import com.l2jmobius.gameserver.util.Util;
public class RecipeController
{
protected static final Logger LOGGER = Logger.getLogger(RecipeController.class.getName());
private static RecipeController _instance;
protected static final Map<L2PcInstance, RecipeItemMaker> _activeMakers = Collections.synchronizedMap(new WeakHashMap<L2PcInstance, RecipeItemMaker>());
public static RecipeController getInstance()
{
return _instance == null ? _instance = new RecipeController() : _instance;
}
public synchronized void requestBookOpen(L2PcInstance player, boolean isDwarvenCraft)
{
RecipeItemMaker maker = null;
if (Config.ALT_GAME_CREATION)
{
maker = _activeMakers.get(player);
}
if (maker == null)
{
RecipeBookItemList response = new RecipeBookItemList(isDwarvenCraft, player.getMaxMp());
response.addRecipes(isDwarvenCraft ? player.getDwarvenRecipeBook() : player.getCommonRecipeBook());
player.sendPacket(response);
return;
}
SystemMessage sm = new SystemMessage(SystemMessageId.CANT_ALTER_RECIPEBOOK_WHILE_CRAFTING);
player.sendPacket(sm);
return;
}
public synchronized void requestMakeItemAbort(L2PcInstance player)
{
_activeMakers.remove(player); // TODO: anything else here?
}
public synchronized void requestManufactureItem(L2PcInstance manufacturer, int recipeListId, L2PcInstance player)
{
L2RecipeList recipeList = getValidRecipeList(player, recipeListId);
if (recipeList == null)
{
return;
}
List<L2RecipeList> dwarfRecipes = Arrays.asList(manufacturer.getDwarvenRecipeBook());
List<L2RecipeList> commonRecipes = Arrays.asList(manufacturer.getCommonRecipeBook());
if (!dwarfRecipes.contains(recipeList) && !commonRecipes.contains(recipeList))
{
Util.handleIllegalPlayerAction(player, "Warning!! Character " + player.getName() + " of account " + player.getAccountName() + " sent a false recipe id.", Config.DEFAULT_PUNISH);
return;
}
RecipeItemMaker maker;
if (Config.ALT_GAME_CREATION && ((maker = _activeMakers.get(manufacturer)) != null)) // check if busy
{
player.sendMessage("Manufacturer is busy, please try later.");
return;
}
maker = new RecipeItemMaker(manufacturer, recipeList, player);
if (maker._isValid)
{
if (Config.ALT_GAME_CREATION)
{
_activeMakers.put(manufacturer, maker);
ThreadPoolManager.schedule(maker, 100);
}
else
{
maker.run();
}
}
}
public synchronized void requestMakeItem(L2PcInstance player, int recipeListId)
{
if (player.isInDuel())
{
player.sendPacket(SystemMessageId.CANT_CRAFT_DURING_COMBAT);
return;
}
L2RecipeList recipeList = getValidRecipeList(player, recipeListId);
if (recipeList == null)
{
return;
}
List<L2RecipeList> dwarfRecipes = Arrays.asList(player.getDwarvenRecipeBook());
List<L2RecipeList> commonRecipes = Arrays.asList(player.getCommonRecipeBook());
if (!dwarfRecipes.contains(recipeList) && !commonRecipes.contains(recipeList))
{
Util.handleIllegalPlayerAction(player, "Warning!! Character " + player.getName() + " of account " + player.getAccountName() + " sent a false recipe id.", Config.DEFAULT_PUNISH);
return;
}
RecipeItemMaker maker;
// check if already busy (possible in alt mode only)
if (Config.ALT_GAME_CREATION && ((maker = _activeMakers.get(player)) != null))
{
final SystemMessage sm = new SystemMessage(SystemMessageId.S1_S2);
sm.addString("You are busy creating ");
sm.addItemName(recipeList.getItemId());
player.sendPacket(sm);
return;
}
maker = new RecipeItemMaker(player, recipeList, player);
if (maker._isValid)
{
if (Config.ALT_GAME_CREATION)
{
_activeMakers.put(player, maker);
ThreadPoolManager.schedule(maker, 100);
}
else
{
maker.run();
}
}
}
private class RecipeItemMaker implements Runnable
{
protected boolean _isValid;
protected List<TempItem> _items = null;
protected final L2RecipeList _recipeList;
protected final L2PcInstance _player; // "crafter"
protected final L2PcInstance _target; // "customer"
protected final L2Skill _skill;
protected final int _skillId;
protected final int _skillLevel;
protected double _creationPasses;
protected double _manaRequired;
protected int _price;
protected int _totalItems;
protected int _delay;
public RecipeItemMaker(L2PcInstance pPlayer, L2RecipeList pRecipeList, L2PcInstance pTarget)
{
_player = pPlayer;
_target = pTarget;
_recipeList = pRecipeList;
_isValid = false;
_skillId = _recipeList.isDwarvenRecipe() ? L2Skill.SKILL_CREATE_DWARVEN : L2Skill.SKILL_CREATE_COMMON;
_skillLevel = _player.getSkillLevel(_skillId);
_skill = _player.getKnownSkill(_skillId);
_player.isInCraftMode(true);
if (_player.isAlikeDead())
{
_player.sendMessage("Dead people don't craft.");
_player.sendPacket(ActionFailed.STATIC_PACKET);
abort();
return;
}
if (_target.isAlikeDead())
{
_target.sendMessage("Dead customers can't use manufacture.");
_target.sendPacket(ActionFailed.STATIC_PACKET);
abort();
return;
}
if (_target.isProcessingTransaction())
{
_target.sendMessage("You are busy.");
_target.sendPacket(ActionFailed.STATIC_PACKET);
abort();
return;
}
if (_player.isProcessingTransaction())
{
if (_player != _target)
{
_target.sendMessage("Manufacturer " + _player.getName() + " is busy.");
}
_player.sendPacket(ActionFailed.STATIC_PACKET);
abort();
return;
}
// validate recipe list
if ((_recipeList == null) || (_recipeList.getRecipes().length == 0))
{
_player.sendMessage("No such recipe");
_player.sendPacket(ActionFailed.STATIC_PACKET);
abort();
return;
}
_manaRequired = _recipeList.getMpCost();
// validate skill level
if (_recipeList.getLevel() > _skillLevel)
{
_player.sendMessage("Need skill level " + _recipeList.getLevel());
_player.sendPacket(ActionFailed.STATIC_PACKET);
abort();
return;
}
// check that customer can afford to pay for creation services
if (_player != _target)
{
for (L2ManufactureItem temp : _player.getCreateList().getList())
{
if (temp.getRecipeId() == _recipeList.getId()) // find recipe for item we want manufactured
{
_price = temp.getCost();
if (_target.getAdena() < _price) // check price
{
_target.sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
abort();
return;
}
break;
}
}
}
_items = listItems(false);
// make temporary items
if (_items == null)
{
abort();
return;
}
// calculate reference price
for (TempItem i : _items)
{
_totalItems += i.getQuantity();
}
// initial mana check requires MP as written on recipe
if (_player.getCurrentMp() < _manaRequired)
{
_target.sendPacket(SystemMessageId.NOT_ENOUGH_MP);
abort();
return;
}
// determine number of creation passes needed
// can "equip" skillLevel items each pass
_creationPasses = (_totalItems / _skillLevel) + ((_totalItems % _skillLevel) != 0 ? 1 : 0);
if (Config.ALT_GAME_CREATION && (_creationPasses != 0))
{
_manaRequired /= _creationPasses; // checks to validateMp() will only need portion of mp for one pass
}
updateMakeInfo(true);
updateCurMp();
updateCurLoad();
_player.isInCraftMode(false);
_isValid = true;
}
@Override
public void run()
{
if (!Config.IS_CRAFTING_ENABLED)
{
_target.sendMessage("Item creation is currently disabled.");
abort();
return;
}
if ((_player == null) || (_target == null))
{
LOGGER.warning("player or target == null (disconnected?), aborting" + _target + _player);
abort();
return;
}
if ((_player.isOnline() == 0) || (_target.isOnline() == 0))
{
LOGGER.warning("player or target is not online, aborting " + _target + _player);
abort();
return;
}
if (Config.ALT_GAME_CREATION && (_activeMakers.get(_player) == null))
{
if (_target != _player)
{
_target.sendMessage("Manufacture aborted");
_player.sendMessage("Manufacture aborted");
}
else
{
_player.sendMessage("Item creation aborted");
}
abort();
return;
}
if (Config.ALT_GAME_CREATION && !_items.isEmpty())
{
// check mana
if (!validateMp())
{
return;
}
// use some mp
_player.reduceCurrentMp(_manaRequired);
// update craft window mp bar
updateCurMp();
// grab (equip) some more items with a nice msg to player
grabSomeItems();
// if still not empty, schedule another pass
if (!_items.isEmpty())
{
// divided by RATE_CONSUMABLES_COST to remove craft time increase on higher consumables rates
_delay = (int) ((Config.ALT_GAME_CREATION_SPEED * _player.getMReuseRate(_skill) * GameTimeController.TICKS_PER_SECOND) / Config.RATE_CONSUMABLE_COST) * GameTimeController.MILLIS_IN_TICK;
// FIXME: please fix this packet to show crafting animation (somebody)
MagicSkillUse msk = new MagicSkillUse(_player, _skillId, _skillLevel, _delay, 0);
_player.broadcastPacket(msk);
_player.sendPacket(new SetupGauge(0, _delay));
ThreadPoolManager.schedule(this, 100 + _delay);
}
else
{
// for alt mode, sleep delay msec before finishing
_player.sendPacket(new SetupGauge(0, _delay));
try
{
Thread.sleep(_delay);
}
catch (InterruptedException e)
{
}
finally
{
finishCrafting();
}
}
}
// for old craft mode just finish
else
{
finishCrafting();
}
}
private void finishCrafting()
{
if (!Config.ALT_GAME_CREATION)
{
_player.reduceCurrentMp(_manaRequired);
}
// first take adena for manufacture
if ((_target != _player) && (_price > 0)) // customer must pay for services
{
// attempt to pay for item
L2ItemInstance adenatransfer = _target.transferItem("PayManufacture", _target.getInventory().getAdenaInstance().getObjectId(), _price, _player.getInventory(), _player);
if (adenatransfer == null)
{
_target.sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
abort();
return;
}
}
_items = listItems(true);
// this line actually takes materials from inventory
if (_items == null)
{
// handle possible cheaters here
// (they click craft then try to get rid of items in order to get free craft)
}
else if (Rnd.get(100) < _recipeList.getSuccessRate())
{
rewardPlayer(); // and immediately puts created item in its place
updateMakeInfo(true);
}
else
{
_player.sendMessage("Item(s) failed to create");
if (_target != _player)
{
_target.sendMessage("Item(s) failed to create");
}
updateMakeInfo(false);
}
// update load and mana bar of craft window
updateCurMp();
updateCurLoad();
_activeMakers.remove(_player);
_player.isInCraftMode(false);
_target.sendPacket(new ItemList(_target, false));
}
private void updateMakeInfo(boolean success)
{
if (_target == _player)
{
_target.sendPacket(new RecipeItemMakeInfo(_recipeList.getId(), _target, success));
}
else
{
_target.sendPacket(new RecipeShopItemInfo(_player.getObjectId(), _recipeList.getId()));
}
}
private void updateCurLoad()
{
StatusUpdate su = new StatusUpdate(_target.getObjectId());
su.addAttribute(StatusUpdate.CUR_LOAD, _target.getCurrentLoad());
_target.sendPacket(su);
}
private void updateCurMp()
{
StatusUpdate su = new StatusUpdate(_target.getObjectId());
su.addAttribute(StatusUpdate.CUR_MP, (int) _target.getCurrentMp());
_target.sendPacket(su);
}
private void grabSomeItems()
{
int numItems = _skillLevel;
while ((numItems > 0) && !_items.isEmpty())
{
TempItem item = _items.get(0);
int count = item.getQuantity();
if (count >= numItems)
{
count = numItems;
}
item.setQuantity(item.getQuantity() - count);
if (item.getQuantity() <= 0)
{
_items.remove(0);
}
else
{
_items.set(0, item);
}
numItems -= count;
if (_target == _player)
{
// you equipped ...
SystemMessage sm = new SystemMessage(SystemMessageId.S1_S2_EQUIPPED);
sm.addNumber(count);
sm.addItemName(item.getItemId());
_player.sendPacket(sm);
}
else
{
_target.sendMessage("Manufacturer " + _player.getName() + " used " + count + " " + item.getItemName());
}
}
}
private boolean validateMp()
{
if (_player.getCurrentMp() < _manaRequired)
{
// rest (wait for MP)
if (Config.ALT_GAME_CREATION)
{
_player.sendPacket(new SetupGauge(0, _delay));
ThreadPoolManager.schedule(this, 100 + _delay);
}
// no rest - report no mana
else
{
_target.sendPacket(SystemMessageId.NOT_ENOUGH_MP);
abort();
}
return false;
}
return true;
}
private List<TempItem> listItems(boolean remove)
{
L2RecipeInstance[] recipes = _recipeList.getRecipes();
Inventory inv = _target.getInventory();
final List<TempItem> materials = new ArrayList<>();
for (L2RecipeInstance recipe : recipes)
{
final int quantity = _recipeList.isConsumable() ? (int) (recipe.getQuantity() * Config.RATE_CONSUMABLE_COST) : recipe.getQuantity();
if (quantity > 0)
{
final L2ItemInstance item = inv.getItemByItemId(recipe.getItemId());
// check materials
if ((item == null) || (item.getCount() < quantity))
{
_target.sendMessage("You dont have the right elements for making this item" + (_recipeList.isConsumable() && (Config.RATE_CONSUMABLE_COST != 1) ? ".\nDue to server rates you need " + Config.RATE_CONSUMABLE_COST + "x more material than listed in recipe" : ""));
abort();
return null;
}
// make new temporary object, just for counting puroses
TempItem temp = new TempItem(item, quantity);
materials.add(temp);
}
}
if (remove)
{
for (TempItem tmp : materials)
{
inv.destroyItemByItemId("Manufacture", tmp.getItemId(), tmp.getQuantity(), _target, _player);
}
}
return materials;
}
private void abort()
{
updateMakeInfo(false);
_player.isInCraftMode(false);
_activeMakers.remove(_player);
}
/**
* FIXME: This class should be in some other file, but I don't know where Class explanation: For item counting or checking purposes. When you don't want to modify inventory class contains itemId, quantity, ownerId, referencePrice, but not objectId
*/
private class TempItem
{
// no object id stored, this will be only "list" of items with it's owner
private final int _itemId;
private int _quantity;
private final String _itemName;
/**
* @param item
* @param quantity of that item
*/
public TempItem(L2ItemInstance item, int quantity)
{
super();
_itemId = item.getItemId();
_quantity = quantity;
_itemName = item.getItem().getName();
}
/**
* @return Returns the quantity.
*/
public int getQuantity()
{
return _quantity;
}
/**
* @param quantity The quantity to set.
*/
public void setQuantity(int quantity)
{
_quantity = quantity;
}
/**
* @return Returns the itemId.
*/
public int getItemId()
{
return _itemId;
}
/**
* @return Returns the itemName.
*/
public String getItemName()
{
return _itemName;
}
}
private void rewardPlayer()
{
final int itemId = _recipeList.getItemId();
final int itemCount = _recipeList.getCount();
final L2ItemInstance createdItem = _target.getInventory().addItem("Manufacture", itemId, itemCount, _target, _player);
// inform customer of earned item
SystemMessage sm = null;
if (itemCount > 1)
{
sm = new SystemMessage(SystemMessageId.EARNED_S2_S1_S);
sm.addItemName(itemId);
sm.addNumber(itemCount);
_target.sendPacket(sm);
}
else
{
sm = new SystemMessage(SystemMessageId.EARNED_ITEM);
sm.addItemName(itemId);
_target.sendPacket(sm);
}
if (_target != _player)
{
// inform manufacturer of earned profit
sm = new SystemMessage(SystemMessageId.EARNED_ADENA);
sm.addNumber(_price);
_player.sendPacket(sm);
}
if (Config.ALT_GAME_CREATION)
{
final int recipeLevel = _recipeList.getLevel();
int exp = createdItem.getReferencePrice() * itemCount;
// one variation
// exp -= materialsRefPrice;
// mat. ref. price is not accurate so other method is better
if (exp < 0)
{
exp = 0;
}
// another variation
exp /= recipeLevel;
for (int i = _skillLevel; i > recipeLevel; i--)
{
exp /= 4;
}
final int sp = exp / 10;
// Added multiplication of Creation speed with XP/SP gain
// slower crafting -> more XP, faster crafting -> less XP
// you can use ALT_GAME_CREATION_XP_RATE/SP to
// modify XP/SP gained (default = 1)
_player.addExpAndSp((int) _player.calcStat(Stats.EXPSP_RATE, exp * Config.ALT_GAME_CREATION_XP_RATE * Config.ALT_GAME_CREATION_SPEED, null, null), (int) _player.calcStat(Stats.EXPSP_RATE, sp * Config.ALT_GAME_CREATION_SP_RATE * Config.ALT_GAME_CREATION_SPEED, null, null));
}
updateMakeInfo(true); // success
}
}
private L2RecipeList getValidRecipeList(L2PcInstance player, int id)
{
final L2RecipeList recipeList = RecipeTable.getInstance().getRecipeList(id - 1);
if ((recipeList == null) || (recipeList.getRecipes().length == 0))
{
player.sendMessage("No recipe for: " + id);
player.isInCraftMode(false);
return null;
}
return recipeList;
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Logger;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.util.Memory;
import com.l2jmobius.commons.util.Util;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
/**
* Server status
* @author Nefer
* @version 1.0
*/
public class ServerStatus
{
protected static final Logger LOGGER = Logger.getLogger(ServerStatus.class.getName());
protected ScheduledFuture<?> _scheduledTask;
protected ServerStatus()
{
_scheduledTask = ThreadPoolManager.scheduleAtFixedRate(new ServerStatusTask(), 1800000, 3600000);
}
protected class ServerStatusTask implements Runnable
{
protected final SimpleDateFormat fmt = new SimpleDateFormat("H:mm.");
@Override
public void run()
{
int ActivePlayers = 0;
int OfflinePlayers = 0;
for (L2PcInstance player : L2World.getInstance().getAllPlayers())
{
if (player.isInOfflineMode())
{
OfflinePlayers++;
}
else
{
ActivePlayers++;
}
}
Util.printSection("Server Status");
LOGGER.info("Server Time: " + fmt.format(new Date(System.currentTimeMillis())));
LOGGER.info("Active Players Online: " + ActivePlayers);
LOGGER.info("Offline Players Online: " + OfflinePlayers);
LOGGER.info("Threads: " + Thread.activeCount());
LOGGER.info("Free Memory: " + Memory.getFreeMemory() + " MB");
LOGGER.info("Used memory: " + Memory.getUsedMemory() + " MB");
Util.printSection("Server Status");
}
}
public static ServerStatus getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final ServerStatus _instance = new ServerStatus();
}
}

View File

@@ -0,0 +1,741 @@
/*
* 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;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.BufferTable;
import com.l2jmobius.gameserver.datatables.OfflineTradeTable;
import com.l2jmobius.gameserver.instancemanager.AutoSaveManager;
import com.l2jmobius.gameserver.instancemanager.CastleManorManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.FishingChampionshipManager;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.RaidBossSpawnManager;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Announcements;
import com.l2jmobius.gameserver.model.entity.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.entity.sevensigns.SevenSigns;
import com.l2jmobius.gameserver.model.entity.sevensigns.SevenSignsFestival;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.gameserverpackets.ServerStatus;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.thread.LoginServerThread;
/**
* This class provides the functions for shutting down and restarting the server It closes all open client connections and saves all data.
* @version $Revision: 1.2.4.6 $ $Date: 2009/05/12 19:45:09 $
*/
public class Shutdown extends Thread
{
public enum ShutdownModeType1
{
SIGTERM("Terminating"),
SHUTDOWN("Shutting down"),
RESTART("Restarting"),
ABORT("Aborting"),
TASK_SHUT("Shuting down"),
TASK_RES("Restarting"),
TELL_SHUT("Shuting down"),
TELL_RES("Restarting");
private final String _modeText;
ShutdownModeType1(String modeText)
{
_modeText = modeText;
}
public String getText()
{
return _modeText;
}
}
protected static final Logger LOGGER = Logger.getLogger(Shutdown.class.getName());
private static Shutdown _instance;
private static Shutdown _counterInstance = null;
private int _secondsShut;
private int _shutdownMode;
private boolean _shutdownStarted;
/** 0 */
public static final int SIGTERM = 0;
/** 1 */
public static final int GM_SHUTDOWN = 1;
/** 2 */
public static final int GM_RESTART = 2;
/** 3 */
public static final int ABORT = 3;
/** 4 */
public static final int TASK_SHUTDOWN = 4;
/** 5 */
public static final int TASK_RESTART = 5;
/** 6 */
public static final int TELL_SHUTDOWN = 6;
/** 7 */
public static final int TELL_RESTART = 7;
private static final String[] MODE_TEXT =
{
"SIGTERM",
"shutting down",
"restarting",
"aborting", // standart
"shutting down",
"restarting", // task
"shutting down",
"restarting"
}; // telnet
/**
* This function starts a shutdown count down from Telnet (Copied from Function startShutdown())
* @param IP Which Issued shutdown command
* @param seconds seconds until shutdown
* @param restart true if the server will restart after shutdown
*/
public void startTelnetShutdown(String IP, int seconds, boolean restart)
{
final Announcements _an = Announcements.getInstance();
LOGGER.warning("IP: " + IP + " issued shutdown command. " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
_an.announceToAll("Server is " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
if (restart)
{
_shutdownMode = TELL_RESTART;
}
else
{
_shutdownMode = TELL_SHUTDOWN;
}
if (_shutdownMode > 0)
{
_an.announceToAll("Server is " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
_an.announceToAll("Please exit game now!!");
}
if (_counterInstance != null)
{
_counterInstance._abort();
}
_counterInstance = new Shutdown(seconds, restart, false, true);
_counterInstance.start();
}
/**
* This function aborts a running countdown
* @param IP IP Which Issued shutdown command
*/
public void telnetAbort(String IP)
{
Announcements _an = Announcements.getInstance();
LOGGER.warning("IP: " + IP + " issued shutdown ABORT. " + MODE_TEXT[_shutdownMode] + " has been stopped!");
_an.announceToAll("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!");
if (_counterInstance != null)
{
_counterInstance._abort();
}
}
/**
* Default constructor is only used internal to create the shutdown-hook instance
*/
public Shutdown()
{
_secondsShut = -1;
_shutdownMode = SIGTERM;
_shutdownStarted = false;
}
/**
* This creates a count down instance of Shutdown.
* @param seconds how many seconds until shutdown
* @param restart true is the server shall restart after shutdown
* @param task
* @param telnet
*/
public Shutdown(int seconds, boolean restart, boolean task, boolean telnet)
{
if (seconds < 0)
{
seconds = 0;
}
_secondsShut = seconds;
if (restart)
{
if (!task)
{
_shutdownMode = GM_RESTART;
}
else if (telnet)
{
_shutdownMode = TELL_RESTART;
}
else
{
_shutdownMode = TASK_RESTART;
}
}
else if (!task)
{
_shutdownMode = GM_SHUTDOWN;
}
else if (telnet)
{
_shutdownMode = TELL_SHUTDOWN;
}
else
{
_shutdownMode = TASK_SHUTDOWN;
}
_shutdownStarted = false;
}
/**
* get the shutdown-hook instance the shutdown-hook instance is created by the first call of this function, but it has to be registered externally.
* @return instance of Shutdown, to be used as shutdown hook
*/
public static Shutdown getInstance()
{
if (_instance == null)
{
_instance = new Shutdown();
}
return _instance;
}
public boolean isShutdownStarted()
{
boolean output = _shutdownStarted;
// if a counter is started, the value of shutdownstarted is of counterinstance
if (_counterInstance != null)
{
output = _counterInstance._shutdownStarted;
}
return output;
}
/**
* this function is called, when a new thread starts if this thread is the thread of getInstance, then this is the shutdown hook and we save all data and disconnect all clients. after this thread ends, the server will completely exit if this is not the thread of getInstance, then this is a
* countdown thread. we start the countdown, and when we finished it, and it was not aborted, we tell the shutdown-hook why we call exit, and then call exit when the exit status of the server is 1, startServer.sh / startServer.bat will restart the server.
*/
@Override
public void run()
{
/*
* // disallow new logins try { //Doesnt actually do anything //Server.gameServer.getLoginController().setMaxAllowedOnlinePlayers(0); } catch(Throwable t) { if(Config.ENABLE_ALL_EXCEPTIONS) t.printStackTrace(); }
*/
if (this == _instance)
{
closeServer();
}
else
{
// gm shutdown: send warnings and then call exit to start shutdown sequence
countdown();
if (_shutdownMode != ABORT)
{
// last point where logging is operational :(
LOGGER.warning("GM shutdown countdown is over. " + MODE_TEXT[_shutdownMode] + " NOW!");
closeServer();
}
}
}
/**
* This functions starts a shutdown countdown
* @param activeChar GM who issued the shutdown command
* @param seconds seconds until shutdown
* @param restart true if the server will restart after shutdown
*/
public void startShutdown(L2PcInstance activeChar, int seconds, boolean restart)
{
Announcements _an = Announcements.getInstance();
if (activeChar != null)
{
LOGGER.warning("GM: " + activeChar.getName() + "(" + activeChar.getObjectId() + ") issued shutdown command. " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
}
else
{
LOGGER.warning("External Service issued shutdown command. " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
}
if (restart)
{
_shutdownMode = GM_RESTART;
}
else
{
_shutdownMode = GM_SHUTDOWN;
}
if (_shutdownMode > 0)
{
_an.announceToAll("Server is " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
_an.announceToAll("Please exit game now!!");
}
if (_counterInstance != null)
{
_counterInstance._abort();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart, false, false);
_counterInstance.start();
}
public int getCountdown()
{
return _secondsShut;
}
/**
* This function aborts a running countdown
* @param activeChar GM who issued the abort command
*/
public void abort(L2PcInstance activeChar)
{
Announcements _an = Announcements.getInstance();
if (activeChar != null)
{
LOGGER.warning("GM: " + activeChar.getName() + "(" + activeChar.getObjectId() + ") issued shutdown ABORT. " + MODE_TEXT[_shutdownMode] + " has been stopped!");
}
else
{
LOGGER.warning("External Service issued shutdown ABORT. " + MODE_TEXT[_shutdownMode] + " has been stopped!");
}
_an.announceToAll("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!");
if (_counterInstance != null)
{
_counterInstance._abort();
}
}
/**
* set the shutdown mode
* @param mode what mode shall be set
*/
/*
* private void setMode(int mode) { _shutdownMode = mode; }
*/
/**
* set shutdown mode to ABORT
*/
private void _abort()
{
_shutdownMode = ABORT;
}
/**
* this counts the countdown and reports it to all players countdown is aborted if mode changes to ABORT
*/
/**
* this counts the countdown and reports it to all players countdown is aborted if mode changes to ABORT
*/
private void countdown()
{
try
{
while (_secondsShut > 0)
{
int _seconds;
int _minutes;
int _hours;
_seconds = _secondsShut;
_minutes = _seconds / 60;
_hours = _seconds / 3600;
// announce only every minute after 10 minutes left and every second after 20 seconds
if (((_seconds <= 20) || (_seconds == (_minutes * 10))) && (_seconds <= 600) && (_hours <= 1))
{
SystemMessage sm = new SystemMessage(SystemMessageId.THE_SERVER_WILL_BE_COMING_DOWN_IN_S1_SECONDS);
sm.addString(Integer.toString(_seconds));
Announcements.getInstance().announceToAll(sm);
}
try
{
if (_seconds <= 60)
{
LoginServerThread.getInstance().setServerStatus(ServerStatus.STATUS_DOWN);
}
}
catch (Exception e)
{
// do nothing, we maybe are not connected to LS anymore
}
_secondsShut--;
final int delay = 1000; // milliseconds
Thread.sleep(delay);
if (_shutdownMode == ABORT)
{
break;
}
}
}
catch (InterruptedException e)
{
}
}
private void closeServer()
{
// last byebye, save all data and quit this server
// logging doesnt work here :(
_shutdownStarted = true;
try
{
LoginServerThread.getInstance().interrupt();
}
catch (Throwable t)
{
}
AutoSaveManager.getInstance().stopAutoSaveManager();
// saveData sends messages to exit players, so shutdown selector after it
saveData();
try
{
GameTimeController.getInstance().stopTimer();
}
catch (Throwable t)
{
}
try
{
// GameServer.getSelectorThread().setDaemon(true);
GameServer.getSelectorThread().shutdown();
}
catch (Throwable t)
{
}
// stop all threadpolls
try
{
ThreadPoolManager.shutdown();
}
catch (Throwable t)
{
}
LOGGER.info("Committing all data, last chance...");
// commit data, last chance
try
{
DatabaseFactory.getInstance().close();
}
catch (Throwable t)
{
}
LOGGER.info("All database data committed.");
System.runFinalization();
System.gc();
LOGGER.info("Memory cleanup, recycled unused objects.");
LOGGER.info("[STATUS] Server shutdown successfully.");
// server will quit, when this function ends.
/*
* switch (_shutdownMode) { case GM_SHUTDOWN: _instance.setMode(GM_SHUTDOWN); System.exit(0); break; case GM_RESTART: _instance.setMode(GM_RESTART); System.exit(2); break; case TASK_SHUTDOWN: _instance.setMode(TASK_SHUTDOWN); System.exit(4); break; case TASK_RESTART:
* _instance.setMode(TASK_RESTART); System.exit(5); break; case TELL_SHUTDOWN: _instance.setMode(TELL_SHUTDOWN); System.exit(6); break; case TELL_RESTART: _instance.setMode(TELL_RESTART); System.exit(7); break; }
*/
if (_instance._shutdownMode == GM_RESTART)
{
Runtime.getRuntime().halt(2);
}
else if (_instance._shutdownMode == TASK_RESTART)
{
Runtime.getRuntime().halt(5);
}
else if (_instance._shutdownMode == TASK_SHUTDOWN)
{
Runtime.getRuntime().halt(4);
}
else if (_instance._shutdownMode == TELL_RESTART)
{
Runtime.getRuntime().halt(7);
}
else if (_instance._shutdownMode == TELL_SHUTDOWN)
{
Runtime.getRuntime().halt(6);
}
else
{
Runtime.getRuntime().halt(0);
}
}
/**
* this sends a last byebye, disconnects all players and saves data
*/
private synchronized void saveData()
{
Announcements _an = Announcements.getInstance();
switch (_shutdownMode)
{
case SIGTERM:
{
LOGGER.info("SIGTERM received. Shutting down NOW!");
break;
}
case GM_SHUTDOWN:
{
LOGGER.info("GM shutdown received. Shutting down NOW!");
break;
}
case GM_RESTART:
{
LOGGER.info("GM restart received. Restarting NOW!");
break;
}
case TASK_SHUTDOWN:
{
LOGGER.info("Auto task shutdown received. Shutting down NOW!");
break;
}
case TASK_RESTART:
{
LOGGER.info("Auto task restart received. Restarting NOW!");
break;
}
case TELL_SHUTDOWN:
{
LOGGER.info("Telnet shutdown received. Shutting down NOW!");
break;
}
case TELL_RESTART:
{
LOGGER.info("Telnet restart received. Restarting NOW!");
break;
}
}
try
{
_an.announceToAll("Server is " + MODE_TEXT[_shutdownMode] + " NOW!");
}
catch (Throwable t)
{
}
try
{
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{
OfflineTradeTable.storeOffliners();
}
}
catch (Throwable t)
{
LOGGER.warning("Error saving offline shops. " + t);
}
try
{
wait(1000);
}
catch (InterruptedException e1)
{
}
// Disconnect all the players from the server
disconnectAllCharacters();
try
{
wait(5000);
}
catch (InterruptedException e1)
{
}
// Save players data!
saveAllPlayers();
try
{
wait(10000);
}
catch (InterruptedException e1)
{
}
// Seven Signs data is now saved along with Festival data.
if (!SevenSigns.getInstance().isSealValidationPeriod())
{
SevenSignsFestival.getInstance().saveFestivalData(false);
}
// Save Seven Signs data before closing. :)
SevenSigns.getInstance().saveSevenSignsData(null, true);
LOGGER.info("SevenSigns: All info saved!!");
// Save all raidboss status
RaidBossSpawnManager.getInstance().cleanUp();
LOGGER.info("RaidBossSpawnManager: All raidboss info saved!!");
// Save all Grandboss status
GrandBossManager.getInstance().cleanUp();
LOGGER.info("GrandBossManager: All Grand Boss info saved!!");
// Save data CountStore
TradeController.getInstance().dataCountStore();
LOGGER.info("TradeController: All count Item Saved");
// Save Olympiad status
try
{
Olympiad.getInstance().saveOlympiadStatus();
}
catch (Exception e)
{
e.printStackTrace();
}
LOGGER.info("Olympiad System: Data saved!!");
// Save Cursed Weapons data before closing.
CursedWeaponsManager.getInstance().saveData();
// Save all manor data
CastleManorManager.getInstance().save();
// Save Fishing tournament data
FishingChampionshipManager.getInstance().shutdown();
LOGGER.info("Fishing Championship data has been saved.");
// Schemes save.
BufferTable.getInstance().saveSchemes();
LOGGER.info("BufferTable data has been saved.");
// Save all global (non-player specific) Quest data that needs to persist after reboot
if (!Config.ALT_DEV_NO_QUESTS)
{
QuestManager.getInstance().save();
}
// Save items on ground before closing
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance().saveInDb();
ItemsOnGroundManager.getInstance().cleanUp();
LOGGER.info("ItemsOnGroundManager: All items on ground saved!!");
}
try
{
wait(5000);
}
catch (InterruptedException e)
{
// never happens :p
}
}
private void saveAllPlayers()
{
LOGGER.info("Saving all players data...");
for (L2PcInstance player : L2World.getInstance().getAllPlayers())
{
if (player == null)
{
continue;
}
// Logout Character
try
{
// Save player status
player.store();
}
catch (Throwable t)
{
}
}
}
/**
* this disconnects all clients from the server
*/
private void disconnectAllCharacters()
{
LOGGER.info("Disconnecting all players from the Server...");
for (L2PcInstance player : L2World.getInstance().getAllPlayers())
{
if (player == null)
{
continue;
}
try
{
// Player Disconnect
if (player.getClient() != null)
{
player.getClient().sendPacket(ServerClose.STATIC_PACKET);
player.getClient().close(0);
player.getClient().setActiveChar(null);
player.setClient(null);
}
}
catch (Throwable t)
{
}
}
}
}

View File

@@ -0,0 +1,687 @@
/*
* 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;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.xml.ItemTable;
import com.l2jmobius.gameserver.model.L2TradeList;
import com.l2jmobius.gameserver.model.actor.instance.L2ItemInstance;
/**
* This class ...
* @version $Revision: 1.5.4.13 $ $Date: 2005/04/06 16:13:38 $
*/
public class TradeController
{
private static Logger LOGGER = Logger.getLogger(TradeController.class.getName());
private static TradeController _instance;
private int _nextListId;
private final Map<Integer, L2TradeList> _lists;
private final Map<Integer, L2TradeList> _listsTaskItem;
/** Task launching the function for restore count of Item (Clan Hall) */
public class RestoreCount implements Runnable
{
private final int _timer;
public RestoreCount(int time)
{
_timer = time;
}
@Override
public void run()
{
try
{
restoreCount(_timer);
dataTimerSave(_timer);
ThreadPoolManager.schedule(new RestoreCount(_timer), (long) _timer * 60 * 60 * 1000);
}
catch (Throwable t)
{
}
}
}
public static TradeController getInstance()
{
if (_instance == null)
{
_instance = new TradeController();
}
return _instance;
}
private TradeController()
{
_lists = new HashMap<>();
_listsTaskItem = new HashMap<>();
final File buylistData = new File(Config.DATAPACK_ROOT, "data/buylists.csv");
if (buylistData.exists())
{
LOGGER.warning("Do, please, remove buylists from data folder and use SQL buylist instead");
String line = null;
int dummyItemCount = 0;
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
reader = new FileReader(buylistData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
dummyItemCount += parseList(line);
}
if (Config.DEBUG)
{
LOGGER.info("created " + dummyItemCount + " Dummy-Items for buylists");
}
LOGGER.info("TradeController: Loaded " + _lists.size() + " Buylists.");
}
catch (Exception e)
{
LOGGER.warning("error while creating trade controller in line: " + (lnr == null ? 0 : lnr.getLineNumber()) + " " + e);
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
else
{
LOGGER.info("No buylists found in data folder, using SQL buylist instead.");
/**
* Initialize Shop buylist
*/
int dummyItemCount = 0;
boolean LimitedItem = false;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement1 = con.prepareStatement("SELECT * FROM merchant_shopids");
ResultSet rset1 = statement1.executeQuery();
while (rset1.next())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM merchant_buylists WHERE shop_id=? ORDER BY `order` ASC");
statement.setString(1, String.valueOf(rset1.getInt("shop_id")));
ResultSet rset = statement.executeQuery();
if (rset.next())
{
LimitedItem = false;
dummyItemCount++;
L2TradeList buy1 = new L2TradeList(rset1.getInt("shop_id"));
int itemId = rset.getInt("item_id");
int price = rset.getInt("price");
int count = rset.getInt("count");
int currentCount = rset.getInt("currentCount");
int time = rset.getInt("time");
L2ItemInstance item = ItemTable.getInstance().createDummyItem(itemId);
if (item == null)
{
rset.close();
statement.close();
continue;
}
if (count > -1)
{
item.setCountDecrease(true);
LimitedItem = true;
}
if (!rset1.getString("npc_id").equals("gm") && (price < (item.getReferencePrice() / 2)))
{
LOGGER.warning("L2TradeList " + buy1.getListId() + " itemId " + itemId + " has an ADENA sell price lower then reference price.. Automatically Updating it..");
price = item.getReferencePrice();
}
item.setPriceToSell(price);
item.setTime(time);
item.setInitCount(count);
if (currentCount > -1)
{
item.setCount(currentCount);
}
else
{
item.setCount(count);
}
buy1.addItem(item);
buy1.setNpcId(rset1.getString("npc_id"));
try
{
while (rset.next()) // TODO aici
{
dummyItemCount++;
itemId = rset.getInt("item_id");
price = rset.getInt("price");
count = rset.getInt("count");
time = rset.getInt("time");
currentCount = rset.getInt("currentCount");
final L2ItemInstance item2 = ItemTable.getInstance().createDummyItem(itemId);
if (item2 == null)
{
continue;
}
if (count > -1)
{
item2.setCountDecrease(true);
LimitedItem = true;
}
if (!rset1.getString("npc_id").equals("gm") && (price < (item2.getReferencePrice() / 2)))
{
LOGGER.warning("L2TradeList " + buy1.getListId() + " itemId " + itemId + " has an ADENA sell price lower then reference price.. Automatically Updating it..");
price = item2.getReferencePrice();
}
item2.setPriceToSell(price);
item2.setTime(time);
item2.setInitCount(count);
if (currentCount > -1)
{
item2.setCount(currentCount);
}
else
{
item2.setCount(count);
}
buy1.addItem(item2);
}
}
catch (Exception e)
{
LOGGER.warning("TradeController: Problem with buylist " + buy1.getListId() + " item " + itemId);
}
if (LimitedItem)
{
_listsTaskItem.put(new Integer(buy1.getListId()), buy1);
}
else
{
_lists.put(new Integer(buy1.getListId()), buy1);
}
_nextListId = Math.max(_nextListId, buy1.getListId() + 1);
}
rset.close();
statement.close();
}
rset1.close();
statement1.close();
if (Config.DEBUG)
{
LOGGER.info("created " + dummyItemCount + " Dummy-Items for buylists");
}
LOGGER.info("TradeController: Loaded " + _lists.size() + " Buylists.");
LOGGER.info("TradeController: Loaded " + _listsTaskItem.size() + " Limited Buylists.");
/*
* Restore Task for reinitialyze count of buy item
*/
try
{
int time = 0;
long savetimer = 0;
final long currentMillis = System.currentTimeMillis();
PreparedStatement statement2 = con.prepareStatement("SELECT DISTINCT time, savetimer FROM merchant_buylists WHERE time <> 0 ORDER BY time");
ResultSet rset2 = statement2.executeQuery();
while (rset2.next())
{
time = rset2.getInt("time");
savetimer = rset2.getLong("savetimer");
if ((savetimer - currentMillis) > 0)
{
ThreadPoolManager.schedule(new RestoreCount(time), savetimer - System.currentTimeMillis());
}
else
{
ThreadPoolManager.schedule(new RestoreCount(time), 0);
}
}
rset2.close();
statement2.close();
}
catch (Exception e)
{
LOGGER.warning("TradeController: Could not restore Timer for Item count.");
e.printStackTrace();
}
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
LOGGER.warning("TradeController: Buylists could not be initialized.");
e.printStackTrace();
}
/*
* If enabled, initialize the custom buylist
*/
if (Config.CUSTOM_MERCHANT_TABLES)// Custom merchat Tabels
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final int initialSize = _lists.size();
PreparedStatement statement1 = con.prepareStatement("SELECT * FROM custom_merchant_shopids");
ResultSet rset1 = statement1.executeQuery();
while (rset1.next())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM custom_merchant_buylists WHERE shop_id=? ORDER BY `order` ASC");
statement.setString(1, String.valueOf(rset1.getInt("shop_id")));
ResultSet rset = statement.executeQuery();
if (rset.next())
{
LimitedItem = false;
dummyItemCount++;
L2TradeList buy1 = new L2TradeList(rset1.getInt("shop_id"));
int itemId = rset.getInt("item_id");
int price = rset.getInt("price");
int count = rset.getInt("count");
int currentCount = rset.getInt("currentCount");
int time = rset.getInt("time");
L2ItemInstance item = ItemTable.getInstance().createDummyItem(itemId);
if (item == null)
{
rset.close();
statement.close();
continue;
}
if (count > -1)
{
item.setCountDecrease(true);
LimitedItem = true;
}
if (!rset1.getString("npc_id").equals("gm") && (price < (item.getReferencePrice() / 2)))
{
LOGGER.warning("L2TradeList " + buy1.getListId() + " itemId " + itemId + " has an ADENA sell price lower then reference price.. Automatically Updating it..");
price = item.getReferencePrice();
}
item.setPriceToSell(price);
item.setTime(time);
item.setInitCount(count);
if (currentCount > -1)
{
item.setCount(currentCount);
}
else
{
item.setCount(count);
}
buy1.addItem(item);
buy1.setNpcId(rset1.getString("npc_id"));
try
{
while (rset.next())
{
dummyItemCount++;
itemId = rset.getInt("item_id");
price = rset.getInt("price");
count = rset.getInt("count");
time = rset.getInt("time");
currentCount = rset.getInt("currentCount");
L2ItemInstance item2 = ItemTable.getInstance().createDummyItem(itemId);
if (item2 == null)
{
continue;
}
if (count > -1)
{
item2.setCountDecrease(true);
LimitedItem = true;
}
if (!rset1.getString("npc_id").equals("gm") && (price < (item2.getReferencePrice() / 2)))
{
LOGGER.warning("L2TradeList " + buy1.getListId() + " itemId " + itemId + " has an ADENA sell price lower then reference price.. Automatically Updating it..");
price = item2.getReferencePrice();
}
item2.setPriceToSell(price);
item2.setTime(time);
item2.setInitCount(count);
if (currentCount > -1)
{
item2.setCount(currentCount);
}
else
{
item2.setCount(count);
}
buy1.addItem(item2);
}
}
catch (Exception e)
{
LOGGER.warning("TradeController: Problem with buylist " + buy1.getListId() + " item " + itemId);
}
if (LimitedItem)
{
_listsTaskItem.put(new Integer(buy1.getListId()), buy1);
}
else
{
_lists.put(new Integer(buy1.getListId()), buy1);
}
_nextListId = Math.max(_nextListId, buy1.getListId() + 1);
}
rset.close();
statement.close();
}
rset1.close();
statement1.close();
if (Config.DEBUG)
{
LOGGER.info("created " + dummyItemCount + " Dummy-Items for buylists");
}
LOGGER.info("TradeController: Loaded " + (_lists.size() - initialSize) + " Custom Buylists.");
/**
* Restore Task for reinitialyze count of buy item
*/
try
{
int time = 0;
long savetimer = 0;
final long currentMillis = System.currentTimeMillis();
PreparedStatement statement2 = con.prepareStatement("SELECT DISTINCT time, savetimer FROM custom_merchant_buylists WHERE time <> 0 ORDER BY time");
ResultSet rset2 = statement2.executeQuery();
while (rset2.next())
{
time = rset2.getInt("time");
savetimer = rset2.getLong("savetimer");
if ((savetimer - currentMillis) > 0)
{
ThreadPoolManager.schedule(new RestoreCount(time), savetimer - System.currentTimeMillis());
}
else
{
ThreadPoolManager.schedule(new RestoreCount(time), 0);
}
}
rset2.close();
statement2.close();
}
catch (Exception e)
{
LOGGER.warning("TradeController: Could not restore Timer for Item count.");
e.printStackTrace();
}
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
LOGGER.warning("TradeController: Buylists could not be initialized.");
e.printStackTrace();
}
}
}
}
private int parseList(String line)
{
int itemCreated = 0;
StringTokenizer st = new StringTokenizer(line, ";");
final int listId = Integer.parseInt(st.nextToken());
L2TradeList buy1 = new L2TradeList(listId);
while (st.hasMoreTokens())
{
final int itemId = Integer.parseInt(st.nextToken());
int price = Integer.parseInt(st.nextToken());
final L2ItemInstance item = ItemTable.getInstance().createDummyItem(itemId);
if (price < (item.getReferencePrice() / 2))
{
LOGGER.warning("L2TradeList " + listId + " itemId " + itemId + " has an ADENA sell price lower then reference price.. Automatically Updating it..");
price = item.getReferencePrice();
}
item.setPriceToSell(price);
buy1.addItem(item);
itemCreated++;
}
_lists.put(new Integer(buy1.getListId()), buy1);
return itemCreated;
}
public L2TradeList getBuyList(int listId)
{
if (_lists.get(new Integer(listId)) != null)
{
return _lists.get(new Integer(listId));
}
return _listsTaskItem.get(new Integer(listId));
}
public List<L2TradeList> getBuyListByNpcId(int npcId)
{
final List<L2TradeList> lists = new ArrayList<>();
for (L2TradeList list : _lists.values())
{
if (list.getNpcId().startsWith("gm"))
{
continue;
}
if (npcId == Integer.parseInt(list.getNpcId()))
{
lists.add(list);
}
}
for (L2TradeList list : _listsTaskItem.values())
{
if (list.getNpcId().startsWith("gm"))
{
continue;
}
if (npcId == Integer.parseInt(list.getNpcId()))
{
lists.add(list);
}
}
return lists;
}
protected void restoreCount(int time)
{
if (_listsTaskItem == null)
{
return;
}
for (L2TradeList list : _listsTaskItem.values())
{
list.restoreCount(time);
}
}
protected void dataTimerSave(int time)
{
final long timerSave = System.currentTimeMillis() + ((long) time * 60 * 60 * 1000);
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("UPDATE merchant_buylists SET savetimer =? WHERE time =?");
statement.setLong(1, timerSave);
statement.setInt(2, time);
statement.executeUpdate();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("TradeController: Could not update Timer save in Buylist");
}
}
public void dataCountStore()
{
int listId;
if (_listsTaskItem == null)
{
return;
}
PreparedStatement statement;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
for (L2TradeList list : _listsTaskItem.values())
{
if (list == null)
{
continue;
}
listId = list.getListId();
for (L2ItemInstance Item : list.getItems())
{
if (Item.getCount() < Item.getInitCount()) // needed?
{
statement = con.prepareStatement("UPDATE merchant_buylists SET currentCount=? WHERE item_id=? AND shop_id=?");
statement.setInt(1, Item.getCount());
statement.setInt(2, Item.getItemId());
statement.setInt(3, listId);
statement.executeUpdate();
statement.close();
}
}
}
}
catch (Exception e)
{
LOGGER.warning("TradeController: Could not store Count Item");
}
}
/**
* @return
*/
public synchronized int getNextId()
{
return _nextListId++;
}
/**
* This will reload buylists info from DataBase
*/
public static void reload()
{
_instance = new TradeController();
}
}

View File

@@ -0,0 +1,993 @@
/*
* 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.ai;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.concurrent.Future;
import java.util.logging.Logger;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.position.Location;
import com.l2jmobius.gameserver.model.extender.BaseExtender.EventType;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.AutoAttackStart;
import com.l2jmobius.gameserver.network.serverpackets.AutoAttackStop;
import com.l2jmobius.gameserver.network.serverpackets.CharMoveToLocation;
import com.l2jmobius.gameserver.network.serverpackets.Die;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocationInVehicle;
import com.l2jmobius.gameserver.network.serverpackets.MoveToPawn;
import com.l2jmobius.gameserver.network.serverpackets.StopMove;
import com.l2jmobius.gameserver.network.serverpackets.StopRotation;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
/**
* Mother class of all objects AI in the world.<BR>
* <BR>
* AbastractAI :<BR>
* <BR>
* <li>L2CharacterAI</li><BR>
* <BR>
*/
abstract class AbstractAI implements Ctrl
{
protected static final Logger LOGGER = Logger.getLogger(AbstractAI.class.getName());
class FollowTask implements Runnable
{
protected int _range = 60;
protected boolean newtask = true;
public FollowTask()
{
// null
}
public FollowTask(int range)
{
_range = range;
}
@Override
public void run()
{
try
{
if (_followTask == null)
{
return;
}
final L2Character follow = getFollowTarget();
if (follow == null)
{
stopFollow();
return;
}
if (!_actor.isInsideRadius(follow, _range, true, false))
{
moveToPawn(follow, _range);
}
else if (newtask)
{
newtask = false;
_actor.broadcastPacket(new MoveToPawn(_actor, follow, _range));
}
}
catch (Throwable t)
{
LOGGER.warning(t.getMessage());
}
}
}
/** The character that this AI manages */
protected final L2Character _actor;
/** An accessor for private methods of the actor */
protected final L2Character.AIAccessor _accessor;
/** Current long-term intention */
private CtrlIntention _intention = AI_INTENTION_IDLE;
/** Current long-term intention parameter */
private Object _intentionArg0 = null;
/** Current long-term intention parameter */
private Object _intentionArg1 = null;
/** Flags about client's state, in order to know which messages to send */
protected boolean _clientMoving;
/** Flags about client's state, in order to know which messages to send */
protected boolean _clientAutoAttacking;
/** Flags about client's state, in order to know which messages to send */
protected int _clientMovingToPawnOffset;
/** Different targets this AI maintains */
private L2Object _target;
private L2Character _castTarget;
private L2Character _attackTarget;
private L2Character _followTarget;
/** Diferent internal state flags */
private int _moveToPawnTimeout;
protected Future<?> _followTask = null;
private static final int FOLLOW_INTERVAL = 1000;
private static final int ATTACK_FOLLOW_INTERVAL = 500;
/**
* Constructor of AbstractAI.<BR>
* <BR>
* @param accessor The AI accessor of the L2Character
*/
protected AbstractAI(L2Character.AIAccessor accessor)
{
_accessor = accessor;
// Get the L2Character managed by this Accessor AI
_actor = accessor.getActor();
}
/**
* Return the L2Character managed by this Accessor AI.<BR>
* <BR>
*/
@Override
public L2Character getActor()
{
return _actor;
}
/**
* Set the Intention of this AbstractAI.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is USED by AI classes</B></FONT><BR>
* <BR>
* <B><U> Overriden in </U> : </B><BR>
* <B>L2AttackableAI</B> : Create an AI Task executed every 1s (if necessary)<BR>
* <B>L2PlayerAI</B> : Stores the current AI intention parameters to later restore it if necessary<BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
public synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
_intention = intention;
_intentionArg0 = arg0;
_intentionArg1 = arg1;
}
/**
* Launch the L2CharacterAI onIntention method corresponding to the new Intention.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
*/
@Override
public final void setIntention(CtrlIntention intention)
{
setIntention(intention, null, null);
}
/**
* Launch the L2CharacterAI onIntention method corresponding to the new Intention.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention (optional target)
*/
@Override
public final void setIntention(CtrlIntention intention, Object arg0)
{
setIntention(intention, arg0, null);
}
/**
* Launch the L2CharacterAI onIntention method corresponding to the new Intention.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention (optional target)
* @param arg1 The second parameter of the Intention (optional target)
*/
@Override
public final void setIntention(CtrlIntention intention, Object arg0, Object arg1)
{
if (!_actor.isVisible() || !_actor.hasAI())
{
return;
}
// Stop the follow mode if necessary
if ((intention != AI_INTENTION_FOLLOW) && (intention != AI_INTENTION_ATTACK))
{
stopFollow();
}
// Launch the onIntention method of the L2CharacterAI corresponding to the new Intention
switch (intention)
{
case AI_INTENTION_IDLE:
{
onIntentionIdle();
break;
}
case AI_INTENTION_ACTIVE:
{
onIntentionActive();
break;
}
case AI_INTENTION_REST:
{
onIntentionRest();
break;
}
case AI_INTENTION_ATTACK:
{
onIntentionAttack((L2Character) arg0);
break;
}
case AI_INTENTION_CAST:
{
onIntentionCast((L2Skill) arg0, (L2Object) arg1);
break;
}
case AI_INTENTION_MOVE_TO:
{
onIntentionMoveTo((Location) arg0);
break;
}
case AI_INTENTION_MOVE_TO_IN_A_BOAT:
{
onIntentionMoveToInABoat((Location) arg0, (Location) arg1);
break;
}
case AI_INTENTION_FOLLOW:
{
onIntentionFollow((L2Character) arg0);
break;
}
case AI_INTENTION_PICK_UP:
{
onIntentionPickUp((L2Object) arg0);
break;
}
case AI_INTENTION_INTERACT:
{
onIntentionInteract((L2Object) arg0);
break;
}
}
_actor.fireEvent(EventType.SETINTENTION.name, new Object[]
{
intention
});
}
/**
* Launch the L2CharacterAI onEvt method corresponding to the Event.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned periode)</B></FONT><BR>
* <BR>
* @param evt The event whose the AI must be notified
*/
@Override
public final void notifyEvent(CtrlEvent evt)
{
notifyEvent(evt, null, null);
}
/**
* Launch the L2CharacterAI onEvt method corresponding to the Event.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned periode)</B></FONT><BR>
* <BR>
* @param evt The event whose the AI must be notified
* @param arg0 The first parameter of the Event (optional target)
*/
@Override
public final void notifyEvent(CtrlEvent evt, Object arg0)
{
notifyEvent(evt, arg0, null);
}
/**
* Launch the L2CharacterAI onEvt method corresponding to the Event.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned periode)</B></FONT><BR>
* <BR>
* @param evt The event whose the AI must be notified
* @param arg0 The first parameter of the Event (optional target)
* @param arg1 The second parameter of the Event (optional target)
*/
@Override
public final void notifyEvent(CtrlEvent evt, Object arg0, Object arg1)
{
if (!_actor.isVisible() || !_actor.hasAI() || ((_actor instanceof L2PcInstance) && (((L2PcInstance) _actor).isOnline() == 0)) || ((_actor instanceof L2PcInstance) && ((L2PcInstance) _actor).isInOfflineMode()))
{
return;
}
/*
* if (Config.DEBUG) LOGGER.warning("AbstractAI: notifyEvent -> " + evt + " " + arg0 + " " + arg1);
*/
switch (evt)
{
case EVT_THINK:
{
onEvtThink();
break;
}
case EVT_ATTACKED:
{
onEvtAttacked((L2Character) arg0);
break;
}
case EVT_AGGRESSION:
{
onEvtAggression((L2Character) arg0, ((Number) arg1).intValue());
break;
}
case EVT_STUNNED:
{
onEvtStunned((L2Character) arg0);
break;
}
case EVT_SLEEPING:
{
onEvtSleeping((L2Character) arg0);
break;
}
case EVT_ROOTED:
{
onEvtRooted((L2Character) arg0);
break;
}
case EVT_CONFUSED:
{
onEvtConfused((L2Character) arg0);
break;
}
case EVT_MUTED:
{
onEvtMuted((L2Character) arg0);
break;
}
case EVT_READY_TO_ACT:
{
onEvtReadyToAct();
break;
}
case EVT_USER_CMD:
{
onEvtUserCmd(arg0, arg1);
break;
}
case EVT_ARRIVED:
{
onEvtArrived();
break;
}
case EVT_ARRIVED_REVALIDATE:
{
onEvtArrivedRevalidate();
break;
}
case EVT_ARRIVED_BLOCKED:
{
onEvtArrivedBlocked((Location) arg0);
break;
}
case EVT_FORGET_OBJECT:
{
onEvtForgetObject((L2Object) arg0);
break;
}
case EVT_CANCEL:
{
onEvtCancel();
break;
}
case EVT_DEAD:
{
onEvtDead();
break;
}
case EVT_FAKE_DEATH:
{
onEvtFakeDeath();
break;
}
case EVT_FINISH_CASTING:
{
onEvtFinishCasting();
break;
}
}
}
protected abstract void onIntentionIdle();
protected abstract void onIntentionActive();
protected abstract void onIntentionRest();
protected abstract void onIntentionAttack(L2Character target);
protected abstract void onIntentionCast(L2Skill skill, L2Object target);
protected abstract void onIntentionMoveTo(Location destination);
protected abstract void onIntentionMoveToInABoat(Location destination, Location origin);
protected abstract void onIntentionFollow(L2Character target);
protected abstract void onIntentionPickUp(L2Object item);
protected abstract void onIntentionInteract(L2Object object);
protected abstract void onEvtThink();
protected abstract void onEvtAttacked(L2Character attacker);
protected abstract void onEvtAggression(L2Character target, int aggro);
protected abstract void onEvtStunned(L2Character attacker);
protected abstract void onEvtSleeping(L2Character attacker);
protected abstract void onEvtRooted(L2Character attacker);
protected abstract void onEvtConfused(L2Character attacker);
protected abstract void onEvtMuted(L2Character attacker);
protected abstract void onEvtReadyToAct();
protected abstract void onEvtUserCmd(Object arg0, Object arg1);
protected abstract void onEvtArrived();
protected abstract void onEvtArrivedRevalidate();
protected abstract void onEvtArrivedBlocked(Location blocked_at_pos);
protected abstract void onEvtForgetObject(L2Object object);
protected abstract void onEvtCancel();
protected abstract void onEvtDead();
protected abstract void onEvtFakeDeath();
protected abstract void onEvtFinishCasting();
/**
* Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
protected void clientActionFailed()
{
if (_actor instanceof L2PcInstance)
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
}
}
/**
* Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
* @param pawn
* @param offset
*/
public void moveToPawn(L2Object pawn, int offset)
{
// Chek if actor can move
if (!_actor.isMovementDisabled())
{
if (offset < 10)
{
offset = 10;
}
// prevent possible extra calls to this function (there is none?),
// also don't send movetopawn packets too often
boolean sendPacket = true;
if (_clientMoving && (getTarget() == pawn))
{
if (_clientMovingToPawnOffset == offset)
{
if (GameTimeController.getGameTicks() < _moveToPawnTimeout)
{
return;
}
sendPacket = false;
}
else if (_actor.isOnGeodataPath())
{
// minimum time to calculate new route is 2 seconds
if (GameTimeController.getGameTicks() < (_moveToPawnTimeout + 10))
{
return;
}
}
}
// Set AI movement data
_clientMoving = true;
_clientMovingToPawnOffset = offset;
setTarget(pawn);
_moveToPawnTimeout = GameTimeController.getGameTicks();
_moveToPawnTimeout += /* 1000 */200 / GameTimeController.MILLIS_IN_TICK;
if ((pawn == null) || (_accessor == null))
{
return;
}
// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
_accessor.moveTo(pawn.getX(), pawn.getY(), pawn.getZ(), offset);
if (!_actor.isMoving())
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
// Send a Server->Client packet MoveToPawn/CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
if (pawn instanceof L2Character)
{
if (_actor.isOnGeodataPath())
{
_actor.broadcastPacket(new CharMoveToLocation(_actor));
_clientMovingToPawnOffset = 0;
}
else if (sendPacket)
{
_actor.broadcastPacket(new MoveToPawn(_actor, (L2Character) pawn, offset));
}
}
else
{
_actor.broadcastPacket(new CharMoveToLocation(_actor));
}
}
else
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
}
}
/**
* Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
* @param x
* @param y
* @param z
*/
public void moveTo(int x, int y, int z)
{
// Chek if actor can move
if (!_actor.isMovementDisabled())
{
// Set AI movement data
_clientMoving = true;
_clientMovingToPawnOffset = 0;
// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
_accessor.moveTo(x, y, z);
// Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
CharMoveToLocation msg = new CharMoveToLocation(_actor);
_actor.broadcastPacket(msg);
msg = null;
}
else
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
}
}
protected void moveToInABoat(Location destination, Location origin)
{
// Chek if actor can move
if (!_actor.isMovementDisabled())
{
// Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
// CharMoveToLocation msg = new CharMoveToLocation(_actor);
if (((L2PcInstance) _actor).getBoat() != null)
{
MoveToLocationInVehicle msg = new MoveToLocationInVehicle(_actor, destination, origin);
_actor.broadcastPacket(msg);
msg = null;
}
}
else
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
}
}
/**
* Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
* @param pos
*/
protected void clientStopMoving(Location pos)
{
/*
* if (true && _actor instanceof L2PcInstance){ LOGGER.warning("clientStopMoving();"); Thread.dumpStack(); }
*/
// Stop movement of the L2Character
if (_actor.isMoving())
{
_accessor.stopMove(pos);
}
_clientMovingToPawnOffset = 0;
if (_clientMoving || (pos != null))
{
_clientMoving = false;
// Send a Server->Client packet StopMove to the actor and all L2PcInstance in its _knownPlayers
StopMove msg = new StopMove(_actor);
_actor.broadcastPacket(msg);
msg = null;
if (pos != null)
{
// Send a Server->Client packet StopRotation to the actor and all L2PcInstance in its _knownPlayers
StopRotation sr = new StopRotation(_actor, pos.getHeading(), 0);
_actor.sendPacket(sr);
_actor.broadcastPacket(sr);
sr = null;
}
}
}
// Client has already arrived to target, no need to force StopMove packet
protected void clientStoppedMoving()
{
if (_clientMovingToPawnOffset > 0) // movetoPawn needs to be stopped
{
_clientMovingToPawnOffset = 0;
StopMove msg = new StopMove(_actor);
_actor.broadcastPacket(msg);
msg = null;
}
_clientMoving = false;
}
/**
* Start the actor Auto Attack client side by sending Server->Client packet AutoAttackStart <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
/*
* public void clientStartAutoAttack() { if(!isAutoAttacking()) { // Send a Server->Client packet AutoAttackStart to the actor and all L2PcInstance in its _knownPlayers _actor.broadcastPacket(new AutoAttackStart(_actor.getObjectId())); setAutoAttacking(true); }
* AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor); }
*/
/**
* Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
/*
* public void clientStopAutoAttack() { if(_actor instanceof L2PcInstance) { if(!AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor) && isAutoAttacking()) { AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor); } } else if(isAutoAttacking()) {
* _actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId())); } setAutoAttacking(false); }
*/
/**
* Start the actor Auto Attack client side by sending Server->Client packet AutoAttackStart <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
public void clientStartAutoAttack()
{
if ((((_actor instanceof L2NpcInstance) && !(_actor instanceof L2Attackable)) && !(_actor instanceof L2Playable)))
{
return;
}
if (_actor instanceof L2Summon)
{
final L2Summon summon = (L2Summon) _actor;
if (summon.getOwner() != null)
{
summon.getOwner().getAI().clientStartAutoAttack();
}
return;
}
if (!isAutoAttacking())
{
if ((_actor instanceof L2PcInstance) && (((L2PcInstance) _actor).getPet() != null))
{
((L2PcInstance) _actor).getPet().broadcastPacket(new AutoAttackStart(((L2PcInstance) _actor).getPet().getObjectId()));
}
// Send a Server->Client packet AutoAttackStart to the actor and all L2PcInstance in its _knownPlayers
_actor.broadcastPacket(new AutoAttackStart(_actor.getObjectId()));
setAutoAttacking(true);
}
AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
}
/**
* Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
public void clientStopAutoAttack()
{
if (_actor instanceof L2Summon)
{
final L2Summon summon = (L2Summon) _actor;
if (summon.getOwner() != null)
{
summon.getOwner().getAI().clientStopAutoAttack();
}
return;
}
final boolean isAutoAttacking = isAutoAttacking();
if (_actor instanceof L2PcInstance)
{
if (!AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor) && isAutoAttacking)
{
AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
}
}
else if (isAutoAttacking)
{
_actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
setAutoAttacking(false);
}
}
/**
* Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
protected void clientNotifyDead()
{
// Send a Server->Client packet Die to the actor and all L2PcInstance in its _knownPlayers
Die msg = new Die(_actor);
_actor.broadcastPacket(msg);
msg = null;
// Init AI
setIntention(AI_INTENTION_IDLE);
setTarget(null);
setAttackTarget(null);
setCastTarget(null);
// Cancel the follow task if necessary
stopFollow();
}
/**
* Update the state of this actor client side by sending Server->Client packet MoveToPawn/CharMoveToLocation and AutoAttackStart to the L2PcInstance player.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
* @param player The L2PcIstance to notify with state of this L2Character
*/
public void describeStateToPlayer(L2PcInstance player)
{
if (_clientMoving)
{
final L2Character follow = getFollowTarget();
if ((_clientMovingToPawnOffset != 0) && (follow != null))
{
// Send a Server->Client packet MoveToPawn to the actor and all L2PcInstance in its _knownPlayers
MoveToPawn msg = new MoveToPawn(_actor, follow, _clientMovingToPawnOffset);
player.sendPacket(msg);
msg = null;
}
else
{
// Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
CharMoveToLocation msg = new CharMoveToLocation(_actor);
player.sendPacket(msg);
msg = null;
}
}
}
/**
* Create and Launch an AI Follow Task to execute every 1s.<BR>
* <BR>
* @param target The L2Character to follow
*/
public synchronized void startFollow(L2Character target)
{
if (_followTask != null)
{
_followTask.cancel(false);
_followTask = null;
}
// Create and Launch an AI Follow Task to execute every 1s
_followTarget = target;
_followTask = ThreadPoolManager.scheduleAtFixedRate(new FollowTask(), 5, FOLLOW_INTERVAL);
}
/**
* Create and Launch an AI Follow Task to execute every 0.5s, following at specified range.<BR>
* <BR>
* @param target The L2Character to follow
* @param range
*/
public synchronized void startFollow(L2Character target, int range)
{
if (_followTask != null)
{
_followTask.cancel(false);
_followTask = null;
}
_followTarget = target;
_followTask = ThreadPoolManager.scheduleAtFixedRate(new FollowTask(range), 5, ATTACK_FOLLOW_INTERVAL);
}
/**
* Stop an AI Follow Task.<BR>
* <BR>
*/
public synchronized void stopFollow()
{
if (_followTask != null)
{
// Stop the Follow Task
_followTask.cancel(false);
_followTask = null;
}
_followTarget = null;
}
protected synchronized L2Character getFollowTarget()
{
return _followTarget;
}
protected synchronized L2Object getTarget()
{
return _target;
}
protected synchronized void setTarget(L2Object target)
{
_target = target;
}
protected synchronized void setCastTarget(L2Character target)
{
_castTarget = target;
}
/**
* @return the current cast target.
*/
public synchronized L2Character getCastTarget()
{
return _castTarget;
}
protected synchronized void setAttackTarget(L2Character target)
{
_attackTarget = target;
}
/**
* Return current attack target.<BR>
* <BR>
*/
@Override
public synchronized L2Character getAttackTarget()
{
return _attackTarget;
}
public synchronized boolean isAutoAttacking()
{
return _clientAutoAttacking;
}
public synchronized void setAutoAttacking(boolean isAutoAttacking)
{
_clientAutoAttacking = isAutoAttacking;
}
/**
* @return the _intentionArg0
*/
public synchronized Object get_intentionArg0()
{
return _intentionArg0;
}
/**
* @param _intentionArg0 the _intentionArg0 to set
*/
public synchronized void set_intentionArg0(Object _intentionArg0)
{
this._intentionArg0 = _intentionArg0;
}
/**
* @return the _intentionArg1
*/
public synchronized Object get_intentionArg1()
{
return _intentionArg1;
}
/**
* @param _intentionArg1 the _intentionArg1 to set
*/
public synchronized void set_intentionArg1(Object _intentionArg1)
{
this._intentionArg1 = _intentionArg1;
}
/**
* Return the current Intention.<BR>
* <BR>
*/
@Override
public synchronized CtrlIntention getIntention()
{
return _intention;
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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.ai;
import com.l2jmobius.gameserver.model.actor.L2Character;
/**
* Interface of AI and client state. To correctly send messages to client we need it's state. For example, if we've sent 'StartAutoAttack' message, we need to send 'StopAutoAttack' message before any other action. Or if we've sent 'MoveToPawn', we need to send 'StopMove' when the movement of a
* character is canceled (by Root spell or any other reason). Thus, we need to know the state of client, i.e. which messages we've sent and how the client will show the scene. Close to this task is the task of AI. If a player's character is attacking a mob, his ATTACK may be interrupted by an event,
* that temporary disable attacking. But when the possibility to ATTACK will be enabled, the character must continue the ATTACK. For mobs it may be more complex, since we want them to decide when to use magic, or when to follow the player for physical combat, or when to escape, to help another mob,
* etc. This interface is hiding complexity of server<->client interaction and multiple states of a character. It allows to set a desired, simple "wish" of a character, and the implementation of this interface will take care about the rest. The goal of a character may be like "ATTACK", "random walk"
* and so on. To reach the goal implementation will split it into several small actions, several steps (possibly repeatable). Like "run to target" then "hit it", then if target is not dead - repeat. This flow of simpler steps may be interrupted by incoming events. Like a character's movement was
* disabled (by Root spell, for instance). Depending on character's ability AI may choose to wait, or to use magic ATTACK and so on. Additionally incoming events are compared with client's state of the character, and required network messages are sent to client's, i.e. if we have incoming event that
* character's movement was disabled, it causes changing if its Behavior, and if client's state for the character is "moving" we send messages to clients to stop the avatar/mob.
*/
public interface Ctrl
{
/**
* @return the character this AI serves
*/
L2Character getActor();
/**
* @return the current intention.
*/
CtrlIntention getIntention();
/**
* @return the current attack target.
*/
L2Character getAttackTarget();
/**
* Set general state/intention for AI, with optional data
* @param intention
*/
void setIntention(CtrlIntention intention);
void setIntention(CtrlIntention intention, Object arg0);
void setIntention(CtrlIntention intention, Object arg0, Object arg1);
/**
* Event, that notifies about previous step result, or user command, that does not change current general intention
* @param evt
*/
void notifyEvent(CtrlEvent evt);
void notifyEvent(CtrlEvent evt, Object arg0);
void notifyEvent(CtrlEvent evt, Object arg0, Object arg1);
}

View File

@@ -0,0 +1,99 @@
/*
* 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.ai;
/**
* This class contains an enum of each possibles evenements that can happen on an AI character.
*/
public enum CtrlEvent
{
/**
* Something has changed, usually a previous step has being completed or maybe was completed, the AI must thing on next action
*/
EVT_THINK,
/**
* The actor was attacked. This event comes each time a physical or magical attack was done on the actor. NPC may start attack in responce, or ignore this event if they already attack someone, or change target and so on.
*/
EVT_ATTACKED,
/** Increase/decrease aggression towards a target, or reduce global aggression if target is null */
EVT_AGGRESSION,
/** Actor is in stun state */
EVT_STUNNED,
/** Actor starts/stops sleeping */
EVT_SLEEPING,
/** Actor is in rooted state (cannot move) */
EVT_ROOTED,
/**
* An event that previous action was completed. The action may be an attempt to physically/magically hit an enemy, or an action that discarded attack attempt has finished.
*/
EVT_READY_TO_ACT,
/**
* User's command, like using a combat magic or changing weapon, etc. The command is not intended to change final goal
*/
EVT_USER_CMD,
/**
* The actor arrived to assigned location, or it's a time to modify movement destination (follow, interact, random move and others intentions).
*/
EVT_ARRIVED,
/**
* The actor arrived to an intermidiate point, and needs revalidate destination. This is sent when follow/move to pawn if destination is far away.
*/
EVT_ARRIVED_REVALIDATE,
/** The actor cannot move anymore. */
EVT_ARRIVED_BLOCKED,
/** Forgets an object (if it's used as attack target, follow target and so on */
EVT_FORGET_OBJECT,
/**
* Attempt to cancel current step execution, but not change the intention. For example, the actor was putted into a stun, so it's current attack or movement has to be canceled. But after the stun state expired, the actor may try to attack again. Another usage for CANCEL is a user's attempt to
* cancel a cast/bow attack and so on.
*/
EVT_CANCEL,
/** The character is dead */
EVT_DEAD,
/** The character looks like dead */
EVT_FAKE_DEATH,
/** The character attack anyone randomly **/
EVT_CONFUSED,
/** The character cannot cast spells anymore **/
EVT_MUTED,
/** The character flee in randoms directions **/
EVT_AFFRAID,
/** The character finish casting **/
EVT_FINISH_CASTING,
/** The character betrayed its master */
EVT_BETRAYED
}

View File

@@ -0,0 +1,56 @@
/*
* 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.ai;
/**
* Enumaration of generic intentions of an NPC/PC, an intention may require several steps to be completed
*/
public enum CtrlIntention
{
/** Do nothing, disconnect AI of NPC if no players around */
AI_INTENTION_IDLE,
/** Alerted state without goal : scan attackable targets, random walk, etc */
AI_INTENTION_ACTIVE,
/** Rest (sit until attacked) */
AI_INTENTION_REST,
/**
* Attack target (cast combat magic, go to target, combat), may be ignored, if target is locked on another character or a peacefull zone and so on
*/
AI_INTENTION_ATTACK,
/** Cast a spell, depending on the spell - may start or stop attacking */
AI_INTENTION_CAST,
/** Just move to another location */
AI_INTENTION_MOVE_TO,
/** Like move, but check target's movement and follow it */
AI_INTENTION_FOLLOW,
/** PickUp and item, (got to item, pickup it, become idle */
AI_INTENTION_PICK_UP,
/** Move to target, then interact */
AI_INTENTION_INTERACT,
/** Move to another location in a boat */
AI_INTENTION_MOVE_TO_IN_A_BOAT
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,573 @@
/*
* 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.ai;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import java.util.ArrayList;
import java.util.List;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.datatables.MobGroupTable;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.MobGroup;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Character.AIAccessor;
import com.l2jmobius.gameserver.model.actor.instance.L2ControllableMobInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2FolkInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.util.Util;
/**
* @author littlecrow AI for controllable mobs
*/
public class L2ControllableMobAI extends L2AttackableAI
{
public static final int AI_IDLE = 1;
public static final int AI_NORMAL = 2;
public static final int AI_FORCEATTACK = 3;
public static final int AI_FOLLOW = 4;
public static final int AI_CAST = 5;
public static final int AI_ATTACK_GROUP = 6;
private int _alternateAI;
private boolean _isThinking; // to prevent thinking recursively
private boolean _isNotMoving;
private L2Character _forcedTarget;
private MobGroup _targetGroup;
protected void thinkFollow()
{
final L2Attackable me = (L2Attackable) _actor;
if (!Util.checkIfInRange(MobGroupTable.FOLLOW_RANGE, me, getForcedTarget(), true))
{
final int signX = Rnd.nextInt(2) == 0 ? -1 : 1;
final int signY = Rnd.nextInt(2) == 0 ? -1 : 1;
final int randX = Rnd.nextInt(MobGroupTable.FOLLOW_RANGE);
final int randY = Rnd.nextInt(MobGroupTable.FOLLOW_RANGE);
moveTo(getForcedTarget().getX() + (signX * randX), getForcedTarget().getY() + (signY * randY), getForcedTarget().getZ());
}
}
@Override
protected void onEvtThink()
{
if (isThinking() || _actor.isAllSkillsDisabled())
{
return;
}
setThinking(true);
try
{
switch (getAlternateAI())
{
case AI_IDLE:
{
if (getIntention() != CtrlIntention.AI_INTENTION_ACTIVE)
{
setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
}
break;
}
case AI_FOLLOW:
{
thinkFollow();
break;
}
case AI_CAST:
{
thinkCast();
break;
}
case AI_FORCEATTACK:
{
thinkForceAttack();
break;
}
case AI_ATTACK_GROUP:
{
thinkAttackGroup();
break;
}
default:
{
if (getIntention() == AI_INTENTION_ACTIVE)
{
thinkActive();
}
else if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
break;
}
}
}
finally
{
setThinking(false);
}
}
protected void thinkCast()
{
if ((getAttackTarget() == null) || getAttackTarget().isAlikeDead())
{
setAttackTarget(findNextRndTarget());
clientStopMoving(null);
}
if (getAttackTarget() == null)
{
return;
}
((L2Attackable) _actor).setTarget(getAttackTarget());
if (!_actor.isMuted())
{
// check distant skills
int max_range = 0;
for (L2Skill sk : _actor.getAllSkills())
{
if (Util.checkIfInRange(sk.getCastRange(), _actor, getAttackTarget(), true) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, sk.getCastRange());
}
if (!isNotMoving())
{
moveToPawn(getAttackTarget(), max_range);
}
return;
}
}
protected void thinkAttackGroup()
{
final L2Character target = getForcedTarget();
if ((target == null) || target.isAlikeDead())
{
// try to get next group target
setForcedTarget(findNextGroupTarget());
clientStopMoving(null);
}
if (target == null)
{
return;
}
_actor.setTarget(target);
// as a response, we put the target in a forced attack mode
final L2ControllableMobInstance theTarget = (L2ControllableMobInstance) target;
final L2ControllableMobAI ctrlAi = (L2ControllableMobAI) theTarget.getAI();
ctrlAi.forceAttack(_actor);
final L2Skill[] skills = _actor.getAllSkills();
final double dist2 = _actor.getPlanDistanceSq(target.getX(), target.getY());
final int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + target.getTemplate().collisionRadius;
int max_range = range;
if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
{
// check distant skills
for (L2Skill sk : skills)
{
final int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, castRange);
}
if (!isNotMoving())
{
moveToPawn(target, range);
}
return;
}
_accessor.doAttack(target);
}
protected void thinkForceAttack()
{
if ((getForcedTarget() == null) || getForcedTarget().isAlikeDead())
{
clientStopMoving(null);
setIntention(AI_INTENTION_ACTIVE);
setAlternateAI(AI_IDLE);
}
_actor.setTarget(getForcedTarget());
final L2Skill[] skills = _actor.getAllSkills();
final double dist2 = _actor.getPlanDistanceSq(getForcedTarget().getX(), getForcedTarget().getY());
final int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + getForcedTarget().getTemplate().collisionRadius;
int max_range = range;
if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
{
// check distant skills
for (L2Skill sk : skills)
{
final int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, castRange);
}
if (!isNotMoving())
{
moveToPawn(getForcedTarget(), _actor.getPhysicalAttackRange()/* range */);
}
return;
}
_accessor.doAttack(getForcedTarget());
}
protected void thinkAttack()
{
if ((getAttackTarget() == null) || getAttackTarget().isAlikeDead())
{
if (getAttackTarget() != null)
{
// stop hating
L2Attackable npc = (L2Attackable) _actor;
npc.stopHating(getAttackTarget());
}
setIntention(AI_INTENTION_ACTIVE);
}
else
{
// notify aggression
if (((L2NpcInstance) _actor).getFactionId() != null)
{
for (L2Object obj : _actor.getKnownList().getKnownObjects().values())
{
if (!(obj instanceof L2NpcInstance))
{
continue;
}
L2NpcInstance npc = (L2NpcInstance) obj;
String faction_id = ((L2NpcInstance) _actor).getFactionId();
if (!faction_id.equalsIgnoreCase(npc.getFactionId()))
{
continue;
}
if (_actor.isInsideRadius(npc, npc.getFactionRange(), false, true) && (Math.abs(getAttackTarget().getZ() - npc.getZ()) < 200))
{
npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
}
}
}
_actor.setTarget(getAttackTarget());
final L2Skill[] skills = _actor.getAllSkills();
final double dist2 = _actor.getPlanDistanceSq(getAttackTarget().getX(), getAttackTarget().getY());
final int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + getAttackTarget().getTemplate().collisionRadius;
int max_range = range;
if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
{
// check distant skills
for (L2Skill sk : skills)
{
final int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, castRange);
}
moveToPawn(getAttackTarget(), range);
return;
}
// Force mobs to attack anybody if confused.
L2Character hated;
if (_actor.isConfused())
{
hated = findNextRndTarget();
}
else
{
hated = getAttackTarget();
}
if (hated == null)
{
setIntention(AI_INTENTION_ACTIVE);
return;
}
if (hated != getAttackTarget())
{
setAttackTarget(hated);
}
if (!_actor.isMuted() && (skills.length > 0) && (Rnd.nextInt(5) == 3))
{
for (L2Skill sk : skills)
{
final int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
}
}
_accessor.doAttack(getAttackTarget());
}
}
private void thinkActive()
{
setAttackTarget(findNextRndTarget());
L2Character hated;
if (_actor.isConfused())
{
hated = findNextRndTarget();
}
else
{
hated = getAttackTarget();
}
if (hated != null)
{
_actor.setRunning();
setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated);
}
return;
}
private boolean autoAttackCondition(L2Character target)
{
if ((target == null) || !(_actor instanceof L2Attackable))
{
return false;
}
final L2Attackable me = (L2Attackable) _actor;
if ((target instanceof L2FolkInstance) || (target instanceof L2DoorInstance))
{
return false;
}
if (target.isAlikeDead() || !me.isInsideRadius(target, me.getAggroRange(), false, false) || (Math.abs(_actor.getZ() - target.getZ()) > 100))
{
return false;
}
// Check if the target isn't invulnerable
if (target.isInvul())
{
return false;
}
// Check if the target is a L2PcInstance
if (target instanceof L2PcInstance)
{
// Check if the target isn't in silent move mode
if (((L2PcInstance) target).isSilentMoving())
{
return false;
}
}
if (target instanceof L2NpcInstance)
{
return false;
}
return me.isAggressive();
}
private L2Character findNextRndTarget()
{
final int aggroRange = ((L2Attackable) _actor).getAggroRange();
L2Attackable npc = (L2Attackable) _actor;
int npcX, npcY, targetX, targetY;
double dy, dx;
final double dblAggroRange = aggroRange * aggroRange;
final List<L2Character> potentialTarget = new ArrayList<>();
for (L2Object obj : npc.getKnownList().getKnownObjects().values())
{
if (!(obj instanceof L2Character))
{
continue;
}
npcX = npc.getX();
npcY = npc.getY();
targetX = obj.getX();
targetY = obj.getY();
dx = npcX - targetX;
dy = npcY - targetY;
if (((dx * dx) + (dy * dy)) > dblAggroRange)
{
continue;
}
final L2Character target = (L2Character) obj;
if (autoAttackCondition(target))
{
potentialTarget.add(target);
}
}
if (potentialTarget.size() == 0)
{
return null;
}
// we choose a random target
final int choice = Rnd.nextInt(potentialTarget.size());
final L2Character target = potentialTarget.get(choice);
return target;
}
private L2ControllableMobInstance findNextGroupTarget()
{
return getGroupTarget().getRandomMob();
}
public L2ControllableMobAI(AIAccessor accessor)
{
super(accessor);
setAlternateAI(AI_IDLE);
}
public int getAlternateAI()
{
return _alternateAI;
}
public void setAlternateAI(int _alternateai)
{
_alternateAI = _alternateai;
}
public void forceAttack(L2Character target)
{
setAlternateAI(AI_FORCEATTACK);
setForcedTarget(target);
}
public void forceAttackGroup(MobGroup group)
{
setForcedTarget(null);
setGroupTarget(group);
setAlternateAI(AI_ATTACK_GROUP);
}
public void stop()
{
setAlternateAI(AI_IDLE);
clientStopMoving(null);
}
public void move(int x, int y, int z)
{
moveTo(x, y, z);
}
public void follow(L2Character target)
{
setAlternateAI(AI_FOLLOW);
setForcedTarget(target);
}
public boolean isThinking()
{
return _isThinking;
}
public boolean isNotMoving()
{
return _isNotMoving;
}
public void setNotMoving(boolean isNotMoving)
{
_isNotMoving = isNotMoving;
}
public void setThinking(boolean isThinking)
{
_isThinking = isThinking;
}
private synchronized L2Character getForcedTarget()
{
return _forcedTarget;
}
private synchronized MobGroup getGroupTarget()
{
return _targetGroup;
}
private synchronized void setForcedTarget(L2Character forcedTarget)
{
_forcedTarget = forcedTarget;
}
private synchronized void setGroupTarget(MobGroup targetGroup)
{
_targetGroup = targetGroup;
}
}

View File

@@ -0,0 +1,214 @@
/*
* 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.ai;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2FortSiegeGuardInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2SiegeGuardInstance;
import com.l2jmobius.gameserver.model.actor.position.Location;
/**
* @author mkizub TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
*/
public class L2DoorAI extends L2CharacterAI
{
public L2DoorAI(L2DoorInstance.AIAccessor accessor)
{
super(accessor);
}
// rather stupid AI... well, it's for doors :D
@Override
protected void onIntentionIdle()
{
// null;
}
@Override
protected void onIntentionActive()
{
// null;
}
@Override
protected void onIntentionRest()
{
// null;
}
@Override
protected void onIntentionAttack(L2Character target)
{
// null;
}
@Override
protected void onIntentionCast(L2Skill skill, L2Object target)
{
// null;
}
@Override
protected void onIntentionMoveTo(Location destination)
{
// null;
}
@Override
protected void onIntentionFollow(L2Character target)
{
// null;
}
@Override
protected void onIntentionPickUp(L2Object item)
{
// null;
}
@Override
protected void onIntentionInteract(L2Object object)
{
// null;
}
@Override
protected void onEvtThink()
{
// null;
}
@Override
protected void onEvtAttacked(L2Character attacker)
{
L2DoorInstance me = (L2DoorInstance) _actor;
ThreadPoolManager.execute(new onEventAttackedDoorTask(me, attacker));
}
@Override
protected void onEvtAggression(L2Character target, int aggro)
{
// null;
}
@Override
protected void onEvtStunned(L2Character attacker)
{
// null;
}
@Override
protected void onEvtSleeping(L2Character attacker)
{
// null;
}
@Override
protected void onEvtRooted(L2Character attacker)
{
// null;
}
@Override
protected void onEvtReadyToAct()
{
// null;
}
@Override
protected void onEvtUserCmd(Object arg0, Object arg1)
{
// null;
}
@Override
protected void onEvtArrived()
{
// null;
}
@Override
protected void onEvtArrivedRevalidate()
{
// null;
}
@Override
protected void onEvtArrivedBlocked(Location blocked_at_pos)
{
// null;
}
@Override
protected void onEvtForgetObject(L2Object object)
{
// null;
}
@Override
protected void onEvtCancel()
{
// null;
}
@Override
protected void onEvtDead()
{
// null;
}
private class onEventAttackedDoorTask implements Runnable
{
private final L2DoorInstance _door;
private final L2Character _attacker;
public onEventAttackedDoorTask(L2DoorInstance door, L2Character attacker)
{
_door = door;
_attacker = attacker;
}
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
_door.getKnownList().updateKnownObjects();
for (L2SiegeGuardInstance guard : _door.getKnownSiegeGuards())
{
if ((guard != null) && (guard.getAI() != null) && _actor.isInsideRadius(guard, guard.getFactionRange(), false, true) && (Math.abs(_attacker.getZ() - guard.getZ()) < 200))
{
guard.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attacker, 15);
}
}
for (L2FortSiegeGuardInstance guard : _door.getKnownFortSiegeGuards())
{
if ((guard != null) && (guard.getAI() != null) && _actor.isInsideRadius(guard, guard.getFactionRange(), false, true) && (Math.abs(_attacker.getZ() - guard.getZ()) < 200))
{
guard.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attacker, 15);
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,244 @@
/*
* 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.ai;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.gameserver.datatables.csv.NpcWalkerRoutesTable;
import com.l2jmobius.gameserver.model.L2NpcWalkerNode;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcWalkerInstance;
import com.l2jmobius.gameserver.model.actor.position.Location;
public class L2NpcWalkerAI extends L2CharacterAI implements Runnable
{
private static final int DEFAULT_MOVE_DELAY = 0;
private long _nextMoveTime;
private boolean _walkingToNextPoint = false;
/**
* home points for xyz
*/
int _homeX, _homeY, _homeZ;
/**
* route of the current npc
*/
private final List<L2NpcWalkerNode> _route = NpcWalkerRoutesTable.getInstance().getRouteForNpc(getActor().getNpcId());
/**
* current node
*/
private int _currentPos;
/**
* Constructor of L2CharacterAI.<BR>
* <BR>
* @param accessor The AI accessor of the L2Character
*/
public L2NpcWalkerAI(L2Character.AIAccessor accessor)
{
super(accessor);
// Do we really need 2 minutes delay before start?
// no we dont... :)
ThreadPoolManager.scheduleAtFixedRate(this, 0, 1000);
}
@Override
public void run()
{
onEvtThink();
}
@Override
protected void onEvtThink()
{
if (!Config.ALLOW_NPC_WALKERS)
{
return;
}
if (isWalkingToNextPoint())
{
checkArrived();
return;
}
if (_nextMoveTime < System.currentTimeMillis())
{
walkToLocation();
}
}
/**
* If npc can't walk to it's target then just teleport to next point
* @param blocked_at_pos ignoring it
*/
@Override
protected void onEvtArrivedBlocked(Location blocked_at_pos)
{
LOGGER.warning("NpcWalker ID: " + getActor().getNpcId() + ": Blocked at rote position [" + _currentPos + "], coords: " + blocked_at_pos.getX() + ", " + blocked_at_pos.getY() + ", " + blocked_at_pos.getZ() + ". Teleporting to next point");
if (_route.size() <= _currentPos)
{
return;
}
final int destinationX = _route.get(_currentPos).getMoveX();
final int destinationY = _route.get(_currentPos).getMoveY();
final int destinationZ = _route.get(_currentPos).getMoveZ();
getActor().teleToLocation(destinationX, destinationY, destinationZ, false);
super.onEvtArrivedBlocked(blocked_at_pos);
}
private void checkArrived()
{
if (_route.size() <= _currentPos)
{
return;
}
final int destinationX = _route.get(_currentPos).getMoveX();
final int destinationY = _route.get(_currentPos).getMoveY();
final int destinationZ = _route.get(_currentPos).getMoveZ();
if ((getActor().getX() == destinationX) && (getActor().getY() == destinationY) && (getActor().getZ() == destinationZ))
{
String chat = _route.get(_currentPos).getChatText();
if ((chat != null) && !chat.equals("NULL"))
{
try
{
getActor().broadcastChat(chat);
}
catch (ArrayIndexOutOfBoundsException e)
{
LOGGER.info("L2NpcWalkerInstance: Error, " + e);
}
}
// time in millis
long delay = _route.get(_currentPos).getDelay() * 1000;
// sleeps between each move
if (delay < 0)
{
delay = DEFAULT_MOVE_DELAY;
if (Config.DEVELOPER)
{
LOGGER.warning("Wrong Delay Set in Npc Walker Functions = " + delay + " secs, using default delay: " + DEFAULT_MOVE_DELAY + " secs instead.");
}
}
_nextMoveTime = System.currentTimeMillis() + delay;
setWalkingToNextPoint(false);
}
}
private void walkToLocation()
{
if (_currentPos < (_route.size() - 1))
{
_currentPos++;
}
else
{
_currentPos = 0;
}
if (_route.size() <= _currentPos)
{
return;
}
final boolean moveType = _route.get(_currentPos).getRunning();
/**
* false - walking true - Running
*/
if (moveType)
{
getActor().setRunning();
}
else
{
getActor().setWalking();
}
// now we define destination
final int destinationX = _route.get(_currentPos).getMoveX();
final int destinationY = _route.get(_currentPos).getMoveY();
final int destinationZ = _route.get(_currentPos).getMoveZ();
// notify AI of MOVE_TO
setWalkingToNextPoint(true);
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(destinationX, destinationY, destinationZ, 0));
}
@Override
public L2NpcWalkerInstance getActor()
{
return (L2NpcWalkerInstance) super.getActor();
}
public int getHomeX()
{
return _homeX;
}
public int getHomeY()
{
return _homeY;
}
public int getHomeZ()
{
return _homeZ;
}
public void setHomeX(int homeX)
{
_homeX = homeX;
}
public void setHomeY(int homeY)
{
_homeY = homeY;
}
public void setHomeZ(int homeZ)
{
_homeZ = homeZ;
}
public boolean isWalkingToNextPoint()
{
return _walkingToNextPoint;
}
public void setWalkingToNextPoint(boolean value)
{
_walkingToNextPoint = value;
}
}

View File

@@ -0,0 +1,378 @@
/*
* 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.ai;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
import java.util.EmptyStackException;
import java.util.Stack;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Character.AIAccessor;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2StaticObjectInstance;
import com.l2jmobius.gameserver.model.actor.knownlist.ObjectKnownList.KnownListAsynchronousUpdateTask;
import com.l2jmobius.gameserver.model.actor.position.Location;
public class L2PlayerAI extends L2CharacterAI
{
private boolean _thinking; // to prevent recursive thinking
class IntentionCommand
{
protected CtrlIntention _crtlIntention;
protected Object _arg0, _arg1;
protected IntentionCommand(CtrlIntention pIntention, Object pArg0, Object pArg1)
{
_crtlIntention = pIntention;
_arg0 = pArg0;
_arg1 = pArg1;
}
}
private final Stack<IntentionCommand> _interuptedIntentions = new Stack<>();
private synchronized Stack<IntentionCommand> getInterruptedIntentions()
{
return _interuptedIntentions;
}
public L2PlayerAI(AIAccessor accessor)
{
super(accessor);
}
/**
* Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.<BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
@Override
public void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
/*
* if (Config.DEBUG) LOGGER.warning("L2PlayerAI: changeIntention -> " + intention + " " + arg0 + " " + arg1);
*/
// nothing to do if it does not CAST intention
if (intention != AI_INTENTION_CAST)
{
super.changeIntention(intention, arg0, arg1);
return;
}
final CtrlIntention _intention = getIntention();
final Object _intentionArg0 = get_intentionArg0();
final Object _intentionArg1 = get_intentionArg1();
// do nothing if next intention is same as current one.
if ((intention == _intention) && (arg0 == _intentionArg0) && (arg1 == _intentionArg1))
{
super.changeIntention(intention, arg0, arg1);
return;
}
/*
* if (Config.DEBUG) LOGGER.warning("L2PlayerAI: changeIntention -> Saving current intention: " + _intention + " " + _intention_arg0 + " " + _intention_arg1);
*/
// push current intention to stack
getInterruptedIntentions().push(new IntentionCommand(_intention, _intentionArg0, _intentionArg1));
super.changeIntention(intention, arg0, arg1);
}
/**
* Finalize the casting of a skill. This method overrides L2CharacterAI method.<BR>
* <BR>
* <B>What it does:</B> Check if actual intention is set to CAST and, if so, retrieves latest intention before the actual CAST and set it as the current intention for the player
*/
@Override
protected void onEvtFinishCasting()
{
// forget interupted actions after offensive skill
final L2Skill skill = get_skill();
if ((skill != null) && skill.isOffensive())
{
getInterruptedIntentions().clear();
}
if (getIntention() == AI_INTENTION_CAST)
{
// run interupted intention if it remain.
if (!getInterruptedIntentions().isEmpty())
{
IntentionCommand cmd = null;
try
{
cmd = getInterruptedIntentions().pop();
}
catch (EmptyStackException ese)
{
}
/*
* if (Config.DEBUG) LOGGER.warning("L2PlayerAI: onEvtFinishCasting -> " + cmd._intention + " " + cmd._arg0 + " " + cmd._arg1);
*/
if ((cmd != null) && (cmd._crtlIntention != AI_INTENTION_CAST)) // previous state shouldn't be casting
{
setIntention(cmd._crtlIntention, cmd._arg0, cmd._arg1);
}
else
{
setIntention(AI_INTENTION_IDLE);
}
}
else
{
/*
* if (Config.DEBUG) LOGGER.warning("L2PlayerAI: no previous intention set... Setting it to IDLE");
*/
// set intention to idle if skill doesn't change intention.
setIntention(AI_INTENTION_IDLE);
}
}
}
@Override
protected void onIntentionRest()
{
if (getIntention() != AI_INTENTION_REST)
{
changeIntention(AI_INTENTION_REST, null, null);
setTarget(null);
if (getAttackTarget() != null)
{
setAttackTarget(null);
}
clientStopMoving(null);
}
}
@Override
protected void clientStopMoving(Location pos)
{
super.clientStopMoving(pos);
final L2PcInstance _player = (L2PcInstance) _actor;
if (_player.getPosticipateSit())
{
_player.sitDown();
}
}
@Override
protected void onIntentionActive()
{
setIntention(AI_INTENTION_IDLE);
}
@Override
protected void clientNotifyDead()
{
_clientMovingToPawnOffset = 0;
_clientMoving = false;
super.clientNotifyDead();
}
private void thinkAttack()
{
final L2Character target = getAttackTarget();
if (target == null)
{
return;
}
if (checkTargetLostOrDead(target))
{
// Notify the target
setAttackTarget(null);
return;
}
if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange()))
{
return;
}
_accessor.doAttack(target);
return;
}
private void thinkCast()
{
final L2Character target = getCastTarget();
final L2Skill skill = get_skill();
// if (Config.DEBUG) LOGGER.warning("L2PlayerAI: thinkCast -> Start");
if (checkTargetLost(target))
{
if (skill.isOffensive() && (getAttackTarget() != null))
{
// Notify the target
setCastTarget(null);
}
return;
}
if (target != null)
{
if (maybeMoveToPawn(target, _actor.getMagicalAttackRange(skill)))
{
return;
}
}
if (skill.getHitTime() > 50)
{
clientStopMoving(null);
}
final L2Object oldTarget = _actor.getTarget();
if (oldTarget != null)
{
// Replace the current target by the cast target
if ((target != null) && (oldTarget != target))
{
_actor.setTarget(getCastTarget());
}
// Launch the Cast of the skill
_accessor.doCast(get_skill());
// Restore the initial target
if ((target != null) && (oldTarget != target))
{
_actor.setTarget(oldTarget);
}
}
else
{
_accessor.doCast(skill);
}
return;
}
private void thinkPickUp()
{
if (_actor.isAllSkillsDisabled())
{
return;
}
final L2Object target = getTarget();
if (checkTargetLost(target))
{
return;
}
if (maybeMoveToPawn(target, 36))
{
return;
}
setIntention(AI_INTENTION_IDLE);
((L2PcInstance.AIAccessor) _accessor).doPickupItem(target);
return;
}
private void thinkInteract()
{
if (_actor.isAllSkillsDisabled())
{
return;
}
final L2Object target = getTarget();
if (checkTargetLost(target))
{
return;
}
if (maybeMoveToPawn(target, 36))
{
return;
}
if (!(target instanceof L2StaticObjectInstance))
{
((L2PcInstance.AIAccessor) _accessor).doInteract((L2Character) target);
}
setIntention(AI_INTENTION_IDLE);
return;
}
@Override
protected void onEvtThink()
{
if (_thinking || _actor.isAllSkillsDisabled())
{
return;
}
_thinking = true;
try
{
if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
else if (getIntention() == AI_INTENTION_CAST)
{
thinkCast();
}
else if (getIntention() == AI_INTENTION_PICK_UP)
{
thinkPickUp();
}
else if (getIntention() == AI_INTENTION_INTERACT)
{
thinkInteract();
}
}
finally
{
_thinking = false;
}
}
@Override
protected void onEvtArrivedRevalidate()
{
ThreadPoolManager.execute(new KnownListAsynchronousUpdateTask(_actor));
super.onEvtArrivedRevalidate();
}
}

View File

@@ -0,0 +1,866 @@
/*
* 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.ai;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.concurrent.Future;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.geodata.GeoData;
import com.l2jmobius.gameserver.model.L2Effect;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2FolkInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2SiegeGuardInstance;
/**
* This class manages AI of L2Attackable.<BR>
* <BR>
*/
public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
{
// protected static final Logger LOGGER = Logger.getLogger(L2SiegeGuardAI.class);
private static final int MAX_ATTACK_TIMEOUT = 300; // int ticks, i.e. 30 seconds
/** The L2Attackable AI task executed every 1s (call onEvtThink method) */
private Future<?> _aiTask;
/** The delay after wich the attacked is stopped */
private int _attackTimeout;
/** The L2Attackable aggro counter */
private int _globalAggro;
/** The flag used to indicate that a thinking action is in progress */
private boolean _thinking; // to prevent recursive thinking
private final int _attackRange;
/**
* Constructor of L2AttackableAI.<BR>
* <BR>
* @param accessor The AI accessor of the L2Character
*/
public L2SiegeGuardAI(L2Character.AIAccessor accessor)
{
super(accessor);
_attackTimeout = Integer.MAX_VALUE;
_globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
_attackRange = ((L2Attackable) _actor).getPhysicalAttackRange();
}
@Override
public void run()
{
// Launch actions corresponding to the Event Think
onEvtThink();
}
/**
* Return True if the target is autoattackable (depends on the actor type).<BR>
* <BR>
* <B><U> Actor is a L2GuardInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk or a Door</li>
* <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li>
* <li>The target is in the actor Aggro range and is at the same height</li>
* <li>The L2PcInstance target has karma (=PK)</li>
* <li>The L2MonsterInstance target is aggressive</li><BR>
* <BR>
* <B><U> Actor is a L2SiegeGuardInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk or a Door</li>
* <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li>
* <li>The target is in the actor Aggro range and is at the same height</li>
* <li>A siege is in progress</li>
* <li>The L2PcInstance target isn't a Defender</li> <BR>
* <BR>
* <B><U> Actor is a L2FriendlyMobInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk, a Door or another L2NpcInstance</li>
* <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li>
* <li>The target is in the actor Aggro range and is at the same height</li>
* <li>The L2PcInstance target has karma (=PK)</li><BR>
* <BR>
* <B><U> Actor is a L2MonsterInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk, a Door or another L2NpcInstance</li>
* <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li>
* <li>The target is in the actor Aggro range and is at the same height</li>
* <li>The actor is Aggressive</li><BR>
* <BR>
* @param target The targeted L2Object
* @return
*/
private boolean autoAttackCondition(L2Character target)
{
// Check if the target isn't another guard, folk or a door
if ((target == null) || (target instanceof L2SiegeGuardInstance) || (target instanceof L2FolkInstance) || (target instanceof L2DoorInstance) || target.isAlikeDead() || target.isInvul())
{
return false;
}
// Get the owner if the target is a summon
if (target instanceof L2Summon)
{
L2PcInstance owner = ((L2Summon) target).getOwner();
if (_actor.isInsideRadius(owner, 1000, true, false))
{
target = owner;
}
}
// Check if the target is a L2PcInstance
if (target instanceof L2PcInstance)
{
// Check if the target isn't in silent move mode AND too far (>100)
if (((L2PcInstance) target).isSilentMoving() && !_actor.isInsideRadius(target, 250, false, false))
{
return false;
}
}
// Los Check Here
return _actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target);
}
/**
* Set the Intention of this L2CharacterAI and create an AI Task executed every 1s (call onEvtThink method) for this L2Attackable.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : If actor _knowPlayer isn't EMPTY, AI_INTENTION_IDLE will be change in AI_INTENTION_ACTIVE</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
@Override
public void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
if (Config.DEBUG)
{
LOGGER.info("L2SiegeAI.changeIntention(" + intention + ", " + arg0 + ", " + arg1 + ")");
}
((L2Attackable) _actor).setisReturningToSpawnPoint(false);
if (intention == AI_INTENTION_IDLE /* || intention == AI_INTENTION_ACTIVE */) // active becomes idle if only a summon is present
{
// Check if actor is not dead
if (!_actor.isAlikeDead())
{
L2Attackable npc = (L2Attackable) _actor;
// If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE
if (npc.getKnownList().getKnownPlayers().size() > 0)
{
intention = AI_INTENTION_ACTIVE;
}
else
{
intention = AI_INTENTION_IDLE;
}
}
if (intention == AI_INTENTION_IDLE)
{
// Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE
super.changeIntention(AI_INTENTION_IDLE, null, null);
// Stop AI task and detach AI from NPC
if (_aiTask != null)
{
_aiTask.cancel(true);
_aiTask = null;
}
// Cancel the AI
_accessor.detachAI();
return;
}
}
// Set the Intention of this L2AttackableAI to intention
super.changeIntention(intention, arg0, arg1);
// If not idle - create an AI task (schedule onEvtThink repeatedly)
if (_aiTask == null)
{
_aiTask = ThreadPoolManager.scheduleAtFixedRate(this, 1000, 1000);
}
}
/**
* Manage the Attack Intention : Stop current Attack (if necessary), Calculate attack timeout, Start a new Attack and Launch Think Event.<BR>
* <BR>
* @param target The L2Character to attack
*/
@Override
protected void onIntentionAttack(L2Character target)
{
// Calculate the attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
// if (_actor.getTarget() != null)
super.onIntentionAttack(target);
}
/**
* Manage AI standard thinks of a L2Attackable (called by onEvtThink).<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update every 1s the _globalAggro counter to come close to 0</li>
* <li>If the actor is Aggressive and can attack, add all autoAttackable L2Character in its Aggro Range to its _aggroList, chose a target and order to attack it</li>
* <li>If the actor can't attack, order to it to return to its home location</li>
*/
private void thinkActive()
{
L2Attackable npc = (L2Attackable) _actor;
// Update every 1s the _globalAggro counter to come close to 0
if (_globalAggro != 0)
{
if (_globalAggro < 0)
{
_globalAggro++;
}
else
{
_globalAggro--;
}
}
// Add all autoAttackable L2Character in L2Attackable Aggro Range to its _aggroList with 0 damage and 1 hate
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(_attackRange))
{
if (target == null)
{
continue;
}
if (autoAttackCondition(target)) // check aggression
{
// Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
final int hating = npc.getHating(target);
// Add the attacker to the L2Attackable _aggroList with 0 damage and 1 hate
if (hating == 0)
{
npc.addDamageHate(target, 0, 1);
}
}
}
// Chose a target from its aggroList
L2Character hated;
// Force mobs to attak anybody if confused
if (_actor.isConfused())
{
hated = getAttackTarget();
}
else
{
hated = npc.getMostHated();
}
// Order to the L2Attackable to attack the target
if (hated != null)
{
// Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
final int aggro = npc.getHating(hated);
if ((aggro + _globalAggro) > 0)
{
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
// Set the AI Intention to AI_INTENTION_ATTACK
setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated, null);
}
return;
}
}
// Order to the L2SiegeGuardInstance to return to its home location because there's no target to attack
((L2SiegeGuardInstance) _actor).returnHome();
return;
}
private void attackPrepare()
{
// Get all information needed to chose between physical or magical attack
L2Skill[] skills = null;
double dist_2 = 0;
int range = 0;
L2SiegeGuardInstance sGuard = (L2SiegeGuardInstance) _actor;
final L2Character attackTarget = getAttackTarget();
try
{
_actor.setTarget(attackTarget);
skills = _actor.getAllSkills();
dist_2 = _actor.getPlanDistanceSq(attackTarget.getX(), attackTarget.getY());
range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + attackTarget.getTemplate().collisionRadius;
}
catch (NullPointerException e)
{
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
// never attack defenders
if ((attackTarget instanceof L2PcInstance) && sGuard.getCastle().getSiege().checkIsDefender(((L2PcInstance) attackTarget).getClan()))
{
// Cancel the target
sGuard.stopHating(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
if (!GeoData.getInstance().canSeeTarget(_actor, attackTarget))
{
// Siege guards differ from normal mobs currently:
// If target cannot seen, don't attack any more
sGuard.stopHating(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
// Check if the actor isn't muted and if it is far from target
if (!_actor.isMuted() && (dist_2 > ((range + 20) * (range + 20))))
{
// check for long ranged skills and heal/buff skills
if (!Config.ALT_GAME_MOB_ATTACK_AI || ((_actor instanceof L2MonsterInstance) && (Rnd.nextInt(100) <= 5)))
{
for (L2Skill sk : skills)
{
final int castRange = sk.getCastRange();
if (((sk.getSkillType() == L2Skill.SkillType.BUFF) || (sk.getSkillType() == L2Skill.SkillType.HEAL) || ((dist_2 >= ((castRange * castRange) / 9)) && (dist_2 <= (castRange * castRange)) && (castRange > 70))) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !sk.isPassive())
{
if ((sk.getSkillType() == L2Skill.SkillType.BUFF) || (sk.getSkillType() == L2Skill.SkillType.HEAL))
{
boolean useSkillSelf = true;
if (((sk.getSkillType() == L2Skill.SkillType.BUFF) || (sk.getSkillType() == L2Skill.SkillType.HEAL) || ((dist_2 >= ((castRange * castRange) / 9)) && (dist_2 <= (castRange * castRange)) && (castRange > 70))) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !sk.isPassive())
{
useSkillSelf = false;
break;
}
if (sk.getSkillType() == L2Skill.SkillType.BUFF)
{
L2Effect[] effects = _actor.getAllEffects();
for (int i = 0; (effects != null) && (i < effects.length); i++)
{
final L2Effect effect = effects[i];
if (effect.getSkill() == sk)
{
useSkillSelf = false;
break;
}
}
}
if (useSkillSelf)
{
_actor.setTarget(_actor);
}
}
L2Object OldTarget = _actor.getTarget();
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
// Check if the L2SiegeGuardInstance is attacking, knows the target and can't run
if (!_actor.isAttackingNow() && (_actor.getRunSpeed() == 0) && _actor.getKnownList().knowsObject(attackTarget))
{
// Cancel the target
_actor.getKnownList().removeKnownObject(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
}
else
{
final double dx = _actor.getX() - attackTarget.getX();
final double dy = _actor.getY() - attackTarget.getY();
final double dz = _actor.getZ() - attackTarget.getZ();
final double homeX = attackTarget.getX() - sGuard.getHomeX();
final double homeY = attackTarget.getY() - sGuard.getHomeY();
// Check if the L2SiegeGuardInstance isn't too far from it's home location
if ((((dx * dx) + (dy * dy)) > 10000) && (((homeX * homeX) + (homeY * homeY)) > 3240000) && _actor.getKnownList().knowsObject(attackTarget))
{
// Cancel the target
_actor.getKnownList().removeKnownObject(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
}
else // Temporary hack for preventing guards jumping off towers,
// before replacing this with effective geodata checks and AI modification
if ((dz * dz) < (170 * 170))
{
moveToPawn(attackTarget, range);
}
}
return;
}
// Else, if the actor is muted and far from target, just "move to pawn"
else if (_actor.isMuted() && (dist_2 > ((range + 20) * (range + 20))))
{
// Temporary hack for preventing guards jumping off towers,
// before replacing this with effective geodata checks and AI modification
final double dz = _actor.getZ() - attackTarget.getZ();
// normally 130 if guard z coordinates correct
if ((dz * dz) < (170 * 170))
{
moveToPawn(attackTarget, range);
}
return;
}
// Else, if this is close enough to attack
else if (dist_2 <= ((range + 20) * (range + 20)))
{
// Force mobs to attak anybody if confused
L2Character hated = null;
if (_actor.isConfused())
{
hated = attackTarget;
}
else
{
hated = ((L2Attackable) _actor).getMostHated();
}
if (hated == null)
{
setIntention(AI_INTENTION_ACTIVE, null, null);
return;
}
if (hated != attackTarget)
{
setAttackTarget(hated);
}
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// check for close combat skills && heal/buff skills
if (!_actor.isMuted() && (Rnd.nextInt(100) <= 5))
{
for (L2Skill sk : skills)
{
final int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist_2) && (castRange <= 70) && !sk.isPassive() && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !_actor.isSkillDisabled(sk))
{
if ((sk.getSkillType() == L2Skill.SkillType.BUFF) || (sk.getSkillType() == L2Skill.SkillType.HEAL))
{
boolean useSkillSelf = true;
if ((sk.getSkillType() == L2Skill.SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
{
useSkillSelf = false;
break;
}
if (sk.getSkillType() == L2Skill.SkillType.BUFF)
{
final L2Effect[] effects = _actor.getAllEffects();
for (int i = 0; (effects != null) && (i < effects.length); i++)
{
final L2Effect effect = effects[i];
if (effect.getSkill() == sk)
{
useSkillSelf = false;
break;
}
}
}
if (useSkillSelf)
{
_actor.setTarget(_actor);
}
}
L2Object OldTarget = _actor.getTarget();
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
// Finally, do the physical attack itself
_accessor.doAttack(getAttackTarget());
}
}
/**
* Manage AI attack thinks of a L2Attackable (called by onEvtThink).<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update the attack timeout if actor is running</li>
* <li>If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE</li>
* <li>Call all L2Object of its Faction inside the Faction Range</li>
* <li>Chose a target and order to attack it with magic skill or physical attack</li><BR>
* <BR>
* TODO: Manage casting rules to healer mobs (like Ant Nurses)
*/
private void thinkAttack()
{
if (Config.DEBUG)
{
LOGGER.info("L2SiegeGuardAI.thinkAttack(); timeout=" + (_attackTimeout - GameTimeController.getGameTicks()));
}
if (_attackTimeout < GameTimeController.getGameTicks())
{
// Check if the actor is running
if (_actor.isRunning())
{
// Set the actor movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance
_actor.setWalking();
// Calculate a new attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
}
}
final L2Character attackTarget = getAttackTarget();
// Check if target is dead or if timeout is expired to stop this attack
if ((attackTarget == null) || attackTarget.isAlikeDead() || (_attackTimeout < GameTimeController.getGameTicks()))
{
// Stop hating this target after the attack timeout or if target is dead
if (attackTarget != null)
{
L2Attackable npc = (L2Attackable) _actor;
npc.stopHating(attackTarget);
}
// Cancel target and timeout
_attackTimeout = Integer.MAX_VALUE;
setAttackTarget(null);
// Set the AI Intention to AI_INTENTION_ACTIVE
setIntention(AI_INTENTION_ACTIVE, null, null);
_actor.setWalking();
return;
}
attackPrepare();
factionNotify();
}
private final void factionNotify()
{
final L2Character actor = getActor();
final L2Character target = getAttackTarget();
// Call all L2Object of its Faction inside the Faction Range
if ((actor == null) || (target == null) || (((L2NpcInstance) actor).getFactionId() == null))
{
return;
}
if (target.isInvul())
{
return;
}
// Go through all L2Object that belong to its faction
for (L2Character cha : actor.getKnownList().getKnownCharactersInRadius(1000))
{
if (cha == null)
{
continue;
}
if (!(cha instanceof L2NpcInstance))
{
continue;
}
L2NpcInstance npc = (L2NpcInstance) cha;
String faction_id = ((L2NpcInstance) actor).getFactionId();
if (!faction_id.equalsIgnoreCase(npc.getFactionId()))
{
continue;
}
// Check if the L2Object is inside the Faction Range of the actor
if ((npc.getAI() != null) && ((npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE)) && actor.isInsideRadius(npc, npc.getFactionRange(), false, true) && target.isInsideRadius(npc, npc.getFactionRange(), false, true))
{
if (Config.PATHFINDING > 0)
{
if (GeoData.getInstance().canSeeTarget(npc, target))
{
// Notify the L2Object AI with EVT_AGGRESSION
final L2CharacterAI ai = npc.getAI();
if (ai != null)
{
ai.notifyEvent(CtrlEvent.EVT_AGGRESSION, target, 1);
}
}
}
else if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600))
{
// Notify the L2Object AI with EVT_AGGRESSION
final L2CharacterAI ai = npc.getAI();
if (ai != null)
{
ai.notifyEvent(CtrlEvent.EVT_AGGRESSION, target, 1);
}
}
}
}
}
/**
* Manage AI thinking actions of a L2Attackable.<BR>
* <BR>
*/
@Override
protected void onEvtThink()
{
// Check if the actor can't use skills and if a thinking action isn't already in progress
if (_thinking || _actor.isAllSkillsDisabled())
{
return;
}
// Start thinking action
_thinking = true;
try
{
// Manage AI thinks of a L2Attackable
if (getIntention() == AI_INTENTION_ACTIVE)
{
thinkActive();
}
else if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
}
finally
{
// Stop thinking action
_thinking = false;
}
}
/**
* Launch actions corresponding to the Event Attacked.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Init the attack : Calculate the attack timeout, Set the _globalAggro to 0, Add the attacker to the actor _aggroList</li>
* <li>Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance</li>
* <li>Set the Intention to AI_INTENTION_ATTACK</li> <BR>
* <BR>
* @param attacker The L2Character that attacks the actor
*/
@Override
protected void onEvtAttacked(L2Character attacker)
{
// Calculate the attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// Set the _globalAggro to 0 to permit attack even just after spawn
if (_globalAggro < 0)
{
_globalAggro = 0;
}
// Add the attacker to the _aggroList of the actor
((L2Attackable) _actor).addDamageHate(attacker, 0, 1);
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
// Set the Intention to AI_INTENTION_ATTACK
if (getIntention() != AI_INTENTION_ATTACK)
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker, null);
}
super.onEvtAttacked(attacker);
}
/**
* Launch actions corresponding to the Event Aggression.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Add the target to the actor _aggroList or update hate if already present</li>
* <li>Set the actor Intention to AI_INTENTION_ATTACK (if actor is L2GuardInstance check if it isn't too far from its home location)</li><BR>
* <BR>
* @param target The L2Character that attacks
* @param aggro The value of hate to add to the actor against the target
*/
@Override
protected void onEvtAggression(L2Character target, int aggro)
{
if (_actor == null)
{
return;
}
L2Attackable me = (L2Attackable) _actor;
if (target != null)
{
// Add the target to the actor _aggroList or update hate if already present
me.addDamageHate(target, 0, aggro);
// Get the hate of the actor against the target
aggro = me.getHating(target);
if (aggro <= 0)
{
if (me.getMostHated() == null)
{
_globalAggro = -25;
me.clearAggroList();
setIntention(AI_INTENTION_IDLE, null, null);
}
return;
}
// Set the actor AI Intention to AI_INTENTION_ATTACK
if (getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
{
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
L2SiegeGuardInstance sGuard = (L2SiegeGuardInstance) _actor;
final double homeX = target.getX() - sGuard.getHomeX();
final double homeY = target.getY() - sGuard.getHomeY();
// Check if the L2SiegeGuardInstance is not too far from its home location
if (((homeX * homeX) + (homeY * homeY)) < 3240000)
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, target, null);
}
}
}
else
{
// currently only for setting lower general aggro
if (aggro >= 0)
{
return;
}
L2Character mostHated = me.getMostHated();
if (mostHated == null)
{
_globalAggro = -25;
return;
}
for (L2Character aggroed : me.getAggroListRP().keySet())
{
me.addDamageHate(aggroed, 0, aggro);
}
aggro = me.getHating(mostHated);
if (aggro <= 0)
{
_globalAggro = -25;
me.clearAggroList();
setIntention(AI_INTENTION_IDLE, null, null);
}
}
}
@Override
protected void onEvtDead()
{
stopAITask();
super.onEvtDead();
}
public void stopAITask()
{
if (_aiTask != null)
{
_aiTask.cancel(false);
_aiTask = null;
}
_accessor.detachAI();
}
}

View File

@@ -0,0 +1,223 @@
/*
* 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.ai;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Character.AIAccessor;
import com.l2jmobius.gameserver.model.actor.L2Summon;
public class L2SummonAI extends L2CharacterAI
{
private boolean _thinking; // to prevent recursive thinking
private L2Summon summon;
public L2SummonAI(AIAccessor accessor)
{
super(accessor);
}
@Override
protected void onIntentionIdle()
{
stopFollow();
onIntentionActive();
}
@Override
protected void onIntentionActive()
{
L2Summon summon = (L2Summon) _actor;
if (summon.getFollowStatus())
{
setIntention(AI_INTENTION_FOLLOW, summon.getOwner());
}
else
{
super.onIntentionActive();
}
}
private void thinkAttack()
{
summon = (L2Summon) _actor;
L2Object target = null;
target = summon.getTarget();
// Like L2OFF if the target is dead the summon must go back to his owner
if ((target != null) && (summon != null) && ((L2Character) target).isDead())
{
summon.setFollowStatus(true);
}
if (checkTargetLostOrDead(getAttackTarget()))
{
setAttackTarget(null);
return;
}
if (maybeMoveToPawn(getAttackTarget(), _actor.getPhysicalAttackRange()))
{
return;
}
clientStopMoving(null);
_accessor.doAttack(getAttackTarget());
return;
}
private void thinkCast()
{
L2Summon summon = (L2Summon) _actor;
final L2Character target = getCastTarget();
if (checkTargetLost(target))
{
setCastTarget(null);
return;
}
final L2Skill skill = get_skill();
if (maybeMoveToPawn(target, _actor.getMagicalAttackRange(skill)))
{
return;
}
clientStopMoving(null);
summon.setFollowStatus(false);
setIntention(AI_INTENTION_IDLE);
_accessor.doCast(skill);
return;
}
private void thinkPickUp()
{
if (_actor.isAllSkillsDisabled())
{
return;
}
final L2Object target = getTarget();
if (checkTargetLost(target))
{
return;
}
if (maybeMoveToPawn(target, 36))
{
return;
}
setIntention(AI_INTENTION_IDLE);
((L2Summon.AIAccessor) _accessor).doPickupItem(target);
return;
}
private void thinkInteract()
{
if (_actor.isAllSkillsDisabled())
{
return;
}
final L2Object target = getTarget();
if (checkTargetLost(target))
{
return;
}
if (maybeMoveToPawn(target, 36))
{
return;
}
setIntention(AI_INTENTION_IDLE);
return;
}
@Override
protected void onEvtThink()
{
if (_thinking || _actor.isAllSkillsDisabled())
{
return;
}
_thinking = true;
try
{
if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
else if (getIntention() == AI_INTENTION_CAST)
{
thinkCast();
}
else if (getIntention() == AI_INTENTION_PICK_UP)
{
thinkPickUp();
}
else if (getIntention() == AI_INTENTION_INTERACT)
{
thinkInteract();
}
}
finally
{
_thinking = false;
}
}
@Override
protected void onEvtFinishCasting()
{
super.onEvtFinishCasting();
final L2Summon summon = (L2Summon) _actor;
L2Object target = null;
target = summon.getTarget();
if (target == null)
{
return;
}
if (summon.getAI().getIntention() != AI_INTENTION_ATTACK)
{
summon.setFollowStatus(true);
}
else if (((L2Character) target).isDead())
{
summon.setFollowStatus(true);
}
}
}

View File

@@ -0,0 +1,397 @@
/*
* 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.cache;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.sql.ClanTable;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Clan;
/**
* @author Layane
*/
public class CrestCache
{
private static Logger LOGGER = Logger.getLogger(CrestCache.class.getName());
private static CrestCache _instance;
private final Map<Integer, byte[]> _cachePledge = new HashMap<>();
private final Map<Integer, byte[]> _cachePledgeLarge = new HashMap<>();
private final Map<Integer, byte[]> _cacheAlly = new HashMap<>();
private int _loadedFiles;
private long _bytesBuffLen;
public static CrestCache getInstance()
{
if (_instance == null)
{
_instance = new CrestCache();
}
return _instance;
}
public CrestCache()
{
convertOldPedgeFiles();
reload();
}
public void reload()
{
final FileFilter filter = new BmpFilter();
final File dir = new File(Config.DATAPACK_ROOT, "data/crests/");
final File[] files = dir.listFiles(filter);
byte[] content;
synchronized (this)
{
_loadedFiles = 0;
_bytesBuffLen = 0;
_cachePledge.clear();
_cachePledgeLarge.clear();
_cacheAlly.clear();
}
for (File file : files)
{
RandomAccessFile f = null;
synchronized (this)
{
try
{
f = new RandomAccessFile(file, "r");
content = new byte[(int) f.length()];
f.readFully(content);
if (file.getName().startsWith("Crest_Large_"))
{
_cachePledgeLarge.put(Integer.valueOf(file.getName().substring(12, file.getName().length() - 4)), content);
}
else if (file.getName().startsWith("Crest_"))
{
_cachePledge.put(Integer.valueOf(file.getName().substring(6, file.getName().length() - 4)), content);
}
else if (file.getName().startsWith("AllyCrest_"))
{
_cacheAlly.put(Integer.valueOf(file.getName().substring(10, file.getName().length() - 4)), content);
}
_loadedFiles++;
_bytesBuffLen += content.length;
}
catch (Exception e)
{
LOGGER.warning("problem with crest bmp file " + e);
}
finally
{
if (f != null)
{
try
{
f.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
}
LOGGER.info("Cache[Crest]: " + String.format("%.3f", getMemoryUsage()) + "MB on " + getLoadedFiles() + " files loaded.");
}
public void convertOldPedgeFiles()
{
File dir = new File(Config.DATAPACK_ROOT, "data/crests/");
File[] files = dir.listFiles(new OldPledgeFilter());
if (files == null)
{
LOGGER.info("No old crest files found in \"data/crests/\"!!! May be you deleted them?");
return;
}
for (File file : files)
{
final int clanId = Integer.parseInt(file.getName().substring(7, file.getName().length() - 4));
LOGGER.info("Found old crest file \"" + file.getName() + "\" for clanId " + clanId);
final int newId = IdFactory.getInstance().getNextId();
L2Clan clan = ClanTable.getInstance().getClan(clanId);
if (clan != null)
{
removeOldPledgeCrest(clan.getCrestId());
file.renameTo(new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + newId + ".bmp"));
LOGGER.info("Renamed Clan crest to new format: Crest_" + newId + ".bmp");
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("UPDATE clan_data SET crest_id = ? WHERE clan_id = ?");
statement.setInt(1, newId);
statement.setInt(2, clan.getClanId());
statement.executeUpdate();
statement.close();
}
catch (SQLException e)
{
LOGGER.warning("could not update the crest id:" + e.getMessage());
}
clan.setCrestId(newId);
clan.setHasCrest(true);
}
else
{
LOGGER.info("Clan Id: " + clanId + " does not exist in table.. deleting.");
file.delete();
}
}
}
public float getMemoryUsage()
{
return (float) _bytesBuffLen / 1048576;
}
public int getLoadedFiles()
{
return _loadedFiles;
}
public byte[] getPledgeCrest(int id)
{
return _cachePledge.get(id);
}
public byte[] getPledgeCrestLarge(int id)
{
return _cachePledgeLarge.get(id);
}
public byte[] getAllyCrest(int id)
{
return _cacheAlly.get(id);
}
public void removePledgeCrest(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + id + ".bmp");
_cachePledge.remove(id);
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public void removePledgeCrestLarge(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_Large_" + id + ".bmp");
_cachePledgeLarge.remove(id);
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public void removeOldPledgeCrest(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Pledge_" + id + ".bmp");
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public void removeAllyCrest(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/AllyCrest_" + id + ".bmp");
_cacheAlly.remove(id);
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public boolean savePledgeCrest(int newId, byte[] data)
{
boolean output = false;
final File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + newId + ".bmp");
FileOutputStream out = null;
try
{
out = new FileOutputStream(crestFile);
out.write(data);
_cachePledge.put(newId, data);
output = true;
}
catch (IOException e)
{
LOGGER.warning("Error saving pledge crest" + crestFile + " " + e);
}
finally
{
if (out != null)
{
try
{
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
return output;
}
public boolean savePledgeCrestLarge(int newId, byte[] data)
{
boolean output = false;
final File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_Large_" + newId + ".bmp");
FileOutputStream out = null;
try
{
out = new FileOutputStream(crestFile);
out.write(data);
_cachePledgeLarge.put(newId, data);
output = true;
}
catch (IOException e)
{
LOGGER.warning("Error saving Large pledge crest" + crestFile + " " + e);
}
finally
{
if (out != null)
{
try
{
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
return output;
}
public boolean saveAllyCrest(int newId, byte[] data)
{
boolean output = false;
final File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/AllyCrest_" + newId + ".bmp");
FileOutputStream out = null;
try
{
out = new FileOutputStream(crestFile);
out.write(data);
_cacheAlly.put(newId, data);
output = true;
}
catch (IOException e)
{
LOGGER.warning("Error saving ally crest" + crestFile + " " + e);
}
finally
{
if (out != null)
{
try
{
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
return output;
}
class BmpFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
return file.getName().endsWith(".bmp");
}
}
class OldPledgeFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
return file.getName().startsWith("Pledge_");
}
}
}

View File

@@ -0,0 +1,251 @@
/*
* 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.cache;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.util.Util;
/**
* @author Layane
*/
public class HtmCache
{
private static Logger LOGGER = Logger.getLogger(HtmCache.class.getName());
private static HtmCache _instance;
private final Map<Integer, String> _cache;
private int _loadedFiles;
private long _bytesBuffLen;
public static HtmCache getInstance()
{
if (_instance == null)
{
_instance = new HtmCache();
}
return _instance;
}
public HtmCache()
{
_cache = new HashMap<>();
reload();
}
public void reload()
{
reload(Config.DATAPACK_ROOT);
}
public void reload(File f)
{
if (!Config.LAZY_CACHE)
{
LOGGER.info("Html cache start...");
parseDir(f);
LOGGER.info("Cache[HTML]: " + String.format("%.3f", getMemoryUsage()) + " megabytes on " + getLoadedFiles() + " files loaded");
}
else
{
_cache.clear();
_loadedFiles = 0;
_bytesBuffLen = 0;
LOGGER.info("Cache[HTML]: Running lazy cache");
}
}
public void reloadPath(File f)
{
parseDir(f);
LOGGER.info("Cache[HTML]: Reloaded specified path.");
}
public double getMemoryUsage()
{
return (float) _bytesBuffLen / 1048576;
}
public int getLoadedFiles()
{
return _loadedFiles;
}
class HtmFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
if (!file.isDirectory())
{
return file.getName().endsWith(".htm") || file.getName().endsWith(".html");
}
return true;
}
}
private void parseDir(File dir)
{
FileFilter filter = new HtmFilter();
File[] files = dir.listFiles(filter);
for (File file : files)
{
if (!file.isDirectory())
{
loadFile(file);
}
else
{
parseDir(file);
}
}
}
public String loadFile(File file)
{
final HtmFilter filter = new HtmFilter();
String content = null;
if (file.exists() && filter.accept(file) && !file.isDirectory())
{
FileInputStream fis = null;
BufferedInputStream bis = null;
try
{
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
final int bytes = bis.available();
final byte[] raw = new byte[bytes];
bis.read(raw);
content = new String(raw, "UTF-8");
content = content.replaceAll("\r\n", "\n");
content = content.replaceAll("(?s)<!--.*?-->", ""); // Remove html comments
final String relpath = Util.getRelativePath(Config.DATAPACK_ROOT, file);
final int hashcode = relpath.hashCode();
final String oldContent = _cache.get(hashcode);
if (oldContent == null)
{
_bytesBuffLen += bytes;
_loadedFiles++;
}
else
{
_bytesBuffLen = (_bytesBuffLen - oldContent.length()) + bytes;
}
_cache.put(hashcode, content);
}
catch (Exception e)
{
LOGGER.warning("problem with htm file " + e);
e.printStackTrace();
}
finally
{
if (bis != null)
{
try
{
bis.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (fis != null)
{
try
{
fis.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
return content;
}
public String getHtmForce(String path)
{
String content = getHtm(path);
if (content == null)
{
content = "<html><body>My text is missing:<br>" + path + "</body></html>";
LOGGER.warning("Cache[HTML]: Missing HTML page: " + path);
}
return content;
}
public String getHtm(String path)
{
String content = _cache.get(path.hashCode());
if (Config.LAZY_CACHE && (content == null))
{
content = loadFile(new File(Config.DATAPACK_ROOT, path));
}
return content;
}
public boolean contains(String path)
{
return _cache.containsKey(path.hashCode());
}
/**
* Check if an HTM exists and can be loaded
* @param path The path to the HTM
* @return
*/
public boolean isLoadable(String path)
{
File file = new File(path);
HtmFilter filter = new HtmFilter();
if (file.exists() && filter.accept(file) && !file.isDirectory())
{
return true;
}
return false;
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.cache;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
/**
* @author -Nemesiss-
*/
public class WarehouseCacheManager
{
private static WarehouseCacheManager _instance;
protected final Map<L2PcInstance, Long> _cachedWh;
protected final long _cacheTime;
public static WarehouseCacheManager getInstance()
{
if (_instance == null)
{
_instance = new WarehouseCacheManager();
}
return _instance;
}
private WarehouseCacheManager()
{
_cacheTime = Config.WAREHOUSE_CACHE_TIME * 60000L; // 60*1000 = 60000
_cachedWh = new ConcurrentHashMap<>();
ThreadPoolManager.scheduleAtFixedRate(new CacheScheduler(), 120000, 60000);
}
public void addCacheTask(L2PcInstance pc)
{
_cachedWh.put(pc, System.currentTimeMillis());
}
public void remCacheTask(L2PcInstance pc)
{
_cachedWh.remove(pc);
}
public class CacheScheduler implements Runnable
{
@Override
public void run()
{
final long cTime = System.currentTimeMillis();
for (L2PcInstance pc : _cachedWh.keySet())
{
if ((cTime - _cachedWh.get(pc)) > _cacheTime)
{
pc.clearWarehouse();
_cachedWh.remove(pc);
}
}
}
}
}

View File

@@ -0,0 +1,257 @@
/*
* 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.communitybbs.BB;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.communitybbs.Manager.ForumsBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.TopicBBSManager;
public class Forum
{
// Types
public static final int ROOT = 0;
public static final int NORMAL = 1;
public static final int CLAN = 2;
public static final int MEMO = 3;
public static final int MAIL = 4;
// Permissions
public static final int INVISIBLE = 0;
public static final int ALL = 1;
public static final int CLANMEMBERONLY = 2;
public static final int OWNERONLY = 3;
private static Logger LOGGER = Logger.getLogger(Forum.class.getName());
private final List<Forum> _children;
private final Map<Integer, Topic> _topic;
private final int _forumId;
private String _forumName;
private int _forumType;
private int _forumPost;
private int _forumPerm;
private final Forum _fParent;
private int _ownerID;
private boolean _loaded = false;
/**
* @param Forumid
* @param FParent
*/
public Forum(int Forumid, Forum FParent)
{
_forumId = Forumid;
_fParent = FParent;
_children = new ArrayList<>();
_topic = new HashMap<>();
}
/**
* @param name
* @param parent
* @param type
* @param perm
* @param OwnerID
*/
public Forum(String name, Forum parent, int type, int perm, int OwnerID)
{
_forumName = name;
_forumId = ForumsBBSManager.getInstance().getANewID();
_forumType = type;
_forumPost = 0;
_forumPerm = perm;
_fParent = parent;
_ownerID = OwnerID;
_children = new ArrayList<>();
_topic = new HashMap<>();
parent._children.add(this);
ForumsBBSManager.getInstance().addForum(this);
_loaded = true;
}
private void load()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM forums WHERE forum_id=?");
statement.setInt(1, _forumId);
ResultSet result = statement.executeQuery();
if (result.next())
{
_forumName = result.getString("forum_name");
_forumPost = result.getInt("forum_post");
_forumType = result.getInt("forum_type");
_forumPerm = result.getInt("forum_perm");
_ownerID = result.getInt("forum_owner_id");
}
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Data error on Forum " + _forumId + " : " + e);
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM topic WHERE topic_forum_id=? ORDER BY topic_id DESC");
statement.setInt(1, _forumId);
ResultSet result = statement.executeQuery();
while (result.next())
{
Topic t = new Topic(Topic.ConstructorType.RESTORE, result.getInt("topic_id"), result.getInt("topic_forum_id"), result.getString("topic_name"), result.getLong("topic_date"), result.getString("topic_ownername"), result.getInt("topic_ownerid"), result.getInt("topic_type"), result.getInt("topic_reply"));
_topic.put(t.getID(), t);
if (t.getID() > TopicBBSManager.getInstance().getMaxID(this))
{
TopicBBSManager.getInstance().setMaxID(t.getID(), this);
}
}
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Data error on Forum " + _forumId + " : " + e);
}
}
private void getChildren()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT forum_id FROM forums WHERE forum_parent=?");
statement.setInt(1, _forumId);
ResultSet result = statement.executeQuery();
while (result.next())
{
final Forum f = new Forum(result.getInt("forum_id"), this);
_children.add(f);
ForumsBBSManager.getInstance().addForum(f);
}
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Data error on Forum (children): " + e);
}
}
public int getTopicSize()
{
vload();
return _topic.size();
}
public Topic getTopic(int j)
{
vload();
return _topic.get(j);
}
public void addTopic(Topic t)
{
vload();
_topic.put(t.getID(), t);
}
public int getID()
{
return _forumId;
}
public String getName()
{
vload();
return _forumName;
}
public int getType()
{
vload();
return _forumType;
}
/**
* @param name
* @return
*/
public Forum getChildByName(String name)
{
vload();
for (Forum f : _children)
{
if (f.getName().equals(name))
{
return f;
}
}
return null;
}
public void rmTopicByID(int id)
{
_topic.remove(id);
}
public void insertIntoDb()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("INSERT INTO forums (forum_id,forum_name,forum_parent,forum_post,forum_type,forum_perm,forum_owner_id) values (?,?,?,?,?,?,?)");
statement.setInt(1, _forumId);
statement.setString(2, _forumName);
statement.setInt(3, _fParent.getID());
statement.setInt(4, _forumPost);
statement.setInt(5, _forumType);
statement.setInt(6, _forumPerm);
statement.setInt(7, _ownerID);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while saving new Forum to db " + e);
}
}
public void vload()
{
if (!_loaded)
{
load();
getChildren();
_loaded = true;
}
}
}

View File

@@ -0,0 +1,176 @@
/*
* 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.communitybbs.BB;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.communitybbs.Manager.PostBBSManager;
/**
* @author Maktakien
*/
public class Post
{
private static Logger LOGGER = Logger.getLogger(Post.class.getName());
public class CPost
{
public int postId;
public String postOwner;
public int postOwnerId;
public long postDate;
public int postTopicId;
public int postForumId;
public String postTxt;
}
private final List<CPost> _post;
/**
* @param _PostOwner
* @param _PostOwnerID
* @param date
* @param tid
* @param _PostForumID
* @param txt
*/
public Post(String _PostOwner, int _PostOwnerID, long date, int tid, int _PostForumID, String txt)
{
_post = new ArrayList<>();
CPost cp = new CPost();
cp.postId = 0;
cp.postOwner = _PostOwner;
cp.postOwnerId = _PostOwnerID;
cp.postDate = date;
cp.postTopicId = tid;
cp.postForumId = _PostForumID;
cp.postTxt = txt;
_post.add(cp);
insertindb(cp);
}
public void insertindb(CPost cp)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("INSERT INTO posts (post_id,post_owner_name,post_ownerid,post_date,post_topic_id,post_forum_id,post_txt) values (?,?,?,?,?,?,?)");
statement.setInt(1, cp.postId);
statement.setString(2, cp.postOwner);
statement.setInt(3, cp.postOwnerId);
statement.setLong(4, cp.postDate);
statement.setInt(5, cp.postTopicId);
statement.setInt(6, cp.postForumId);
statement.setString(7, cp.postTxt);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while saving new Post to db " + e);
}
}
public Post(Topic t)
{
_post = new ArrayList<>();
load(t);
}
public CPost getCPost(int id)
{
int i = 0;
for (CPost cp : _post)
{
if (i++ == id)
{
return cp;
}
}
return null;
}
public void deleteMe(Topic t)
{
PostBBSManager.getInstance().delPostByTopic(t);
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("DELETE FROM posts WHERE post_forum_id=? AND post_topic_id=?");
statement.setInt(1, t.getForumID());
statement.setInt(2, t.getID());
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while deleting post: " + e.getMessage());
}
}
private void load(Topic t)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM posts WHERE post_forum_id=? AND post_topic_id=? ORDER BY post_id ASC");
statement.setInt(1, t.getForumID());
statement.setInt(2, t.getID());
ResultSet result = statement.executeQuery();
while (result.next())
{
CPost cp = new CPost();
cp.postId = result.getInt("post_id");
cp.postOwner = result.getString("post_owner_name");
cp.postOwnerId = result.getInt("post_ownerid");
cp.postDate = result.getLong("post_date");
cp.postTopicId = result.getInt("post_topic_id");
cp.postForumId = result.getInt("post_forum_id");
cp.postTxt = result.getString("post_txt");
_post.add(cp);
}
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Data error on Post " + t.getForumID() + "/" + t.getID() + " : " + e);
}
}
public void updateText(int i)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
CPost cp = getCPost(i);
PreparedStatement statement = con.prepareStatement("UPDATE posts SET post_txt=? WHERE post_id=? AND post_topic_id=? AND post_forum_id=?");
statement.setString(1, cp.postTxt);
statement.setInt(2, cp.postId);
statement.setInt(3, cp.postTopicId);
statement.setInt(4, cp.postForumId);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while saving new Post to db " + e);
}
}
}

View File

@@ -0,0 +1,141 @@
/*
* 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.communitybbs.BB;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.communitybbs.Manager.TopicBBSManager;
public class Topic
{
private static Logger LOGGER = Logger.getLogger(Topic.class.getName());
public static final int MORMAL = 0;
public static final int MEMO = 1;
private final int _id;
private final int _forumId;
private final String _topicName;
private final long _date;
private final String _ownerName;
private final int _ownerId;
private final int _type;
private final int _cReply;
/**
* @param ct
* @param id
* @param fid
* @param name
* @param date
* @param oname
* @param oid
* @param type
* @param Creply
*/
public Topic(ConstructorType ct, int id, int fid, String name, long date, String oname, int oid, int type, int Creply)
{
_id = id;
_forumId = fid;
_topicName = name;
_date = date;
_ownerName = oname;
_ownerId = oid;
_type = type;
_cReply = Creply;
TopicBBSManager.getInstance().addTopic(this);
if (ct == ConstructorType.CREATE)
{
insertIntoDb();
}
}
private void insertIntoDb()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("INSERT INTO topic (topic_id,topic_forum_id,topic_name,topic_date,topic_ownername,topic_ownerid,topic_type,topic_reply) values (?,?,?,?,?,?,?,?)");
statement.setInt(1, _id);
statement.setInt(2, _forumId);
statement.setString(3, _topicName);
statement.setLong(4, _date);
statement.setString(5, _ownerName);
statement.setInt(6, _ownerId);
statement.setInt(7, _type);
statement.setInt(8, _cReply);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while saving new Topic to db " + e);
}
}
public enum ConstructorType
{
RESTORE,
CREATE
}
public int getID()
{
return _id;
}
public int getForumID()
{
return _forumId;
}
public String getName()
{
return _topicName;
}
public String getOwnerName()
{
return _ownerName;
}
public long getDate()
{
return _date;
}
public void deleteMe(Forum f)
{
TopicBBSManager.getInstance().delTopic(this);
f.rmTopicByID(getID());
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("DELETE FROM topic WHERE topic_id=? AND topic_forum_id=?");
statement.setInt(1, getID());
statement.setInt(2, f.getID());
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while deleting topic: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.communitybbs;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.communitybbs.Manager.BaseBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.ClanBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.FavoriteBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.FriendsBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.MailBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.PostBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.RegionBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.TopBBSManager;
import com.l2jmobius.gameserver.communitybbs.Manager.TopicBBSManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
public class CommunityBoard
{
/** The bypasses used by the players. */
private final Map<Integer, String> _bypasses = new ConcurrentHashMap<>();
protected CommunityBoard()
{
}
public static CommunityBoard getInstance()
{
return SingletonHolder._instance;
}
public void handleCommands(L2GameClient client, String command)
{
final L2PcInstance activeChar = client.getActiveChar();
if (activeChar == null)
{
return;
}
if (!Config.ENABLE_COMMUNITY_BOARD)
{
activeChar.sendPacket(SystemMessageId.CB_OFFLINE);
return;
}
if (command.startsWith("_bbshome"))
{
TopBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_bbsloc"))
{
RegionBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_bbsclan"))
{
ClanBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_bbsmemo"))
{
TopicBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_bbsmail") || command.equals("_maillist_0_1_0_"))
{
MailBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_friend") || command.startsWith("_block"))
{
FriendsBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_bbstopics"))
{
TopicBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_bbsposts"))
{
PostBBSManager.getInstance().parseCmd(command, activeChar);
}
else if (command.startsWith("_bbsgetfav") || command.startsWith("bbs_add_fav") || command.startsWith("_bbsdelfav_"))
{
FavoriteBBSManager.getInstance().parseCmd(command, activeChar);
}
else
{
BaseBBSManager.separateAndSend("<html><body><br><br><center>The command: " + command + " isn't implemented.</center></body></html>", activeChar);
}
}
public void handleWriteCommands(L2GameClient client, String url, String arg1, String arg2, String arg3, String arg4, String arg5)
{
final L2PcInstance activeChar = client.getActiveChar();
if (activeChar == null)
{
return;
}
if (!Config.ENABLE_COMMUNITY_BOARD)
{
activeChar.sendPacket(SystemMessageId.CB_OFFLINE);
return;
}
if (url.equals("Topic"))
{
TopicBBSManager.getInstance().parseWrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("Post"))
{
PostBBSManager.getInstance().parseWrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("_bbsloc"))
{
RegionBBSManager.getInstance().parseWrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("_bbsclan"))
{
ClanBBSManager.getInstance().parseWrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("Mail"))
{
MailBBSManager.getInstance().parseWrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("_friend"))
{
FriendsBBSManager.getInstance().parseWrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else
{
BaseBBSManager.separateAndSend("<html><body><br><br><center>The command: " + url + " isn't implemented.</center></body></html>", activeChar);
}
}
/**
* Sets the last bypass used by the player.
* @param player the player
* @param title the title
* @param bypass the bypass
*/
public void addBypass(L2PcInstance player, String title, String bypass)
{
_bypasses.put(player.getObjectId(), title + "&" + bypass);
}
/**
* Removes the last bypass used by the player.
* @param player the player
* @return the last bypass used
*/
public String removeBypass(L2PcInstance player)
{
return _bypasses.remove(player.getObjectId());
}
private static class SingletonHolder
{
protected static final CommunityBoard _instance = new CommunityBoard();
}
}

View File

@@ -0,0 +1,124 @@
/*
* 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.communitybbs.Manager;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.serverpackets.ShowBoard;
public abstract class BaseBBSManager
{
protected static final Logger LOGGER = Logger.getLogger(BaseBBSManager.class.getName());
protected static final String CB_PATH = "data/html/CommunityBoard/";
public void parseCmd(String command, L2PcInstance activeChar)
{
separateAndSend("<html><body><br><br><center>The command: " + command + " isn't implemented.</center></body></html>", activeChar);
}
public void parseWrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
separateAndSend("<html><body><br><br><center>The command: " + ar1 + " isn't implemented.</center></body></html>", activeChar);
}
public static void separateAndSend(String html, L2PcInstance acha)
{
if ((html == null) || (acha == null))
{
return;
}
if (html.length() < 4090)
{
acha.sendPacket(new ShowBoard(html, "101"));
acha.sendPacket(ShowBoard.STATIC_SHOWBOARD_102);
acha.sendPacket(ShowBoard.STATIC_SHOWBOARD_103);
}
else if (html.length() < 8180)
{
acha.sendPacket(new ShowBoard(html.substring(0, 4090), "101"));
acha.sendPacket(new ShowBoard(html.substring(4090, html.length()), "102"));
acha.sendPacket(ShowBoard.STATIC_SHOWBOARD_103);
}
else if (html.length() < 12270)
{
acha.sendPacket(new ShowBoard(html.substring(0, 4090), "101"));
acha.sendPacket(new ShowBoard(html.substring(4090, 8180), "102"));
acha.sendPacket(new ShowBoard(html.substring(8180, html.length()), "103"));
}
}
protected static void send1001(String html, L2PcInstance acha)
{
if (html.length() < 8180)
{
acha.sendPacket(new ShowBoard(html, "1001"));
}
}
protected static void send1002(L2PcInstance acha)
{
send1002(acha, " ", " ", "0");
}
protected static void send1002(L2PcInstance activeChar, String string, String string2, String string3)
{
List<String> _arg = new ArrayList<>();
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add(activeChar.getName());
_arg.add(Integer.toString(activeChar.getObjectId()));
_arg.add(activeChar.getAccountName());
_arg.add("9");
_arg.add(string2);
_arg.add(string2);
_arg.add(string);
_arg.add(string3);
_arg.add(string3);
_arg.add("0");
_arg.add("0");
activeChar.sendPacket(new ShowBoard(_arg));
}
/**
* Loads an HTM located in the default CB path.
* @param file : the file to load.
* @param activeChar : the requester.
*/
protected void loadStaticHtm(String file, L2PcInstance activeChar)
{
separateAndSend(HtmCache.getInstance().getHtm(CB_PATH + getFolder() + file), activeChar);
}
/**
* That method is overidden in every board type. It allows to switch of folders following the board.
* @return the folder.
*/
protected String getFolder()
{
return "";
}
}

View File

@@ -0,0 +1,359 @@
/*
* 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.communitybbs.Manager;
import java.util.StringTokenizer;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.communitybbs.CommunityBoard;
import com.l2jmobius.gameserver.datatables.sql.ClanTable;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2ClanMember;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
public class ClanBBSManager extends BaseBBSManager
{
protected ClanBBSManager()
{
}
public static ClanBBSManager getInstance()
{
return SingletonHolder._instance;
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
if (command.equalsIgnoreCase("_bbsclan"))
{
if (activeChar.getClan() == null)
{
sendClanList(activeChar, 1);
}
else
{
sendClanDetails(activeChar, activeChar.getClan().getClanId());
}
}
else if (command.startsWith("_bbsclan"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
final String clanCommand = st.nextToken();
if (clanCommand.equalsIgnoreCase("clan"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Clan", command);
sendClanList(activeChar, Integer.parseInt(st.nextToken()));
}
else if (clanCommand.equalsIgnoreCase("home"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Clan Home", command);
sendClanDetails(activeChar, Integer.parseInt(st.nextToken()));
}
else if (clanCommand.equalsIgnoreCase("mail"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Clan Mail", command);
sendClanMail(activeChar, Integer.parseInt(st.nextToken()));
}
else if (clanCommand.equalsIgnoreCase("management"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Clan Management", command);
sendClanManagement(activeChar, Integer.parseInt(st.nextToken()));
}
else if (clanCommand.equalsIgnoreCase("notice"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Clan Notice", command);
if (st.hasMoreTokens())
{
final String noticeCommand = st.nextToken();
if (!noticeCommand.isEmpty() && (activeChar.getClan() != null))
{
activeChar.getClan().setNoticeEnabledAndStore(Boolean.parseBoolean(noticeCommand));
}
}
sendClanNotice(activeChar, activeChar.getClanId());
}
}
else
{
super.parseCmd(command, activeChar);
}
}
@Override
public void parseWrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (ar1.equalsIgnoreCase("intro"))
{
if (Integer.valueOf(ar2) != activeChar.getClanId())
{
return;
}
final L2Clan clan = ClanTable.getInstance().getClan(activeChar.getClanId());
if (clan == null)
{
return;
}
clan.setIntroduction(ar3, true);
sendClanManagement(activeChar, Integer.valueOf(ar2));
}
else if (ar1.equals("notice"))
{
activeChar.getClan().setNoticeAndStore(ar4);
sendClanNotice(activeChar, activeChar.getClanId());
}
else if (ar1.equalsIgnoreCase("mail"))
{
if (Integer.valueOf(ar2) != activeChar.getClanId())
{
return;
}
final L2Clan clan = ClanTable.getInstance().getClan(activeChar.getClanId());
if (clan == null)
{
return;
}
// Retrieve clans members, and store them under a String.
final StringBuffer membersList = new StringBuffer();
for (L2ClanMember player : clan.getMembers())
{
if (player != null)
{
if (membersList.length() > 0)
{
membersList.append(";");
}
membersList.append(player.getName());
}
}
MailBBSManager.getInstance().sendLetter(membersList.toString(), ar4, ar5, activeChar);
sendClanDetails(activeChar, activeChar.getClanId());
}
else
{
super.parseWrite(ar1, ar2, ar3, ar4, ar5, activeChar);
}
}
@Override
protected String getFolder()
{
return "clan/";
}
private static void sendClanMail(L2PcInstance activeChar, int clanId)
{
final L2Clan clan = ClanTable.getInstance().getClan(clanId);
if (clan == null)
{
return;
}
if ((activeChar.getClanId() != clanId) || !activeChar.isClanLeader())
{
activeChar.sendPacket(SystemMessageId.ONLY_THE_CLAN_LEADER_IS_ENABLED);
sendClanList(activeChar, 1);
return;
}
String content = HtmCache.getInstance().getHtm(CB_PATH + "clan/clanhome-mail.htm");
content = content.replaceAll("%clanid%", Integer.toString(clanId));
content = content.replaceAll("%clanName%", clan.getName());
separateAndSend(content, activeChar);
}
private static void sendClanManagement(L2PcInstance activeChar, int clanId)
{
final L2Clan clan = ClanTable.getInstance().getClan(clanId);
if (clan == null)
{
return;
}
if ((activeChar.getClanId() != clanId) || !activeChar.isClanLeader())
{
activeChar.sendPacket(SystemMessageId.ONLY_THE_CLAN_LEADER_IS_ENABLED);
sendClanList(activeChar, 1);
return;
}
String content = HtmCache.getInstance().getHtm(CB_PATH + "clan/clanhome-management.htm");
content = content.replaceAll("%clanid%", Integer.toString(clan.getClanId()));
send1001(content, activeChar);
send1002(activeChar, clan.getIntroduction(), "", "");
}
private static void sendClanNotice(L2PcInstance activeChar, int clanId)
{
final L2Clan clan = ClanTable.getInstance().getClan(clanId);
if ((clan == null) || (activeChar.getClanId() != clanId))
{
return;
}
if (clan.getLevel() < 2)
{
activeChar.sendPacket(SystemMessageId.NO_CB_IN_MY_CLAN);
sendClanList(activeChar, 1);
return;
}
String content = HtmCache.getInstance().getHtm(CB_PATH + "clan/clanhome-notice.htm");
content = content.replaceAll("%clanid%", Integer.toString(clan.getClanId()));
content = content.replace("%enabled%", "[" + String.valueOf(clan.isNoticeEnabled()) + "]");
content = content.replace("%flag%", String.valueOf(!clan.isNoticeEnabled()));
send1001(content, activeChar);
send1002(activeChar, clan.getNotice(), "", "");
}
private static void sendClanList(L2PcInstance activeChar, int index)
{
String content = HtmCache.getInstance().getHtm(CB_PATH + "clan/clanlist.htm");
// Player got a clan, show the associated header.
final StringBuilder sb = new StringBuilder();
final L2Clan playerClan = activeChar.getClan();
if (playerClan != null)
{
StringUtil.append(sb, "<table width=610 bgcolor=A7A19A><tr><td width=5></td><td width=605><a action=\"bypass _bbsclan;home;", playerClan.getClanId(), "\">[GO TO MY CLAN]</a></td></tr></table>");
}
content = content.replace("%homebar%", sb.toString());
if (index < 1)
{
index = 1;
}
// Cleanup sb.
sb.setLength(0);
// List of clans.
int i = 0;
for (L2Clan cl : ClanTable.getInstance().getClans())
{
if (i > ((index + 1) * 7))
{
break;
}
if (i++ >= ((index - 1) * 7))
{
StringUtil.append(sb, "<table width=610><tr><td width=5></td><td width=150 align=center><a action=\"bypass _bbsclan;home;", cl.getClanId(), "\">", cl.getName(), "</a></td><td width=150 align=center>", cl.getLeaderName(), "</td><td width=100 align=center>", cl.getLevel(), "</td><td width=200 align=center>", cl.getMembersCount(), "</td><td width=5></td></tr></table><br1><img src=\"L2UI.Squaregray\" width=605 height=1><br1>");
}
}
sb.append("<table><tr>");
if (index == 1)
{
sb.append("<td><button action=\"\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16></td>");
}
else
{
StringUtil.append(sb, "<td><button action=\"_bbsclan;clan;", index - 1, "\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16 ></td>");
}
i = 0;
int nbp = ClanTable.getInstance().getClans().length / 8;
if ((nbp * 8) != ClanTable.getInstance().getClans().length)
{
nbp++;
}
for (i = 1; i <= nbp; i++)
{
if (i == index)
{
StringUtil.append(sb, "<td> ", i, " </td>");
}
else
{
StringUtil.append(sb, "<td><a action=\"bypass _bbsclan;clan;", i, "\"> ", i, " </a></td>");
}
}
if (index == nbp)
{
sb.append("<td><button action=\"\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16></td>");
}
else
{
StringUtil.append(sb, "<td><button action=\"bypass _bbsclan;clan;", index + 1, "\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td>");
}
sb.append("</tr></table>");
content = content.replace("%clanlist%", sb.toString());
separateAndSend(content, activeChar);
}
private static void sendClanDetails(L2PcInstance activeChar, int clanId)
{
final L2Clan clan = ClanTable.getInstance().getClan(clanId);
if (clan == null)
{
return;
}
if (clan.getLevel() < 2)
{
activeChar.sendPacket(SystemMessageId.NO_CB_IN_MY_CLAN);
sendClanList(activeChar, 1);
return;
}
// Load different HTM following player case, 3 possibilites : randomer, member, clan leader.
String content;
if (activeChar.getClanId() != clanId)
{
content = HtmCache.getInstance().getHtm(CB_PATH + "clan/clanhome.htm");
}
else if (activeChar.isClanLeader())
{
content = HtmCache.getInstance().getHtm(CB_PATH + "clan/clanhome-leader.htm");
}
else
{
content = HtmCache.getInstance().getHtm(CB_PATH + "clan/clanhome-member.htm");
}
content = content.replaceAll("%clanid%", Integer.toString(clan.getClanId()));
content = content.replace("%clanIntro%", clan.getIntroduction());
content = content.replace("%clanName%", clan.getName());
content = content.replace("%clanLvL%", Integer.toString(clan.getLevel()));
content = content.replace("%clanMembers%", Integer.toString(clan.getMembersCount()));
content = content.replaceAll("%clanLeader%", clan.getLeaderName());
content = content.replace("%allyName%", (clan.getAllyId() > 0) ? clan.getAllyName() : "");
separateAndSend(content, activeChar);
}
private static class SingletonHolder
{
protected static final ClanBBSManager _instance = new ClanBBSManager();
}
}

View File

@@ -0,0 +1,141 @@
/*
* 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.communitybbs.Manager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.communitybbs.CommunityBoard;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.util.Util;
/**
* Favorite board.
* @author Zoey76
*/
public class FavoriteBBSManager extends BaseBBSManager
{
// SQL Queries
private static final String SELECT_FAVORITES = "SELECT * FROM `bbs_favorites` WHERE `playerId`=? ORDER BY `favAddDate` DESC";
private static final String DELETE_FAVORITE = "DELETE FROM `bbs_favorites` WHERE `playerId`=? AND `favId`=?";
private static final String ADD_FAVORITE = "REPLACE INTO `bbs_favorites`(`playerId`, `favTitle`, `favBypass`) VALUES(?, ?, ?)";
protected FavoriteBBSManager()
{
}
public static FavoriteBBSManager getInstance()
{
return SingletonHolder._instance;
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
// None of this commands can be added to favorites.
if (command.startsWith("_bbsgetfav"))
{
// Load Favorite links
final String list = HtmCache.getInstance().getHtm(CB_PATH + "favorite_list.html");
final StringBuilder sb = new StringBuilder();
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(SELECT_FAVORITES))
{
ps.setInt(1, activeChar.getObjectId());
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
String link = list.replaceAll("%fav_bypass%", rs.getString("favBypass"));
link = link.replaceAll("%fav_title%", rs.getString("favTitle"));
final SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
link = link.replaceAll("%fav_add_date%", date.format(rs.getTimestamp("favAddDate")));
link = link.replaceAll("%fav_id%", String.valueOf(rs.getInt("favId")));
sb.append(link);
}
}
String html = HtmCache.getInstance().getHtm(CB_PATH + "favorite.html");
html = html.replaceAll("%fav_list%", sb.toString());
separateAndSend(html, activeChar);
}
catch (Exception e)
{
LOGGER.warning(FavoriteBBSManager.class.getSimpleName() + ": Couldn't load favorite links for player " + activeChar.getName());
}
}
else if (command.startsWith("bbs_add_fav"))
{
final String bypass = CommunityBoard.getInstance().removeBypass(activeChar);
if (bypass != null)
{
final String[] parts = bypass.split("&", 2);
if (parts.length != 2)
{
LOGGER.warning(FavoriteBBSManager.class.getSimpleName() + ": Couldn't add favorite link, " + bypass + " it's not a valid bypass!");
return;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(ADD_FAVORITE))
{
ps.setInt(1, activeChar.getObjectId());
ps.setString(2, parts[0].trim());
ps.setString(3, parts[1].trim());
ps.execute();
// Callback
parseCmd("_bbsgetfav", activeChar);
}
catch (Exception e)
{
LOGGER.warning(FavoriteBBSManager.class.getSimpleName() + ": Couldn't add favorite link " + command + " for player " + activeChar.getName());
}
}
}
else if (command.startsWith("_bbsdelfav_"))
{
final String favId = command.replaceAll("_bbsdelfav_", "");
if (!Util.isDigit(favId))
{
LOGGER.warning(FavoriteBBSManager.class.getSimpleName() + ": Couldn't delete favorite link, " + favId + " it's not a valid ID!");
return;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(DELETE_FAVORITE))
{
ps.setInt(1, activeChar.getObjectId());
ps.setInt(2, Integer.parseInt(favId));
ps.execute();
// Callback
parseCmd("_bbsgetfav", activeChar);
}
catch (Exception e)
{
LOGGER.warning(FavoriteBBSManager.class.getSimpleName() + ": Couldn't delete favorite link ID " + favId + " for player " + activeChar.getName());
}
}
}
private static class SingletonHolder
{
protected static final FavoriteBBSManager _instance = new FavoriteBBSManager();
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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.communitybbs.Manager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.communitybbs.BB.Forum;
public class ForumsBBSManager extends BaseBBSManager
{
private final List<Forum> _table;
private int _lastid = 1;
public static ForumsBBSManager getInstance()
{
return SingletonHolder._instance;
}
protected ForumsBBSManager()
{
_table = new CopyOnWriteArrayList<>();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT forum_id FROM forums WHERE forum_type=0");
ResultSet result = statement.executeQuery();
while (result.next())
{
addForum(new Forum(result.getInt("forum_id"), null));
}
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Data error on Forum (root): " + e.getMessage());
}
}
public void initRoot()
{
for (Forum f : _table)
{
f.vload();
}
LOGGER.info("Loaded " + _table.size() + " forums. Last forum id used: " + _lastid);
}
public void addForum(Forum ff)
{
if (ff == null)
{
return;
}
_table.add(ff);
if (ff.getID() > _lastid)
{
_lastid = ff.getID();
}
}
public Forum getForumByName(String Name)
{
for (Forum f : _table)
{
if (f.getName().equals(Name))
{
return f;
}
}
return null;
}
public Forum createNewForum(String name, Forum parent, int type, int perm, int oid)
{
Forum forum = new Forum(name, parent, type, perm, oid);
forum.insertIntoDb();
return forum;
}
public int getANewID()
{
return ++_lastid;
}
public Forum getForumByID(int id)
{
for (Forum f : _table)
{
if (f.getID() == id)
{
return f;
}
}
return null;
}
private static class SingletonHolder
{
protected static final ForumsBBSManager _instance = new ForumsBBSManager();
}
}

View File

@@ -0,0 +1,381 @@
/*
* 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.communitybbs.Manager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.communitybbs.CommunityBoard;
import com.l2jmobius.gameserver.datatables.sql.CharNameTable;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.FriendList;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public class FriendsBBSManager extends BaseBBSManager
{
private static final String FRIENDLIST_DELETE_BUTTON = "<br>\n<table><tr><td width=10></td><td>Are you sure you want to delete all friends from your Friends List?</td><td width=20></td><td><button value=\"OK\" action=\"bypass _friend;delall\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"></td></tr></table>";
private static final String BLOCKLIST_DELETE_BUTTON = "<br>\n<table><tr><td width=10></td><td>Are you sure you want to delete all players from your Block List?</td><td width=20></td><td><button value=\"OK\" action=\"bypass _block;delall\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"></td></tr></table>";
protected FriendsBBSManager()
{
}
public static FriendsBBSManager getInstance()
{
return SingletonHolder._instance;
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
if (command.startsWith("_friendlist"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Friends List", command);
showFriendsList(activeChar, false);
}
else if (command.startsWith("_blocklist"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Ignore List", command);
showBlockList(activeChar, false);
}
else if (command.startsWith("_friend"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
String action = st.nextToken();
if (action.equals("select"))
{
activeChar.selectFriend((st.hasMoreTokens()) ? Integer.valueOf(st.nextToken()) : 0);
showFriendsList(activeChar, false);
}
else if (action.equals("deselect"))
{
activeChar.deselectFriend((st.hasMoreTokens()) ? Integer.valueOf(st.nextToken()) : 0);
showFriendsList(activeChar, false);
}
else if (action.equals("delall"))
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("DELETE FROM character_friends WHERE char_id = ? OR friend_id = ?");
statement.setInt(1, activeChar.getObjectId());
statement.setInt(2, activeChar.getObjectId());
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("could not delete friends objectid: " + e);
}
for (int friendId : activeChar.getFriendList())
{
L2PcInstance player = L2World.getInstance().getPlayer(friendId);
if (player != null)
{
player.getFriendList().remove(Integer.valueOf(activeChar.getObjectId()));
player.getSelectedFriendList().remove(Integer.valueOf(activeChar.getObjectId()));
player.sendPacket(new FriendList(player)); // update friendList *heavy method*
}
}
activeChar.getFriendList().clear();
activeChar.getSelectedFriendList().clear();
showFriendsList(activeChar, false);
activeChar.sendMessage("You have cleared your friend list.");
activeChar.sendPacket(new FriendList(activeChar));
}
else if (action.equals("delconfirm"))
{
showFriendsList(activeChar, true);
}
else if (action.equals("del"))
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
for (int friendId : activeChar.getSelectedFriendList())
{
PreparedStatement statement = con.prepareStatement("DELETE FROM character_friends WHERE (char_id = ? AND friend_id = ?) OR (char_id = ? AND friend_id = ?)");
statement.setInt(1, activeChar.getObjectId());
statement.setInt(2, friendId);
statement.setInt(3, friendId);
statement.setInt(4, activeChar.getObjectId());
statement.execute();
statement.close();
String name = CharNameTable.getInstance().getPlayerName(friendId);
L2PcInstance player = L2World.getInstance().getPlayer(friendId);
if (player != null)
{
player.getFriendList().remove(Integer.valueOf(activeChar.getObjectId()));
player.sendPacket(new FriendList(player)); // update friendList *heavy method*
}
// Player deleted from your friendlist
activeChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_DELETED_FROM_YOUR_FRIENDS_LIST).addString(name));
activeChar.getFriendList().remove(Integer.valueOf(friendId));
}
}
catch (Exception e)
{
LOGGER.warning("could not delete friend objectid: " + e);
}
activeChar.getSelectedFriendList().clear();
showFriendsList(activeChar, false);
activeChar.sendPacket(new FriendList(activeChar)); // update friendList *heavy method*
}
else if (action.equals("mail"))
{
if (!activeChar.getSelectedFriendList().isEmpty())
{
showMailWrite(activeChar);
}
}
}
else if (command.startsWith("_block"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
String action = st.nextToken();
if (action.equals("select"))
{
activeChar.selectBlock((st.hasMoreTokens()) ? Integer.valueOf(st.nextToken()) : 0);
showBlockList(activeChar, false);
}
else if (action.equals("deselect"))
{
activeChar.deselectBlock((st.hasMoreTokens()) ? Integer.valueOf(st.nextToken()) : 0);
showBlockList(activeChar, false);
}
else if (action.equals("delall"))
{
List<Integer> list = new ArrayList<>();
list.addAll(activeChar.getBlockList().getBlockList());
for (Integer blockId : list)
{
BlockList.removeFromBlockList(activeChar, blockId);
}
activeChar.getSelectedBlocksList().clear();
showBlockList(activeChar, false);
}
else if (action.equals("delconfirm"))
{
showBlockList(activeChar, true);
}
else if (action.equals("del"))
{
for (Integer blockId : activeChar.getSelectedBlocksList())
{
BlockList.removeFromBlockList(activeChar, blockId);
}
activeChar.getSelectedBlocksList().clear();
showBlockList(activeChar, false);
}
}
else
{
super.parseCmd(command, activeChar);
}
}
@Override
public void parseWrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (ar1.equalsIgnoreCase("mail"))
{
MailBBSManager.getInstance().sendLetter(ar2, ar4, ar5, activeChar);
showFriendsList(activeChar, false);
}
else
{
super.parseWrite(ar1, ar2, ar3, ar4, ar5, activeChar);
}
}
private static void showFriendsList(L2PcInstance activeChar, boolean delMsg)
{
String content = HtmCache.getInstance().getHtm(CB_PATH + "friend/friend-list.htm");
if (content == null)
{
return;
}
// Retrieve activeChar's friendlist and selected
final List<Integer> list = activeChar.getFriendList();
final List<Integer> slist = activeChar.getSelectedFriendList();
final StringBuilder sb = new StringBuilder();
// Friendlist
for (Integer id : list)
{
if (slist.contains(id))
{
continue;
}
final String friendName = CharNameTable.getInstance().getPlayerName(id);
if (friendName == null)
{
continue;
}
final L2PcInstance friend = L2World.getInstance().getPlayer(id);
StringUtil.append(sb, "<a action=\"bypass _friend;select;", id, "\">[Select]</a>&nbsp;", friendName, " ", (((friend != null) && (friend.isOnline() == 1)) ? "(on)" : "(off)"), "<br1>");
}
content = content.replaceAll("%friendslist%", sb.toString());
// Cleanup sb.
sb.setLength(0);
// Selected friendlist
for (Integer id : slist)
{
final String friendName = CharNameTable.getInstance().getPlayerName(id);
if (friendName == null)
{
continue;
}
final L2PcInstance friend = L2World.getInstance().getPlayer(id);
StringUtil.append(sb, "<a action=\"bypass _friend;deselect;", id, "\">[Deselect]</a>&nbsp;", friendName, " ", (((friend != null) && (friend.isOnline() == 1)) ? "(on)" : "(off)"), "<br1>");
}
content = content.replaceAll("%selectedFriendsList%", sb.toString());
// Delete button.
content = content.replaceAll("%deleteMSG%", (delMsg) ? FRIENDLIST_DELETE_BUTTON : "");
separateAndSend(content, activeChar);
}
private static void showBlockList(L2PcInstance activeChar, boolean delMsg)
{
String content = HtmCache.getInstance().getHtm(CB_PATH + "friend/friend-blocklist.htm");
if (content == null)
{
return;
}
// Retrieve activeChar's blocklist and selected
final List<Integer> list = activeChar.getBlockList().getBlockList();
final List<Integer> slist = activeChar.getSelectedBlocksList();
final StringBuilder sb = new StringBuilder();
// Blocklist
for (Integer id : list)
{
if (slist.contains(id))
{
continue;
}
final String blockName = CharNameTable.getInstance().getPlayerName(id);
if (blockName == null)
{
continue;
}
final L2PcInstance block = L2World.getInstance().getPlayer(id);
StringUtil.append(sb, "<a action=\"bypass _block;select;", id, "\">[Select]</a>&nbsp;", blockName, " ", (((block != null) && (block.isOnline() == 1)) ? "(on)" : "(off)"), "<br1>");
}
content = content.replaceAll("%blocklist%", sb.toString());
// Cleanup sb.
sb.setLength(0);
// Selected Blocklist
for (Integer id : slist)
{
final String blockName = CharNameTable.getInstance().getPlayerName(id);
if (blockName == null)
{
continue;
}
final L2PcInstance block = L2World.getInstance().getPlayer(id);
StringUtil.append(sb, "<a action=\"bypass _block;deselect;", id, "\">[Deselect]</a>&nbsp;", blockName, " ", (((block != null) && (block.isOnline() == 1)) ? "(on)" : "(off)"), "<br1>");
}
content = content.replaceAll("%selectedBlocksList%", sb.toString());
// Delete button.
content = content.replaceAll("%deleteMSG%", (delMsg) ? BLOCKLIST_DELETE_BUTTON : "");
separateAndSend(content, activeChar);
}
public static final void showMailWrite(L2PcInstance activeChar)
{
String content = HtmCache.getInstance().getHtm(CB_PATH + "friend/friend-mail.htm");
if (content == null)
{
return;
}
final StringBuilder sb = new StringBuilder();
for (int id : activeChar.getSelectedFriendList())
{
String friendName = CharNameTable.getInstance().getPlayerName(id);
if (friendName == null)
{
continue;
}
if (sb.length() > 0)
{
sb.append(";");
}
sb.append(friendName);
}
content = content.replaceAll("%list%", sb.toString());
separateAndSend(content, activeChar);
}
@Override
protected String getFolder()
{
return "friend/";
}
private static class SingletonHolder
{
protected static final FriendsBBSManager _instance = new FriendsBBSManager();
}
}

View File

@@ -0,0 +1,868 @@
/*
* 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.communitybbs.Manager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.communitybbs.CommunityBoard;
import com.l2jmobius.gameserver.datatables.sql.CharNameTable;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExMailArrived;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* @author JIV, Johan, Vital
*/
public class MailBBSManager extends BaseBBSManager
{
private enum MailType
{
INBOX("Inbox", "<a action=\"bypass _bbsmail\">Inbox</a>"),
SENTBOX("Sent Box", "<a action=\"bypass _bbsmail;sentbox\">Sent Box</a>"),
ARCHIVE("Mail Archive", "<a action=\"bypass _bbsmail;archive\">Mail Archive</a>"),
TEMPARCHIVE("Temporary Mail Archive", "<a action=\"bypass _bbsmail;temp_archive\">Temporary Mail Archive</a>");
private final String _description;
private final String _bypass;
private MailType(String description, String bypass)
{
_description = description;
_bypass = bypass;
}
public String getDescription()
{
return _description;
}
public String getBypass()
{
return _bypass;
}
public static final MailType[] VALUES = values();
}
private final Map<Integer, List<Mail>> _mails = new HashMap<>();
private int _lastid = 0;
private static final String SELECT_CHAR_MAILS = "SELECT * FROM character_mail WHERE charId = ? ORDER BY letterId ASC";
private static final String INSERT_NEW_MAIL = "INSERT INTO character_mail (charId, letterId, senderId, location, recipientNames, subject, message, sentDate, unread) VALUES (?,?,?,?,?,?,?,?,?)";
private static final String DELETE_MAIL = "DELETE FROM character_mail WHERE letterId = ?";
private static final String MARK_MAIL_READ = "UPDATE character_mail SET unread = ? WHERE letterId = ?";
private static final String SET_LETTER_LOC = "UPDATE character_mail SET location = ? WHERE letterId = ?";
private static final String SELECT_LAST_ID = "SELECT letterId FROM character_mail ORDER BY letterId DESC LIMIT 1";
public class Mail
{
int charId;
int letterId;
int senderId;
MailType location;
String recipientNames;
String subject;
String message;
Timestamp sentDate;
String sentDateString;
boolean unread;
}
public static MailBBSManager getInstance()
{
return SingletonHolder._instance;
}
protected MailBBSManager()
{
initId();
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
CommunityBoard.getInstance().addBypass(activeChar, "Mail Command", command);
if (command.equals("_bbsmail") || command.equals("_maillist_0_1_0_"))
{
showMailList(activeChar, 1, MailType.INBOX);
}
else if (command.startsWith("_bbsmail"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
String action = st.nextToken();
if (action.equals("inbox") || action.equals("sentbox") || action.equals("archive") || action.equals("temparchive"))
{
final int page = (st.hasMoreTokens()) ? Integer.parseInt(st.nextToken()) : 1;
final String sType = (st.hasMoreTokens()) ? st.nextToken() : "";
final String search = (st.hasMoreTokens()) ? st.nextToken() : "";
showMailList(activeChar, page, Enum.valueOf(MailType.class, action.toUpperCase()), sType, search);
}
else if (action.equals("crea"))
{
showWriteView(activeChar);
}
else if (action.equals("view"))
{
final int letterId = (st.hasMoreTokens()) ? Integer.parseInt(st.nextToken()) : -1;
Mail letter = getLetter(activeChar, letterId);
if (letter == null)
{
showLastForum(activeChar);
}
else
{
showLetterView(activeChar, letter);
if (letter.unread)
{
setLetterToRead(activeChar, letter.letterId);
}
}
}
else if (action.equals("reply"))
{
final int letterId = (st.hasMoreTokens()) ? Integer.parseInt(st.nextToken()) : -1;
Mail letter = getLetter(activeChar, letterId);
if (letter == null)
{
showLastForum(activeChar);
}
else
{
showWriteView(activeChar, getCharName(letter.senderId), letter);
}
}
else if (action.equals("del"))
{
final int letterId = (st.hasMoreTokens()) ? Integer.parseInt(st.nextToken()) : -1;
Mail letter = getLetter(activeChar, letterId);
if (letter != null)
{
deleteLetter(activeChar, letter.letterId);
}
showLastForum(activeChar);
}
else if (action.equals("store"))
{
final int letterId = (st.hasMoreTokens()) ? Integer.parseInt(st.nextToken()) : -1;
Mail letter = getLetter(activeChar, letterId);
if (letter != null)
{
setLetterLocation(activeChar, letter.letterId, MailType.ARCHIVE);
}
showMailList(activeChar, 1, MailType.ARCHIVE);
}
}
else
{
super.parseCmd(command, activeChar);
}
}
@Override
public void parseWrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (ar1.equals("Send"))
{
sendLetter(ar3, ar4, ar5, activeChar);
showMailList(activeChar, 1, MailType.SENTBOX);
}
else if (ar1.startsWith("Search"))
{
StringTokenizer st = new StringTokenizer(ar1, ";");
st.nextToken();
showMailList(activeChar, 1, Enum.valueOf(MailType.class, st.nextToken().toUpperCase()), ar4, ar5);
}
else
{
super.parseWrite(ar1, ar2, ar3, ar4, ar5, activeChar);
}
}
private void initId()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement(SELECT_LAST_ID);
ResultSet result = statement.executeQuery();
while (result.next())
{
if (result.getInt(1) > _lastid)
{
_lastid = result.getInt(1);
}
}
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning(getClass().getSimpleName() + ": data error on MailBBS (initId): " + e);
e.printStackTrace();
}
}
private synchronized int getNewMailId()
{
return ++_lastid;
}
private List<Mail> getPlayerMails(int objId)
{
List<Mail> _letters = _mails.get(objId);
if (_letters == null)
{
_letters = new ArrayList<>();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement(SELECT_CHAR_MAILS);
statement.setInt(1, objId);
ResultSet result = statement.executeQuery();
while (result.next())
{
Mail letter = new Mail();
letter.charId = result.getInt("charId");
letter.letterId = result.getInt("letterId");
letter.senderId = result.getInt("senderId");
letter.location = Enum.valueOf(MailType.class, result.getString("location").toUpperCase());
letter.recipientNames = result.getString("recipientNames");
letter.subject = result.getString("subject");
letter.message = result.getString("message");
letter.sentDate = result.getTimestamp("sentDate");
letter.sentDateString = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(letter.sentDate);
letter.unread = result.getInt("unread") != 0;
_letters.add(0, letter);
}
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("couldnt load mail for ID:" + objId + " " + e.getMessage());
}
_mails.put(objId, _letters);
}
return _letters;
}
private Mail getLetter(L2PcInstance activeChar, int letterId)
{
for (Mail letter : getPlayerMails(activeChar.getObjectId()))
{
if (letter.letterId == letterId)
{
return letter;
}
}
return null;
}
private static String abbreviate(String s, int maxWidth)
{
return s.length() > maxWidth ? s.substring(0, maxWidth) : s;
}
public int checkUnreadMail(L2PcInstance activeChar)
{
int count = 0;
for (Mail letter : getPlayerMails(activeChar.getObjectId()))
{
if (letter.unread)
{
count++;
}
}
return count;
}
private void showMailList(L2PcInstance activeChar, int page, MailType type)
{
showMailList(activeChar, page, type, "", "");
}
private void showMailList(L2PcInstance activeChar, int page, MailType type, String sType, String search)
{
List<Mail> letters;
if (!sType.equals("") && !search.equals(""))
{
letters = new ArrayList<>();
boolean byTitle = sType.equalsIgnoreCase("title");
for (Mail letter : getPlayerMails(activeChar.getObjectId()))
{
if (byTitle && letter.subject.toLowerCase().contains(search.toLowerCase()))
{
letters.add(letter);
}
else if (!byTitle)
{
String writer = getCharName(letter.senderId);
if (writer.toLowerCase().contains(search.toLowerCase()))
{
letters.add(letter);
}
}
}
}
else
{
letters = getPlayerMails(activeChar.getObjectId());
}
final int countMails = getCountLetters(activeChar.getObjectId(), type, sType, search);
final int maxpage = getMaxPageId(countMails);
if (page > maxpage)
{
page = maxpage;
}
if (page < 1)
{
page = 1;
}
activeChar.setMailPosition(page);
int index = 0, minIndex = 0, maxIndex = 0;
maxIndex = (page == 1 ? page * 9 : (page * 10) - 1);
minIndex = maxIndex - 9;
String content = HtmCache.getInstance().getHtm(CB_PATH + "mail/mail.htm");
content = content.replace("%inbox%", Integer.toString(getCountLetters(activeChar.getObjectId(), MailType.INBOX, "", "")));
content = content.replace("%sentbox%", Integer.toString(getCountLetters(activeChar.getObjectId(), MailType.SENTBOX, "", "")));
content = content.replace("%archive%", Integer.toString(getCountLetters(activeChar.getObjectId(), MailType.ARCHIVE, "", "")));
content = content.replace("%temparchive%", Integer.toString(getCountLetters(activeChar.getObjectId(), MailType.TEMPARCHIVE, "", "")));
content = content.replace("%type%", type.getDescription());
content = content.replace("%htype%", type.toString().toLowerCase());
final StringBuilder sb = new StringBuilder();
for (Mail letter : letters)
{
if (letter.location.equals(type))
{
if (index < minIndex)
{
index++;
continue;
}
if (index > maxIndex)
{
break;
}
StringUtil.append(sb, "<table width=610><tr><td width=5></td><td width=150>", getCharName(letter.senderId), "</td><td width=300><a action=\"bypass _bbsmail;view;", letter.letterId, "\">");
if (letter.unread)
{
sb.append("<font color=\"LEVEL\">");
}
sb.append(abbreviate(letter.subject, 51));
if (letter.unread)
{
sb.append("</font>");
}
StringUtil.append(sb, "</a></td><td width=150>", letter.sentDateString, "</td><td width=5></td></tr></table><img src=\"L2UI.Squaregray\" width=610 height=1>");
index++;
}
}
content = content.replace("%maillist%", sb.toString());
// CLeanup sb.
sb.setLength(0);
final String fullSearch = (!sType.equals("") && !search.equals("")) ? ";" + sType + ";" + search : "";
StringUtil.append(sb, "<td><table><tr><td></td></tr><tr><td><button action=\"bypass _bbsmail;", type, ";", (page == 1 ? page : page - 1), fullSearch, "\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16></td></tr></table></td>");
int i = 0;
if (maxpage > 21)
{
if (page <= 11)
{
for (i = 1; i <= (10 + page); i++)
{
if (i == page)
{
StringUtil.append(sb, "<td> ", i, " </td>");
}
else
{
StringUtil.append(sb, "<td><a action=\"bypass _bbsmail;", type, ";", i, fullSearch, "\"> ", i, " </a></td>");
}
}
}
else if ((page > 11) && ((maxpage - page) > 10))
{
for (i = (page - 10); i <= (page - 1); i++)
{
if (i == page)
{
continue;
}
StringUtil.append(sb, "<td><a action=\"bypass _bbsmail;", type, ";", i, fullSearch, "\"> ", i, " </a></td>");
}
for (i = page; i <= (page + 10); i++)
{
if (i == page)
{
StringUtil.append(sb, "<td> ", i, " </td>");
}
else
{
StringUtil.append(sb, "<td><a action=\"bypass _bbsmail;", type, ";", i, fullSearch, "\"> ", i, " </a></td>");
}
}
}
else if ((maxpage - page) <= 10)
{
for (i = (page - 10); i <= maxpage; i++)
{
if (i == page)
{
StringUtil.append(sb, "<td> ", i, " </td>");
}
else
{
StringUtil.append(sb, "<td><a action=\"bypass _bbsmail;", type, ";", i, fullSearch, "\"> ", i, " </a></td>");
}
}
}
}
else
{
for (i = 1; i <= maxpage; i++)
{
if (i == page)
{
StringUtil.append(sb, "<td> ", i, " </td>");
}
else
{
StringUtil.append(sb, "<td><a action=\"bypass _bbsmail;", type, ";", i, fullSearch, "\"> ", i, " </a></td>");
}
}
}
StringUtil.append(sb, "<td><table><tr><td></td></tr><tr><td><button action=\"bypass _bbsmail;", type, ";", (page == maxpage ? page : page + 1), fullSearch, "\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td></tr></table></td>");
content = content.replace("%maillistlength%", sb.toString());
separateAndSend(content, activeChar);
}
private void showLetterView(L2PcInstance activeChar, Mail letter)
{
if (letter == null)
{
showMailList(activeChar, 1, MailType.INBOX);
return;
}
String content = HtmCache.getInstance().getHtm(CB_PATH + "mail/mail-show.htm");
String link = letter.location.getBypass() + "&nbsp;&gt;&nbsp;" + letter.subject;
content = content.replace("%maillink%", link);
content = content.replace("%writer%", getCharName(letter.senderId));
content = content.replace("%sentDate%", letter.sentDateString);
content = content.replace("%receiver%", letter.recipientNames);
content = content.replace("%delDate%", "Unknown");
content = content.replace("%title%", letter.subject.replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;"));
content = content.replace("%mes%", letter.message.replaceAll("\r\n", "<br>").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;"));
content = content.replace("%letterId%", letter.letterId + "");
separateAndSend(content, activeChar);
}
private static void showWriteView(L2PcInstance activeChar)
{
String content = HtmCache.getInstance().getHtm(CB_PATH + "mail/mail-write.htm");
separateAndSend(content, activeChar);
}
private static void showWriteView(L2PcInstance activeChar, String parcipientName, Mail letter)
{
String content = HtmCache.getInstance().getHtm(CB_PATH + "mail/mail-reply.htm");
String link = letter.location.getBypass() + "&nbsp;&gt;&nbsp;<a action=\"bypass _bbsmail;view;" + letter.letterId + "\">" + letter.subject + "</a>&nbsp;&gt;&nbsp;";
content = content.replace("%maillink%", link);
content = content.replace("%recipients%", letter.senderId == activeChar.getObjectId() ? letter.recipientNames : getCharName(letter.senderId));
content = content.replace("%letterId%", letter.letterId + "");
send1001(content, activeChar);
send1002(activeChar, " ", "Re: " + letter.subject, "0");
}
public void sendLetter(String recipients, String subject, String message, L2PcInstance activeChar)
{
// Current time.
final long currentDate = Calendar.getInstance().getTimeInMillis();
// Get the current time - 1 day under timestamp format.
final Timestamp ts = new Timestamp(currentDate - 86400000L);
// Check sender mails based on previous timestamp. If more than 10 mails have been found for today, then cancel the use.
if (getPlayerMails(activeChar.getObjectId()).stream().filter(l -> l.sentDate.after(ts) && (l.location == MailType.SENTBOX)).count() >= 10)
{
activeChar.sendPacket(SystemMessageId.NO_MORE_MESSAGES_TODAY);
return;
}
// Format recipient names. If more than 5 are found, cancel the mail.
final String[] recipientNames = recipients.trim().split(";");
if ((recipientNames.length > 5) && !activeChar.isGM())
{
activeChar.sendPacket(SystemMessageId.ONLY_FIVE_RECIPIENTS);
return;
}
// Edit subject, if none.
if ((subject == null) || subject.isEmpty())
{
subject = "(no subject)";
}
// Edit message.
message = message.replaceAll("\n", "<br1>");
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
// Get the current time under timestamp format.
final Timestamp time = new Timestamp(currentDate);
PreparedStatement statement = null;
for (String recipientName : recipientNames)
{
// Recipient is an invalid player, or is the sender.
final int recipientId = CharNameTable.getInstance().getPlayerObjectId(recipientName);
if ((recipientId <= 0) || (recipientId == activeChar.getObjectId()))
{
activeChar.sendPacket(SystemMessageId.INCORRECT_TARGET);
continue;
}
final L2PcInstance recipientPlayer = L2World.getInstance().getPlayer(recipientId);
if (!activeChar.isGM())
{
// Sender is a regular player, while recipient is a GM.
if (isGM(recipientId))
{
activeChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CANNOT_MAIL_GM_S1).addString(recipientName));
continue;
}
// The recipient is on block mode.
if (isBlocked(activeChar, recipientId))
{
activeChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_BLOCKED_YOU_CANNOT_MAIL).addString(recipientName));
continue;
}
// The recipient box is already full.
if (isRecipInboxFull(recipientId))
{
activeChar.sendPacket(SystemMessageId.MESSAGE_NOT_SENT);
if (recipientPlayer != null)
{
recipientPlayer.sendPacket(SystemMessageId.MAILBOX_FULL);
}
continue;
}
}
final int id = getNewMailId();
if (statement == null)
{
statement = con.prepareStatement(INSERT_NEW_MAIL);
statement.setInt(3, activeChar.getObjectId());
statement.setString(4, "inbox");
statement.setString(5, recipients);
statement.setString(6, abbreviate(subject, 128));
statement.setString(7, message);
statement.setTimestamp(8, time);
statement.setInt(9, 1);
}
statement.setInt(1, recipientId);
statement.setInt(2, id);
statement.execute();
final Mail letter = new Mail();
letter.charId = recipientId;
letter.letterId = id;
letter.senderId = activeChar.getObjectId();
letter.location = MailType.INBOX;
letter.recipientNames = recipients;
letter.subject = abbreviate(subject, 128);
letter.message = message;
letter.sentDate = time;
letter.sentDateString = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(letter.sentDate);
letter.unread = true;
getPlayerMails(recipientId).add(0, letter);
if (recipientPlayer != null)
{
recipientPlayer.sendPacket(SystemMessageId.NEW_MAIL);
recipientPlayer.sendPacket(new PlaySound("systemmsg_e.1233"));
recipientPlayer.sendPacket(ExMailArrived.STATIC_PACKET);
}
}
// Create a copy into activeChar's sent box, if at least one recipient has been reached.
if (statement != null)
{
final int id = getNewMailId();
statement.setInt(1, activeChar.getObjectId());
statement.setInt(2, id);
statement.setString(4, "sentbox");
statement.setInt(9, 0);
statement.execute();
statement.close();
final Mail letter = new Mail();
letter.charId = activeChar.getObjectId();
letter.letterId = id;
letter.senderId = activeChar.getObjectId();
letter.location = MailType.SENTBOX;
letter.recipientNames = recipients;
letter.subject = abbreviate(subject, 128);
letter.message = message;
letter.sentDate = time;
letter.sentDateString = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(letter.sentDate);
letter.unread = false;
getPlayerMails(activeChar.getObjectId()).add(0, letter);
activeChar.sendPacket(SystemMessageId.SENT_MAIL);
}
}
catch (Exception e)
{
LOGGER.warning("couldnt send letter for " + activeChar.getName() + " " + e.getMessage());
}
}
private int getCountLetters(int objId, MailType location, String sType, String search)
{
int count = 0;
if (!sType.equals("") && !search.equals(""))
{
boolean byTitle = sType.equalsIgnoreCase("title");
for (Mail letter : getPlayerMails(objId))
{
if (!letter.location.equals(location))
{
continue;
}
if (byTitle && letter.subject.toLowerCase().contains(search.toLowerCase()))
{
count++;
}
else if (!byTitle)
{
String writer = getCharName(letter.senderId);
if (writer.toLowerCase().contains(search.toLowerCase()))
{
count++;
}
}
}
}
else
{
for (Mail letter : getPlayerMails(objId))
{
if (letter.location.equals(location))
{
count++;
}
}
}
return count;
}
private static boolean isBlocked(L2PcInstance activeChar, int recipId)
{
for (L2PcInstance player : L2World.getInstance().getAllPlayers())
{
if (player.getObjectId() == recipId)
{
if (BlockList.isInBlockList(player, activeChar))
{
return true;
}
return false;
}
}
return false;
}
private void deleteLetter(L2PcInstance activeChar, int letterId)
{
for (Mail letter : getPlayerMails(activeChar.getObjectId()))
{
if (letter.letterId == letterId)
{
getPlayerMails(activeChar.getObjectId()).remove(letter);
break;
}
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement(DELETE_MAIL);
statement.setInt(1, letterId);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("couldnt delete letter " + letterId + " " + e);
}
}
private void setLetterToRead(L2PcInstance activeChar, int letterId)
{
getLetter(activeChar, letterId).unread = false;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement(MARK_MAIL_READ);
statement.setInt(1, 0);
statement.setInt(2, letterId);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("couldnt set unread to false for " + letterId + " " + e);
}
}
private void setLetterLocation(L2PcInstance activeChar, int letterId, MailType location)
{
getLetter(activeChar, letterId).location = location;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement(SET_LETTER_LOC);
statement.setString(1, location.toString().toLowerCase());
statement.setInt(2, letterId);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("couldnt set location to false for " + letterId + " " + e);
}
}
private static String getCharName(int charId)
{
String name = CharNameTable.getInstance().getPlayerName(charId);
return name == null ? "Unknown" : name;
}
private static boolean isGM(int charId)
{
boolean isGM = false;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT accesslevel FROM characters WHERE obj_Id = ?");
statement.setInt(1, charId);
ResultSet result = statement.executeQuery();
result.next();
isGM = result.getInt(1) > 0;
result.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning(e.getMessage());
}
return isGM;
}
private boolean isRecipInboxFull(int charId)
{
return getCountLetters(charId, MailType.INBOX, "", "") >= 100;
}
private void showLastForum(L2PcInstance activeChar)
{
final int page = activeChar.getMailPosition() % 1000;
final int type = activeChar.getMailPosition() / 1000;
showMailList(activeChar, page, MailType.VALUES[type]);
}
private static int getMaxPageId(int letterCount)
{
if (letterCount < 1)
{
return 1;
}
if ((letterCount % 10) == 0)
{
return letterCount / 10;
}
return (letterCount / 10) + 1;
}
private static class SingletonHolder
{
protected static final MailBBSManager _instance = new MailBBSManager();
}
}

View File

@@ -0,0 +1,218 @@
/*
* 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.communitybbs.Manager;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import com.l2jmobius.gameserver.communitybbs.CommunityBoard;
import com.l2jmobius.gameserver.communitybbs.BB.Forum;
import com.l2jmobius.gameserver.communitybbs.BB.Post;
import com.l2jmobius.gameserver.communitybbs.BB.Topic;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
public class PostBBSManager extends BaseBBSManager
{
private final Map<Topic, Post> _postByTopic;
public static PostBBSManager getInstance()
{
return SingletonHolder._instance;
}
protected PostBBSManager()
{
_postByTopic = new HashMap<>();
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
if (command.startsWith("_bbsposts;read;"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Posts Command", command);
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
int idp = Integer.parseInt(st.nextToken());
String index = null;
if (st.hasMoreTokens())
{
index = st.nextToken();
}
int ind = 0;
if (index == null)
{
ind = 1;
}
else
{
ind = Integer.parseInt(index);
}
showPost((TopicBBSManager.getInstance().getTopicByID(idp)), ForumsBBSManager.getInstance().getForumByID(idf), activeChar, ind);
}
else if (command.startsWith("_bbsposts;edit;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
int idt = Integer.parseInt(st.nextToken());
int idp = Integer.parseInt(st.nextToken());
showEditPost((TopicBBSManager.getInstance().getTopicByID(idt)), ForumsBBSManager.getInstance().getForumByID(idf), activeChar, idp);
}
else
{
super.parseCmd(command, activeChar);
}
}
@Override
public void parseWrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
StringTokenizer st = new StringTokenizer(ar1, ";");
int idf = Integer.parseInt(st.nextToken());
int idt = Integer.parseInt(st.nextToken());
int idp = Integer.parseInt(st.nextToken());
final Forum forum = ForumsBBSManager.getInstance().getForumByID(idf);
if (forum == null)
{
separateAndSend("<html><body><br><br><center>The forum named '" + idf + "' doesn't exist.</center></body></html>", activeChar);
return;
}
final Topic topic = forum.getTopic(idt);
if (topic == null)
{
separateAndSend("<html><body><br><br><center>The topic named '" + idt + "' doesn't exist.</center></body></html>", activeChar);
return;
}
final Post post = getPostByTopic(topic);
if (post.getCPost(idp) == null)
{
separateAndSend("<html><body><br><br><center>The post named '" + idp + "' doesn't exist.</center></body></html>", activeChar);
return;
}
post.getCPost(idp).postTxt = ar4;
post.updateText(idp);
parseCmd("_bbsposts;read;" + forum.getID() + ";" + topic.getID(), activeChar);
}
public Post getPostByTopic(Topic t)
{
Post post = _postByTopic.get(t);
if (post == null)
{
post = load(t);
_postByTopic.put(t, post);
}
return post;
}
public void delPostByTopic(Topic t)
{
_postByTopic.remove(t);
}
public void addPostByTopic(Post p, Topic t)
{
if (_postByTopic.get(t) == null)
{
_postByTopic.put(t, p);
}
}
private static Post load(Topic t)
{
return new Post(t);
}
private void showEditPost(Topic topic, Forum forum, L2PcInstance activeChar, int idp)
{
if ((forum == null) || (topic == null))
{
separateAndSend("<html><body><br><br><center>This forum and/or topic don't exit.</center></body></html>", activeChar);
return;
}
Post p = getPostByTopic(topic);
if (p == null)
{
separateAndSend("<html><body><br><br><center>This post doesn't exist.</center></body></html>", activeChar);
return;
}
showHtmlEditPost(topic, activeChar, forum, p);
}
private void showPost(Topic topic, Forum forum, L2PcInstance activeChar, int ind)
{
if ((forum == null) || (topic == null))
{
separateAndSend("<html><body><br><br><center>This forum and/or topic don't exist.</center></body></html>", activeChar);
}
else if (forum.getType() == Forum.MEMO)
{
showMemoPost(topic, activeChar, forum);
}
else
{
separateAndSend("<html><body><br><br><center>The forum named '" + forum.getName() + "' isn't implemented.</center></body></html>", activeChar);
}
}
private static void showHtmlEditPost(Topic topic, L2PcInstance activeChar, Forum forum, Post p)
{
final String html = "<html><body><br><br><table border=0 width=610><tr><td width=10></td><td width=600 align=left><a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">" + forum.getName() + " Form</a></td></tr></table><img src=\"L2UI.squareblank\" width=\"1\" height=\"10\"><center><table border=0 cellspacing=0 cellpadding=0><tr><td width=610><img src=\"sek.cbui355\" width=\"610\" height=\"1\"><br1><img src=\"sek.cbui355\" width=\"610\" height=\"1\"></td></tr></table><table fixwidth=610 border=0 cellspacing=0 cellpadding=0><tr><td><img src=\"l2ui.mini_logo\" width=5 height=20></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=1></td><td align=center FIXWIDTH=60 height=29>&$413;</td><td FIXWIDTH=540>" + topic.getName() + "</td><td><img src=\"l2ui.mini_logo\" width=5 height=1></td></tr></table><table fixwidth=610 border=0 cellspacing=0 cellpadding=0><tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=1></td><td align=center FIXWIDTH=60 height=29 valign=top>&$427;</td><td align=center FIXWIDTH=540><MultiEdit var =\"Content\" width=535 height=313></td><td><img src=\"l2ui.mini_logo\" width=5 height=1></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr></table><table fixwidth=610 border=0 cellspacing=0 cellpadding=0><tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=1></td><td align=center FIXWIDTH=60 height=29>&nbsp;</td><td align=center FIXWIDTH=70><button value=\"&$140;\" action=\"Write Post " + forum.getID() + ";" + topic.getID() + ";0 _ Content Content Content\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td><td align=center FIXWIDTH=70><button value = \"&$141;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"> </td><td align=center FIXWIDTH=400>&nbsp;</td><td><img src=\"l2ui.mini_logo\" width=5 height=1></td></tr></table></center></body></html>";
send1001(html, activeChar);
send1002(activeChar, p.getCPost(0).postTxt, topic.getName(), DateFormat.getInstance().format(new Date(topic.getDate())));
}
private void showMemoPost(Topic topic, L2PcInstance activeChar, Forum forum)
{
Post p = getPostByTopic(topic);
Locale locale = Locale.getDefault();
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL, locale);
String mes = p.getCPost(0).postTxt.replace(">", "&gt;");
mes = mes.replace("<", "&lt;");
mes = mes.replace("\n", "<br1>");
final String html = "<html><body><br><br><table border=0 width=610><tr><td width=10></td><td width=600 align=left><a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">Memo Form</a></td></tr></table><img src=\"L2UI.squareblank\" width=\"1\" height=\"10\"><center><table border=0 cellspacing=0 cellpadding=0 bgcolor=333333><tr><td height=10></td></tr><tr><td fixWIDTH=55 align=right valign=top>&$413; : &nbsp;</td><td fixWIDTH=380 valign=top>" + topic.getName() + "</td><td fixwidth=5></td><td fixwidth=50></td><td fixWIDTH=120></td></tr><tr><td height=10></td></tr><tr><td align=right><font color=\"AAAAAA\" >&$417; : &nbsp;</font></td><td><font color=\"AAAAAA\">" + topic.getOwnerName() + "</font></td><td></td><td><font color=\"AAAAAA\">&$418; :</font></td><td><font color=\"AAAAAA\">" + dateFormat.format(p.getCPost(0).postDate) + "</font></td></tr><tr><td height=10></td></tr></table><br><table border=0 cellspacing=0 cellpadding=0><tr><td fixwidth=5></td><td FIXWIDTH=600 align=left>" + mes + "</td><td fixqqwidth=5></td></tr></table><br><img src=\"L2UI.squareblank\" width=\"1\" height=\"5\"><img src=\"L2UI.squaregray\" width=\"610\" height=\"1\"><img src=\"L2UI.squareblank\" width=\"1\" height=\"5\"><table border=0 cellspacing=0 cellpadding=0 FIXWIDTH=610><tr><td width=50><button value=\"&$422;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"></td><td width=560 align=right><table border=0 cellspacing=0><tr><td FIXWIDTH=300></td><td><button value = \"&$424;\" action=\"bypass _bbsposts;edit;" + forum.getID() + ";" + topic.getID() + ";0\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>&nbsp;<td><button value = \"&$425;\" action=\"bypass _bbstopics;del;" + forum.getID() + ";" + topic.getID() + "\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>&nbsp;<td><button value = \"&$421;\" action=\"bypass _bbstopics;crea;" + forum.getID() + "\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>&nbsp;</tr></table></td></tr></table><br><br><br></center></body></html>";
separateAndSend(html, activeChar);
}
private static class SingletonHolder
{
protected static final PostBBSManager _instance = new PostBBSManager();
}
}

View File

@@ -0,0 +1,123 @@
/*
* 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.communitybbs.Manager;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.StringTokenizer;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.communitybbs.CommunityBoard;
import com.l2jmobius.gameserver.datatables.sql.ClanTable;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
import com.l2jmobius.gameserver.instancemanager.ClanHallManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.ClanHall;
import com.l2jmobius.gameserver.model.entity.siege.Castle;
public class RegionBBSManager extends BaseBBSManager
{
protected RegionBBSManager()
{
}
public static RegionBBSManager getInstance()
{
return SingletonHolder._instance;
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
if (command.equals("_bbsloc"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Region>", command);
showRegionsList(activeChar);
}
else if (command.startsWith("_bbsloc"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Region>", command);
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
showRegion(activeChar, Integer.parseInt(st.nextToken()));
}
else
{
super.parseCmd(command, activeChar);
}
}
@Override
protected String getFolder()
{
return "region/";
}
private static void showRegionsList(L2PcInstance activeChar)
{
final String content = HtmCache.getInstance().getHtm(CB_PATH + "region/castlelist.htm");
final StringBuilder sb = new StringBuilder(500);
for (Castle castle : CastleManager.getInstance().getCastles())
{
final L2Clan owner = ClanTable.getInstance().getClan(castle.getOwnerId());
StringUtil.append(sb, "<table><tr><td width=5></td><td width=160><a action=\"bypass _bbsloc;", castle.getCastleId(), "\">", castle.getName(), "</a></td><td width=160>", ((owner != null) ? "<a action=\"bypass _bbsclan;home;" + owner.getClanId() + "\">" + owner.getName() + "</a>" : "None"), "</td><td width=160>", (((owner != null) && (owner.getAllyId() > 0)) ? owner.getAllyName() : "None"), "</td><td width=120>", ((owner != null) ? castle.getTaxPercent() : "0"), "</td><td width=5></td></tr></table><br1><img src=\"L2UI.Squaregray\" width=605 height=1><br1>");
}
separateAndSend(content.replace("%castleList%", sb.toString()), activeChar);
}
private static void showRegion(L2PcInstance activeChar, int castleId)
{
final Castle castle = CastleManager.getInstance().getCastleById(castleId);
final L2Clan owner = ClanTable.getInstance().getClan(castle.getOwnerId());
String content = HtmCache.getInstance().getHtm(CB_PATH + "region/castle.htm");
content = content.replace("%castleName%", castle.getName());
content = content.replace("%tax%", Integer.toString(castle.getTaxPercent()));
content = content.replace("%lord%", ((owner != null) ? owner.getLeaderName() : "None"));
content = content.replace("%clanName%", ((owner != null) ? "<a action=\"bypass _bbsclan;home;" + owner.getClanId() + "\">" + owner.getName() + "</a>" : "None"));
content = content.replace("%allyName%", (((owner != null) && (owner.getAllyId() > 0)) ? owner.getAllyName() : "None"));
content = content.replace("%siegeDate%", new SimpleDateFormat("yyyy-MM-dd HH:mm").format(castle.getSiegeDate().getTimeInMillis()));
final StringBuilder sb = new StringBuilder(200);
final List<ClanHall> clanHalls = ClanHallManager.getInstance().getClanHallsByLocation(castle.getName());
if ((clanHalls != null) && !clanHalls.isEmpty())
{
sb.append("<br><br><table width=610 bgcolor=A7A19A><tr><td width=5></td><td width=200>Clan Hall Name</td><td width=200>Owning Clan</td><td width=200>Clan Leader Name</td><td width=5></td></tr></table><br1>");
for (ClanHall ch : clanHalls)
{
final L2Clan chOwner = ClanTable.getInstance().getClan(ch.getOwnerId());
StringUtil.append(sb, "<table><tr><td width=5></td><td width=200>", ch.getName(), "</td><td width=200>", ((chOwner != null) ? "<a action=\"bypass _bbsclan;home;" + chOwner.getClanId() + "\">" + chOwner.getName() + "</a>" : "None"), "</td><td width=200>", ((chOwner != null) ? chOwner.getLeaderName() : "None"), "</td><td width=5></td></tr></table><br1><img src=\"L2UI.Squaregray\" width=605 height=1><br1>");
}
}
separateAndSend(content.replace("%hallsList%", sb.toString()), activeChar);
}
private static class SingletonHolder
{
protected static final RegionBBSManager _instance = new RegionBBSManager();
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.communitybbs.Manager;
import java.util.StringTokenizer;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
public class TopBBSManager extends BaseBBSManager
{
protected TopBBSManager()
{
}
public static TopBBSManager getInstance()
{
return SingletonHolder._instance;
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
if (command.equals("_bbshome"))
{
loadStaticHtm("index.htm", activeChar);
}
else if (command.startsWith("_bbshome;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
loadStaticHtm(st.nextToken(), activeChar);
}
else
{
super.parseCmd(command, activeChar);
}
}
@Override
protected String getFolder()
{
return "top/";
}
private static class SingletonHolder
{
protected static final TopBBSManager _instance = new TopBBSManager();
}
}

View File

@@ -0,0 +1,341 @@
/*
* 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.communitybbs.Manager;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.communitybbs.CommunityBoard;
import com.l2jmobius.gameserver.communitybbs.BB.Forum;
import com.l2jmobius.gameserver.communitybbs.BB.Post;
import com.l2jmobius.gameserver.communitybbs.BB.Topic;
import com.l2jmobius.gameserver.datatables.sql.ClanTable;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
public class TopicBBSManager extends BaseBBSManager
{
private final List<Topic> _table;
private final Map<Forum, Integer> _maxId;
public static TopicBBSManager getInstance()
{
return SingletonHolder._instance;
}
protected TopicBBSManager()
{
_table = new ArrayList<>();
_maxId = new ConcurrentHashMap<>();
}
@Override
public void parseWrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (ar1.equals("crea"))
{
Forum f = ForumsBBSManager.getInstance().getForumByID(Integer.parseInt(ar2));
if (f == null)
{
separateAndSend("<html><body><br><br><center>The forum named '" + ar2 + "' doesn't exist.</center></body></html>", activeChar);
return;
}
f.vload();
Topic t = new Topic(Topic.ConstructorType.CREATE, TopicBBSManager.getInstance().getMaxID(f) + 1, Integer.parseInt(ar2), ar5, Calendar.getInstance().getTimeInMillis(), activeChar.getName(), activeChar.getObjectId(), Topic.MEMO, 0);
f.addTopic(t);
TopicBBSManager.getInstance().setMaxID(t.getID(), f);
Post p = new Post(activeChar.getName(), activeChar.getObjectId(), Calendar.getInstance().getTimeInMillis(), t.getID(), f.getID(), ar4);
PostBBSManager.getInstance().addPostByTopic(p, t);
parseCmd("_bbsmemo", activeChar);
}
else if (ar1.equals("del"))
{
Forum f = ForumsBBSManager.getInstance().getForumByID(Integer.parseInt(ar2));
if (f == null)
{
separateAndSend("<html><body><br><br><center>The forum named '" + ar2 + "' doesn't exist.</center></body></html>", activeChar);
return;
}
Topic t = f.getTopic(Integer.parseInt(ar3));
if (t == null)
{
separateAndSend("<html><body><br><br><center>The topic named '" + ar3 + "' doesn't exist.</center></body></html>", activeChar);
return;
}
Post p = PostBBSManager.getInstance().getPostByTopic(t);
if (p != null)
{
p.deleteMe(t);
}
t.deleteMe(f);
parseCmd("_bbsmemo", activeChar);
}
else
{
super.parseWrite(ar1, ar2, ar3, ar4, ar5, activeChar);
}
}
@Override
public void parseCmd(String command, L2PcInstance activeChar)
{
if (command.equals("_bbsmemo"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Memo Command", command);
showTopics(activeChar.getMemo(), activeChar, 1, activeChar.getMemo().getID());
}
else if (command.startsWith("_bbstopics;read"))
{
CommunityBoard.getInstance().addBypass(activeChar, "Topics Command", command);
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
String index = null;
if (st.hasMoreTokens())
{
index = st.nextToken();
}
int ind = 0;
if (index == null)
{
ind = 1;
}
else
{
ind = Integer.parseInt(index);
}
showTopics(ForumsBBSManager.getInstance().getForumByID(idf), activeChar, ind, idf);
}
else if (command.startsWith("_bbstopics;crea"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
showNewTopic(ForumsBBSManager.getInstance().getForumByID(idf), activeChar, idf);
}
else if (command.startsWith("_bbstopics;del"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
int idt = Integer.parseInt(st.nextToken());
Forum f = ForumsBBSManager.getInstance().getForumByID(idf);
if (f == null)
{
separateAndSend("<html><body><br><br><center>The forum named '" + idf + "' doesn't exist.</center></body></html>", activeChar);
return;
}
Topic t = f.getTopic(idt);
if (t == null)
{
separateAndSend("<html><body><br><br><center>The topic named '" + idt + "' doesn't exist.</center></body></html>", activeChar);
return;
}
Post p = PostBBSManager.getInstance().getPostByTopic(t);
if (p != null)
{
p.deleteMe(t);
}
t.deleteMe(f);
parseCmd("_bbsmemo", activeChar);
}
else
{
super.parseCmd(command, activeChar);
}
}
public void addTopic(Topic tt)
{
_table.add(tt);
}
public void delTopic(Topic topic)
{
_table.remove(topic);
}
public void setMaxID(int id, Forum f)
{
_maxId.put(f, id);
}
public int getMaxID(Forum f)
{
Integer i = _maxId.get(f);
if (i == null)
{
return 0;
}
return i;
}
public Topic getTopicByID(int idf)
{
for (Topic t : _table)
{
if (t.getID() == idf)
{
return t;
}
}
return null;
}
private static void showNewTopic(Forum forum, L2PcInstance activeChar, int idf)
{
if (forum == null)
{
separateAndSend("<html><body><br><br><center>The forum named '" + idf + "' doesn't exist.</center></body></html>", activeChar);
return;
}
if (forum.getType() == Forum.MEMO)
{
showMemoNewTopics(forum, activeChar);
}
else
{
separateAndSend("<html><body><br><br><center>The forum named '" + forum.getName() + "' doesn't exist.</center></body></html>", activeChar);
}
}
private static void showMemoNewTopics(Forum forum, L2PcInstance activeChar)
{
final String html = "<html><body><br><br><table border=0 width=610><tr><td width=10></td><td width=600 align=left><a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">Memo Form</a></td></tr></table><img src=\"L2UI.squareblank\" width=\"1\" height=\"10\"><center><table border=0 cellspacing=0 cellpadding=0><tr><td width=610><img src=\"sek.cbui355\" width=\"610\" height=\"1\"><br1><img src=\"sek.cbui355\" width=\"610\" height=\"1\"></td></tr></table><table fixwidth=610 border=0 cellspacing=0 cellpadding=0><tr><td><img src=\"l2ui.mini_logo\" width=5 height=20></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=1></td><td align=center FIXWIDTH=60 height=29>&$413;</td><td FIXWIDTH=540><edit var = \"Title\" width=540 height=13></td><td><img src=\"l2ui.mini_logo\" width=5 height=1></td></tr></table><table fixwidth=610 border=0 cellspacing=0 cellpadding=0><tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=1></td><td align=center FIXWIDTH=60 height=29 valign=top>&$427;</td><td align=center FIXWIDTH=540><MultiEdit var =\"Content\" width=535 height=313></td><td><img src=\"l2ui.mini_logo\" width=5 height=1></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr></table><table fixwidth=610 border=0 cellspacing=0 cellpadding=0><tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=1></td><td align=center FIXWIDTH=60 height=29>&nbsp;</td><td align=center FIXWIDTH=70><button value=\"&$140;\" action=\"Write Topic crea " + forum.getID() + " Title Content Title\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td><td align=center FIXWIDTH=70><button value = \"&$141;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"> </td><td align=center FIXWIDTH=400>&nbsp;</td><td><img src=\"l2ui.mini_logo\" width=5 height=1></td></tr></table></center></body></html>";
send1001(html, activeChar);
send1002(activeChar);
}
private void showTopics(Forum forum, L2PcInstance activeChar, int index, int idf)
{
if (forum == null)
{
separateAndSend("<html><body><br><br><center>The forum named '" + idf + "' doesn't exist.</center></body></html>", activeChar);
return;
}
if (forum.getType() == Forum.MEMO)
{
showMemoTopics(forum, activeChar, index);
}
else
{
separateAndSend("<html><body><br><br><center>The forum named '" + forum.getName() + "' doesn't exist.</center></body></html>", activeChar);
}
}
private void showMemoTopics(Forum forum, L2PcInstance activeChar, int index)
{
forum.vload();
final StringBuilder sb = new StringBuilder("<html><body><br><br><table border=0 width=610><tr><td width=10></td><td width=600 align=left><a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">Memo Form</a></td></tr></table><img src=\"L2UI.squareblank\" width=\"1\" height=\"10\"><center><table border=0 cellspacing=0 cellpadding=2 bgcolor=888888 width=610><tr><td FIXWIDTH=5></td><td FIXWIDTH=415 align=center>&$413;</td><td FIXWIDTH=120 align=center></td><td FIXWIDTH=70 align=center>&$418;</td></tr></table>");
final DateFormat dateFormat = DateFormat.getInstance();
for (int i = 0, j = getMaxID(forum) + 1; i < (12 * index); j--)
{
if (j < 0)
{
break;
}
Topic t = forum.getTopic(j);
if (t != null)
{
if (i++ >= (12 * (index - 1)))
{
StringUtil.append(sb, "<table border=0 cellspacing=0 cellpadding=5 WIDTH=610><tr><td FIXWIDTH=5></td><td FIXWIDTH=415><a action=\"bypass _bbsposts;read;", forum.getID(), ";", t.getID(), "\">", t.getName(), "</a></td><td FIXWIDTH=120 align=center></td><td FIXWIDTH=70 align=center>", dateFormat.format(new Date(t.getDate())), "</td></tr></table><img src=\"L2UI.Squaregray\" width=\"610\" height=\"1\">");
}
}
}
sb.append("<br><table width=610 cellspace=0 cellpadding=0><tr><td width=50><button value=\"&$422;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"></td><td width=510 align=center><table border=0><tr>");
if (index == 1)
{
sb.append("<td><button action=\"\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16 ></td>");
}
else
{
StringUtil.append(sb, "<td><button action=\"bypass _bbstopics;read;", forum.getID(), ";", index - 1, "\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16 ></td>");
}
int nbp;
nbp = forum.getTopicSize() / 8;
if ((nbp * 8) != ClanTable.getInstance().getClans().length)
{
nbp++;
}
for (int i = 1; i <= nbp; i++)
{
if (i == index)
{
StringUtil.append(sb, "<td> ", i, " </td>");
}
else
{
StringUtil.append(sb, "<td><a action=\"bypass _bbstopics;read;", forum.getID(), ";", i, "\"> ", i, " </a></td>");
}
}
if (index == nbp)
{
sb.append("<td><button action=\"\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td>");
}
else
{
StringUtil.append(sb, "<td><button action=\"bypass _bbstopics;read;", forum.getID(), ";", index + 1, "\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td>");
}
StringUtil.append(sb, "</tr></table></td><td align=right><button value = \"&$421;\" action=\"bypass _bbstopics;crea;", forum.getID(), "\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td></tr><tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr><tr><td></td><td align=center><table border=0><tr><td></td><td><edit var = \"Search\" width=130 height=11></td><td><button value=\"&$420;\" action=\"Write 5 -2 0 Search _ _\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"></td></tr></table></td></tr></table><br><br><br></center></body></html>");
separateAndSend(sb.toString(), activeChar);
}
private static class SingletonHolder
{
protected static final TopicBBSManager _instance = new TopicBBSManager();
}
}

View File

@@ -0,0 +1,248 @@
/*
* 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.datatables;
/**
* @author FBIagent<br>
*/
public class AccessLevel
{
/**
* The logger<br>
*/
// private final static Log LOGGER = LogFactory.getLog(AccessLevel.class);
/**
* The access level<br>
*/
private int _accessLevel = 0;
/**
* The access level name<br>
*/
private String _name = null;
/**
* The name color for the access level<br>
*/
private int _nameColor = 0;
/**
* The title color for the access level<br>
*/
private int _titleColor = 0;
/**
* Flag to determine if the access level has gm access<br>
*/
private boolean _isGm = false;
/** Flag for peace zone attack */
private boolean _allowPeaceAttack = false;
/** Flag for fixed res */
private boolean _allowFixedRes = false;
/** Flag for transactions */
private boolean _allowTransaction = false;
/** Flag for AltG commands */
private boolean _allowAltG = false;
/** Flag to give damage */
private boolean _giveDamage = false;
/** Flag to take aggro */
private boolean _takeAggro = false;
/** Flag to gain exp in party */
private boolean _gainExp = false;
// L2EMU_ ADD - Rayan
private boolean _useNameColor = true;
private boolean _useTitleColor = false;
private boolean _canDisableGmStatus = false;
// L2EMU_ ADD
/**
* Initializes members<br>
* <br>
* @param accessLevel as int<br>
* @param name as String<br>
* @param nameColor as int<br>
* @param titleColor as int<br>
* @param isGm as boolean<br>
* @param allowPeaceAttack as boolean<br>
* @param allowFixedRes as boolean<br>
* @param allowTransaction as boolean<br>
* @param allowAltG as boolean<br>
* @param giveDamage as boolean<br>
* @param takeAggro as boolean<br>
* @param gainExp as boolean<br>
* @param useNameColor as boolean<br>
* @param useTitleColor as boolean<br>
* @param canDisableGmStatus
*/
public AccessLevel(int accessLevel, String name, int nameColor, int titleColor, boolean isGm, boolean allowPeaceAttack, boolean allowFixedRes, boolean allowTransaction, boolean allowAltG, boolean giveDamage, boolean takeAggro, boolean gainExp, boolean useNameColor, boolean useTitleColor, boolean canDisableGmStatus)
{
_accessLevel = accessLevel;
_name = name;
_nameColor = nameColor;
_titleColor = titleColor;
_isGm = isGm;
_allowPeaceAttack = allowPeaceAttack;
_allowFixedRes = allowFixedRes;
_allowTransaction = allowTransaction;
_allowAltG = allowAltG;
_giveDamage = giveDamage;
_takeAggro = takeAggro;
_gainExp = gainExp;
// L2EMU_ ADD - Rayan
_useNameColor = useNameColor;
_useTitleColor = useTitleColor;
_canDisableGmStatus = canDisableGmStatus;
// L2EMU_ ADD
}
/**
* Returns the access level<br>
* <br>
* @return int: access level<br>
*/
public int getLevel()
{
return _accessLevel;
}
/**
* Returns the access level name<br>
* <br>
* @return String: access level name<br>
*/
public String getName()
{
return _name;
}
/**
* Returns the name color of the access level<br>
* <br>
* @return int: the name color for the access level<br>
*/
public int getNameColor()
{
return _nameColor;
}
/**
* Returns the title color color of the access level<br>
* <br>
* @return int: the title color for the access level<br>
*/
public int getTitleColor()
{
return _titleColor;
}
/**
* Retuns if the access level has gm access or not<br>
* <br>
* @return boolean: true if access level have gm access, otherwise false<br>
*/
public boolean isGm()
{
return _isGm;
}
/**
* Returns if the access level is allowed to attack in peace zone or not<br>
* <br>
* @return boolean: true if the access level is allowed to attack in peace zone, otherwise false<br>
*/
public boolean allowPeaceAttack()
{
return _allowPeaceAttack;
}
/**
* @return true if the access level is allowed to use fixed res, otherwise false.
*/
public boolean allowFixedRes()
{
return _allowFixedRes;
}
/**
* Returns if the access level is allowed to perform transactions or not<br>
* <br>
* @return boolean: true if access level is allowed to perform transactions, otherwise false<br>
*/
public boolean allowTransaction()
{
return _allowTransaction;
}
/**
* Returns if the access level is allowed to use AltG commands or not<br>
* <br>
* @return boolean: true if access level is allowed to use AltG commands, otherwise false<br>
*/
public boolean allowAltG()
{
return _allowAltG;
}
/**
* Returns if the access level can give damage or not<br>
* <br>
* @return boolean: true if the access level can give damage, otherwise false<br>
*/
public boolean canGiveDamage()
{
return _giveDamage;
}
/**
* Returns if the access level can take aggro or not<br>
* <br>
* @return boolean: true if the access level can take aggro, otherwise false<br>
*/
public boolean canTakeAggro()
{
return _takeAggro;
}
/**
* Returns if the access level can gain exp or not<br>
* <br>
* @return boolean: true if the access level can gain exp, otherwise false<br>
*/
public boolean canGainExp()
{
return _gainExp;
}
// L2EMU_ADD - Rayan
public boolean useNameColor()
{
return _useNameColor;
}
public boolean useTitleColor()
{
return _useTitleColor;
}
/**
* Retuns if the access level is a gm that can temp disable gm access<br>
* <br>
* @return boolean: true if is a gm that can temp disable gm access, otherwise false<br>
*/
public boolean canDisableGmStatus()
{
return _canDisableGmStatus;
}
}

View File

@@ -0,0 +1,290 @@
/*
* 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.datatables;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.model.holders.BuffSkillHolder;
/**
* This class loads available skills and stores players' buff schemes into _schemesTable.
*/
public class BufferTable
{
private static final Logger LOGGER = Logger.getLogger(BufferTable.class.getName());
private static final String LOAD_SCHEMES = "SELECT * FROM buffer_schemes";
private static final String DELETE_SCHEMES = "TRUNCATE TABLE buffer_schemes";
private static final String INSERT_SCHEME = "INSERT INTO buffer_schemes (object_id, scheme_name, skills) VALUES (?,?,?)";
private final Map<Integer, HashMap<String, ArrayList<Integer>>> _schemesTable = new ConcurrentHashMap<>();
private final Map<Integer, BuffSkillHolder> _availableBuffs = new LinkedHashMap<>();
public BufferTable()
{
int count = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement st = con.prepareStatement(LOAD_SCHEMES);
ResultSet rs = st.executeQuery();
while (rs.next())
{
final int objectId = rs.getInt("object_id");
final String schemeName = rs.getString("scheme_name");
final String[] skills = rs.getString("skills").split(",");
ArrayList<Integer> schemeList = new ArrayList<>();
for (String skill : skills)
{
// Don't feed the skills list if the list is empty.
if (skill.isEmpty())
{
break;
}
schemeList.add(Integer.valueOf(skill));
}
setScheme(objectId, schemeName, schemeList);
count++;
}
rs.close();
st.close();
}
catch (Exception e)
{
LOGGER.warning("BufferTable: Failed to load buff schemes : " + e);
}
try
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File("./data/buffer_skills.xml"));
final Node n = doc.getFirstChild();
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (!d.getNodeName().equalsIgnoreCase("category"))
{
continue;
}
final String category = d.getAttributes().getNamedItem("type").getNodeValue();
for (Node c = d.getFirstChild(); c != null; c = c.getNextSibling())
{
if (!c.getNodeName().equalsIgnoreCase("buff"))
{
continue;
}
final NamedNodeMap attrs = c.getAttributes();
final int skillId = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
_availableBuffs.put(skillId, new BuffSkillHolder(skillId, Integer.parseInt(attrs.getNamedItem("price").getNodeValue()), category, attrs.getNamedItem("desc").getNodeValue()));
}
}
}
catch (Exception e)
{
LOGGER.warning("BufferTable: Failed to load buff info : " + e);
}
LOGGER.info("BufferTable: Loaded " + count + " players schemes and " + _availableBuffs.size() + " available buffs.");
}
public void saveSchemes()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
// Delete all entries from database.
PreparedStatement st = con.prepareStatement(DELETE_SCHEMES);
st.execute();
st.close();
st = con.prepareStatement(INSERT_SCHEME);
// Save _schemesTable content.
for (Map.Entry<Integer, HashMap<String, ArrayList<Integer>>> player : _schemesTable.entrySet())
{
for (Map.Entry<String, ArrayList<Integer>> scheme : player.getValue().entrySet())
{
// Build a String composed of skill ids seperated by a ",".
final StringBuilder sb = new StringBuilder();
for (int skillId : scheme.getValue())
{
StringUtil.append(sb, skillId, ",");
}
// Delete the last "," : must be called only if there is something to delete !
if (sb.length() > 0)
{
sb.setLength(sb.length() - 1);
}
st.setInt(1, player.getKey());
st.setString(2, scheme.getKey());
st.setString(3, sb.toString());
st.addBatch();
}
}
st.executeBatch();
st.close();
}
catch (Exception e)
{
LOGGER.warning("BufferTable: Error while saving schemes : " + e);
}
}
public void setScheme(int playerId, String schemeName, ArrayList<Integer> list)
{
if (!_schemesTable.containsKey(playerId))
{
_schemesTable.put(playerId, new HashMap<String, ArrayList<Integer>>());
}
else if (_schemesTable.get(playerId).size() >= Config.BUFFER_MAX_SCHEMES)
{
return;
}
_schemesTable.get(playerId).put(schemeName, list);
}
/**
* @param playerId : The player objectId to check.
* @return the list of schemes for a given player.
*/
public Map<String, ArrayList<Integer>> getPlayerSchemes(int playerId)
{
return _schemesTable.get(playerId);
}
/**
* @param playerId : The player objectId to check.
* @param schemeName : The scheme name to check.
* @return the List holding skills for the given scheme name and player, or null (if scheme or player isn't registered).
*/
public List<Integer> getScheme(int playerId, String schemeName)
{
if ((_schemesTable.get(playerId) == null) || (_schemesTable.get(playerId).get(schemeName) == null))
{
return Collections.emptyList();
}
return _schemesTable.get(playerId).get(schemeName);
}
/**
* @param playerId : The player objectId to check.
* @param schemeName : The scheme name to check.
* @param skillId : The skill id to check.
* @return true if the skill is already registered on the scheme, or false otherwise.
*/
public boolean getSchemeContainsSkill(int playerId, String schemeName, int skillId)
{
final List<Integer> skills = getScheme(playerId, schemeName);
if (skills.isEmpty())
{
return false;
}
for (int id : skills)
{
if (id == skillId)
{
return true;
}
}
return false;
}
/**
* @param groupType : The type of skills to return.
* @return a list of skills ids based on the given groupType.
*/
public List<Integer> getSkillsIdsByType(String groupType)
{
List<Integer> skills = new ArrayList<>();
for (BuffSkillHolder skill : _availableBuffs.values())
{
if (skill.getType().equalsIgnoreCase(groupType))
{
skills.add(skill.getId());
}
}
return skills;
}
/**
* @return a list of all buff types available.
*/
public List<String> getSkillTypes()
{
List<String> skillTypes = new ArrayList<>();
for (BuffSkillHolder skill : _availableBuffs.values())
{
if (!skillTypes.contains(skill.getType()))
{
skillTypes.add(skill.getType());
}
}
return skillTypes;
}
public BuffSkillHolder getAvailableBuff(int skillId)
{
return _availableBuffs.get(skillId);
}
public static BufferTable getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final BufferTable INSTANCE = new BufferTable();
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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.datatables;
import java.util.ArrayList;
import java.util.List;
/**
* This class has just one simple function to return the item id of a crown regarding to castleid
* @author evill33t
*/
public class CrownTable
{
private static List<Integer> _crownList = new ArrayList<>();
public static List<Integer> getCrownList()
{
if (_crownList.isEmpty())
{
_crownList.add(6841); // Crown of the lord
_crownList.add(6834); // Innadril
_crownList.add(6835); // Dion
_crownList.add(6836); // Goddard
_crownList.add(6837); // Oren
_crownList.add(6838); // Gludio
_crownList.add(6839); // Giran
_crownList.add(6840); // Aden
_crownList.add(8182); // Rune
_crownList.add(8183); // Schuttgart
}
return _crownList;
}
public static int getCrownId(int CastleId)
{
int CrownId = 0;
switch (CastleId)
{
// Gludio
case 1:
{
CrownId = 6838;
break;
}
// Dion
case 2:
{
CrownId = 6835;
break;
}
// Giran
case 3:
{
CrownId = 6839;
break;
}
// Oren
case 4:
{
CrownId = 6837;
break;
}
// Aden
case 5:
{
CrownId = 6840;
break;
}
// Innadril
case 6:
{
CrownId = 6834;
break;
}
// Goddard
case 7:
{
CrownId = 6836;
break;
}
// Rune
case 8:
{
CrownId = 8182;
break;
}
// Schuttgart
case 9:
{
CrownId = 8183;
break;
}
default:
{
CrownId = 0;
break;
}
}
return CrownId;
}
}

View File

@@ -0,0 +1,200 @@
/*
* 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.datatables;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.gameserver.model.L2Object;
/**
* This class ...
* @version $Revision$ $Date$
*/
public class DesireTable
{
public static final DesireType[] DEFAULT_DESIRES =
{
DesireType.FEAR,
DesireType.DISLIKE,
DesireType.HATE,
DesireType.DAMAGE
};
public enum DesireType
{
FEAR,
DISLIKE,
HATE,
DAMAGE
}
class DesireValue
{
private float _value;
DesireValue()
{
this(0f);
}
DesireValue(Float pValue)
{
_value = pValue;
}
public void addValue(float pValue)
{
_value += pValue;
}
public float getValue()
{
return _value;
}
}
class Desires
{
private final Map<DesireType, DesireValue> _desireTable;
public Desires(DesireType... desireList)
{
_desireTable = new HashMap<>();
for (DesireType desire : desireList)
{
_desireTable.put(desire, new DesireValue());
}
}
public DesireValue getDesireValue(DesireType type)
{
return _desireTable.get(type);
}
public void addValue(DesireType type, float value)
{
DesireValue temp = getDesireValue(type);
if (temp != null)
{
temp.addValue(value);
}
}
public void createDesire(DesireType type)
{
_desireTable.put(type, new DesireValue());
}
public void deleteDesire(DesireType type)
{
_desireTable.remove(type);
}
}
private final Map<L2Object, Desires> _objectDesireTable;
private final Desires _generalDesires;
private final DesireType[] _desireTypes;
public DesireTable(DesireType... desireList)
{
_desireTypes = desireList;
_objectDesireTable = new HashMap<>();
_generalDesires = new Desires(_desireTypes);
}
public float getDesireValue(DesireType type)
{
return _generalDesires.getDesireValue(type).getValue();
}
public float getDesireValue(L2Object object, DesireType type)
{
final Desires desireList = _objectDesireTable.get(object);
if (desireList == null)
{
return 0f;
}
return desireList.getDesireValue(type).getValue();
}
public void addDesireValue(DesireType type, float value)
{
_generalDesires.addValue(type, value);
}
public void addDesireValue(L2Object object, DesireType type, float value)
{
Desires desireList = _objectDesireTable.get(object);
if (desireList != null)
{
desireList.addValue(type, value);
}
}
public void createDesire(DesireType type)
{
_generalDesires.createDesire(type);
}
public void deleteDesire(DesireType type)
{
_generalDesires.deleteDesire(type);
}
public void createDesire(L2Object object, DesireType type)
{
Desires desireList = _objectDesireTable.get(object);
if (desireList != null)
{
desireList.createDesire(type);
}
}
public void deleteDesire(L2Object object, DesireType type)
{
Desires desireList = _objectDesireTable.get(object);
if (desireList != null)
{
desireList.deleteDesire(type);
}
}
public void addKnownObject(L2Object object)
{
if (object != null)
{
addKnownObject(object, DesireType.DISLIKE, DesireType.FEAR, DesireType.DAMAGE, DesireType.HATE);
}
}
public void addKnownObject(L2Object object, DesireType... desireList)
{
if (object != null)
{
_objectDesireTable.put(object, new Desires(desireList));
}
}
}

View File

@@ -0,0 +1,200 @@
/*
* 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.datatables;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.L2GameServerPacket;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class stores references to all online game masters. (access level > 100)
* @version $Revision: 1.2.2.1.2.7 $ $Date: 2005/04/05 19:41:24 $
*/
public class GmListTable
{
protected static final Logger LOGGER = Logger.getLogger(GmListTable.class.getName());
private static GmListTable _instance;
/** Set(L2PcInstance>) containing all the GM in game */
private final Map<L2PcInstance, Boolean> _gmList;
public static GmListTable getInstance()
{
if (_instance == null)
{
_instance = new GmListTable();
}
return _instance;
}
public static void reload()
{
_instance = null;
getInstance();
}
public List<L2PcInstance> getAllGms(boolean includeHidden)
{
final List<L2PcInstance> tmpGmList = new ArrayList<>();
for (Entry<L2PcInstance, Boolean> n : _gmList.entrySet())
{
if (includeHidden || !n.getValue())
{
tmpGmList.add(n.getKey());
}
}
return tmpGmList;
}
public List<String> getAllGmNames(boolean includeHidden)
{
final List<String> tmpGmList = new ArrayList<>();
for (Entry<L2PcInstance, Boolean> n : _gmList.entrySet())
{
if (!n.getValue())
{
tmpGmList.add(n.getKey().getName());
}
else if (includeHidden)
{
tmpGmList.add(n.getKey().getName() + " (invis)");
}
}
return tmpGmList;
}
private GmListTable()
{
LOGGER.info("GmListTable: initalized.");
_gmList = new ConcurrentHashMap<>();
}
/**
* Add a L2PcInstance player to the Set _gmList
* @param player
* @param hidden
*/
public void addGm(L2PcInstance player, boolean hidden)
{
if (Config.DEBUG)
{
LOGGER.info("added gm: " + player.getName());
}
_gmList.put(player, hidden);
}
public void deleteGm(L2PcInstance player)
{
if (Config.DEBUG)
{
LOGGER.info("deleted gm: " + player.getName());
}
_gmList.remove(player);
}
/**
* GM will be displayed on clients GM list.
* @param player the player
*/
public void showGm(L2PcInstance player)
{
if (_gmList.containsKey(player))
{
_gmList.put(player, false);
}
}
/**
* GM will no longer be displayed on clients GM list.
* @param player the player
*/
public void hideGm(L2PcInstance player)
{
if (_gmList.containsKey(player))
{
_gmList.put(player, true);
}
}
public boolean isGmOnline(boolean includeHidden)
{
for (boolean b : _gmList.values())
{
if (includeHidden || !b)
{
return true;
}
}
return false;
}
public void sendListToPlayer(L2PcInstance player)
{
if (isGmOnline(player.isGM()))
{
SystemMessage sm = new SystemMessage(SystemMessageId.GM_LIST);
player.sendPacket(sm);
for (String name : getAllGmNames(player.isGM()))
{
final SystemMessage sm1 = new SystemMessage(SystemMessageId.GM_S1);
sm1.addString(name);
player.sendPacket(sm1);
}
}
else
{
SystemMessage sm2 = new SystemMessage(SystemMessageId.NO_GM_PROVIDING_SERVICE_NOW);
player.sendPacket(sm2);
}
}
public static void broadcastToGMs(L2GameServerPacket packet)
{
for (L2PcInstance gm : getInstance().getAllGms(true))
{
gm.sendPacket(packet);
}
}
public static void broadcastMessageToGMs(String message)
{
for (L2PcInstance gm : getInstance().getAllGms(true))
{
// prevents a NPE.
if (gm != null)
{
gm.sendPacket(SystemMessage.sendString(message));
}
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.datatables;
import com.l2jmobius.gameserver.model.L2Skill;
/**
* @author BiTi
*/
public class HeroSkillTable
{
private static HeroSkillTable _instance;
private static L2Skill[] _heroSkills;
private HeroSkillTable()
{
_heroSkills = new L2Skill[5];
_heroSkills[0] = SkillTable.getInstance().getInfo(395, 1);
_heroSkills[1] = SkillTable.getInstance().getInfo(396, 1);
_heroSkills[2] = SkillTable.getInstance().getInfo(1374, 1);
_heroSkills[3] = SkillTable.getInstance().getInfo(1375, 1);
_heroSkills[4] = SkillTable.getInstance().getInfo(1376, 1);
}
public static HeroSkillTable getInstance()
{
if (_instance == null)
{
_instance = new HeroSkillTable();
}
return _instance;
}
public static L2Skill[] getHeroSkills()
{
return _heroSkills;
}
public static boolean isHeroSkill(int skillid)
{
Integer[] _HeroSkillsId = new Integer[]
{
395,
396,
1374,
1375,
1376
};
for (int id : _HeroSkillsId)
{
if (id == skillid)
{
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.datatables;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.gameserver.model.MobGroup;
import com.l2jmobius.gameserver.model.actor.instance.L2ControllableMobInstance;
/**
* @author littlecrow
*/
public class MobGroupTable
{
private static MobGroupTable _instance;
private final Map<Integer, MobGroup> _groupMap;
public static final int FOLLOW_RANGE = 300;
public static final int RANDOM_RANGE = 300;
public MobGroupTable()
{
_groupMap = new HashMap<>();
}
public static MobGroupTable getInstance()
{
if (_instance == null)
{
_instance = new MobGroupTable();
}
return _instance;
}
public void addGroup(int groupKey, MobGroup group)
{
_groupMap.put(groupKey, group);
}
public MobGroup getGroup(int groupKey)
{
return _groupMap.get(groupKey);
}
public int getGroupCount()
{
return _groupMap.size();
}
public MobGroup getGroupForMob(L2ControllableMobInstance mobInst)
{
for (MobGroup mobGroup : _groupMap.values())
{
if (mobGroup.isGroupMember(mobInst))
{
return mobGroup;
}
}
return null;
}
public MobGroup[] getGroups()
{
return _groupMap.values().toArray(new MobGroup[getGroupCount()]);
}
public boolean removeGroup(int groupKey)
{
return _groupMap.remove(groupKey) != null;
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.datatables;
import com.l2jmobius.gameserver.model.L2Skill;
/**
* @author -Nemesiss-
*/
public class NobleSkillTable
{
private static NobleSkillTable _instance;
private static L2Skill[] _nobleSkills;
private NobleSkillTable()
{
_nobleSkills = new L2Skill[8];
_nobleSkills[0] = SkillTable.getInstance().getInfo(1323, 1);
_nobleSkills[1] = SkillTable.getInstance().getInfo(325, 1);
_nobleSkills[2] = SkillTable.getInstance().getInfo(326, 1);
_nobleSkills[3] = SkillTable.getInstance().getInfo(327, 1);
_nobleSkills[4] = SkillTable.getInstance().getInfo(1324, 1);
_nobleSkills[5] = SkillTable.getInstance().getInfo(1325, 1);
_nobleSkills[6] = SkillTable.getInstance().getInfo(1326, 1);
_nobleSkills[7] = SkillTable.getInstance().getInfo(1327, 1);
}
public static NobleSkillTable getInstance()
{
if (_instance == null)
{
_instance = new NobleSkillTable();
}
return _instance;
}
public L2Skill[] GetNobleSkills()
{
return _nobleSkills;
}
}

View File

@@ -0,0 +1,422 @@
/*
* 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.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Calendar;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2ManufactureItem;
import com.l2jmobius.gameserver.model.L2ManufactureList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.TradeList.TradeItem;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.L2GameClient.GameClientState;
import com.l2jmobius.gameserver.thread.LoginServerThread;
/**
* @author Shyla
*/
public class OfflineTradeTable
{
private static Logger LOGGER = Logger.getLogger(OfflineTradeTable.class.getName());
// SQL DEFINITIONS
private static final String SAVE_OFFLINE_STATUS = "INSERT INTO character_offline_trade (`charId`,`time`,`type`,`title`) VALUES (?,?,?,?)";
private static final String SAVE_ITEMS = "INSERT INTO character_offline_trade_items (`charId`,`item`,`count`,`price`,`enchant`) VALUES (?,?,?,?,?)";
private static final String DELETE_OFFLINE_TABLE_ALL_ITEMS = "delete from character_offline_trade_items where charId=?";
private static final String DELETE_OFFLINE_TRADER = "DELETE FROM character_offline_trade where charId=?";
private static final String CLEAR_OFFLINE_TABLE = "DELETE FROM character_offline_trade";
private static final String CLEAR_OFFLINE_TABLE_ITEMS = "DELETE FROM character_offline_trade_items";
private static final String LOAD_OFFLINE_STATUS = "SELECT * FROM character_offline_trade";
private static final String LOAD_OFFLINE_ITEMS = "SELECT * FROM character_offline_trade_items WHERE charId = ?";
// called when server will go off, different from storeOffliner because
// of store of normal sellers/buyers also if not in offline mode
public static void storeOffliners()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement stm = con.prepareStatement(CLEAR_OFFLINE_TABLE);
stm.execute();
stm.close();
stm = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS);
stm.execute();
stm.close();
con.setAutoCommit(false); // avoid halfway done
stm = con.prepareStatement(SAVE_OFFLINE_STATUS);
final PreparedStatement stm_items = con.prepareStatement(SAVE_ITEMS);
for (L2PcInstance pc : L2World.getInstance().getAllPlayers())
{
try
{
// without second check, server will store all guys that are in shop mode
if ((pc.getPrivateStoreType() != L2PcInstance.STORE_PRIVATE_NONE)/* && (pc.isOffline()) */)
{
stm.setInt(1, pc.getObjectId()); // Char Id
stm.setLong(2, pc.getOfflineStartTime());
stm.setInt(3, pc.getPrivateStoreType()); // store type
String title = null;
switch (pc.getPrivateStoreType())
{
case L2PcInstance.STORE_PRIVATE_BUY:
{
if (!Config.OFFLINE_TRADE_ENABLE)
{
continue;
}
title = pc.getBuyList().getTitle();
for (TradeItem i : pc.getBuyList().getItems())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getItem().getItemId());
stm_items.setLong(3, i.getCount());
stm_items.setLong(4, i.getPrice());
stm_items.setLong(5, i.getEnchant());
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
}
case L2PcInstance.STORE_PRIVATE_SELL:
case L2PcInstance.STORE_PRIVATE_PACKAGE_SELL:
{
if (!Config.OFFLINE_TRADE_ENABLE)
{
continue;
}
title = pc.getSellList().getTitle();
pc.getSellList().updateItems();
for (TradeItem i : pc.getSellList().getItems())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getObjectId());
stm_items.setLong(3, i.getCount());
stm_items.setLong(4, i.getPrice());
stm_items.setLong(5, i.getEnchant());
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
}
case L2PcInstance.STORE_PRIVATE_MANUFACTURE:
{
if (!Config.OFFLINE_CRAFT_ENABLE)
{
continue;
}
title = pc.getCreateList().getStoreName();
for (L2ManufactureItem i : pc.getCreateList().getList())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getRecipeId());
stm_items.setLong(3, 0);
stm_items.setLong(4, i.getCost());
stm_items.setLong(5, 0);
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
}
default:
{
// LOGGER.info( "OfflineTradersTable[storeTradeItems()]: Error while saving offline trader: " + pc.getObjectId() + ", store type: "+pc.getPrivateStoreType());
// no save for this kind of shop
continue;
}
}
stm.setString(4, title);
stm.executeUpdate();
stm.clearParameters();
con.commit(); // flush
}
}
catch (Exception e)
{
LOGGER.warning("OfflineTradersTable[storeTradeItems()]: Error while saving offline trader: " + pc.getObjectId() + " " + e);
}
}
stm.close();
stm_items.close();
LOGGER.info("Offline traders stored.");
}
catch (Exception e)
{
LOGGER.warning("OfflineTradersTable[storeTradeItems()]: Error while saving offline traders: " + e);
}
}
public static void restoreOfflineTraders()
{
LOGGER.info("Loading offline traders...");
int nTraders = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement stm = con.prepareStatement(LOAD_OFFLINE_STATUS);
final ResultSet rs = stm.executeQuery();
while (rs.next())
{
final long time = rs.getLong("time");
if (Config.OFFLINE_MAX_DAYS > 0)
{
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
cal.add(Calendar.DAY_OF_YEAR, Config.OFFLINE_MAX_DAYS);
if (cal.getTimeInMillis() <= System.currentTimeMillis())
{
LOGGER.info("Offline trader with id " + rs.getInt("charId") + " reached OfflineMaxDays, kicked.");
continue;
}
}
final int type = rs.getInt("type");
if (type == L2PcInstance.STORE_PRIVATE_NONE)
{
continue;
}
L2PcInstance player = null;
try
{
final L2GameClient client = new L2GameClient(null);
player = L2PcInstance.load(rs.getInt("charId"));
client.setActiveChar(player);
client.setAccountName(player.getAccountName());
client.setState(GameClientState.IN_GAME);
player.setClient(client);
player.setOfflineMode(true);
player.setOnlineStatus(false);
player.setOfflineStartTime(time);
if (Config.OFFLINE_SLEEP_EFFECT)
{
player.startAbnormalEffect(L2Character.ABNORMAL_EFFECT_SLEEP);
}
player.spawnMe(player.getX(), player.getY(), player.getZ());
LoginServerThread.getInstance().addGameServerLogin(player.getAccountName(), client);
final PreparedStatement stm_items = con.prepareStatement(LOAD_OFFLINE_ITEMS);
stm_items.setInt(1, player.getObjectId());
final ResultSet items = stm_items.executeQuery();
switch (type)
{
case L2PcInstance.STORE_PRIVATE_BUY:
{
while (items.next())
{
player.getBuyList().addItemByItemId(items.getInt(2), items.getInt(3), items.getInt(4), items.getInt(5));
}
player.getBuyList().setTitle(rs.getString("title"));
break;
}
case L2PcInstance.STORE_PRIVATE_SELL:
case L2PcInstance.STORE_PRIVATE_PACKAGE_SELL:
{
while (items.next())
{
player.getSellList().addItem(items.getInt(2), items.getInt(3), items.getInt(4));
}
player.getSellList().setTitle(rs.getString("title"));
player.getSellList().setPackaged(type == L2PcInstance.STORE_PRIVATE_PACKAGE_SELL);
break;
}
case L2PcInstance.STORE_PRIVATE_MANUFACTURE:
{
final L2ManufactureList createList = new L2ManufactureList();
while (items.next())
{
createList.add(new L2ManufactureItem(items.getInt(2), items.getInt(4)));
}
player.setCreateList(createList);
player.getCreateList().setStoreName(rs.getString("title"));
break;
}
default:
{
LOGGER.info("Offline trader " + player.getName() + " finished to sell his items");
}
}
items.close();
stm_items.close();
player.sitDown();
if (Config.OFFLINE_MODE_SET_INVULNERABLE)
{
player.setIsInvul(true);
}
if (Config.OFFLINE_SET_NAME_COLOR)
{
player._originalNameColorOffline = player.getAppearance().getNameColor();
player.getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
}
player.setPrivateStoreType(type);
player.setOnlineStatus(true);
player.restoreEffects();
player.broadcastUserInfo();
nTraders++;
}
catch (Exception e)
{
LOGGER.warning("OfflineTradersTable[loadOffliners()]: Error loading trader: " + e);
if (player != null)
{
player.logout();
}
}
}
rs.close();
stm.close();
LOGGER.info("Loaded: " + nTraders + " offline trader(s)");
}
catch (Exception e)
{
LOGGER.warning("OfflineTradersTable[loadOffliners()]: Error while loading offline traders: " + e);
}
}
public static void storeOffliner(L2PcInstance pc)
{
if ((pc.getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_NONE) || (!pc.isInOfflineMode()))
{
return;
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement stm = con.prepareStatement(DELETE_OFFLINE_TABLE_ALL_ITEMS);
stm.setInt(1, pc.getObjectId());
stm.execute();
stm.clearParameters();
stm.close();
stm = con.prepareStatement(DELETE_OFFLINE_TRADER);
stm.setInt(1, pc.getObjectId());
stm.execute();
stm.clearParameters();
stm.close();
con.setAutoCommit(false); // avoid halfway done
stm = con.prepareStatement(SAVE_OFFLINE_STATUS);
final PreparedStatement stm_items = con.prepareStatement(SAVE_ITEMS);
boolean save = true;
try
{
stm.setInt(1, pc.getObjectId()); // Char Id
stm.setLong(2, pc.getOfflineStartTime());
stm.setInt(3, pc.getPrivateStoreType()); // store type
String title = null;
switch (pc.getPrivateStoreType())
{
case L2PcInstance.STORE_PRIVATE_BUY:
{
if (!Config.OFFLINE_TRADE_ENABLE)
{
break;
}
title = pc.getBuyList().getTitle();
for (TradeItem i : pc.getBuyList().getItems())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getItem().getItemId());
stm_items.setLong(3, i.getCount());
stm_items.setLong(4, i.getPrice());
stm_items.setLong(5, i.getEnchant());
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
}
case L2PcInstance.STORE_PRIVATE_SELL:
case L2PcInstance.STORE_PRIVATE_PACKAGE_SELL:
{
if (!Config.OFFLINE_TRADE_ENABLE)
{
break;
}
title = pc.getSellList().getTitle();
pc.getSellList().updateItems();
for (TradeItem i : pc.getSellList().getItems())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getObjectId());
stm_items.setLong(3, i.getCount());
stm_items.setLong(4, i.getPrice());
stm_items.setLong(5, i.getEnchant());
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
}
case L2PcInstance.STORE_PRIVATE_MANUFACTURE:
{
if (!Config.OFFLINE_CRAFT_ENABLE)
{
break;
}
title = pc.getCreateList().getStoreName();
for (L2ManufactureItem i : pc.getCreateList().getList())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getRecipeId());
stm_items.setLong(3, 0);
stm_items.setLong(4, i.getCost());
stm_items.setLong(5, 0);
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
}
default:
{
// LOGGER.info( "OfflineTradersTable[storeOffliner()]: Error while saving offline trader: " + pc.getObjectId() + ", store type: "+pc.getPrivateStoreType());
// no save for this kind of shop
save = false;
}
}
if (save)
{
stm.setString(4, title);
stm.executeUpdate();
stm.clearParameters();
con.commit(); // flush
}
}
catch (Exception e)
{
LOGGER.warning("OfflineTradersTable[storeOffliner()]: Error while saving offline trader: " + pc.getObjectId() + " " + e);
}
stm.close();
stm_items.close();
}
catch (Exception e)
{
LOGGER.warning("OfflineTradersTable[storeOffliner()]: Error while saving offline traders: " + e);
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.datatables;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.gameserver.engines.DocumentEngine;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.templates.item.L2WeaponType;
public class SkillTable
{
// private static Logger LOGGER = Logger.getLogger(SkillTable.class);
private static SkillTable _instance;
private final Map<Integer, L2Skill> _skills;
private final boolean _initialized = true;
public static SkillTable getInstance()
{
if (_instance == null)
{
_instance = new SkillTable();
}
return _instance;
}
private SkillTable()
{
_skills = new HashMap<>();
DocumentEngine.getInstance().loadAllSkills(_skills);
}
public void reload()
{
_instance = new SkillTable();
}
public boolean isInitialized()
{
return _initialized;
}
/**
* Provides the skill hash
* @param skill The L2Skill to be hashed
* @return SkillTable.getSkillHashCode(skill.getId(), skill.getLevel())
*/
public static int getSkillHashCode(L2Skill skill)
{
return SkillTable.getSkillHashCode(skill.getId(), skill.getLevel());
}
/**
* Centralized method for easier change of the hashing sys
* @param skillId The Skill Id
* @param skillLevel The Skill Level
* @return The Skill hash number
*/
public static int getSkillHashCode(int skillId, int skillLevel)
{
return (skillId * 256) + skillLevel;
}
public L2Skill getInfo(int skillId, int level)
{
return _skills.get(SkillTable.getSkillHashCode(skillId, level));
}
public int getMaxLevel(int magicId, int level)
{
L2Skill temp;
while (level < 100)
{
level++;
temp = _skills.get(SkillTable.getSkillHashCode(magicId, level));
if (temp == null)
{
return level - 1;
}
}
return level;
}
private static final L2WeaponType[] weaponDbMasks =
{
L2WeaponType.ETC,
L2WeaponType.BOW,
L2WeaponType.POLE,
L2WeaponType.DUALFIST,
L2WeaponType.DUAL,
L2WeaponType.BLUNT,
L2WeaponType.SWORD,
L2WeaponType.DAGGER,
L2WeaponType.BIGSWORD,
L2WeaponType.ROD,
L2WeaponType.BIGBLUNT
};
public int calcWeaponsAllowed(int mask)
{
if (mask == 0)
{
return 0;
}
int weaponsAllowed = 0;
for (int i = 0; i < weaponDbMasks.length; i++)
{
if ((mask & (1 << i)) != 0)
{
weaponsAllowed |= weaponDbMasks[i].mask();
}
}
return weaponsAllowed;
}
}

View File

@@ -0,0 +1,414 @@
/*
* 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.datatables.csv;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.ClanHallManager;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.entity.ClanHall;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.gameserver.templates.chars.L2CharTemplate;
public class DoorTable
{
private static Logger LOGGER = Logger.getLogger(DoorTable.class.getName());
private Map<Integer, L2DoorInstance> _staticItems;
private static DoorTable _instance;
public static DoorTable getInstance()
{
if (_instance == null)
{
_instance = new DoorTable();
}
return _instance;
}
public DoorTable()
{
_staticItems = new HashMap<>();
// parseData();
}
public void reloadAll()
{
respawn();
}
public void respawn()
{
// L2DoorInstance[] currentDoors = getDoors();
_staticItems = null;
_instance = new DoorTable();
}
public void parseData()
{
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
final File doorData = new File(Config.DATAPACK_ROOT, "data/csv/door.csv");
reader = new FileReader(doorData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
String line = null;
LOGGER.info("Searching clan halls doors:");
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
final L2DoorInstance door = parseList(line);
_staticItems.put(door.getDoorId(), door);
door.spawnMe(door.getX(), door.getY(), door.getZ());
final ClanHall clanhall = ClanHallManager.getInstance().getNearbyClanHall(door.getX(), door.getY(), 500);
if (clanhall != null)
{
clanhall.getDoors().add(door);
door.setClanHall(clanhall);
if (Config.DEBUG)
{
LOGGER.warning("door " + door.getDoorName() + " attached to ch " + clanhall.getName());
}
}
}
LOGGER.info("DoorTable: Loaded " + _staticItems.size() + " Door Templates.");
}
catch (FileNotFoundException e)
{
_initialized = false;
LOGGER.warning("door.csv is missing in data csv folder");
}
catch (IOException e)
{
_initialized = false;
LOGGER.warning("error while creating door table " + e);
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
public static L2DoorInstance parseList(String line)
{
StringTokenizer st = new StringTokenizer(line, ";");
String name = st.nextToken();
final int id = Integer.parseInt(st.nextToken());
final int x = Integer.parseInt(st.nextToken());
final int y = Integer.parseInt(st.nextToken());
final int z = Integer.parseInt(st.nextToken());
final int rangeXMin = Integer.parseInt(st.nextToken());
final int rangeYMin = Integer.parseInt(st.nextToken());
final int rangeZMin = Integer.parseInt(st.nextToken());
final int rangeXMax = Integer.parseInt(st.nextToken());
final int rangeYMax = Integer.parseInt(st.nextToken());
final int rangeZMax = Integer.parseInt(st.nextToken());
final int hp = Integer.parseInt(st.nextToken());
final int pdef = Integer.parseInt(st.nextToken());
final int mdef = Integer.parseInt(st.nextToken());
boolean unlockable = false;
if (st.hasMoreTokens())
{
unlockable = Boolean.parseBoolean(st.nextToken());
}
boolean autoOpen = false;
if (st.hasMoreTokens())
{
autoOpen = Boolean.parseBoolean(st.nextToken());
}
if (rangeXMin > rangeXMax)
{
LOGGER.warning("Error in door data, ID:" + id);
}
if (rangeYMin > rangeYMax)
{
LOGGER.warning("Error in door data, ID:" + id);
}
if (rangeZMin > rangeZMax)
{
LOGGER.warning("Error in door data, ID:" + id);
}
int collisionRadius; // (max) radius for movement checks
if ((rangeXMax - rangeXMin) > (rangeYMax - rangeYMin))
{
collisionRadius = rangeYMax - rangeYMin;
}
else
{
collisionRadius = rangeXMax - rangeXMin;
}
StatsSet npcDat = new StatsSet();
npcDat.set("npcId", id);
npcDat.set("level", 0);
npcDat.set("jClass", "door");
npcDat.set("baseSTR", 0);
npcDat.set("baseCON", 0);
npcDat.set("baseDEX", 0);
npcDat.set("baseINT", 0);
npcDat.set("baseWIT", 0);
npcDat.set("baseMEN", 0);
npcDat.set("baseShldDef", 0);
npcDat.set("baseShldRate", 0);
npcDat.set("baseAccCombat", 38);
npcDat.set("baseEvasRate", 38);
npcDat.set("baseCritRate", 38);
// npcDat.set("name", "");
npcDat.set("collision_radius", collisionRadius);
npcDat.set("collision_height", rangeZMax - rangeZMin);
npcDat.set("sex", "male");
npcDat.set("type", "");
npcDat.set("baseAtkRange", 0);
npcDat.set("baseMpMax", 0);
npcDat.set("baseCpMax", 0);
npcDat.set("rewardExp", 0);
npcDat.set("rewardSp", 0);
npcDat.set("basePAtk", 0);
npcDat.set("baseMAtk", 0);
npcDat.set("basePAtkSpd", 0);
npcDat.set("aggroRange", 0);
npcDat.set("baseMAtkSpd", 0);
npcDat.set("rhand", 0);
npcDat.set("lhand", 0);
npcDat.set("armor", 0);
npcDat.set("baseWalkSpd", 0);
npcDat.set("baseRunSpd", 0);
npcDat.set("name", name);
npcDat.set("baseHpMax", hp);
npcDat.set("baseHpReg", 3.e-3f);
npcDat.set("baseMpReg", 3.e-3f);
npcDat.set("basePDef", pdef);
npcDat.set("baseMDef", mdef);
L2CharTemplate template = new L2CharTemplate(npcDat);
final L2DoorInstance door = new L2DoorInstance(IdFactory.getInstance().getNextId(), template, id, name, unlockable);
door.setRange(rangeXMin, rangeYMin, rangeZMin, rangeXMax, rangeYMax, rangeZMax);
try
{
door.setMapRegion(MapRegionTable.getInstance().getMapRegion(x, y));
}
catch (Exception e)
{
LOGGER.warning("Error in door data, ID:" + id + " " + e);
}
door.setCurrentHpMp(door.getMaxHp(), door.getMaxMp());
door.setOpen(autoOpen);
door.setXYZInvisible(x, y, z);
return door;
}
public boolean isInitialized()
{
return _initialized;
}
private boolean _initialized = true;
public L2DoorInstance getDoor(Integer id)
{
return _staticItems.get(id);
}
public void putDoor(L2DoorInstance door)
{
_staticItems.put(door.getDoorId(), door);
}
public L2DoorInstance[] getDoors()
{
final L2DoorInstance[] _allTemplates = _staticItems.values().toArray(new L2DoorInstance[_staticItems.size()]);
return _allTemplates;
}
/**
* Performs a check and sets up a scheduled task for those doors that require auto opening/closing.
*/
public void checkAutoOpen()
{
for (L2DoorInstance doorInst : getDoors())
{
// Garden of Eva (every 7 minutes)
if (doorInst.getDoorName().startsWith("goe"))
{
doorInst.setAutoActionDelay(420000);
}
// Tower of Insolence (every 5 minutes)
else if (doorInst.getDoorName().startsWith("aden_tower"))
{
doorInst.setAutoActionDelay(300000);
}
// Cruma Tower (every 20 minutes)
else if (doorInst.getDoorName().startsWith("cruma"))
{
doorInst.setAutoActionDelay(1200000);
}
}
}
public boolean checkIfDoorsBetween(AbstractNodeLoc start, AbstractNodeLoc end)
{
return checkIfDoorsBetween(start.getX(), start.getY(), start.getZ(), end.getX(), end.getY(), end.getZ());
}
public boolean checkIfDoorsBetween(int x, int y, int z, int tx, int ty, int tz)
{
int region;
try
{
region = MapRegionTable.getInstance().getMapRegion(x, y);
}
catch (Exception e)
{
return false;
}
for (L2DoorInstance doorInst : getDoors())
{
if (doorInst.getMapRegion() != region)
{
continue;
}
if (doorInst.getXMax() == 0)
{
continue;
}
// line segment goes through box
// heavy approximation disabling some shooting angles especially near 2-piece doors
// but most calculations should stop short
// phase 1, x
if (((x <= doorInst.getXMax()) && (tx >= doorInst.getXMin())) || ((tx <= doorInst.getXMax()) && (x >= doorInst.getXMin())))
{
// phase 2, y
if (((y <= doorInst.getYMax()) && (ty >= doorInst.getYMin())) || ((ty <= doorInst.getYMax()) && (y >= doorInst.getYMin())))
{
// phase 3, basically only z remains but now we calculate it with another formula (by rage)
// in some cases the direct line check (only) in the beginning isn't sufficient,
// when char z changes a lot along the path
if ((doorInst.getStatus().getCurrentHp() > 0) && !doorInst.getOpen())
{
final int px1 = doorInst.getXMin();
final int py1 = doorInst.getYMin();
final int pz1 = doorInst.getZMin();
final int px2 = doorInst.getXMax();
final int py2 = doorInst.getYMax();
final int pz2 = doorInst.getZMax();
final int l = tx - x;
final int m = ty - y;
final int n = tz - z;
int dk = ((doorInst.getA() * l) + (doorInst.getB() * m) + (doorInst.getC() * n));
if (dk == 0)
{
continue; // Parallel
}
final float p = (float) ((doorInst.getA() * x) + (doorInst.getB() * y) + (doorInst.getC() * z) + doorInst.getD()) / (float) dk;
final int fx = (int) (x - (l * p));
final int fy = (int) (y - (m * p));
final int fz = (int) (z - (n * p));
if (((Math.min(x, tx) <= fx) && (fx <= Math.max(x, tx))) && ((Math.min(y, ty) <= fy) && (fy <= Math.max(y, ty))) && ((Math.min(z, tz) <= fz) && (fz <= Math.max(z, tz))))
{
if ((((fx >= px1) && (fx <= px2)) || ((fx >= px2) && (fx <= px1))) && (((fy >= py1) && (fy <= py2)) || ((fy >= py2) && (fy <= py1))) && (((fz >= pz1) && (fz <= pz2)) || ((fz >= pz2) && (fz <= pz1))))
{
return true; // Door between
}
}
}
}
}
}
return false;
}
}

View File

@@ -0,0 +1,178 @@
/*
* 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.datatables.csv;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.L2ExtractableItem;
import com.l2jmobius.gameserver.model.L2ExtractableProductItem;
/**
* @author FBIagent
*/
public class ExtractableItemsData
{
private static Logger LOGGER = Logger.getLogger(ExtractableItemsData.class.getName());
// Map<itemid, L2ExtractableItem>
private Map<Integer, L2ExtractableItem> _items;
private static ExtractableItemsData _instance = null;
public static ExtractableItemsData getInstance()
{
if (_instance == null)
{
_instance = new ExtractableItemsData();
}
return _instance;
}
public ExtractableItemsData()
{
_items = new HashMap<>();
Scanner s = null;
try
{
s = new Scanner(new File(Config.DATAPACK_ROOT + "/data/csv/extractable_items.csv"));
int lineCount = 0;
while (s.hasNextLine())
{
lineCount++;
final String line = s.nextLine();
if (line.startsWith("#"))
{
continue;
}
else if (line.equals(""))
{
continue;
}
final String[] lineSplit = line.split(";");
int itemID = 0;
try
{
itemID = Integer.parseInt(lineSplit[0]);
}
catch (Exception e)
{
LOGGER.info("Extractable items data: Error in line " + lineCount + " -> invalid item id or wrong seperator after item id!");
LOGGER.info(" " + line);
return;
}
final List<L2ExtractableProductItem> product_temp = new ArrayList<>(lineSplit.length);
for (int i = 0; i < (lineSplit.length - 1); i++)
{
String[] lineSplit2 = lineSplit[i + 1].split(",");
if (lineSplit2.length != 3)
{
LOGGER.info("Extractable items data: Error in line " + lineCount + " -> wrong seperator!");
LOGGER.info(" " + line);
continue;
}
int production = 0, amount = 0, chance = 0;
try
{
production = Integer.parseInt(lineSplit2[0]);
amount = Integer.parseInt(lineSplit2[1]);
chance = Integer.parseInt(lineSplit2[2]);
}
catch (Exception e)
{
LOGGER.info("Extractable items data: Error in line " + lineCount + " -> incomplete/invalid production data or wrong seperator!");
LOGGER.info(" " + line);
continue;
}
product_temp.add(new L2ExtractableProductItem(production, amount, chance));
}
int fullChances = 0;
for (L2ExtractableProductItem Pi : product_temp)
{
fullChances += Pi.getChance();
}
if (fullChances > 100)
{
LOGGER.info("Extractable items data: Error in line " + lineCount + " -> all chances together are more then 100!");
LOGGER.info(" " + line);
continue;
}
_items.put(itemID, new L2ExtractableItem(itemID, product_temp));
}
LOGGER.info("Extractable items data: Loaded " + _items.size() + " extractable items!");
}
catch (Exception e)
{
// if(Config.ENABLE_ALL_EXCEPTIONS)
e.printStackTrace();
LOGGER.info("Extractable items data: Can not find './data/csv/extractable_items.csv'");
}
finally
{
if (s != null)
{
try
{
s.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
public L2ExtractableItem getExtractableItem(int itemID)
{
return _items.get(itemID);
}
public int[] itemIDs()
{
final int size = _items.size();
final int[] result = new int[size];
int i = 0;
for (L2ExtractableItem ei : _items.values())
{
result[i] = ei.getItemId();
i++;
}
return result;
}
}

View File

@@ -0,0 +1,225 @@
/*
* 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.datatables.csv;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.datatables.sql.SkillTreeTable;
import com.l2jmobius.gameserver.model.FishData;
/**
* @author -Nemesiss-
*/
public class FishTable
{
private static Logger LOGGER = Logger.getLogger(SkillTreeTable.class.getName());
private static final FishTable _instance = new FishTable();
private static List<FishData> _fishsNormal;
private static List<FishData> _fishsEasy;
private static List<FishData> _fishsHard;
public static FishData fish;
public static FishTable getInstance()
{
return _instance;
}
private FishTable()
{
int count = 0;
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
final File fileData = new File(Config.DATAPACK_ROOT + "/data/csv/fish.csv");
reader = new FileReader(fileData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
String line = null;
_fishsEasy = new ArrayList<>();
_fishsNormal = new ArrayList<>();
_fishsHard = new ArrayList<>();
FishData fish;
// format:
// id;level;name;hp;hpregen;fish_type;fish_group;fish_guts;guts_check_time;wait_time;combat_time
while ((line = lnr.readLine()) != null)
{
// ignore comments
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
final StringTokenizer st = new StringTokenizer(line, ";");
final int id = Integer.parseInt(st.nextToken());
final int lvl = Integer.parseInt(st.nextToken());
final String name = st.nextToken();
final int hp = Integer.parseInt(st.nextToken());
final int hpreg = Integer.parseInt(st.nextToken());
final int type = Integer.parseInt(st.nextToken());
final int group = Integer.parseInt(st.nextToken());
final int fish_guts = Integer.parseInt(st.nextToken());
final int guts_check_time = Integer.parseInt(st.nextToken());
final int wait_time = Integer.parseInt(st.nextToken());
final int combat_time = Integer.parseInt(st.nextToken());
fish = new FishData(id, lvl, name, hp, hpreg, type, group, fish_guts, guts_check_time, wait_time, combat_time);
switch (fish.getGroup())
{
case 0:
{
_fishsEasy.add(fish);
break;
}
case 1:
{
_fishsNormal.add(fish);
break;
}
case 2:
{
_fishsHard.add(fish);
}
}
}
count = _fishsEasy.size() + _fishsNormal.size() + _fishsHard.size();
}
catch (FileNotFoundException e)
{
LOGGER.warning("fish.csv is missing in data folder");
}
catch (IOException e0)
{
LOGGER.warning("Error while creating table: " + e0.getMessage() + "\n" + e0);
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
LOGGER.info("FishTable: Loaded " + count + " Fishes.");
}
/**
* @param lvl
* @param type
* @param group
* @return List of Fish that can be fished
*/
public List<FishData> getfish(int lvl, int type, int group)
{
final List<FishData> result = new ArrayList<>();
List<FishData> _Fishs = null;
switch (group)
{
case 0:
{
_Fishs = _fishsEasy;
break;
}
case 1:
{
_Fishs = _fishsNormal;
break;
}
case 2:
{
_Fishs = _fishsHard;
}
}
if (_Fishs == null)
{
// the fish list is empty
LOGGER.warning("Fish are not defined !");
return null;
}
for (FishData f : _Fishs)
{
if (f.getLevel() != lvl)
{
continue;
}
if (f.getType() != type)
{
continue;
}
result.add(f);
}
if (result.size() == 0)
{
LOGGER.warning("Cant Find Any Fish!? - Lvl: " + lvl + " Type: " + type);
}
return result;
}
}

View File

@@ -0,0 +1,167 @@
/*
* 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.datatables.csv;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.gameserver.templates.item.L2Henna;
/**
* This class ...
* @version $Revision$ $Date$
*/
public class HennaTable
{
private static Logger LOGGER = Logger.getLogger(HennaTable.class.getName());
private static HennaTable _instance;
private final Map<Integer, L2Henna> _henna;
private final boolean _initialized = true;
public static HennaTable getInstance()
{
if (_instance == null)
{
_instance = new HennaTable();
}
return _instance;
}
private HennaTable()
{
_henna = new HashMap<>();
restoreHennaData();
}
private void restoreHennaData()
{
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
final File fileData = new File(Config.DATAPACK_ROOT + "/data/csv/henna.csv");
reader = new FileReader(fileData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
String line = null;
while ((line = lnr.readLine()) != null)
{
// ignore comments
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
final StringTokenizer st = new StringTokenizer(line, ";");
StatsSet hennaDat = new StatsSet();
final int id = Integer.parseInt(st.nextToken());
hennaDat.set("symbol_id", id);
st.nextToken(); // next token...ignore name
hennaDat.set("dye", Integer.parseInt(st.nextToken()));
hennaDat.set("amount", Integer.parseInt(st.nextToken()));
hennaDat.set("price", Integer.parseInt(st.nextToken()));
hennaDat.set("stat_INT", Integer.parseInt(st.nextToken()));
hennaDat.set("stat_STR", Integer.parseInt(st.nextToken()));
hennaDat.set("stat_CON", Integer.parseInt(st.nextToken()));
hennaDat.set("stat_MEM", Integer.parseInt(st.nextToken()));
hennaDat.set("stat_DEX", Integer.parseInt(st.nextToken()));
hennaDat.set("stat_WIT", Integer.parseInt(st.nextToken()));
L2Henna template = new L2Henna(hennaDat);
_henna.put(id, template);
}
LOGGER.info("HennaTable: Loaded " + _henna.size() + " Templates.");
}
catch (FileNotFoundException e)
{
LOGGER.warning(Config.DATAPACK_ROOT + "/data/csv/henna.csv is missing in data folder");
}
catch (IOException e0)
{
LOGGER.warning("Error while creating table: " + e0.getMessage() + "\n" + e0);
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
public boolean isInitialized()
{
return _initialized;
}
public L2Henna getTemplate(int id)
{
return _henna.get(id);
}
}

View File

@@ -0,0 +1,623 @@
/*
* 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.datatables.csv;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.instancemanager.ArenaManager;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
import com.l2jmobius.gameserver.instancemanager.ClanHallManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.TownManager;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.position.Location;
import com.l2jmobius.gameserver.model.entity.ClanHall;
import com.l2jmobius.gameserver.model.entity.siege.Castle;
import com.l2jmobius.gameserver.model.entity.siege.Fort;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.model.zone.type.L2ArenaZone;
import com.l2jmobius.gameserver.model.zone.type.L2ClanHallZone;
import com.l2jmobius.gameserver.model.zone.type.L2TownZone;
public class MapRegionTable
{
private static Logger LOGGER = Logger.getLogger(MapRegionTable.class.getName());
private static MapRegionTable _instance;
private final int[][] _regions = new int[19][21];
private final int[][] _pointsWithKarmas;
public enum TeleportWhereType
{
Castle,
ClanHall,
SiegeFlag,
Town,
Fortress
}
public static MapRegionTable getInstance()
{
if (_instance == null)
{
_instance = new MapRegionTable();
}
return _instance;
}
private MapRegionTable()
{
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
final File fileData = new File(Config.DATAPACK_ROOT + "/data/csv/mapregion.csv");
reader = new FileReader(fileData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
String line = null;
int region;
while ((line = lnr.readLine()) != null)
{
// ignore comments
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
final StringTokenizer st = new StringTokenizer(line, ";");
region = Integer.parseInt(st.nextToken());
for (int j = 0; j < 10; j++)
{
_regions[j][region] = Integer.parseInt(st.nextToken());
}
}
}
catch (FileNotFoundException e)
{
LOGGER.warning("mapregion.csv is missing in data folder");
}
catch (NoSuchElementException e1)
{
LOGGER.warning("Error for structure CSV file: ");
e1.printStackTrace();
}
catch (IOException e0)
{
LOGGER.warning("Error while creating table: " + e0);
e0.printStackTrace();
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
_pointsWithKarmas = new int[19][3];
// Talking Island
_pointsWithKarmas[0][0] = -79077;
_pointsWithKarmas[0][1] = 240355;
_pointsWithKarmas[0][2] = -3440;
// Elven
_pointsWithKarmas[1][0] = 43503;
_pointsWithKarmas[1][1] = 40398;
_pointsWithKarmas[1][2] = -3450;
// DarkElven
_pointsWithKarmas[2][0] = 1675;
_pointsWithKarmas[2][1] = 19581;
_pointsWithKarmas[2][2] = -3110;
// Orc
_pointsWithKarmas[3][0] = -44413;
_pointsWithKarmas[3][1] = -121762;
_pointsWithKarmas[3][2] = -235;
// Dwalf
_pointsWithKarmas[4][0] = 12009;
_pointsWithKarmas[4][1] = -187319;
_pointsWithKarmas[4][2] = -3309;
// Gludio
_pointsWithKarmas[5][0] = -18872;
_pointsWithKarmas[5][1] = 126216;
_pointsWithKarmas[5][2] = -3280;
// Gludin
_pointsWithKarmas[6][0] = -85915;
_pointsWithKarmas[6][1] = 150402;
_pointsWithKarmas[6][2] = -3060;
// Dion
_pointsWithKarmas[7][0] = 23652;
_pointsWithKarmas[7][1] = 144823;
_pointsWithKarmas[7][2] = -3330;
// Giran
_pointsWithKarmas[8][0] = 79125;
_pointsWithKarmas[8][1] = 154197;
_pointsWithKarmas[8][2] = -3490;
// Oren
_pointsWithKarmas[9][0] = 73840;
_pointsWithKarmas[9][1] = 58193;
_pointsWithKarmas[9][2] = -2730;
// Aden
_pointsWithKarmas[10][0] = 44413;
_pointsWithKarmas[10][1] = 22610;
_pointsWithKarmas[10][2] = 235;
// Hunters
_pointsWithKarmas[11][0] = 114137;
_pointsWithKarmas[11][1] = 72993;
_pointsWithKarmas[11][2] = -2445;
// Giran
_pointsWithKarmas[12][0] = 79125;
_pointsWithKarmas[12][1] = 154197;
_pointsWithKarmas[12][2] = -3490;
// heine
_pointsWithKarmas[13][0] = 119536;
_pointsWithKarmas[13][1] = 218558;
_pointsWithKarmas[13][2] = -3495;
// Rune Castle Town
_pointsWithKarmas[14][0] = 42931;
_pointsWithKarmas[14][1] = -44733;
_pointsWithKarmas[14][2] = -1326;
// Goddard
_pointsWithKarmas[15][0] = 147419;
_pointsWithKarmas[15][1] = -64980;
_pointsWithKarmas[15][2] = -3457;
// Schuttgart
_pointsWithKarmas[16][0] = 85184;
_pointsWithKarmas[16][1] = -138560;
_pointsWithKarmas[16][2] = -2256;
// TODO Primeval Isle
_pointsWithKarmas[18][0] = 10468;
_pointsWithKarmas[18][1] = -24569;
_pointsWithKarmas[18][2] = -3645;
}
public final int getMapRegion(int posX, int posY)
{
return _regions[getMapRegionX(posX)][getMapRegionY(posY)];
}
public final int getMapRegionX(int posX)
{
return (posX >> 15) + 4;// + centerTileX;
}
public final int getMapRegionY(int posY)
{
return (posY >> 15) + 10;// + centerTileX;
}
public int getAreaCastle(L2Character activeChar)
{
final int area = getClosestTownNumber(activeChar);
int castle;
switch (area)
{
case 0:
{
castle = 1;
break;// Talking Island Village
}
case 1:
{
castle = 4;
break; // Elven Village
}
case 2:
{
castle = 4;
break; // Dark Elven Village
}
case 3:
{
castle = 9;
break; // Orc Village
}
case 4:
{
castle = 9;
break; // Dwarven Village
}
case 5:
{
castle = 1;
break; // Town of Gludio
}
case 6:
{
castle = 1;
break; // Gludin Village
}
case 7:
{
castle = 2;
break; // Town of Dion
}
case 8:
{
castle = 3;
break; // Town of Giran
}
case 9:
{
castle = 4;
break; // Town of Oren
}
case 10:
{
castle = 5;
break; // Town of Aden
}
case 11:
{
castle = 5;
break; // Hunters Village
}
case 12:
{
castle = 3;
break; // Giran Harbor
}
case 13:
{
castle = 6;
break; // Heine
}
case 14:
{
castle = 8;
break; // Rune Township
}
case 15:
{
castle = 7;
break; // Town of Goddard
}
case 16:
{
castle = 9;
break; // Town of Shuttgart
}
case 17:
{
castle = 4;
break; // Ivory Tower
}
case 18:
{
castle = 8;
break; // Primeval Isle Wharf
}
default:
{
castle = 5;
break; // Town of Aden
}
}
return castle;
}
public int getClosestTownNumber(L2Character activeChar)
{
return getMapRegion(activeChar.getX(), activeChar.getY());
}
public String getClosestTownName(L2Character activeChar)
{
final int nearestTownId = getMapRegion(activeChar.getX(), activeChar.getY());
String nearestTown;
switch (nearestTownId)
{
case 0:
{
nearestTown = "Talking Island Village";
break;
}
case 1:
{
nearestTown = "Elven Village";
break;
}
case 2:
{
nearestTown = "Dark Elven Village";
break;
}
case 3:
{
nearestTown = "Orc Village";
break;
}
case 4:
{
nearestTown = "Dwarven Village";
break;
}
case 5:
{
nearestTown = "Town of Gludio";
break;
}
case 6:
{
nearestTown = "Gludin Village";
break;
}
case 7:
{
nearestTown = "Town of Dion";
break;
}
case 8:
{
nearestTown = "Town of Giran";
break;
}
case 9:
{
nearestTown = "Town of Oren";
break;
}
case 10:
{
nearestTown = "Town of Aden";
break;
}
case 11:
{
nearestTown = "Hunters Village";
break;
}
case 12:
{
nearestTown = "Giran Harbor";
break;
}
case 13:
{
nearestTown = "Heine";
break;
}
case 14:
{
nearestTown = "Rune Township";
break;
}
case 15:
{
nearestTown = "Town of Goddard";
break;
}
case 16:
{
nearestTown = "Town of Shuttgart";
break; // //TODO@ (Check mapregion table)[Luno]
}
case 18:
{
nearestTown = "Primeval Isle";
break;
}
default:
{
nearestTown = "Town of Aden";
break;
}
}
return nearestTown;
}
public Location getTeleToLocation(L2Character activeChar, TeleportWhereType teleportWhere)
{
int[] coord;
if (activeChar instanceof L2PcInstance)
{
final L2PcInstance player = (L2PcInstance) activeChar;
// If in Monster Derby Track
if (player.isInsideZone(ZoneId.MONSTERTRACK))
{
return new Location(12661, 181687, -3560);
}
Castle castle = null;
Fort fort = null;
ClanHall clanhall = null;
if (player.getClan() != null)
{
// If teleport to clan hall
if (teleportWhere == TeleportWhereType.ClanHall)
{
clanhall = ClanHallManager.getInstance().getClanHallByOwner(player.getClan());
if (clanhall != null)
{
final L2ClanHallZone zone = clanhall.getZone();
if (zone != null)
{
return zone.getSpawn();
}
}
}
// If teleport to castle
if (teleportWhere == TeleportWhereType.Castle)
{
castle = CastleManager.getInstance().getCastleByOwner(player.getClan());
}
// If teleport to fort
if (teleportWhere == TeleportWhereType.Fortress)
{
fort = FortManager.getInstance().getFortByOwner(player.getClan());
}
// Check if player is on castle&fortress ground
if (castle == null)
{
castle = CastleManager.getInstance().getCastle(player);
}
if (fort == null)
{
fort = FortManager.getInstance().getFort(player);
}
if ((castle != null) && (castle.getCastleId() > 0))
{
// If Teleporting to castle or
// If is on caslte with siege and player's clan is defender
if ((teleportWhere == TeleportWhereType.Castle) || ((teleportWhere == TeleportWhereType.Castle) && castle.getSiege().getIsInProgress() && (castle.getSiege().getDefenderClan(player.getClan()) != null)))
{
coord = castle.getZone().getSpawn();
return new Location(coord[0], coord[1], coord[2]);
}
if ((teleportWhere == TeleportWhereType.SiegeFlag) && castle.getSiege().getIsInProgress())
{
// Check if player's clan is attacker
List<L2NpcInstance> flags = castle.getSiege().getFlag(player.getClan());
if ((flags != null) && !flags.isEmpty())
{
// Spawn to flag - Need more work to get player to the nearest flag
final L2NpcInstance flag = flags.get(0);
return new Location(flag.getX(), flag.getY(), flag.getZ());
}
}
}
else if ((fort != null) && (fort.getFortId() > 0))
{
// teleporting to castle or fortress
// is on caslte with siege and player's clan is defender
if ((teleportWhere == TeleportWhereType.Fortress) || ((teleportWhere == TeleportWhereType.Fortress) && fort.getSiege().getIsInProgress() && (fort.getSiege().getDefenderClan(player.getClan()) != null)))
{
coord = fort.getZone().getSpawn();
return new Location(coord[0], coord[1], coord[2]);
}
if ((teleportWhere == TeleportWhereType.SiegeFlag) && fort.getSiege().getIsInProgress())
{
// check if player's clan is attacker
List<L2NpcInstance> flags = fort.getSiege().getFlag(player.getClan());
if ((flags != null) && !flags.isEmpty())
{
// spawn to flag
final L2NpcInstance flag = flags.get(0);
return new Location(flag.getX(), flag.getY(), flag.getZ());
}
}
}
}
// teleport RED PK 5+ to Floran Village
if ((player.getPkKills() > 5) && (player.getKarma() > 1))
{
return new Location(17817, 170079, -3530);
}
// Karma player land out of city
if (player.getKarma() > 1)
{
final int closest = getMapRegion(activeChar.getX(), activeChar.getY());
if ((closest >= 0) && (closest < _pointsWithKarmas.length))
{
return new Location(_pointsWithKarmas[closest][0], _pointsWithKarmas[closest][1], _pointsWithKarmas[closest][2]);
}
return new Location(17817, 170079, -3530);
}
// Checking if in arena
final L2ArenaZone arena = ArenaManager.getInstance().getArena(player);
if (arena != null)
{
coord = arena.getSpawnLoc();
return new Location(coord[0], coord[1], coord[2]);
}
}
// Get the nearest town
L2TownZone local_zone = null;
if ((activeChar != null) && ((local_zone = TownManager.getInstance().getClosestTown(activeChar)) != null))
{
coord = local_zone.getSpawnLoc();
return new Location(coord[0], coord[1], coord[2]);
}
local_zone = TownManager.getInstance().getTown(9); // giran
coord = local_zone.getSpawnLoc();
return new Location(coord[0], coord[1], coord[2]);
}
}

View File

@@ -0,0 +1,180 @@
/*
* 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.datatables.csv;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.L2NpcWalkerNode;
/**
* Main Table to Load Npc Walkers Routes and Chat SQL Table.<br>
* @author Rayan RPG for L2Emu Project
* @since 927
*/
public class NpcWalkerRoutesTable
{
protected static final Logger LOGGER = Logger.getLogger(NpcWalkerRoutesTable.class.getName());
private static NpcWalkerRoutesTable _instance;
private List<L2NpcWalkerNode> _routes;
public static NpcWalkerRoutesTable getInstance()
{
if (_instance == null)
{
_instance = new NpcWalkerRoutesTable();
LOGGER.info("Initializing Walkers Routes Table.");
}
return _instance;
}
private NpcWalkerRoutesTable()
{
// not here
}
public void load()
{
_routes = new ArrayList<>();
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
final File fileData = new File(Config.DATAPACK_ROOT + "/data/csv/walker_routes.csv");
reader = new FileReader(fileData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
L2NpcWalkerNode route;
String line = null;
// format:
// route_id;npc_id;move_point;chatText;move_x;move_y;move_z;delay;running
while ((line = lnr.readLine()) != null)
{
// ignore comments
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
route = new L2NpcWalkerNode();
final StringTokenizer st = new StringTokenizer(line, ";");
final int route_id = Integer.parseInt(st.nextToken());
final int npc_id = Integer.parseInt(st.nextToken());
final String move_point = st.nextToken();
final String chatText = st.nextToken();
final int move_x = Integer.parseInt(st.nextToken());
final int move_y = Integer.parseInt(st.nextToken());
final int move_z = Integer.parseInt(st.nextToken());
final int delay = Integer.parseInt(st.nextToken());
final boolean running = Boolean.parseBoolean(st.nextToken());
route.setRouteId(route_id);
route.setNpcId(npc_id);
route.setMovePoint(move_point);
route.setChatText(chatText);
route.setMoveX(move_x);
route.setMoveY(move_y);
route.setMoveZ(move_z);
route.setDelay(delay);
route.setRunning(running);
_routes.add(route);
}
LOGGER.info("WalkerRoutesTable: Loaded " + _routes.size() + " Npc Walker Routes.");
}
catch (FileNotFoundException e)
{
LOGGER.warning("walker_routes.csv is missing in data folder");
}
catch (IOException e0)
{
LOGGER.warning("Error while creating table: " + e0.getMessage() + "\n" + e0);
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
public List<L2NpcWalkerNode> getRouteForNpc(int id)
{
final List<L2NpcWalkerNode> _return = new ArrayList<>();
for (L2NpcWalkerNode node : _routes)
{
if (node.getNpcId() == id)
{
_return.add(node);
}
}
return _return;
}
}

View File

@@ -0,0 +1,236 @@
/*
* 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.datatables.csv;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.RecipeController;
import com.l2jmobius.gameserver.model.L2RecipeList;
import com.l2jmobius.gameserver.model.actor.instance.L2RecipeInstance;
/**
* @author programmos
*/
public class RecipeTable extends RecipeController
{
private static final Logger LOGGER = Logger.getLogger(RecipeTable.class.getName());
private final Map<Integer, L2RecipeList> _lists;
private static RecipeTable instance;
public static RecipeTable getInstance()
{
if (instance == null)
{
instance = new RecipeTable();
}
return instance;
}
private RecipeTable()
{
_lists = new HashMap<>();
String line = null;
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
final File recipesData = new File(Config.DATAPACK_ROOT, "data/recipes.csv");
reader = new FileReader(recipesData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
parseList(line);
}
LOGGER.info("RecipeController: Loaded " + _lists.size() + " Recipes.");
}
catch (Exception e)
{
if (lnr != null)
{
LOGGER.warning("error while creating recipe controller in linenr: " + lnr.getLineNumber() + " " + e);
}
else
{
LOGGER.warning("No recipes were found in data folder");
}
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
// TODO XMLize the recipe list
private void parseList(String line)
{
try
{
StringTokenizer st = new StringTokenizer(line, ";");
final List<L2RecipeInstance> recipePartList = new ArrayList<>();
// we use common/dwarf for easy reading of the recipes.csv file
String recipeTypeString = st.nextToken();
// now parse the string into a boolean
boolean isDwarvenRecipe;
if (recipeTypeString.equalsIgnoreCase("dwarven"))
{
isDwarvenRecipe = true;
}
else if (recipeTypeString.equalsIgnoreCase("common"))
{
isDwarvenRecipe = false;
}
else
{ // prints a helpfull message
LOGGER.warning("Error parsing recipes.csv, unknown recipe type " + recipeTypeString);
return;
}
String recipeName = st.nextToken();
final int id = Integer.parseInt(st.nextToken());
final int recipeId = Integer.parseInt(st.nextToken());
final int level = Integer.parseInt(st.nextToken());
// material
StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");
while (st2.hasMoreTokens())
{
StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");
final int rpItemId = Integer.parseInt(st3.nextToken());
final int quantity = Integer.parseInt(st3.nextToken());
L2RecipeInstance rp = new L2RecipeInstance(rpItemId, quantity);
recipePartList.add(rp);
}
final int itemId = Integer.parseInt(st.nextToken());
final int count = Integer.parseInt(st.nextToken());
// npc fee
/* String notdoneyet = */st.nextToken();
final int mpCost = Integer.parseInt(st.nextToken());
final int successRate = Integer.parseInt(st.nextToken());
L2RecipeList recipeList = new L2RecipeList(id, level, recipeId, recipeName, successRate, mpCost, itemId, count, isDwarvenRecipe);
for (L2RecipeInstance recipePart : recipePartList)
{
recipeList.addRecipe(recipePart);
}
_lists.put(new Integer(_lists.size()), recipeList);
}
catch (Exception e)
{
LOGGER.warning("Exception in RecipeController.parseList() " + e);
}
}
public int getRecipesCount()
{
return _lists.size();
}
public L2RecipeList getRecipeList(int listId)
{
return _lists.get(listId);
}
public L2RecipeList getRecipeByItemId(int itemId)
{
for (int i = 0; i < _lists.size(); i++)
{
final L2RecipeList find = _lists.get(new Integer(i));
if (find.getRecipeId() == itemId)
{
return find;
}
}
return null;
}
public L2RecipeList getRecipeById(int recId)
{
for (int i = 0; i < _lists.size(); i++)
{
final L2RecipeList find = _lists.get(new Integer(i));
if (find.getId() == recId)
{
return find;
}
}
return null;
}
}

View File

@@ -0,0 +1,155 @@
/*
* 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.datatables.csv;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.actor.instance.L2StaticObjectInstance;
public class StaticObjects
{
private static Logger LOGGER = Logger.getLogger(StaticObjects.class.getName());
private static StaticObjects _instance;
private final Map<Integer, L2StaticObjectInstance> _staticObjects;
public static StaticObjects getInstance()
{
if (_instance == null)
{
_instance = new StaticObjects();
}
return _instance;
}
public StaticObjects()
{
_staticObjects = new HashMap<>();
parseData();
LOGGER.info("StaticObject: Loaded " + _staticObjects.size() + " StaticObject Templates.");
}
private void parseData()
{
FileReader reader = null;
BufferedReader buff = null;
LineNumberReader lnr = null;
try
{
final File doorData = new File(Config.DATAPACK_ROOT, "data/csv/staticobjects.csv");
reader = new FileReader(doorData);
buff = new BufferedReader(reader);
lnr = new LineNumberReader(buff);
String line = null;
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
L2StaticObjectInstance obj = parse(line);
_staticObjects.put(obj.getStaticObjectId(), obj);
}
}
catch (FileNotFoundException e)
{
LOGGER.warning("staticobjects.csv is missing in data csv folder");
}
catch (Exception e)
{
LOGGER.warning("error while creating StaticObjects table " + e);
}
finally
{
if (lnr != null)
{
try
{
lnr.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (buff != null)
{
try
{
buff.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
}
public static L2StaticObjectInstance parse(String line)
{
StringTokenizer st = new StringTokenizer(line, ";");
st.nextToken(); // Pass over static object name (not used in server)
final int id = Integer.parseInt(st.nextToken());
final int x = Integer.parseInt(st.nextToken());
final int y = Integer.parseInt(st.nextToken());
final int z = Integer.parseInt(st.nextToken());
final int type = Integer.parseInt(st.nextToken());
final String texture = st.nextToken();
final int map_x = Integer.parseInt(st.nextToken());
final int map_y = Integer.parseInt(st.nextToken());
final L2StaticObjectInstance obj = new L2StaticObjectInstance(IdFactory.getInstance().getNextId());
obj.setType(type);
obj.setStaticObjectId(id);
obj.setXYZ(x, y, z);
obj.setMap(texture, map_x, map_y);
obj.spawnMe();
return obj;
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.datatables.csv;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.L2SummonItem;
public class SummonItemsData
{
private static Logger LOGGER = Logger.getLogger(SummonItemsData.class.getName());
private final Map<Integer, L2SummonItem> _summonitems;
private static SummonItemsData _instance;
public static SummonItemsData getInstance()
{
if (_instance == null)
{
_instance = new SummonItemsData();
}
return _instance;
}
public SummonItemsData()
{
_summonitems = new HashMap<>();
Scanner s = null;
try
{
s = new Scanner(new File(Config.DATAPACK_ROOT + "/data/csv/summon_items.csv"));
int lineCount = 0;
while (s.hasNextLine())
{
lineCount++;
String line = s.nextLine();
if (line.startsWith("#"))
{
continue;
}
else if (line.equals(""))
{
continue;
}
final String[] lineSplit = line.split(";");
boolean ok = true;
int itemID = 0, npcID = 0;
byte summonType = 0;
try
{
itemID = Integer.parseInt(lineSplit[0]);
npcID = Integer.parseInt(lineSplit[1]);
summonType = Byte.parseByte(lineSplit[2]);
}
catch (Exception e)
{
LOGGER.info("Summon items data: Error in line " + lineCount + " -> incomplete/invalid data or wrong seperator!");
LOGGER.info(" " + line);
ok = false;
}
if (!ok)
{
continue;
}
L2SummonItem summonitem = new L2SummonItem(itemID, npcID, summonType);
_summonitems.put(itemID, summonitem);
}
}
catch (Exception e)
{
LOGGER.info("Summon items data: Can not find './data/csv/summon_items.csv'");
}
finally
{
if (s != null)
{
s.close();
}
}
LOGGER.info("Summon items data: Loaded " + _summonitems.size() + " summon items.");
}
public L2SummonItem getSummonItem(int itemId)
{
return _summonitems.get(itemId);
}
public int[] itemIDs()
{
final int size = _summonitems.size();
final int[] result = new int[size];
int i = 0;
for (L2SummonItem si : _summonitems.values())
{
result[i] = si.getItemId();
i++;
}
return result;
}
}

View File

@@ -0,0 +1,239 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.AccessLevel;
/**
* @author FBIagent<br>
*/
public class AccessLevels
{
private static final Logger LOGGER = Logger.getLogger(AccessLevels.class.getName());
/**
* The one and only instance of this class, retriveable by getInstance()<br>
*/
private static AccessLevels _instance = null;
/**
* Reserved master access level<br>
*/
// public static final int _masterAccessLevelNum = Config.MASTERACCESS_LEVEL;
/**
* The master access level which can use everything<br>
*/
// L2EMU_EDIT - Rayan -
public AccessLevel _masterAccessLevel;/*
* = new AccessLevel(_masterAccessLevelNum, "Master Access", Config.MASTERACCESS_NAME_COLOR, Config.MASTERACCESS_TITLE_COLOR, true, true, true, true, true, true, true, true, true, true, true); //L2EMU_EDIT /** Reserved user access level<br>
*/
// public static final int _userAccessLevelNum = 0;
/**
* The user access level which can do no administrative tasks<br>
*/
// L2EMU_EDIT - Rayan -
public AccessLevel _userAccessLevel;/*
* = new AccessLevel(_userAccessLevelNum, "User", Integer.decode("0xFFFFFF"), Integer.decode("0xFFFFFF"), false, false, false, true, false, true, true, true, true, true, false); //L2EMU_EDIT /** Map of access levels defined in database<br>
*/
private final Map<Integer, AccessLevel> _accessLevels = new HashMap<>();
/**
* Loads the access levels from database<br>
*/
private AccessLevels()
{
_masterAccessLevel = new AccessLevel(Config.MASTERACCESS_LEVEL, "Master Access", Config.MASTERACCESS_NAME_COLOR, Config.MASTERACCESS_TITLE_COLOR, true, true, true, true, true, true, true, true, true, true, true);
_userAccessLevel = new AccessLevel(Config.USERACCESS_LEVEL, "User", Integer.decode("0xFFFFFF"), Integer.decode("0xFFFFFF"), false, false, false, true, false, true, true, true, true, true, false);
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement stmt = con.prepareStatement("SELECT * FROM `access_levels` ORDER BY `accessLevel` DESC");
final ResultSet rset = stmt.executeQuery();
int accessLevel = 0;
String name = null;
int nameColor = 0;
int titleColor = 0;
boolean isGm = false;
boolean allowPeaceAttack = false;
boolean allowFixedRes = false;
boolean allowTransaction = false;
boolean allowAltG = false;
boolean giveDamage = false;
boolean takeAggro = false;
boolean gainExp = false;
// L2EMU_ADD
boolean useNameColor = true;
boolean useTitleColor = false;
boolean canDisableGmStatus = true;
// L2EMU_ADD
while (rset.next())
{
accessLevel = rset.getInt("accessLevel");
name = rset.getString("name");
if (accessLevel == Config.USERACCESS_LEVEL)
{
LOGGER.info("AccessLevels: Access level with name " + name + " is using reserved user access level " + Config.USERACCESS_LEVEL + ". Ignoring it...");
continue;
}
else if (accessLevel == Config.MASTERACCESS_LEVEL)
{
LOGGER.info("AccessLevels: Access level with name " + name + " is using reserved master access level " + Config.MASTERACCESS_LEVEL + ". Ignoring it...");
continue;
}
else if (accessLevel < 0)
{
LOGGER.info("AccessLevels: Access level with name " + name + " is using banned access level state(below 0). Ignoring it...");
continue;
}
try
{
nameColor = Integer.decode("0x" + rset.getString("nameColor"));
}
catch (NumberFormatException nfe)
{
LOGGER.warning(nfe.getMessage());
try
{
nameColor = Integer.decode("0xFFFFFF");
}
catch (NumberFormatException nfe2)
{
LOGGER.warning(nfe.getMessage());
}
}
try
{
titleColor = Integer.decode("0x" + rset.getString("titleColor"));
}
catch (NumberFormatException nfe)
{
LOGGER.warning(nfe.getMessage());
try
{
titleColor = Integer.decode("0x77FFFF");
}
catch (NumberFormatException nfe2)
{
LOGGER.warning(nfe.getMessage());
}
}
isGm = rset.getBoolean("isGm");
allowPeaceAttack = rset.getBoolean("allowPeaceAttack");
allowFixedRes = rset.getBoolean("allowFixedRes");
allowTransaction = rset.getBoolean("allowTransaction");
allowAltG = rset.getBoolean("allowAltg");
giveDamage = rset.getBoolean("giveDamage");
takeAggro = rset.getBoolean("takeAggro");
gainExp = rset.getBoolean("gainExp");
// L2EMU_ADD - Rayan for temp access
useNameColor = rset.getBoolean("useNameColor");
useTitleColor = rset.getBoolean("useTitleColor");
canDisableGmStatus = rset.getBoolean("canDisableGmStatus");
// L2EMU_EDIT - Rayan for temp access
_accessLevels.put(accessLevel, new AccessLevel(accessLevel, name, nameColor, titleColor, isGm, allowPeaceAttack, allowFixedRes, allowTransaction, allowAltG, giveDamage, takeAggro, gainExp, useNameColor, useTitleColor, canDisableGmStatus));
// L2EMU_EDIT
}
rset.close();
stmt.close();
}
catch (SQLException e)
{
LOGGER.warning("AccessLevels: Error loading from database " + e);
}
// LOGGER.info("AccessLevels: Loaded " + _accessLevels.size() + " Access Levels from database.");
LOGGER.info("AccessLevels: Master Access Level is " + Config.MASTERACCESS_LEVEL);
LOGGER.info("AccessLevels: User Access Level is " + Config.USERACCESS_LEVEL);
if (Config.DEBUG)
{
for (int actual : _accessLevels.keySet())
{
final AccessLevel actual_access = _accessLevels.get(actual);
LOGGER.info("AccessLevels: " + actual_access.getName() + " Access Level is " + actual_access.getLevel());
}
}
}
/**
* Returns the one and only instance of this class<br>
* <br>
* @return AccessLevels: the one and only instance of this class<br>
*/
public static AccessLevels getInstance()
{
return _instance == null ? (_instance = new AccessLevels()) : _instance;
}
/**
* Returns the access level by characterAccessLevel<br>
* <br>
* @param accessLevelNum as int<br>
* <br>
* @return AccessLevel: AccessLevel instance by char access level<br>
*/
public AccessLevel getAccessLevel(int accessLevelNum)
{
AccessLevel accessLevel = null;
synchronized (_accessLevels)
{
accessLevel = _accessLevels.get(accessLevelNum);
}
return accessLevel;
}
public void addBanAccessLevel(int accessLevel)
{
synchronized (_accessLevels)
{
if (accessLevel > -1)
{
return;
}
// L2EMU_ADD - Rayan -
_accessLevels.put(accessLevel, new AccessLevel(accessLevel, "Banned", Integer.decode("0x000000"), Integer.decode("0x000000"), false, false, false, false, false, false, false, false, false, false, false));
// L2EMU_ADD
}
}
public static void reload()
{
_instance = null;
getInstance();
}
}

View File

@@ -0,0 +1,153 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.AccessLevel;
/**
* @author FBIagent<br>
*/
public class AdminCommandAccessRights
{
/**
* The logger<br>
*/
protected static final Logger LOGGER = Logger.getLogger(AdminCommandAccessRights.class.getName());
/**
* The one and only instance of this class, retriveable by getInstance()<br>
*/
private static AdminCommandAccessRights _instance = null;
/**
* The access rights<br>
*/
private final Map<String, Integer> adminCommandAccessRights = new HashMap<>();
/**
* Loads admin command access rights from database<br>
*/
private AdminCommandAccessRights()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement stmt = con.prepareStatement("SELECT * FROM admin_command_access_rights");
final ResultSet rset = stmt.executeQuery();
String adminCommand = null;
int accessLevels = 1;
while (rset.next())
{
adminCommand = rset.getString("adminCommand");
accessLevels = rset.getInt("accessLevels");
adminCommandAccessRights.put(adminCommand, accessLevels);
}
rset.close();
stmt.close();
}
catch (SQLException e)
{
LOGGER.warning("Admin Access Rights: Error loading from database " + e);
}
LOGGER.info("Admin Access Rights: Loaded " + adminCommandAccessRights.size() + " Access Rigths from database.");
}
/**
* Returns the one and only instance of this class<br>
* <br>
* @return AdminCommandAccessRights: the one and only instance of this class<br>
*/
public static AdminCommandAccessRights getInstance()
{
return _instance == null ? (_instance = new AdminCommandAccessRights()) : _instance;
}
public static void reload()
{
_instance = null;
getInstance();
}
public int accessRightForCommand(String command)
{
int out = -1;
if (adminCommandAccessRights.containsKey(command))
{
out = adminCommandAccessRights.get(command);
}
return out;
}
public boolean hasAccess(String adminCommand, AccessLevel accessLevel)
{
if (accessLevel.getLevel() <= 0)
{
return false;
}
if (!accessLevel.isGm())
{
return false;
}
if (accessLevel.getLevel() == Config.MASTERACCESS_LEVEL)
{
return true;
}
// L2EMU_ADD - Visor123 need parse command before check
String command = adminCommand;
if (adminCommand.indexOf(" ") != -1)
{
command = adminCommand.substring(0, adminCommand.indexOf(" "));
}
// L2EMU_ADD
int acar = 0;
if (adminCommandAccessRights.get(command) != null)
{
acar = adminCommandAccessRights.get(command);
}
if (acar == 0)
{
LOGGER.warning("Admin Access Rights: No rights defined for admin command " + command + ".");
return false;
}
else if (acar >= accessLevel.getLevel())
{
return true;
}
else
{
return false;
}
}
}

View File

@@ -0,0 +1,165 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2ArmorSet;
public class ArmorSetsTable
{
private static final Logger LOGGER = Logger.getLogger(ArmorSetsTable.class.getName());
private static ArmorSetsTable _instance;
public Map<Integer, L2ArmorSet> armorSets;
private final Map<Integer, ArmorDummy> cusArmorSets;
public static ArmorSetsTable getInstance()
{
if (_instance == null)
{
_instance = new ArmorSetsTable();
}
return _instance;
}
private ArmorSetsTable()
{
armorSets = new HashMap<>();
cusArmorSets = new HashMap<>();
loadData();
}
private void loadData()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT id, chest, legs, head, gloves, feet, skill_id, shield, shield_skill_id, enchant6skill FROM armorsets");
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
final int id = rset.getInt("id");
final int chest = rset.getInt("chest");
final int legs = rset.getInt("legs");
final int head = rset.getInt("head");
final int gloves = rset.getInt("gloves");
final int feet = rset.getInt("feet");
final int skill_id = rset.getInt("skill_id");
final int shield = rset.getInt("shield");
final int shield_skill_id = rset.getInt("shield_skill_id");
final int enchant6skill = rset.getInt("enchant6skill");
armorSets.put(chest, new L2ArmorSet(chest, legs, head, gloves, feet, skill_id, shield, shield_skill_id, enchant6skill));
cusArmorSets.put(id, new ArmorDummy(chest, legs, head, gloves, feet, skill_id, shield));
}
LOGGER.info("Loaded: " + armorSets.size() + " armor sets.");
rset.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while loading armor sets data " + e);
}
}
public boolean setExists(int chestId)
{
return armorSets.containsKey(chestId);
}
public L2ArmorSet getSet(int chestId)
{
return armorSets.get(chestId);
}
public void addObj(int v, L2ArmorSet s)
{
armorSets.put(v, s);
}
public ArmorDummy getCusArmorSets(int id)
{
return cusArmorSets.get(id);
}
public class ArmorDummy
{
private final int _chest;
private final int _legs;
private final int _head;
private final int _gloves;
private final int _feet;
private final int _skill_id;
private final int _shield;
public ArmorDummy(int chest, int legs, int head, int gloves, int feet, int skill_id, int shield)
{
_chest = chest;
_legs = legs;
_head = head;
_gloves = gloves;
_feet = feet;
_skill_id = skill_id;
_shield = shield;
}
public int getChest()
{
return _chest;
}
public int getLegs()
{
return _legs;
}
public int getHead()
{
return _head;
}
public int getGloves()
{
return _gloves;
}
public int getFeet()
{
return _feet;
}
public int getSkill_id()
{
return _skill_id;
}
public int getShield()
{
return _shield;
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
public class CharNameTable
{
private static final Logger LOGGER = Logger.getLogger(CharNameTable.class.getName());
private static CharNameTable _instance;
public static CharNameTable getInstance()
{
if (_instance == null)
{
_instance = new CharNameTable();
}
return _instance;
}
public synchronized boolean doesCharNameExist(String name)
{
boolean result = true;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT account_name FROM characters WHERE char_name=?");
statement.setString(1, name);
final ResultSet rset = statement.executeQuery();
result = rset.next();
statement.close();
rset.close();
}
catch (SQLException e)
{
LOGGER.warning("Could not check existing charname " + e);
}
return result;
}
public String getPlayerName(int objId)
{
String name = "";
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT char_name FROM characters WHERE obj_Id=?");
statement.setInt(1, objId);
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
name = rset.getString(1);
}
statement.close();
rset.close();
}
catch (SQLException e)
{
LOGGER.warning("Could not check existing player name " + e);
e.printStackTrace();
}
return name;
}
public int getPlayerObjectId(String name)
{
int id = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT obj_Id FROM characters WHERE char_name=?");
statement.setString(1, name);
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
id = rset.getInt(1);
}
statement.close();
rset.close();
}
catch (SQLException e)
{
LOGGER.warning("Could not check existing player id " + e);
e.printStackTrace();
}
return id;
}
public int getPlayerAccessLevel(int objId)
{
int accessLevel = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT accesslevel FROM characters WHERE obj_Id=?");
statement.setInt(1, objId);
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
accessLevel = rset.getInt(1);
}
statement.close();
rset.close();
}
catch (SQLException e)
{
LOGGER.warning("Could not check existing player id " + e);
e.printStackTrace();
}
return accessLevel;
}
public int accountCharNumber(String account)
{
int number = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT COUNT(char_name) FROM characters WHERE account_name=?");
statement.setString(1, account);
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
number = rset.getInt(1);
}
statement.close();
rset.close();
}
catch (SQLException e)
{
LOGGER.warning("Could not check existing char number " + e);
e.printStackTrace();
}
return number;
}
}

View File

@@ -0,0 +1,291 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.gameserver.templates.chars.L2PcTemplate;
/**
* @version $Revision: 1.6.2.1.2.10 $ $Date: 2005/03/29 14:00:54 $
*/
public class CharTemplateTable
{
private static Logger LOGGER = Logger.getLogger(CharTemplateTable.class.getName());
private static CharTemplateTable _instance;
private static final String[] CHAR_CLASSES =
{
"Human Fighter",
"Warrior",
"Gladiator",
"Warlord",
"Human Knight",
"Paladin",
"Dark Avenger",
"Rogue",
"Treasure Hunter",
"Hawkeye",
"Human Mystic",
"Human Wizard",
"Sorceror",
"Necromancer",
"Warlock",
"Cleric",
"Bishop",
"Prophet",
"Elven Fighter",
"Elven Knight",
"Temple Knight",
"Swordsinger",
"Elven Scout",
"Plainswalker",
"Silver Ranger",
"Elven Mystic",
"Elven Wizard",
"Spellsinger",
"Elemental Summoner",
"Elven Oracle",
"Elven Elder",
"Dark Fighter",
"Palus Knight",
"Shillien Knight",
"Bladedancer",
"Assassin",
"Abyss Walker",
"Phantom Ranger",
"Dark Elven Mystic",
"Dark Elven Wizard",
"Spellhowler",
"Phantom Summoner",
"Shillien Oracle",
"Shillien Elder",
"Orc Fighter",
"Orc Raider",
"Destroyer",
"Orc Monk",
"Tyrant",
"Orc Mystic",
"Orc Shaman",
"Overlord",
"Warcryer",
"Dwarven Fighter",
"Dwarven Scavenger",
"Bounty Hunter",
"Dwarven Artisan",
"Warsmith",
"dummyEntry1",
"dummyEntry2",
"dummyEntry3",
"dummyEntry4",
"dummyEntry5",
"dummyEntry6",
"dummyEntry7",
"dummyEntry8",
"dummyEntry9",
"dummyEntry10",
"dummyEntry11",
"dummyEntry12",
"dummyEntry13",
"dummyEntry14",
"dummyEntry15",
"dummyEntry16",
"dummyEntry17",
"dummyEntry18",
"dummyEntry19",
"dummyEntry20",
"dummyEntry21",
"dummyEntry22",
"dummyEntry23",
"dummyEntry24",
"dummyEntry25",
"dummyEntry26",
"dummyEntry27",
"dummyEntry28",
"dummyEntry29",
"dummyEntry30",
"Duelist",
"DreadNought",
"Phoenix Knight",
"Hell Knight",
"Sagittarius",
"Adventurer",
"Archmage",
"Soultaker",
"Arcana Lord",
"Cardinal",
"Hierophant",
"Eva Templar",
"Sword Muse",
"Wind Rider",
"Moonlight Sentinel",
"Mystic Muse",
"Elemental Master",
"Eva's Saint",
"Shillien Templar",
"Spectral Dancer",
"Ghost Hunter",
"Ghost Sentinel",
"Storm Screamer",
"Spectral Master",
"Shillien Saint",
"Titan",
"Grand Khauatari",
"Dominator",
"Doomcryer",
"Fortune Seeker",
"Maestro"
};
private final Map<Integer, L2PcTemplate> _templates;
public static CharTemplateTable getInstance()
{
if (_instance == null)
{
_instance = new CharTemplateTable();
}
return _instance;
}
private CharTemplateTable()
{
_templates = new HashMap<>();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM class_list, char_templates, lvlupgain WHERE class_list.id = char_templates.classId AND class_list.id = lvlupgain.classId ORDER BY class_list.id");
ResultSet rset = statement.executeQuery();
while (rset.next())
{
StatsSet set = new StatsSet();
// ClassId classId = ClassId.values()[rset.getInt("id")];
set.set("classId", rset.getInt("id"));
set.set("className", rset.getString("className"));
set.set("raceId", rset.getInt("raceId"));
set.set("baseSTR", rset.getInt("STR"));
set.set("baseCON", rset.getInt("CON"));
set.set("baseDEX", rset.getInt("DEX"));
set.set("baseINT", rset.getInt("_INT"));
set.set("baseWIT", rset.getInt("WIT"));
set.set("baseMEN", rset.getInt("MEN"));
set.set("baseHpMax", rset.getFloat("defaultHpBase"));
set.set("lvlHpAdd", rset.getFloat("defaultHpAdd"));
set.set("lvlHpMod", rset.getFloat("defaultHpMod"));
set.set("baseMpMax", rset.getFloat("defaultMpBase"));
set.set("baseCpMax", rset.getFloat("defaultCpBase"));
set.set("lvlCpAdd", rset.getFloat("defaultCpAdd"));
set.set("lvlCpMod", rset.getFloat("defaultCpMod"));
set.set("lvlMpAdd", rset.getFloat("defaultMpAdd"));
set.set("lvlMpMod", rset.getFloat("defaultMpMod"));
set.set("baseHpReg", 1.5);
set.set("baseMpReg", 0.9);
set.set("basePAtk", rset.getInt("p_atk"));
set.set("basePDef", /* classId.isMage()? 77 : 129 */rset.getInt("p_def"));
set.set("baseMAtk", rset.getInt("m_atk"));
set.set("baseMDef", rset.getInt("char_templates.m_def"));
set.set("classBaseLevel", rset.getInt("class_lvl"));
set.set("basePAtkSpd", rset.getInt("p_spd"));
set.set("baseMAtkSpd", /* classId.isMage()? 166 : 333 */rset.getInt("char_templates.m_spd"));
set.set("baseCritRate", rset.getInt("char_templates.critical") / 10);
set.set("baseRunSpd", rset.getInt("move_spd"));
set.set("baseWalkSpd", 0);
set.set("baseShldDef", 0);
set.set("baseShldRate", 0);
set.set("baseAtkRange", 40);
set.set("spawnX", rset.getInt("x"));
set.set("spawnY", rset.getInt("y"));
set.set("spawnZ", rset.getInt("z"));
L2PcTemplate ct;
set.set("collision_radius", rset.getDouble("m_col_r"));
set.set("collision_height", rset.getDouble("m_col_h"));
ct = new L2PcTemplate(set);
// 5items must go here
for (int x = 1; x < 6; x++)
{
if (rset.getInt("items" + x) != 0)
{
ct.addItem(rset.getInt("items" + x));
}
}
_templates.put(ct.classId.getId(), ct);
}
statement.close();
rset.close();
}
catch (SQLException e)
{
LOGGER.warning("error while loading char templates " + e.getMessage());
}
LOGGER.info("CharTemplateTable: Loaded " + _templates.size() + " Character Templates.");
}
public L2PcTemplate getTemplate(ClassId classId)
{
return getTemplate(classId.getId());
}
public L2PcTemplate getTemplate(int classId)
{
final int key = classId;
return _templates.get(key);
}
public static final String getClassNameById(int classId)
{
return CHAR_CLASSES[classId];
}
public static final int getClassIdByName(String className)
{
int currId = 1;
for (String name : CHAR_CLASSES)
{
if (name.equalsIgnoreCase(className))
{
break;
}
currId++;
}
return currId;
}
// public L2CharTemplate[] getAllTemplates()
// {
// return _templates.values().toArray(new L2CharTemplate[_templates.size()]);
// }
}

View File

@@ -0,0 +1,592 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.SiegeManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2ClanMember;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.siege.Fort;
import com.l2jmobius.gameserver.model.entity.siege.FortSiege;
import com.l2jmobius.gameserver.model.entity.siege.Siege;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.PledgeShowInfoUpdate;
import com.l2jmobius.gameserver.network.serverpackets.PledgeShowMemberListAll;
import com.l2jmobius.gameserver.network.serverpackets.PledgeShowMemberListUpdate;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.UserInfo;
import com.l2jmobius.gameserver.util.Util;
/**
* This class ...
* @version $Revision: 1.11.2.5.2.5 $ $Date: 2005/03/27 15:29:18 $
*/
public class ClanTable
{
private static Logger LOGGER = Logger.getLogger(ClanTable.class.getName());
private static ClanTable _instance;
private final Map<Integer, L2Clan> _clans;
public static ClanTable getInstance()
{
if (_instance == null)
{
_instance = new ClanTable();
}
return _instance;
}
public static void reload()
{
_instance = null;
getInstance();
}
public L2Clan[] getClans()
{
return _clans.values().toArray(new L2Clan[_clans.size()]);
}
public int getTopRate(int clan_id)
{
L2Clan clan = getClan(clan_id);
if (clan.getLevel() < 3)
{
return 0;
}
int i = 1;
for (L2Clan clans : getClans())
{
if (clan != clans)
{
if (clan.getLevel() < clans.getLevel())
{
i++;
}
else if (clan.getLevel() == clans.getLevel())
{
if (clan.getReputationScore() <= clans.getReputationScore())
{
i++;
}
}
}
}
return i;
}
private ClanTable()
{
_clans = new HashMap<>();
L2Clan clan;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT * FROM clan_data");
final ResultSet result = statement.executeQuery();
// Count the clans
int clanCount = 0;
while (result.next())
{
_clans.put(Integer.parseInt(result.getString("clan_id")), new L2Clan(Integer.parseInt(result.getString("clan_id"))));
clan = getClan(Integer.parseInt(result.getString("clan_id")));
if (clan.getDissolvingExpiryTime() != 0)
{
if (clan.getDissolvingExpiryTime() < System.currentTimeMillis())
{
destroyClan(clan.getClanId());
}
else
{
scheduleRemoveClan(clan.getClanId());
}
}
clan.setNoticeEnabled(result.getBoolean("enabled"));
clan.setNotice(result.getString("notice"));
clan.setIntroduction(result.getString("introduction"), false);
clanCount++;
}
result.close();
statement.close();
LOGGER.info("Restored " + clanCount + " clans from the database.");
}
catch (Exception e)
{
LOGGER.warning("Data error on ClanTable " + e);
}
restorewars();
}
/**
* @param clanId
* @return
*/
public L2Clan getClan(int clanId)
{
return _clans.get(clanId);
}
public L2Clan getClanByName(String clanName)
{
for (L2Clan clan : getClans())
{
if (clan.getName().equalsIgnoreCase(clanName))
{
return clan;
}
}
return null;
}
/**
* Creates a new clan and store clan info to database
* @param player
* @param clanName
* @return NULL if clan with same name already exists
*/
public L2Clan createClan(L2PcInstance player, String clanName)
{
if (null == player)
{
return null;
}
LOGGER.info("{" + player.getObjectId() + "}({" + player.getName() + "}) requested a clan creation.");
if (10 > player.getLevel())
{
player.sendPacket(SystemMessageId.YOU_DO_NOT_MEET_CRITERIA_IN_ORDER_TO_CREATE_A_CLAN);
return null;
}
if (0 != player.getClanId())
{
player.sendPacket(SystemMessageId.FAILED_TO_CREATE_CLAN);
return null;
}
if (System.currentTimeMillis() < player.getClanCreateExpiryTime())
{
player.sendPacket(SystemMessageId.YOU_MUST_WAIT_XX_DAYS_BEFORE_CREATING_A_NEW_CLAN);
return null;
}
if (!isValidCalnName(player, clanName))
{
return null;
}
final L2Clan clan = new L2Clan(IdFactory.getInstance().getNextId(), clanName);
final L2ClanMember leader = new L2ClanMember(clan, player.getName(), player.getLevel(), player.getClassId().getId(), player.getObjectId(), player.getPledgeType(), player.getPowerGrade(), player.getTitle());
clan.setLeader(leader);
leader.setPlayerInstance(player);
clan.store();
player.setClan(clan);
player.setPledgeClass(leader.calculatePledgeClass(player));
player.setClanPrivileges(L2Clan.CP_ALL);
LOGGER.info("New clan created: {" + clan.getClanId() + "} {" + clan.getName() + "}");
_clans.put(new Integer(clan.getClanId()), clan);
// should be update packet only
player.sendPacket(new PledgeShowInfoUpdate(clan));
player.sendPacket(new PledgeShowMemberListAll(clan, player));
player.sendPacket(new UserInfo(player));
player.sendPacket(new PledgeShowMemberListUpdate(player));
player.sendPacket(SystemMessageId.CLAN_CREATED);
return clan;
}
public boolean isValidCalnName(L2PcInstance player, String clanName)
{
if (!Util.isAlphaNumeric(clanName) || (clanName.length() < 2))
{
player.sendPacket(SystemMessageId.CLAN_NAME_INCORRECT);
return false;
}
if (clanName.length() > 16)
{
player.sendPacket(SystemMessageId.CLAN_NAME_TOO_LONG);
return false;
}
if (getClanByName(clanName) != null)
{
final SystemMessage sm = new SystemMessage(SystemMessageId.S1_ALREADY_EXISTS);
sm.addString(clanName);
player.sendPacket(sm);
return false;
}
Pattern pattern;
try
{
pattern = Pattern.compile(Config.CLAN_NAME_TEMPLATE);
}
catch (PatternSyntaxException e) // case of illegal pattern
{
LOGGER.warning("ERROR: Clan name pattern of config is wrong!");
pattern = Pattern.compile(".*");
}
final Matcher match = pattern.matcher(clanName);
if (!match.matches())
{
player.sendPacket(SystemMessageId.CLAN_NAME_INCORRECT);
return false;
}
return true;
}
public synchronized void destroyClan(int clanId)
{
final L2Clan clan = getClan(clanId);
if (clan == null)
{
return;
}
L2PcInstance leader = null;
if ((clan.getLeader() != null) && ((leader = clan.getLeader().getPlayerInstance()) != null))
{
if (Config.CLAN_LEADER_COLOR_ENABLED && (clan.getLevel() >= Config.CLAN_LEADER_COLOR_CLAN_LEVEL))
{
if (Config.CLAN_LEADER_COLORED == 1)
{
leader.getAppearance().setNameColor(0x000000);
}
else
{
leader.getAppearance().setTitleColor(0xFFFF77);
}
}
// remove clan leader skills
leader.addClanLeaderSkills(false);
}
clan.broadcastToOnlineMembers(new SystemMessage(SystemMessageId.CLAN_HAS_DISPERSED));
final int castleId = clan.getHasCastle();
if (castleId == 0)
{
for (Siege siege : SiegeManager.getInstance().getSieges())
{
siege.removeSiegeClan(clanId);
}
}
final int fortId = clan.getHasFort();
if (fortId == 0)
{
for (FortSiege siege : FortSiegeManager.getInstance().getSieges())
{
siege.removeSiegeClan(clanId);
}
}
final L2ClanMember leaderMember = clan.getLeader();
if (leaderMember == null)
{
clan.getWarehouse().destroyAllItems("ClanRemove", null, null);
}
else
{
clan.getWarehouse().destroyAllItems("ClanRemove", clan.getLeader().getPlayerInstance(), null);
}
for (L2ClanMember member : clan.getMembers())
{
clan.removeClanMember(member.getName(), 0);
}
final int leaderId = clan.getLeaderId();
final int clanLvl = clan.getLevel();
_clans.remove(clanId);
IdFactory.getInstance().releaseId(clanId);
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("DELETE FROM clan_data WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement = con.prepareStatement("DELETE FROM clan_privs WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement = con.prepareStatement("DELETE FROM clan_skills WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement = con.prepareStatement("DELETE FROM clan_subpledges WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement = con.prepareStatement("DELETE FROM clan_wars WHERE clan1=? OR clan2=?");
statement.setInt(1, clanId);
statement.setInt(2, clanId);
statement.execute();
if ((leader == null) && (leaderId != 0) && Config.CLAN_LEADER_COLOR_ENABLED && (clanLvl >= Config.CLAN_LEADER_COLOR_CLAN_LEVEL))
{
String query;
if (Config.CLAN_LEADER_COLORED == 1)
{
query = "UPDATE characters SET name_color = '000000' WHERE obj_Id = ?";
}
else
{
query = "UPDATE characters SET title_color = 'FFFF77' WHERE obj_Id = ?";
}
statement = con.prepareStatement(query);
statement.setInt(1, leaderId);
statement.execute();
}
if (castleId != 0)
{
statement = con.prepareStatement("UPDATE castle SET taxPercent = 0 WHERE id = ?");
statement.setInt(1, castleId);
statement.execute();
}
if (fortId != 0)
{
final Fort fort = FortManager.getInstance().getFortById(fortId);
if (fort != null)
{
final L2Clan owner = fort.getOwnerClan();
if (clan == owner)
{
fort.removeOwner(clan);
}
}
}
LOGGER.info("Clan removed in db: " + clanId);
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while removing clan in db " + e);
}
}
public void scheduleRemoveClan(int clanId)
{
ThreadPoolManager.schedule(() ->
{
if (getClan(clanId) == null)
{
return;
}
if (getClan(clanId).getDissolvingExpiryTime() != 0)
{
destroyClan(clanId);
}
}, getClan(clanId).getDissolvingExpiryTime() - System.currentTimeMillis());
}
public boolean isAllyExists(String allyName)
{
for (L2Clan clan : getClans())
{
if ((clan.getAllyName() != null) && clan.getAllyName().equalsIgnoreCase(allyName))
{
return true;
}
}
return false;
}
public void storeclanswars(int clanId1, int clanId2)
{
final L2Clan clan1 = ClanTable.getInstance().getClan(clanId1);
final L2Clan clan2 = ClanTable.getInstance().getClan(clanId2);
clan1.setEnemyClan(clan2);
clan2.setAttackerClan(clan1);
clan1.broadcastClanStatus();
clan2.broadcastClanStatus();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("REPLACE INTO clan_wars (clan1, clan2, wantspeace1, wantspeace2) VALUES(?,?,?,?)");
statement.setInt(1, clanId1);
statement.setInt(2, clanId2);
statement.setInt(3, 0);
statement.setInt(4, 0);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Could not store clans wars data " + e);
}
// SystemMessage msg = SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_BEGUN);
SystemMessage msg = new SystemMessage(SystemMessageId.CLAN_WAR_DECLARED_AGAINST_S1_IF_KILLED_LOSE_LOW_EXP);
msg.addString(clan2.getName());
clan1.broadcastToOnlineMembers(msg);
// msg = SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_BEGUN);
// msg.addString(clan1.getName());
// clan2.broadcastToOnlineMembers(msg);
// clan1 declared clan war.
msg = new SystemMessage(SystemMessageId.CLAN_S1_DECLARED_WAR);
msg.addString(clan1.getName());
clan2.broadcastToOnlineMembers(msg);
}
public void deleteclanswars(int clanId1, int clanId2)
{
final L2Clan clan1 = ClanTable.getInstance().getClan(clanId1);
final L2Clan clan2 = ClanTable.getInstance().getClan(clanId2);
clan1.deleteEnemyClan(clan2);
clan2.deleteAttackerClan(clan1);
clan1.broadcastClanStatus();
clan2.broadcastClanStatus();
// for(L2ClanMember player: clan1.getMembers())
// {
// if(player.getPlayerInstance()!=null)
// player.getPlayerInstance().setWantsPeace(0);
// }
// for(L2ClanMember player: clan2.getMembers())
// {
// if(player.getPlayerInstance()!=null)
// player.getPlayerInstance().setWantsPeace(0);
// }
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("DELETE FROM clan_wars WHERE clan1=? AND clan2=?");
statement.setInt(1, clanId1);
statement.setInt(2, clanId2);
statement.execute();
// statement = con.prepareStatement("DELETE FROM clan_wars WHERE clan1=? AND clan2=?");
// statement.setInt(1,clanId2);
// statement.setInt(2,clanId1);
// statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Could not restore clans wars data " + e);
}
// SystemMessage msg = SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_ENDED);
SystemMessage msg = new SystemMessage(SystemMessageId.WAR_AGAINST_S1_HAS_STOPPED);
msg.addString(clan2.getName());
clan1.broadcastToOnlineMembers(msg);
msg = new SystemMessage(SystemMessageId.CLAN_S1_HAS_DECIDED_TO_STOP);
msg.addString(clan1.getName());
clan2.broadcastToOnlineMembers(msg);
// msg = SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_ENDED);
// msg.addString(clan1.getName());
// clan2.broadcastToOnlineMembers(msg);
}
public void checkSurrender(L2Clan clan1, L2Clan clan2)
{
int count = 0;
for (L2ClanMember player : clan1.getMembers())
{
if ((player != null) && (player.getPlayerInstance().getWantsPeace() == 1))
{
count++;
}
}
if (count == (clan1.getMembers().length - 1))
{
clan1.deleteEnemyClan(clan2);
clan2.deleteEnemyClan(clan1);
deleteclanswars(clan1.getClanId(), clan2.getClanId());
}
}
private void restorewars()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT clan1, clan2, wantspeace1, wantspeace2 FROM clan_wars");
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
getClan(rset.getInt("clan1")).setEnemyClan(rset.getInt("clan2"));
getClan(rset.getInt("clan2")).setAttackerClan(rset.getInt("clan1"));
}
rset.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Could not restore clan wars data:");
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2ArmorSet;
/**
* @author ProGramMoS
*/
public final class CustomArmorSetsTable
{
private static final Logger LOGGER = Logger.getLogger(CustomArmorSetsTable.class.getName());
private static CustomArmorSetsTable _instance;
public static CustomArmorSetsTable getInstance()
{
if (_instance == null)
{
_instance = new CustomArmorSetsTable();
}
return _instance;
}
public CustomArmorSetsTable()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT chest, legs, head, gloves, feet, skill_id, shield, shield_skill_id, enchant6skill FROM custom_armorsets");
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
final int chest = rset.getInt("chest");
final int legs = rset.getInt("legs");
final int head = rset.getInt("head");
final int gloves = rset.getInt("gloves");
final int feet = rset.getInt("feet");
final int skill_id = rset.getInt("skill_id");
final int shield = rset.getInt("shield");
final int shield_skill_id = rset.getInt("shield_skill_id");
final int enchant6skill = rset.getInt("enchant6skill");
ArmorSetsTable.getInstance().addObj(chest, new L2ArmorSet(chest, legs, head, gloves, feet, skill_id, shield, shield_skill_id, enchant6skill));
}
LOGGER.info("ArmorSetsTable: Loaded custom armor sets.");
statement.close();
rset.close();
}
catch (Exception e)
{
LOGGER.warning("ArmorSetsTable: Error reading Custom ArmorSets table " + e);
}
}
}

View File

@@ -0,0 +1,239 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.csv.HennaTable;
import com.l2jmobius.gameserver.templates.L2HelperBuff;
import com.l2jmobius.gameserver.templates.StatsSet;
/**
* This class represents the Newbie Helper Buff list. Author: Ayor
*/
public class HelperBuffTable
{
private static final Logger LOGGER = Logger.getLogger(HennaTable.class.getName());
private static HelperBuffTable _instance;
/** The table containing all Buff of the Newbie Helper */
public List<L2HelperBuff> helperBuff;
private final boolean _initialized = true;
/**
* The player level since Newbie Helper can give the fisrt buff <BR>
* Used to generate message : "Come back here when you have reached level ...")
*/
private int _magicClassLowestLevel = 100;
private int _physicClassLowestLevel = 100;
/**
* The player level above which Newbie Helper won't give any buff <BR>
* Used to generate message : "Only novice character of level ... or less can receive my support magic.")
*/
private int _magicClassHighestLevel = 1;
private int _physicClassHighestLevel = 1;
public static HelperBuffTable getInstance()
{
if (_instance == null)
{
_instance = new HelperBuffTable();
}
return _instance;
}
public static void reload()
{
_instance = null;
getInstance();
}
/**
* Create and Load the Newbie Helper Buff list from SQL Table helper_buff_list
*/
private HelperBuffTable()
{
helperBuff = new ArrayList<>();
restoreHelperBuffData();
}
/**
* Read and Load the Newbie Helper Buff list from SQL Table helper_buff_list
*/
private void restoreHelperBuffData()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT * FROM helper_buff_list");
final ResultSet helperbuffdata = statement.executeQuery();
fillHelperBuffTable(helperbuffdata);
helperbuffdata.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Table helper_buff_list not found: Update your database " + e);
}
}
/**
* Load the Newbie Helper Buff list from SQL Table helper_buff_list
* @param HelperBuffData
* @throws Exception
*/
private void fillHelperBuffTable(ResultSet HelperBuffData) throws Exception
{
while (HelperBuffData.next())
{
final StatsSet helperBuffDat = new StatsSet();
final int id = HelperBuffData.getInt("id");
helperBuffDat.set("id", id);
helperBuffDat.set("skillID", HelperBuffData.getInt("skill_id"));
helperBuffDat.set("skillLevel", HelperBuffData.getInt("skill_level"));
helperBuffDat.set("lowerLevel", HelperBuffData.getInt("lower_level"));
helperBuffDat.set("upperLevel", HelperBuffData.getInt("upper_level"));
helperBuffDat.set("isMagicClass", HelperBuffData.getString("is_magic_class"));
// Calulate the range level in wich player must be to obtain buff from Newbie Helper
if ("false".equals(HelperBuffData.getString("is_magic_class")))
{
if (HelperBuffData.getInt("lower_level") < _physicClassLowestLevel)
{
_physicClassLowestLevel = HelperBuffData.getInt("lower_level");
}
if (HelperBuffData.getInt("upper_level") > _physicClassHighestLevel)
{
_physicClassHighestLevel = HelperBuffData.getInt("upper_level");
}
}
else
{
if (HelperBuffData.getInt("lower_level") < _magicClassLowestLevel)
{
_magicClassLowestLevel = HelperBuffData.getInt("lower_level");
}
if (HelperBuffData.getInt("upper_level") > _magicClassHighestLevel)
{
_magicClassHighestLevel = HelperBuffData.getInt("upper_level");
}
}
// Add this Helper Buff to the Helper Buff List
final L2HelperBuff template = new L2HelperBuff(helperBuffDat);
helperBuff.add(template);
}
LOGGER.info("Helper Buff Table: Loaded " + helperBuff.size() + " templates");
}
public boolean isInitialized()
{
return _initialized;
}
public L2HelperBuff getHelperBuffTableItem(int id)
{
return helperBuff.get(id);
}
/**
* @return the Helper Buff List
*/
public List<L2HelperBuff> getHelperBuffTable()
{
return helperBuff;
}
/**
* @return Returns the magicClassHighestLevel.
*/
public int getMagicClassHighestLevel()
{
return _magicClassHighestLevel;
}
/**
* @param magicClassHighestLevel The magicClassHighestLevel to set.
*/
public void setMagicClassHighestLevel(int magicClassHighestLevel)
{
_magicClassHighestLevel = magicClassHighestLevel;
}
/**
* @return Returns the magicClassLowestLevel.
*/
public int getMagicClassLowestLevel()
{
return _magicClassLowestLevel;
}
/**
* @param magicClassLowestLevel The magicClassLowestLevel to set.
*/
public void setMagicClassLowestLevel(int magicClassLowestLevel)
{
_magicClassLowestLevel = magicClassLowestLevel;
}
/**
* @return Returns the physicClassHighestLevel.
*/
public int getPhysicClassHighestLevel()
{
return _physicClassHighestLevel;
}
/**
* @param physicClassHighestLevel The physicClassHighestLevel to set.
*/
public void setPhysicClassHighestLevel(int physicClassHighestLevel)
{
_physicClassHighestLevel = physicClassHighestLevel;
}
/**
* @return Returns the physicClassLowestLevel.
*/
public int getPhysicClassLowestLevel()
{
return _physicClassLowestLevel;
}
/**
* @param physicClassLowestLevel The physicClassLowestLevel to set.
*/
public void setPhysicClassLowestLevel(int physicClassLowestLevel)
{
_physicClassLowestLevel = physicClassLowestLevel;
}
}

View File

@@ -0,0 +1,145 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.csv.HennaTable;
import com.l2jmobius.gameserver.model.actor.instance.L2HennaInstance;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.templates.item.L2Henna;
/**
* This class ...
* @version $Revision$ $Date$
*/
public class HennaTreeTable
{
private static Logger LOGGER = Logger.getLogger(HennaTreeTable.class.getName());
private static final HennaTreeTable _instance = new HennaTreeTable();
private final Map<ClassId, List<L2HennaInstance>> _hennaTrees;
private final boolean _initialized = true;
public static HennaTreeTable getInstance()
{
return _instance;
}
private HennaTreeTable()
{
_hennaTrees = new HashMap<>();
int classId = 0;
int count = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT class_name, id, parent_id FROM class_list ORDER BY id");
final ResultSet classlist = statement.executeQuery();
List<L2HennaInstance> list;
// int parentClassId;
// L2Henna henna;
classlist: while (classlist.next())
{
list = new ArrayList<>();
classId = classlist.getInt("id");
final PreparedStatement statement2 = con.prepareStatement("SELECT class_id, symbol_id FROM henna_trees where class_id=? ORDER BY symbol_id");
statement2.setInt(1, classId);
final ResultSet hennatree = statement2.executeQuery();
while (hennatree.next())
{
final int id = hennatree.getInt("symbol_id");
// String name = hennatree.getString("name");
final L2Henna template = HennaTable.getInstance().getTemplate(id);
if (template == null)
{
hennatree.close();
statement2.close();
classlist.close();
statement.close();
continue classlist;
}
final L2HennaInstance temp = new L2HennaInstance(template);
temp.setSymbolId(id);
temp.setItemIdDye(template.getDyeId());
temp.setAmountDyeRequire(template.getAmountDyeRequire());
temp.setPrice(template.getPrice());
temp.setStatINT(template.getStatINT());
temp.setStatSTR(template.getStatSTR());
temp.setStatCON(template.getStatCON());
temp.setStatMEM(template.getStatMEM());
temp.setStatDEX(template.getStatDEX());
temp.setStatWIT(template.getStatWIT());
list.add(temp);
}
_hennaTrees.put(ClassId.values()[classId], list);
hennatree.close();
statement2.close();
count += list.size();
if (Config.DEBUG)
{
LOGGER.info("Henna Tree for Class: " + classId + " has " + list.size() + " Henna Templates.");
}
}
classlist.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while creating henna tree for classId " + classId + " " + e);
}
LOGGER.info("HennaTreeTable: Loaded " + count + " Henna Tree Templates.");
}
public L2HennaInstance[] getAvailableHenna(ClassId classId)
{
final List<L2HennaInstance> henna = _hennaTrees.get(classId);
if (henna == null)
{
// the hennatree for this class is undefined, so we give an empty list
LOGGER.warning("Hennatree for class " + classId + " is not defined!");
return new L2HennaInstance[0];
}
return henna.toArray(new L2HennaInstance[henna.size()]);
}
public boolean isInitialized()
{
return _initialized;
}
}

View File

@@ -0,0 +1,452 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2PetData;
import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
public class L2PetDataTable
{
private static final Logger LOGGER = Logger.getLogger(L2PetInstance.class.getName());
private static L2PetDataTable _instance;
// private static final int[] PET_LIST = { 12077, 12312, 12313, 12311, 12527, 12528, 12526 };
private static Map<Integer, Map<Integer, L2PetData>> _petTable;
public static L2PetDataTable getInstance()
{
if (_instance == null)
{
_instance = new L2PetDataTable();
}
return _instance;
}
private L2PetDataTable()
{
_petTable = new HashMap<>();
}
public void loadPetsData()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT typeID, level, expMax, hpMax, mpMax, patk, pdef, matk, mdef, acc, evasion, crit, speed, atk_speed, cast_speed, feedMax, feedbattle, feednormal, loadMax, hpregen, mpregen, owner_exp_taken FROM pets_stats");
final ResultSet rset = statement.executeQuery();
int petId, petLevel;
while (rset.next())
{
petId = rset.getInt("typeID");
petLevel = rset.getInt("level");
// build the petdata for this level
final L2PetData petData = new L2PetData();
petData.setPetID(petId);
petData.setPetLevel(petLevel);
petData.setPetMaxExp(rset.getInt("expMax"));
petData.setPetMaxHP(rset.getInt("hpMax"));
petData.setPetMaxMP(rset.getInt("mpMax"));
petData.setPetPAtk(rset.getInt("patk"));
petData.setPetPDef(rset.getInt("pdef"));
petData.setPetMAtk(rset.getInt("matk"));
petData.setPetMDef(rset.getInt("mdef"));
petData.setPetAccuracy(rset.getInt("acc"));
petData.setPetEvasion(rset.getInt("evasion"));
petData.setPetCritical(rset.getInt("crit"));
petData.setPetSpeed(rset.getInt("speed"));
petData.setPetAtkSpeed(rset.getInt("atk_speed"));
petData.setPetCastSpeed(rset.getInt("cast_speed"));
petData.setPetMaxFeed(rset.getInt("feedMax"));
petData.setPetFeedNormal(rset.getInt("feednormal"));
petData.setPetFeedBattle(rset.getInt("feedbattle"));
petData.setPetMaxLoad(rset.getInt("loadMax"));
petData.setPetRegenHP(rset.getInt("hpregen"));
petData.setPetRegenMP(rset.getInt("mpregen"));
petData.setPetRegenMP(rset.getInt("mpregen"));
petData.setOwnerExpTaken(rset.getFloat("owner_exp_taken"));
// if its the first data for this petid, we initialize its level Map
if (!_petTable.containsKey(petId))
{
_petTable.put(petId, new HashMap<Integer, L2PetData>());
}
_petTable.get(petId).put(petLevel, petData);
}
rset.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Could not load pets stats " + e);
}
}
public void addPetData(L2PetData petData)
{
final Map<Integer, L2PetData> h = _petTable.get(petData.getPetID());
if (h == null)
{
final Map<Integer, L2PetData> statTable = new HashMap<>();
statTable.put(petData.getPetLevel(), petData);
_petTable.put(petData.getPetID(), statTable);
return;
}
h.put(petData.getPetLevel(), petData);
}
public void addPetData(L2PetData[] petLevelsList)
{
for (L2PetData element : petLevelsList)
{
addPetData(element);
}
}
public L2PetData getPetData(int petID, int petLevel)
{
// LOGGER.info("Getting id "+petID+" level "+ petLevel);
return _petTable.get(petID).get(petLevel);
}
/**
* Pets stuffs
* @param npcId
* @return
*/
public static boolean isWolf(int npcId)
{
return npcId == 12077;
}
public static boolean isSinEater(int npcId)
{
return npcId == 12564;
}
public static boolean isHatchling(int npcId)
{
return (npcId > 12310) && (npcId < 12314);
}
public static boolean isStrider(int npcId)
{
return (npcId > 12525) && (npcId < 12529);
}
public static boolean isWyvern(int npcId)
{
return npcId == 12621;
}
public static boolean isBaby(int npcId)
{
return (npcId > 12779) && (npcId < 12783);
}
public static boolean isPetFood(int itemId)
{
return (itemId == 2515) || (itemId == 4038) || (itemId == 5168) || (itemId == 5169) || (itemId == 6316) || (itemId == 7582);
}
public static boolean isWolfFood(int itemId)
{
return itemId == 2515;
}
public static boolean isSinEaterFood(int itemId)
{
return itemId == 2515;
}
public static boolean isHatchlingFood(int itemId)
{
return itemId == 4038;
}
public static boolean isStriderFood(int itemId)
{
return (itemId == 5168) || (itemId == 5169);
}
public static boolean isWyvernFood(int itemId)
{
return itemId == 6316;
}
public static boolean isBabyFood(int itemId)
{
return itemId == 7582;
}
public static int getFoodItemId(int npcId)
{
if (isWolf(npcId))
{
return 2515;
}
else if (isSinEater(npcId))
{
return 2515;
}
else if (isHatchling(npcId))
{
return 4038;
}
else if (isStrider(npcId))
{
return 5168;
}
else if (isBaby(npcId))
{
return 7582;
}
else
{
return 0;
}
}
public static int getPetIdByItemId(int itemId)
{
switch (itemId)
{
// wolf pet a
case 2375:
{
return 12077;
}
// Sin Eater
case 4425:
{
return 12564;
}
// hatchling of wind
case 3500:
{
return 12311;
}
// hatchling of star
case 3501:
{
return 12312;
}
// hatchling of twilight
case 3502:
{
return 12313;
}
// wind strider
case 4422:
{
return 12526;
}
// Star strider
case 4423:
{
return 12527;
}
// Twilight strider
case 4424:
{
return 12528;
}
// Wyvern
case 8663:
{
return 12621;
}
// Baby Buffalo
case 6648:
{
return 12780;
}
// Baby Cougar
case 6649:
{
return 12782;
}
// Baby Kookaburra
case 6650:
{
return 12781;
}
// unknown item id.. should never happen
default:
{
return 0;
}
}
}
public static int getHatchlingWindId()
{
return 12311;
}
public static int getHatchlingStarId()
{
return 12312;
}
public static int getHatchlingTwilightId()
{
return 12313;
}
public static int getStriderWindId()
{
return 12526;
}
public static int getStriderStarId()
{
return 12527;
}
public static int getStriderTwilightId()
{
return 12528;
}
public static int getWyvernItemId()
{
return 8663;
}
public static int getStriderWindItemId()
{
return 4422;
}
public static int getStriderStarItemId()
{
return 4423;
}
public static int getStriderTwilightItemId()
{
return 4424;
}
public static int getSinEaterItemId()
{
return 4425;
}
public static boolean isPetItem(int itemId)
{
return (itemId == 2375 // wolf
) || (itemId == 4425 // Sin Eater
) || (itemId == 3500) || (itemId == 3501) || (itemId == 3502 // hatchlings
) || (itemId == 4422) || (itemId == 4423) || (itemId == 4424 // striders
) || (itemId == 8663 // Wyvern
) || (itemId == 6648) || (itemId == 6649) || (itemId == 6650); // Babies
}
public static int[] getPetItemsAsNpc(int npcId)
{
switch (npcId)
{
case 12077:// wolf pet a
{
return new int[]
{
2375
};
}
case 12564:// Sin Eater
{
return new int[]
{
4425
};
}
case 12311:// hatchling of wind
case 12312:// hatchling of star
case 12313:// hatchling of twilight
{
return new int[]
{
3500,
3501,
3502
};
}
case 12526:// wind strider
case 12527:// Star strider
case 12528:// Twilight strider
{
return new int[]
{
4422,
4423,
4424
};
}
case 12621:// Wyvern
{
return new int[]
{
8663
};
}
case 12780:// Baby Buffalo
case 12782:// Baby Cougar
case 12781:// Baby Kookaburra
{
return new int[]
{
6648,
6649,
6650
};
}
// unknown item id.. should never happen
default:
{
return new int[]
{
0
};
}
}
}
public static boolean isMountable(int npcId)
{
return (npcId == 12526 // wind strider
) || (npcId == 12527 // star strider
) || (npcId == 12528 // twilight strider
) || (npcId == 12621); // wyvern
}
}

View File

@@ -0,0 +1,117 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2LvlupData;
import com.l2jmobius.gameserver.model.base.ClassId;
/**
* This class ...
* @author NightMarez
* @version $Revision: 1.3.2.4.2.3 $ $Date: 2005/03/27 15:29:18 $
*/
public class LevelUpData
{
private static final String SELECT_ALL = "SELECT classid, defaulthpbase, defaulthpadd, defaulthpmod, defaultcpbase, defaultcpadd, defaultcpmod, defaultmpbase, defaultmpadd, defaultmpmod, class_lvl FROM lvlupgain";
private static final String CLASS_LVL = "class_lvl";
private static final String MP_MOD = "defaultmpmod";
private static final String MP_ADD = "defaultmpadd";
private static final String MP_BASE = "defaultmpbase";
private static final String HP_MOD = "defaulthpmod";
private static final String HP_ADD = "defaulthpadd";
private static final String HP_BASE = "defaulthpbase";
private static final String CP_MOD = "defaultcpmod";
private static final String CP_ADD = "defaultcpadd";
private static final String CP_BASE = "defaultcpbase";
private static final String CLASS_ID = "classid";
private static final Logger LOGGER = Logger.getLogger(LevelUpData.class.getName());
private static LevelUpData _instance;
private final Map<Integer, L2LvlupData> lvlTable;
public static LevelUpData getInstance()
{
if (_instance == null)
{
_instance = new LevelUpData();
}
return _instance;
}
private LevelUpData()
{
lvlTable = new HashMap<>();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement(SELECT_ALL);
final ResultSet rset = statement.executeQuery();
L2LvlupData lvlDat;
while (rset.next())
{
lvlDat = new L2LvlupData();
lvlDat.setClassid(rset.getInt(CLASS_ID));
lvlDat.setClassLvl(rset.getInt(CLASS_LVL));
lvlDat.setClassHpBase(rset.getFloat(HP_BASE));
lvlDat.setClassHpAdd(rset.getFloat(HP_ADD));
lvlDat.setClassHpModifier(rset.getFloat(HP_MOD));
lvlDat.setClassCpBase(rset.getFloat(CP_BASE));
lvlDat.setClassCpAdd(rset.getFloat(CP_ADD));
lvlDat.setClassCpModifier(rset.getFloat(CP_MOD));
lvlDat.setClassMpBase(rset.getFloat(MP_BASE));
lvlDat.setClassMpAdd(rset.getFloat(MP_ADD));
lvlDat.setClassMpModifier(rset.getFloat(MP_MOD));
lvlTable.put(new Integer(lvlDat.getClassid()), lvlDat);
}
statement.close();
rset.close();
LOGGER.info("LevelUpData: Loaded " + lvlTable.size() + " Character Level Up Templates.");
}
catch (Exception e)
{
LOGGER.warning("Error while creating Lvl up data table " + e);
}
}
/**
* @param classId
* @return
*/
public L2LvlupData getTemplate(int classId)
{
return lvlTable.get(classId);
}
public L2LvlupData getTemplate(ClassId classId)
{
return lvlTable.get(classId.getId());
}
}

View File

@@ -0,0 +1,778 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.model.L2DropCategory;
import com.l2jmobius.gameserver.model.L2DropData;
import com.l2jmobius.gameserver.model.L2MinionData;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.skills.BaseStats;
import com.l2jmobius.gameserver.skills.Stats;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.gameserver.templates.chars.L2NpcTemplate;
/**
* This class ...
* @version $Revision: 1.8.2.6.2.9 $ $Date: 2005/04/06 16:13:25 $
*/
public class NpcTable
{
private static final Logger LOGGER = Logger.getLogger(NpcTable.class.getName());
private static NpcTable _instance;
private final Map<Integer, L2NpcTemplate> npcs;
private boolean _initialized = false;
public static NpcTable getInstance()
{
if (_instance == null)
{
_instance = new NpcTable();
}
return _instance;
}
private NpcTable()
{
npcs = new HashMap<>();
restoreNpcData();
}
private void restoreNpcData()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM npc");
final ResultSet npcdata = statement.executeQuery();
fillNpcTable(npcdata, false);
npcdata.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Error creating NPC table. " + e);
}
if (Config.CUSTOM_NPC_TABLE)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM custom_npc");
final ResultSet npcdata = statement.executeQuery();
fillNpcTable(npcdata, true);
npcdata.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Error creating custom NPC table." + e);
}
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT npcid, skillid, level FROM npcskills");
final ResultSet npcskills = statement.executeQuery();
L2NpcTemplate npcDat = null;
L2Skill npcSkill = null;
while (npcskills.next())
{
final int mobId = npcskills.getInt("npcid");
npcDat = npcs.get(mobId);
if (npcDat == null)
{
continue;
}
final int skillId = npcskills.getInt("skillid");
final int level = npcskills.getInt("level");
if ((npcDat.race == null) && (skillId == 4416))
{
npcDat.setRace(level);
continue;
}
npcSkill = SkillTable.getInstance().getInfo(skillId, level);
if (npcSkill == null)
{
continue;
}
npcDat.addSkill(npcSkill);
}
npcskills.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Error reading NPC skills table." + e);
}
if (Config.CUSTOM_DROPLIST_TABLE)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM custom_droplist ORDER BY mobId, chance DESC");
final ResultSet dropData = statement.executeQuery();
int cCount = 0;
while (dropData.next())
{
final int mobId = dropData.getInt("mobId");
final L2NpcTemplate npcDat = npcs.get(mobId);
if (npcDat == null)
{
LOGGER.warning("NPCTable: CUSTOM DROPLIST No npc correlating with id: " + mobId);
continue;
}
final L2DropData dropDat = new L2DropData();
dropDat.setItemId(dropData.getInt("itemId"));
dropDat.setMinDrop(dropData.getInt("min"));
dropDat.setMaxDrop(dropData.getInt("max"));
dropDat.setChance(dropData.getInt("chance"));
final int category = dropData.getInt("category");
npcDat.addDropData(dropDat, category);
cCount++;
}
dropData.close();
statement.close();
LOGGER.info("CustomDropList : Added " + cCount + " custom droplist");
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Error reading NPC CUSTOM drop data." + e);
}
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM droplist ORDER BY mobId, chance DESC");
final ResultSet dropData = statement.executeQuery();
L2DropData dropDat = null;
L2NpcTemplate npcDat = null;
while (dropData.next())
{
final int mobId = dropData.getInt("mobId");
npcDat = npcs.get(mobId);
if (npcDat == null)
{
LOGGER.info("NPCTable: No npc correlating with id: " + mobId);
continue;
}
dropDat = new L2DropData();
dropDat.setItemId(dropData.getInt("itemId"));
dropDat.setMinDrop(dropData.getInt("min"));
dropDat.setMaxDrop(dropData.getInt("max"));
dropDat.setChance(dropData.getInt("chance"));
final int category = dropData.getInt("category");
npcDat.addDropData(dropDat, category);
}
dropData.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Error reading NPC drop data." + e);
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM skill_learn");
final ResultSet learndata = statement.executeQuery();
while (learndata.next())
{
final int npcId = learndata.getInt("npc_id");
final int classId = learndata.getInt("class_id");
final L2NpcTemplate npc = getTemplate(npcId);
if (npc == null)
{
LOGGER.warning("NPCTable: Error getting NPC template ID " + npcId + " while trying to load skill trainer data.");
continue;
}
if (classId >= ClassId.values().length)
{
LOGGER.warning("NPCTable: Error defining learning data for NPC " + npcId + ": specified classId " + classId + " is higher then max one " + (ClassId.values().length - 1) + " specified into ClassID Enum --> check your Database to be complient with it");
continue;
}
npc.addTeachInfo(ClassId.values()[classId]);
}
learndata.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Error reading NPC trainer data." + e);
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT * FROM minions");
final ResultSet minionData = statement.executeQuery();
L2MinionData minionDat = null;
L2NpcTemplate npcDat = null;
int cnt = 0;
while (minionData.next())
{
final int raidId = minionData.getInt("boss_id");
npcDat = npcs.get(raidId);
minionDat = new L2MinionData();
minionDat.setMinionId(minionData.getInt("minion_id"));
minionDat.setAmountMin(minionData.getInt("amount_min"));
minionDat.setAmountMax(minionData.getInt("amount_max"));
npcDat.addRaidData(minionDat);
cnt++;
}
minionData.close();
statement.close();
LOGGER.info("NpcTable: Loaded " + cnt + " Minions.");
}
catch (Exception e)
{
LOGGER.info("Error loading minion data");
e.printStackTrace();
}
_initialized = true;
}
private void fillNpcTable(ResultSet NpcData, boolean custom) throws Exception
{
while (NpcData.next())
{
final StatsSet npcDat = new StatsSet();
final int id = NpcData.getInt("id");
npcDat.set("npcId", id);
npcDat.set("idTemplate", NpcData.getInt("idTemplate"));
// Level: for special bosses could be different
int level = 0;
float diff = 0; // difference between setted value and retail one
boolean minion = false;
switch (id)
{
case 29002: // and minions
case 29003:
case 29004:
case 29005:
{
minion = true;
}
case 29001:// queenAnt
{
if (Config.QA_LEVEL > 0)
{
diff = Config.QA_LEVEL - NpcData.getInt("level");
level = Config.QA_LEVEL;
}
else
{
level = NpcData.getInt("level");
}
}
break;
case 29022:
{ // zaken
if (Config.ZAKEN_LEVEL > 0)
{
diff = Config.ZAKEN_LEVEL - NpcData.getInt("level");
level = Config.ZAKEN_LEVEL;
}
else
{
level = NpcData.getInt("level");
}
}
break;
case 29015: // and minions
case 29016:
case 29017:
case 29018:
{
minion = true;
}
case 29014:// orfen
{
if (Config.ORFEN_LEVEL > 0)
{
diff = Config.ORFEN_LEVEL - NpcData.getInt("level");
level = Config.ORFEN_LEVEL;
}
else
{
level = NpcData.getInt("level");
}
}
break;
case 29007: // and minions
case 29008:
case 290011:
{
minion = true;
}
case 29006: // core
{
if (Config.CORE_LEVEL > 0)
{
diff = Config.CORE_LEVEL - NpcData.getInt("level");
level = Config.CORE_LEVEL;
}
else
{
level = NpcData.getInt("level");
}
}
break;
default:
{
level = NpcData.getInt("level");
}
}
npcDat.set("level", level);
npcDat.set("jClass", NpcData.getString("class"));
npcDat.set("baseShldDef", 0);
npcDat.set("baseShldRate", 0);
npcDat.set("baseCritRate", 4);
npcDat.set("name", NpcData.getString("name"));
npcDat.set("serverSideName", NpcData.getBoolean("serverSideName"));
// npcDat.set("name", "");
npcDat.set("title", NpcData.getString("title"));
npcDat.set("serverSideTitle", NpcData.getBoolean("serverSideTitle"));
npcDat.set("collision_radius", NpcData.getDouble("collision_radius"));
npcDat.set("collision_height", NpcData.getDouble("collision_height"));
npcDat.set("sex", NpcData.getString("sex"));
npcDat.set("type", NpcData.getString("type"));
npcDat.set("baseAtkRange", NpcData.getInt("attackrange"));
// BOSS POWER CHANGES
double multi_value = 1;
if (diff >= 15)
{ // means that there is level customization
multi_value = multi_value * (diff / 10);
}
else if ((diff > 0) && (diff < 15))
{
multi_value = multi_value + (diff / 10);
}
if (minion)
{
multi_value = multi_value * Config.LEVEL_DIFF_MULTIPLIER_MINION; // allow to increase the power of a value
// that for example, at 40 diff levels is
// equal to
// value = ((40/10)*0.8) = 3,2 --> 220 % more
}
else
{
switch (id)
{
case 29001:
{// queenAnt
if (Config.QA_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.QA_POWER_MULTIPLIER;
}
}
break;
case 29022:
{ // zaken
if (Config.ZAKEN_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.ZAKEN_POWER_MULTIPLIER;
}
}
break;
case 29014:
{// orfen
if (Config.ORFEN_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.ORFEN_POWER_MULTIPLIER;
}
}
break;
case 29006:
{ // core
if (Config.CORE_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.CORE_POWER_MULTIPLIER;
}
}
break;
case 29019:
{ // antharas
if (Config.ANTHARAS_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.ANTHARAS_POWER_MULTIPLIER;
}
}
break;
case 29028:
{ // valakas
if (Config.VALAKAS_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.VALAKAS_POWER_MULTIPLIER;
}
}
break;
case 29020:
{ // baium
if (Config.BAIUM_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.BAIUM_POWER_MULTIPLIER;
}
}
break;
case 29045:
{ // frintezza
if (Config.FRINTEZZA_POWER_MULTIPLIER > 0)
{
multi_value = multi_value * Config.FRINTEZZA_POWER_MULTIPLIER;
}
}
break;
default:
{
}
}
}
npcDat.set("rewardExp", NpcData.getInt("exp") * multi_value);
npcDat.set("rewardSp", NpcData.getInt("sp") * multi_value);
npcDat.set("basePAtkSpd", NpcData.getInt("atkspd") * multi_value);
npcDat.set("baseMAtkSpd", NpcData.getInt("matkspd") * multi_value);
npcDat.set("baseHpMax", NpcData.getInt("hp") * multi_value);
npcDat.set("baseMpMax", NpcData.getInt("mp") * multi_value);
npcDat.set("baseHpReg", ((int) NpcData.getFloat("hpreg") * multi_value) > 0 ? NpcData.getFloat("hpreg") : 1.5 + ((level - 1) / 10.0));
npcDat.set("baseMpReg", ((int) NpcData.getFloat("mpreg") * multi_value) > 0 ? NpcData.getFloat("mpreg") : 0.9 + ((0.3 * (level - 1)) / 10.0));
npcDat.set("basePAtk", NpcData.getInt("patk") * multi_value);
npcDat.set("basePDef", NpcData.getInt("pdef") * multi_value);
npcDat.set("baseMAtk", NpcData.getInt("matk") * multi_value);
npcDat.set("baseMDef", NpcData.getInt("mdef") * multi_value);
npcDat.set("aggroRange", NpcData.getInt("aggro"));
npcDat.set("rhand", NpcData.getInt("rhand"));
npcDat.set("lhand", NpcData.getInt("lhand"));
npcDat.set("armor", NpcData.getInt("armor"));
npcDat.set("baseWalkSpd", NpcData.getInt("walkspd"));
npcDat.set("baseRunSpd", NpcData.getInt("runspd"));
// constants, until we have stats in DB
// constants, until we have stats in DB
npcDat.safeSet("baseSTR", NpcData.getInt("str"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
npcDat.safeSet("baseCON", NpcData.getInt("con"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
npcDat.safeSet("baseDEX", NpcData.getInt("dex"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
npcDat.safeSet("baseINT", NpcData.getInt("int"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
npcDat.safeSet("baseWIT", NpcData.getInt("wit"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
npcDat.safeSet("baseMEN", NpcData.getInt("men"), 0, BaseStats.MAX_STAT_VALUE, "Loading npc template id: " + NpcData.getInt("idTemplate"));
/*
* npcDat.set("baseSTR", NpcData.getInt("str")); npcDat.set("baseCON", NpcData.getInt("con")); npcDat.set("baseDEX", NpcData.getInt("dex")); npcDat.set("baseINT", NpcData.getInt("int")); npcDat.set("baseWIT", NpcData.getInt("wit")); npcDat.set("baseMEN", NpcData.getInt("men"));
*/
npcDat.set("baseCpMax", 0);
npcDat.set("factionId", NpcData.getString("faction_id"));
npcDat.set("factionRange", NpcData.getInt("faction_range"));
npcDat.set("isUndead", NpcData.getString("isUndead"));
npcDat.set("absorb_level", NpcData.getString("absorb_level"));
npcDat.set("absorb_type", NpcData.getString("absorb_type"));
final L2NpcTemplate template = new L2NpcTemplate(npcDat, custom);
template.addVulnerability(Stats.BOW_WPN_VULN, 1);
template.addVulnerability(Stats.BLUNT_WPN_VULN, 1);
template.addVulnerability(Stats.DAGGER_WPN_VULN, 1);
npcs.put(id, template);
}
LOGGER.info("NpcTable: Loaded " + npcs.size() + " Npc Templates.");
}
public void reloadNpc(int id)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
// save a copy of the old data
final L2NpcTemplate old = getTemplate(id);
final Map<Integer, L2Skill> skills = new HashMap<>();
skills.putAll(old.getSkills());
final List<L2DropCategory> categories = new ArrayList<>();
if (old.getDropData() != null)
{
categories.addAll(old.getDropData());
}
final ClassId[] classIds = old.getTeachInfo().clone();
final List<L2MinionData> minions = new ArrayList<>();
if (old.getMinionData() != null)
{
minions.addAll(old.getMinionData());
}
if (old.isCustom())
{
final PreparedStatement st = con.prepareStatement("SELECT * FROM custom_npc WHERE id=?");
st.setInt(1, id);
final ResultSet rs = st.executeQuery();
fillNpcTable(rs, true);
rs.close();
st.close();
}
else
{
final PreparedStatement st = con.prepareStatement("SELECT * FROM npc WHERE id=?");
st.setInt(1, id);
final ResultSet rs = st.executeQuery();
fillNpcTable(rs, false);
rs.close();
st.close();
}
// restore additional data from saved copy
final L2NpcTemplate created = getTemplate(id);
for (L2Skill skill : skills.values())
{
created.addSkill(skill);
}
for (ClassId classId : classIds)
{
created.addTeachInfo(classId);
}
for (L2MinionData minion : minions)
{
created.addRaidData(minion);
}
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Could not reload data for NPC " + id + " " + e);
}
}
// just wrapper
public void reloadAllNpc()
{
restoreNpcData();
}
public void saveNpc(StatsSet npc)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final Map<String, Object> set = npc.getSet();
String name = "";
String values = "";
final L2NpcTemplate old = getTemplate(npc.getInteger("npcId"));
for (Object obj : set.keySet())
{
name = (String) obj;
if (!name.equalsIgnoreCase("npcId"))
{
if (values != "")
{
values += ", ";
}
values += name + " = '" + set.get(name) + "'";
}
}
PreparedStatement statement = null;
if (old.isCustom())
{
statement = con.prepareStatement("UPDATE custom_npc SET " + values + " WHERE id = ?");
}
else
{
statement = con.prepareStatement("UPDATE npc SET " + values + " WHERE id = ?");
}
statement.setInt(1, npc.getInteger("npcId"));
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("NPCTable: Could not store new NPC data in database. " + e);
}
}
public boolean isInitialized()
{
return _initialized;
}
public void replaceTemplate(L2NpcTemplate npc)
{
npcs.put(npc.npcId, npc);
}
public L2NpcTemplate getTemplate(int id)
{
return npcs.get(id);
}
public L2NpcTemplate getTemplateByName(String name)
{
for (L2NpcTemplate npcTemplate : npcs.values())
{
if (npcTemplate.name.equalsIgnoreCase(name))
{
return npcTemplate;
}
}
return null;
}
public L2NpcTemplate[] getAllOfLevel(int lvl)
{
final List<L2NpcTemplate> list = new ArrayList<>();
for (L2NpcTemplate t : npcs.values())
{
if (t.level == lvl)
{
list.add(t);
}
}
return list.toArray(new L2NpcTemplate[list.size()]);
}
public L2NpcTemplate[] getAllMonstersOfLevel(int lvl)
{
final List<L2NpcTemplate> list = new ArrayList<>();
for (L2NpcTemplate t : npcs.values())
{
if ((t.level == lvl) && "L2Monster".equals(t.type))
{
list.add(t);
}
}
return list.toArray(new L2NpcTemplate[list.size()]);
}
public L2NpcTemplate[] getAllNpcStartingWith(String letter)
{
final List<L2NpcTemplate> list = new ArrayList<>();
for (L2NpcTemplate t : npcs.values())
{
if (t.name.startsWith(letter) && "L2Npc".equals(t.type))
{
list.add(t);
}
}
return list.toArray(new L2NpcTemplate[list.size()]);
}
/**
* @param classType
* @return
*/
public Set<Integer> getAllNpcOfClassType(String classType)
{
return null;
}
/**
* @param clazz
* @return
*/
public Set<Integer> getAllNpcOfL2jClass(Class<?> clazz)
{
return null;
}
/**
* @param aiType
* @return
*/
public Set<Integer> getAllNpcOfAiType(String aiType)
{
return null;
}
public Map<Integer, L2NpcTemplate> getAllTemplates()
{
return npcs;
}
}

View File

@@ -0,0 +1,123 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
public class PetNameTable
{
private static final Logger LOGGER = Logger.getLogger(PetNameTable.class.getName());
private static PetNameTable _instance;
public static PetNameTable getInstance()
{
if (_instance == null)
{
_instance = new PetNameTable();
}
return _instance;
}
public boolean doesPetNameExist(String name, int petNpcId)
{
boolean result = true;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT name FROM pets p, items i WHERE p.item_obj_id = i.object_id AND name=? AND i.item_id IN (?)");
statement.setString(1, name);
String cond = "";
for (int it : L2PetDataTable.getPetItemsAsNpc(petNpcId))
{
if (cond != "")
{
cond += ", ";
}
cond += it;
}
statement.setString(2, cond);
final ResultSet rset = statement.executeQuery();
result = rset.next();
rset.close();
statement.close();
}
catch (SQLException e)
{
LOGGER.warning("Could not check existing petname " + e);
}
return result;
}
public boolean isValidPetName(String name)
{
boolean result = true;
if (!isAlphaNumeric(name))
{
return result;
}
Pattern pattern;
try
{
pattern = Pattern.compile(Config.PET_NAME_TEMPLATE);
}
catch (PatternSyntaxException e) // case of illegal pattern
{
LOGGER.warning("ERROR : Pet name pattern of config is wrong!");
pattern = Pattern.compile(".*");
}
final Matcher regexp = pattern.matcher(name);
if (!regexp.matches())
{
result = false;
}
return result;
}
private boolean isAlphaNumeric(String text)
{
boolean result = true;
final char[] chars = text.toCharArray();
for (char aChar : chars)
{
if (!Character.isLetterOrDigit(aChar))
{
result = false;
break;
}
}
return result;
}
}

View File

@@ -0,0 +1,119 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2Skill;
/**
* @author l2jserver
*/
public class SkillSpellbookTable
{
private static final Logger LOGGER = Logger.getLogger(SkillTreeTable.class.getName());
private static SkillSpellbookTable _instance;
private static Map<Integer, Integer> skillSpellbooks;
public static SkillSpellbookTable getInstance()
{
if (_instance == null)
{
_instance = new SkillSpellbookTable();
}
return _instance;
}
private SkillSpellbookTable()
{
skillSpellbooks = new HashMap<>();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT skill_id, item_id FROM skill_spellbooks");
final ResultSet spbooks = statement.executeQuery();
while (spbooks.next())
{
skillSpellbooks.put(spbooks.getInt("skill_id"), spbooks.getInt("item_id"));
}
spbooks.close();
statement.close();
LOGGER.info("SkillSpellbookTable: Loaded " + skillSpellbooks.size() + " spellbooks");
}
catch (Exception e)
{
LOGGER.warning("Error while loading spellbook data " + e);
}
}
public int getBookForSkill(int skillId, int level)
{
if ((skillId == L2Skill.SKILL_DIVINE_INSPIRATION) && (level != -1))
{
switch (level)
{
case 1:
{
return 8618; // Ancient Book - Divine Inspiration (Modern Language Version)
}
case 2:
{
return 8619; // Ancient Book - Divine Inspiration (Original Language Version)
}
case 3:
{
return 8620; // Ancient Book - Divine Inspiration (Manuscript)
}
case 4:
{
return 8621; // Ancient Book - Divine Inspiration (Original Version)
}
default:
{
return -1;
}
}
}
if (!skillSpellbooks.containsKey(skillId))
{
return -1;
}
return skillSpellbooks.get(skillId);
}
public int getBookForSkill(L2Skill skill)
{
return getBookForSkill(skill.getId(), -1);
}
public int getBookForSkill(L2Skill skill, int level)
{
return getBookForSkill(skill.getId(), level);
}
}

View File

@@ -0,0 +1,718 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.model.L2EnchantSkillLearn;
import com.l2jmobius.gameserver.model.L2PledgeSkillLearn;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.L2SkillLearn;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.skills.holders.ISkillsHolder;
import com.l2jmobius.gameserver.skills.holders.PlayerSkillHolder;
/**
* This class ...
* @version $Revision: 1.13.2.2.2.8 $ $Date: 2005/04/06 16:13:25 $
*/
public class SkillTreeTable
{
private static final Logger LOGGER = Logger.getLogger(SkillTreeTable.class.getName());
private static SkillTreeTable _instance;
private Map<ClassId, Map<Integer, L2SkillLearn>> _skillTrees;
private List<L2SkillLearn> _fishingSkillTrees; // all common skills (teached by Fisherman)
private List<L2SkillLearn> _expandDwarfCraftSkillTrees; // list of special skill for dwarf (expand dwarf craft) learned by class teacher
private List<L2PledgeSkillLearn> _pledgeSkillTrees; // pledge skill list
private List<L2EnchantSkillLearn> _enchantSkillTrees; // enchant skill list
private SkillTreeTable()
{
int classId = 0;
int count = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT * FROM class_list ORDER BY id");
final ResultSet classlist = statement.executeQuery();
Map<Integer, L2SkillLearn> map;
int parentClassId;
L2SkillLearn skillLearn;
while (classlist.next())
{
map = new HashMap<>();
parentClassId = classlist.getInt("parent_id");
classId = classlist.getInt("id");
final PreparedStatement statement2 = con.prepareStatement("SELECT class_id, skill_id, level, name, sp, min_level FROM skill_trees where class_id=? ORDER BY skill_id, level");
statement2.setInt(1, classId);
final ResultSet skilltree = statement2.executeQuery();
if (parentClassId != -1)
{
final Map<Integer, L2SkillLearn> parentMap = getSkillTrees().get(ClassId.values()[parentClassId]);
map.putAll(parentMap);
}
int prevSkillId = -1;
while (skilltree.next())
{
final int id = skilltree.getInt("skill_id");
final int lvl = skilltree.getInt("level");
final String name = skilltree.getString("name");
final int minLvl = skilltree.getInt("min_level");
final int cost = skilltree.getInt("sp");
if (prevSkillId != id)
{
prevSkillId = id;
}
skillLearn = new L2SkillLearn(id, lvl, minLvl, name, cost, 0, 0);
map.put(SkillTable.getSkillHashCode(id, lvl), skillLearn);
}
getSkillTrees().put(ClassId.values()[classId], map);
skilltree.close();
statement2.close();
count += map.size();
LOGGER.info("SkillTreeTable: skill tree for class " + classId + " has " + map.size() + " skills.");
}
classlist.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Error while creating skill tree (Class ID " + classId + "): " + e);
}
LOGGER.info("SkillTreeTable: Loaded " + count + " skills.");
// Skill tree for fishing skill (from Fisherman)
int count2 = 0;
int count3 = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
_fishingSkillTrees = new ArrayList<>();
_expandDwarfCraftSkillTrees = new ArrayList<>();
final PreparedStatement statement = con.prepareStatement("SELECT skill_id, level, name, sp, min_level, costid, cost, isfordwarf FROM fishing_skill_trees ORDER BY skill_id, level");
final ResultSet skilltree2 = statement.executeQuery();
int prevSkillId = -1;
while (skilltree2.next())
{
final int id = skilltree2.getInt("skill_id");
final int lvl = skilltree2.getInt("level");
final String name = skilltree2.getString("name");
final int minLvl = skilltree2.getInt("min_level");
final int cost = skilltree2.getInt("sp");
final int costId = skilltree2.getInt("costid");
final int costCount = skilltree2.getInt("cost");
final int isDwarven = skilltree2.getInt("isfordwarf");
if (prevSkillId != id)
{
prevSkillId = id;
}
final L2SkillLearn skill = new L2SkillLearn(id, lvl, minLvl, name, cost, costId, costCount);
if (isDwarven == 0)
{
_fishingSkillTrees.add(skill);
}
else
{
_expandDwarfCraftSkillTrees.add(skill);
}
}
skilltree2.close();
statement.close();
count2 = _fishingSkillTrees.size();
count3 = _expandDwarfCraftSkillTrees.size();
}
catch (Exception e)
{
LOGGER.warning("Error while creating fishing skill table " + e);
}
int count4 = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
_enchantSkillTrees = new ArrayList<>();
final PreparedStatement statement = con.prepareStatement("SELECT skill_id, level, name, base_lvl, sp, min_skill_lvl, exp, success_rate76, success_rate77, success_rate78,success_rate79,success_rate80 FROM enchant_skill_trees ORDER BY skill_id, level");
final ResultSet skilltree3 = statement.executeQuery();
int prevSkillId = -1;
while (skilltree3.next())
{
final int id = skilltree3.getInt("skill_id");
final int lvl = skilltree3.getInt("level");
final String name = skilltree3.getString("name");
final int baseLvl = skilltree3.getInt("base_lvl");
final int minSkillLvl = skilltree3.getInt("min_skill_lvl");
final int sp = skilltree3.getInt("sp");
final int exp = skilltree3.getInt("exp");
final byte rate76 = skilltree3.getByte("success_rate76");
final byte rate77 = skilltree3.getByte("success_rate77");
final byte rate78 = skilltree3.getByte("success_rate78");
final byte rate79 = skilltree3.getByte("success_rate79");
final byte rate80 = skilltree3.getByte("success_rate80");
if (prevSkillId != id)
{
prevSkillId = id;
}
_enchantSkillTrees.add(new L2EnchantSkillLearn(id, lvl, minSkillLvl, baseLvl, name, sp, exp, rate76, rate77, rate78, rate79, rate80));
}
skilltree3.close();
statement.close();
count4 = _enchantSkillTrees.size();
}
catch (Exception e)
{
LOGGER.warning("Error while creating enchant skill table " + e);
}
int count5 = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
_pledgeSkillTrees = new ArrayList<>();
final PreparedStatement statement = con.prepareStatement("SELECT skill_id, level, name, clan_lvl, repCost, itemId FROM pledge_skill_trees ORDER BY skill_id, level");
final ResultSet skilltree4 = statement.executeQuery();
int prevSkillId = -1;
while (skilltree4.next())
{
final int id = skilltree4.getInt("skill_id");
final int lvl = skilltree4.getInt("level");
final String name = skilltree4.getString("name");
final int baseLvl = skilltree4.getInt("clan_lvl");
final int sp = skilltree4.getInt("repCost");
final int itemId = skilltree4.getInt("itemId");
if (prevSkillId != id)
{
prevSkillId = id;
}
_pledgeSkillTrees.add(new L2PledgeSkillLearn(id, lvl, baseLvl, name, sp, itemId));
}
skilltree4.close();
statement.close();
count5 = _pledgeSkillTrees.size();
}
catch (Exception e)
{
LOGGER.warning("Error while creating fishing skill table " + e);
}
LOGGER.info("FishingSkillTreeTable: Loaded " + count2 + " general skills.");
LOGGER.info("FishingSkillTreeTable: Loaded " + count3 + " dwarven skills.");
LOGGER.info("EnchantSkillTreeTable: Loaded " + count4 + " enchant skills.");
LOGGER.info("PledgeSkillTreeTable: Loaded " + count5 + " pledge skills.");
}
public static SkillTreeTable getInstance()
{
if (_instance == null)
{
_instance = new SkillTreeTable();
}
return _instance;
}
/**
* Return the minimum level needed to have this Expertise.<BR>
* <BR>
* @param grade The grade level searched
* @return
*/
public int getExpertiseLevel(int grade)
{
if (grade <= 0)
{
return 0;
}
// since expertise comes at same level for all classes we use paladin for now
final Map<Integer, L2SkillLearn> learnMap = getSkillTrees().get(ClassId.paladin);
final int skillHashCode = SkillTable.getSkillHashCode(239, grade);
if (learnMap.containsKey(skillHashCode))
{
return learnMap.get(skillHashCode).getMinLevel();
}
return 0;
}
/**
* Each class receives new skill on certain levels, this methods allow the retrieval of the minimum character level of given class required to learn a given skill
* @param skillId The iD of the skill
* @param classId The classId of the character
* @param skillLvl The SkillLvl
* @return The min level
*/
public int getMinSkillLevel(int skillId, ClassId classId, int skillLvl)
{
final Map<Integer, L2SkillLearn> map = getSkillTrees().get(classId);
final int skillHashCode = SkillTable.getSkillHashCode(skillId, skillLvl);
if (map.containsKey(skillHashCode))
{
return map.get(skillHashCode).getMinLevel();
}
return 0;
}
public int getMinSkillLevel(int skillId, int skillLvl)
{
final int skillHashCode = SkillTable.getSkillHashCode(skillId, skillLvl);
// Look on all classes for this skill (takes the first one found)
for (Map<Integer, L2SkillLearn> map : getSkillTrees().values())
{
// checks if the current class has this skill
if (map.containsKey(skillHashCode))
{
return map.get(skillHashCode).getMinLevel();
}
}
return 0;
}
private Map<ClassId, Map<Integer, L2SkillLearn>> getSkillTrees()
{
if (_skillTrees == null)
{
_skillTrees = new HashMap<>();
}
return _skillTrees;
}
public L2SkillLearn[] getAvailableSkills(L2PcInstance player, ClassId classId)
{
final List<L2SkillLearn> result = getAvailableSkills(player, classId, player);
return result.toArray(new L2SkillLearn[result.size()]);
}
/**
* Gets the available skills.
* @param player the learning skill player.
* @param classId the learning skill class ID.
* @param holder
* @return all available skills for a given {@code player}, {@code classId}, {@code includeByFs} and {@code includeAutoGet}.
*/
private List<L2SkillLearn> getAvailableSkills(L2PcInstance player, ClassId classId, ISkillsHolder holder)
{
final List<L2SkillLearn> result = new ArrayList<>();
final Collection<L2SkillLearn> skills = getSkillTrees().get(classId).values();
if (skills.isEmpty())
{
// The Skill Tree for this class is undefined.
LOGGER.warning(getClass().getSimpleName() + ": Skilltree for class " + classId + " is not defined!");
return result;
}
for (L2SkillLearn skill : skills)
{
if (skill.getMinLevel() <= player.getLevel())
{
final L2Skill oldSkill = holder.getKnownSkill(skill.getId());
if (oldSkill != null)
{
if (oldSkill.getLevel() == (skill.getLevel() - 1))
{
result.add(skill);
}
}
else if (skill.getLevel() == 1)
{
result.add(skill);
}
}
}
return result;
}
public L2SkillLearn[] getAvailableSkills(L2PcInstance cha)
{
final List<L2SkillLearn> result = new ArrayList<>();
final List<L2SkillLearn> skills = new ArrayList<>();
skills.addAll(_fishingSkillTrees);
if (cha.hasDwarvenCraft() && (_expandDwarfCraftSkillTrees != null))
{
skills.addAll(_expandDwarfCraftSkillTrees);
}
final L2Skill[] oldSkills = cha.getAllSkills();
for (L2SkillLearn temp : skills)
{
if (temp.getMinLevel() <= cha.getLevel())
{
boolean knownSkill = false;
for (int j = 0; (j < oldSkills.length) && !knownSkill; j++)
{
if (oldSkills[j].getId() == temp.getId())
{
knownSkill = true;
if (oldSkills[j].getLevel() == (temp.getLevel() - 1))
{
// this is the next level of a skill that we know
result.add(temp);
}
}
}
if (!knownSkill && (temp.getLevel() == 1))
{
// this is a new skill
result.add(temp);
}
}
}
return result.toArray(new L2SkillLearn[result.size()]);
}
public L2EnchantSkillLearn[] getAvailableEnchantSkills(L2PcInstance cha)
{
final List<L2EnchantSkillLearn> result = new ArrayList<>();
final List<L2EnchantSkillLearn> skills = new ArrayList<>();
skills.addAll(_enchantSkillTrees);
final L2Skill[] oldSkills = cha.getAllSkills();
if (cha.getLevel() < 76)
{
return result.toArray(new L2EnchantSkillLearn[result.size()]);
}
for (L2EnchantSkillLearn skillLearn : skills)
{
boolean isKnownSkill = false;
for (L2Skill skill : oldSkills)
{
if (isKnownSkill)
{
continue;
}
if (skill.getId() == skillLearn.getId())
{
isKnownSkill = true;
if (skill.getLevel() == skillLearn.getMinSkillLevel())
{
// this is the next level of a skill that we know
result.add(skillLearn);
}
}
}
}
return result.toArray(new L2EnchantSkillLearn[result.size()]);
}
public L2PledgeSkillLearn[] getAvailablePledgeSkills(L2PcInstance cha)
{
final List<L2PledgeSkillLearn> result = new ArrayList<>();
final List<L2PledgeSkillLearn> skills = _pledgeSkillTrees;
if (skills == null)
{
// the skilltree for this class is undefined, so we give an empty list
LOGGER.warning("No clan skills defined!");
return new L2PledgeSkillLearn[0];
}
final L2Skill[] oldSkills = cha.getClan().getAllSkills();
for (L2PledgeSkillLearn temp : skills)
{
if (temp.getBaseLevel() <= cha.getClan().getLevel())
{
boolean knownSkill = false;
for (int j = 0; (j < oldSkills.length) && !knownSkill; j++)
{
if (oldSkills[j].getId() == temp.getId())
{
knownSkill = true;
if (oldSkills[j].getLevel() == (temp.getLevel() - 1))
{
// this is the next level of a skill that we know
result.add(temp);
}
}
}
if (!knownSkill && (temp.getLevel() == 1))
{
// this is a new skill
result.add(temp);
}
}
}
return result.toArray(new L2PledgeSkillLearn[result.size()]);
}
/**
* Returns all allowed skills for a given class.
* @param classId
* @return all allowed skills for a given class.
*/
public Collection<L2SkillLearn> getAllowedSkills(ClassId classId)
{
return getSkillTrees().get(classId).values();
}
public int getMinLevelForNewSkill(L2PcInstance cha, ClassId classId)
{
int minLevel = 0;
final Collection<L2SkillLearn> skills = getSkillTrees().get(classId).values();
for (L2SkillLearn temp : skills)
{
if ((temp.getMinLevel() > cha.getLevel()) && (temp.getSpCost() != 0))
{
if ((minLevel == 0) || (temp.getMinLevel() < minLevel))
{
minLevel = temp.getMinLevel();
}
}
}
return minLevel;
}
public int getMinLevelForNewSkill(L2PcInstance cha)
{
int minLevel = 0;
final List<L2SkillLearn> skills = new ArrayList<>();
skills.addAll(_fishingSkillTrees);
if (cha.hasDwarvenCraft() && (_expandDwarfCraftSkillTrees != null))
{
skills.addAll(_expandDwarfCraftSkillTrees);
}
for (L2SkillLearn s : skills)
{
if (s.getMinLevel() > cha.getLevel())
{
if ((minLevel == 0) || (s.getMinLevel() < minLevel))
{
minLevel = s.getMinLevel();
}
}
}
return minLevel;
}
public int getSkillCost(L2PcInstance player, L2Skill skill)
{
int skillCost = 100000000;
final ClassId classId = player.getSkillLearningClassId();
final int skillHashCode = SkillTable.getSkillHashCode(skill);
if (getSkillTrees().get(classId).containsKey(skillHashCode))
{
final L2SkillLearn skillLearn = getSkillTrees().get(classId).get(skillHashCode);
if (skillLearn.getMinLevel() <= player.getLevel())
{
skillCost = skillLearn.getSpCost();
if (!player.getClassId().equalsOrChildOf(classId))
{
if (skill.getCrossLearnAdd() < 0)
{
return skillCost;
}
skillCost += skill.getCrossLearnAdd();
skillCost *= skill.getCrossLearnMul();
}
if ((classId.getRace() != player.getRace()) && !player.isSubClassActive())
{
skillCost *= skill.getCrossLearnRace();
}
if (classId.isMage() != player.getClassId().isMage())
{
skillCost *= skill.getCrossLearnProf();
}
}
}
return skillCost;
}
public int getSkillSpCost(L2PcInstance player, L2Skill skill)
{
int skillCost = 100000000;
final L2EnchantSkillLearn[] enchantSkillLearnList = getAvailableEnchantSkills(player);
for (L2EnchantSkillLearn enchantSkillLearn : enchantSkillLearnList)
{
if (enchantSkillLearn.getId() != skill.getId())
{
continue;
}
if (enchantSkillLearn.getLevel() != skill.getLevel())
{
continue;
}
if (76 > player.getLevel())
{
continue;
}
skillCost = enchantSkillLearn.getSpCost();
}
return skillCost;
}
public int getSkillExpCost(L2PcInstance player, L2Skill skill)
{
int skillCost = 100000000;
final L2EnchantSkillLearn[] enchantSkillLearnList = getAvailableEnchantSkills(player);
for (L2EnchantSkillLearn enchantSkillLearn : enchantSkillLearnList)
{
if (enchantSkillLearn.getId() != skill.getId())
{
continue;
}
if (enchantSkillLearn.getLevel() != skill.getLevel())
{
continue;
}
if (76 > player.getLevel())
{
continue;
}
skillCost = enchantSkillLearn.getExp();
}
return skillCost;
}
public byte getSkillRate(L2PcInstance player, L2Skill skill)
{
final L2EnchantSkillLearn[] enchantSkillLearnList = getAvailableEnchantSkills(player);
for (L2EnchantSkillLearn enchantSkillLearn : enchantSkillLearnList)
{
if (enchantSkillLearn.getId() != skill.getId())
{
continue;
}
if (enchantSkillLearn.getLevel() != skill.getLevel())
{
continue;
}
return enchantSkillLearn.getRate(player);
}
return 0;
}
/**
* @param player
* @param classId
* @return
*/
public Collection<L2Skill> getAllAvailableSkills(L2PcInstance player, ClassId classId)
{
// Get available skills
int unLearnable = 0;
final PlayerSkillHolder holder = new PlayerSkillHolder(player.getSkills());
List<L2SkillLearn> learnable = getAvailableSkills(player, classId, holder);
while (learnable.size() > unLearnable)
{
for (L2SkillLearn s : learnable)
{
final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
if ((sk == null) || ((sk.getId() == L2Skill.SKILL_DIVINE_INSPIRATION) && !Config.AUTO_LEARN_DIVINE_INSPIRATION && !player.isGM()))
{
unLearnable++;
continue;
}
holder.addSkill(sk);
}
// Get new available skills, some skills depend of previous skills to be available.
learnable = getAvailableSkills(player, classId, holder);
}
return holder.getSkills().values();
}
}

View File

@@ -0,0 +1,396 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.spawn.L2Spawn;
import com.l2jmobius.gameserver.templates.chars.L2NpcTemplate;
/**
* This class ...
* @author Nightmare
* @version $Revision: 1.5.2.6.2.7 $ $Date: 2005/03/27 15:29:18 $
*/
public class SpawnTable
{
private static final Logger LOGGER = Logger.getLogger(SpawnTable.class.getName());
private static final SpawnTable _instance = new SpawnTable();
private final Map<Integer, L2Spawn> spawntable = new ConcurrentHashMap<>();
private int npcSpawnCount;
private int customSpawnCount;
private int _highestId;
public static SpawnTable getInstance()
{
return _instance;
}
private SpawnTable()
{
if (!Config.ALT_DEV_NO_SPAWNS)
{
fillSpawnTable();
}
}
public Map<Integer, L2Spawn> getSpawnTable()
{
return spawntable;
}
private void fillSpawnTable()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement;
if (Config.DELETE_GMSPAWN_ON_CUSTOM)
{
statement = con.prepareStatement("SELECT id, count, npc_templateid, locx, locy, locz, heading, respawn_delay, loc_id, periodOfDay FROM spawnlist where id NOT in ( select id from custom_notspawned where isCustom = false ) ORDER BY id");
}
else
{
statement = con.prepareStatement("SELECT id, count, npc_templateid, locx, locy, locz, heading, respawn_delay, loc_id, periodOfDay FROM spawnlist ORDER BY id");
}
final ResultSet rset = statement.executeQuery();
L2Spawn spawnDat;
L2NpcTemplate template1;
while (rset.next())
{
template1 = NpcTable.getInstance().getTemplate(rset.getInt("npc_templateid"));
if (template1 != null)
{
if (template1.type.equalsIgnoreCase("L2SiegeGuard"))
{
// Don't spawn
}
else if (template1.type.equalsIgnoreCase("L2RaidBoss"))
{
// Don't spawn raidboss
}
else if (template1.type.equalsIgnoreCase("L2GrandBoss"))
{
// Don't spawn grandboss
}
else if (!Config.ALLOW_CLASS_MASTERS && template1.type.equals("L2ClassMaster"))
{
// Dont' spawn class masters
}
else
{
spawnDat = new L2Spawn(template1);
spawnDat.setId(rset.getInt("id"));
spawnDat.setAmount(rset.getInt("count"));
spawnDat.setX(rset.getInt("locx"));
spawnDat.setY(rset.getInt("locy"));
spawnDat.setZ(rset.getInt("locz"));
spawnDat.setHeading(rset.getInt("heading"));
spawnDat.setRespawnDelay(rset.getInt("respawn_delay"));
final int loc_id = rset.getInt("loc_id");
spawnDat.setLocation(loc_id);
switch (rset.getInt("periodOfDay"))
{
case 0: // default
{
npcSpawnCount += spawnDat.init();
break;
}
case 1: // Day
{
DayNightSpawnManager.getInstance().addDayCreature(spawnDat);
npcSpawnCount++;
break;
}
case 2: // Night
{
DayNightSpawnManager.getInstance().addNightCreature(spawnDat);
npcSpawnCount++;
break;
}
}
spawntable.put(spawnDat.getId(), spawnDat);
if (spawnDat.getId() > _highestId)
{
_highestId = spawnDat.getId();
}
if (spawnDat.getTemplate().getNpcId() == Olympiad.OLY_MANAGER)
{
Olympiad.olymanagers.add(spawnDat);
}
}
}
else
{
LOGGER.warning("SpawnTable: Data missing in NPC table for ID: " + rset.getInt("npc_templateid") + ".");
}
}
rset.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("SpawnTable: Spawn could not be initialized. " + e);
}
LOGGER.info("SpawnTable: Loaded " + spawntable.size() + " Npc Spawn Locations. ");
LOGGER.info("SpawnTable: Total number of NPCs in the world: " + npcSpawnCount);
// -------------------------------Custom Spawnlist----------------------------//
if (Config.CUSTOM_SPAWNLIST_TABLE)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement;
if (Config.DELETE_GMSPAWN_ON_CUSTOM)
{
statement = con.prepareStatement("SELECT id, count, npc_templateid, locx, locy, locz, heading, respawn_delay, loc_id, periodOfDay FROM custom_spawnlist where id NOT in ( select id from custom_notspawned where isCustom = false ) ORDER BY id");
}
else
{
statement = con.prepareStatement("SELECT id, count, npc_templateid, locx, locy, locz, heading, respawn_delay, loc_id, periodOfDay FROM custom_spawnlist ORDER BY id");
}
// PreparedStatement statement = con.prepareStatement("SELECT id, count, npc_templateid, locx, locy, locz, heading, respawn_delay, loc_id, periodOfDay FROM custom_spawnlist ORDER BY id");
final ResultSet rset = statement.executeQuery();
L2Spawn spawnDat;
L2NpcTemplate template1;
while (rset.next())
{
template1 = NpcTable.getInstance().getTemplate(rset.getInt("npc_templateid"));
if (template1 != null)
{
if (template1.type.equalsIgnoreCase("L2SiegeGuard"))
{
// Don't spawn
}
else if (template1.type.equalsIgnoreCase("L2RaidBoss"))
{
// Don't spawn raidboss
}
else if (!Config.ALLOW_CLASS_MASTERS && template1.type.equals("L2ClassMaster"))
{
// Dont' spawn class masters
}
else
{
spawnDat = new L2Spawn(template1);
spawnDat.setId(rset.getInt("id"));
spawnDat.setAmount(rset.getInt("count"));
spawnDat.setX(rset.getInt("locx"));
spawnDat.setY(rset.getInt("locy"));
spawnDat.setZ(rset.getInt("locz"));
spawnDat.setHeading(rset.getInt("heading"));
spawnDat.setRespawnDelay(rset.getInt("respawn_delay"));
final int loc_id = rset.getInt("loc_id");
spawnDat.setLocation(loc_id);
switch (rset.getInt("periodOfDay"))
{
case 0: // default
{
customSpawnCount += spawnDat.init();
break;
}
case 1: // Day
{
DayNightSpawnManager.getInstance().addDayCreature(spawnDat);
customSpawnCount++;
break;
}
case 2: // Night
{
DayNightSpawnManager.getInstance().addNightCreature(spawnDat);
customSpawnCount++;
break;
}
}
spawntable.put(spawnDat.getId(), spawnDat);
if (spawnDat.getId() > _highestId)
{
_highestId = spawnDat.getId();
}
}
}
else
{
LOGGER.warning("CustomSpawnTable: Data missing in NPC table for ID: " + rset.getInt("npc_templateid") + ".");
}
}
rset.close();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("CustomSpawnTable: Spawn could not be initialized. " + e);
}
LOGGER.info("CustomSpawnTable: Loaded " + customSpawnCount + " Npc Spawn Locations. ");
LOGGER.info("CustomSpawnTable: Total number of NPCs in the world: " + customSpawnCount);
}
}
public L2Spawn getTemplate(int id)
{
return spawntable.get(id);
}
public void addNewSpawn(L2Spawn spawn, boolean storeInDb)
{
_highestId++;
spawn.setId(_highestId);
spawntable.put(_highestId, spawn);
if (storeInDb)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("INSERT INTO " + (spawn.isCustom() ? "custom_spawnlist" : "spawnlist") + "(id,count,npc_templateid,locx,locy,locz,heading,respawn_delay,loc_id) values(?,?,?,?,?,?,?,?,?)");
statement.setInt(1, spawn.getId());
statement.setInt(2, spawn.getAmount());
statement.setInt(3, spawn.getNpcId());
statement.setInt(4, spawn.getX());
statement.setInt(5, spawn.getY());
statement.setInt(6, spawn.getZ());
statement.setInt(7, spawn.getHeading());
statement.setInt(8, spawn.getRespawnDelay() / 1000);
statement.setInt(9, spawn.getLocation());
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("SpawnTable: Could not store spawn in the DB. " + e);
}
}
}
public void deleteSpawn(L2Spawn spawn, boolean updateDb)
{
if (spawntable.remove(spawn.getId()) == null)
{
return;
}
if (updateDb)
{
if (Config.DELETE_GMSPAWN_ON_CUSTOM)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("Replace into custom_notspawned VALUES (?,?)");
statement.setInt(1, spawn.getId());
statement.setBoolean(2, false);
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("SpawnTable: Spawn " + spawn.getId() + " could not be insert into DB. " + e);
}
}
else
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("DELETE FROM " + (spawn.isCustom() ? "custom_spawnlist" : "spawnlist") + " WHERE id=?");
statement.setInt(1, spawn.getId());
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("SpawnTable: Spawn " + spawn.getId() + " could not be removed from DB. " + e);
}
}
}
}
// just wrapper
public void reloadAll()
{
fillSpawnTable();
}
/**
* Get all the spawn of a NPC<BR>
* <BR>
* @param activeChar
* @param npcId : ID of the NPC to find.
* @param teleportIndex
*/
public void findNPCInstances(L2PcInstance activeChar, int npcId, int teleportIndex)
{
int index = 0;
for (L2Spawn spawn : spawntable.values())
{
if (npcId == spawn.getNpcId())
{
index++;
if (teleportIndex > -1)
{
if (teleportIndex == index)
{
activeChar.teleToLocation(spawn.getX(), spawn.getY(), spawn.getZ(), true);
}
}
else
{
activeChar.sendMessage(index + " - " + spawn.getTemplate().name + " (" + spawn.getId() + "): " + spawn.getX() + " " + spawn.getY() + " " + spawn.getZ());
}
}
}
if (index == 0)
{
activeChar.sendMessage("No current spawns found.");
}
}
public Map<Integer, L2Spawn> getAllTemplates()
{
return spawntable;
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2TeleportLocation;
/**
* This class ...
* @version $Revision: 1.3.2.2.2.3 $ $Date: 2005/03/27 15:29:18 $
*/
public class TeleportLocationTable
{
private static final Logger LOGGER = Logger.getLogger(TeleportLocationTable.class.getName());
private static TeleportLocationTable _instance;
private Map<Integer, L2TeleportLocation> teleports;
public static TeleportLocationTable getInstance()
{
if (_instance == null)
{
_instance = new TeleportLocationTable();
}
return _instance;
}
private TeleportLocationTable()
{
reloadAll();
}
public void reloadAll()
{
teleports = new HashMap<>();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT Description, id, loc_x, loc_y, loc_z, price, fornoble FROM teleport");
final ResultSet rset = statement.executeQuery();
L2TeleportLocation teleport;
while (rset.next())
{
teleport = new L2TeleportLocation();
teleport.setTeleId(rset.getInt("id"));
teleport.setX(rset.getInt("loc_x"));
teleport.setY(rset.getInt("loc_y"));
teleport.setZ(rset.getInt("loc_z"));
teleport.setPrice(rset.getInt("price"));
teleport.setIsForNoble(rset.getInt("fornoble") == 1);
teleports.put(teleport.getTeleId(), teleport);
}
statement.close();
rset.close();
LOGGER.info("TeleportLocationTable: Loaded " + teleports.size() + " Teleport Location Templates");
}
catch (Exception e)
{
LOGGER.warning("Error while creating teleport table " + e);
}
if (Config.CUSTOM_TELEPORT_TABLE)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT Description, id, loc_x, loc_y, loc_z, price, fornoble FROM custom_teleport");
final ResultSet rset = statement.executeQuery();
L2TeleportLocation teleport;
int _cTeleCount = teleports.size();
while (rset.next())
{
teleport = new L2TeleportLocation();
teleport.setTeleId(rset.getInt("id"));
teleport.setX(rset.getInt("loc_x"));
teleport.setY(rset.getInt("loc_y"));
teleport.setZ(rset.getInt("loc_z"));
teleport.setPrice(rset.getInt("price"));
teleport.setIsForNoble(rset.getInt("fornoble") == 1);
teleports.put(teleport.getTeleId(), teleport);
}
statement.close();
rset.close();
_cTeleCount = teleports.size() - _cTeleCount;
if (_cTeleCount > 0)
{
LOGGER.info("TeleportLocationTable: Loaded " + _cTeleCount + " Custom Teleport Location Templates.");
}
}
catch (Exception e)
{
LOGGER.warning("Error while creating custom teleport table " + e);
}
}
}
/**
* @param id
* @return
*/
public L2TeleportLocation getTemplate(int id)
{
return teleports.get(id);
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.TradeController;
import com.l2jmobius.gameserver.model.L2Territory;
public class TerritoryTable
{
private static final Logger LOGGER = Logger.getLogger(TradeController.class.getName());
private static Map<Integer, L2Territory> _territory = new HashMap<>();
public static TerritoryTable getInstance()
{
return SingletonHolder._instance;
}
public TerritoryTable()
{
_territory.clear();
// load all data at server start
reload_data();
}
public int[] getRandomPoint(Integer terr)
{
return _territory.get(terr).getRandomPoint();
}
public int getProcMax(Integer terr)
{
return _territory.get(terr).getProcMax();
}
public void reload_data()
{
_territory.clear();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("SELECT loc_id, loc_x, loc_y, loc_zmin, loc_zmax, proc FROM `locations`");
final ResultSet rset = statement.executeQuery();
while (rset.next())
{
// final String terr = "sql_terr_" + rset.getString("loc_id");
final int terr = rset.getInt("loc_id");
if (_territory.get(terr) == null)
{
final L2Territory t = new L2Territory();
_territory.put(terr, t);
}
_territory.get(terr).add(rset.getInt("loc_x"), rset.getInt("loc_y"), rset.getInt("loc_zmin"), rset.getInt("loc_zmax"), rset.getInt("proc"));
}
rset.close();
statement.close();
}
catch (Exception e1)
{
LOGGER.warning("Locations couldn't be initialized " + e1);
}
LOGGER.info("TerritoryTable: Loaded " + _territory.size() + " locations.");
}
private static class SingletonHolder
{
protected static final TerritoryTable _instance = new TerritoryTable();
}
}

View File

@@ -0,0 +1,323 @@
/*
* 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.datatables.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.xml.ItemTable;
import com.l2jmobius.gameserver.model.L2TradeList;
import com.l2jmobius.gameserver.model.actor.instance.L2ItemInstance;
/**
* This class manages buylists from database
* @version $Revision: 1.5.4.13 $ $Date: 2005/04/06 16:13:38 $
*/
public class TradeListTable
{
private static final Logger LOGGER = Logger.getLogger(TradeListTable.class.getName());
private static TradeListTable _instance;
private int _nextListId;
private final Map<Integer, L2TradeList> _lists;
/** Task launching the function for restore count of Item (Clan Hall) */
private class RestoreCount implements Runnable
{
private final int timer;
public RestoreCount(int time)
{
timer = time;
}
@Override
public void run()
{
restoreCount(timer);
dataTimerSave(timer);
ThreadPoolManager.schedule(new RestoreCount(timer), (long) timer * 60 * 60 * 1000);
}
}
public static TradeListTable getInstance()
{
if (_instance == null)
{
_instance = new TradeListTable();
}
return _instance;
}
private TradeListTable()
{
_lists = new HashMap<>();
load();
}
private void load(boolean custom)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement1 = con.prepareStatement("SELECT shop_id,npc_id FROM " + (custom ? "custom_merchant_shopids" : "merchant_shopids"));
final ResultSet rset1 = statement1.executeQuery();
while (rset1.next())
{
final PreparedStatement statement = con.prepareStatement("SELECT item_id, price, shop_id, order, count, time, currentCount FROM " + (custom ? "custom_merchant_buylists" : "merchant_buylists") + " WHERE shop_id=? ORDER BY order ASC");
statement.setString(1, String.valueOf(rset1.getInt("shop_id")));
final ResultSet rset = statement.executeQuery();
final L2TradeList buylist = new L2TradeList(rset1.getInt("shop_id"));
buylist.setNpcId(rset1.getString("npc_id"));
int _itemId = 0;
int _itemCount = 0;
int _price = 0;
if (!buylist.isGm() && (NpcTable.getInstance().getTemplate(rset1.getInt("npc_id")) == null))
{
LOGGER.warning("TradeListTable: Merchant id " + rset1.getString("npc_id") + " with buylist " + buylist.getListId() + " does not exist.");
}
try
{
while (rset.next())
{
_itemId = rset.getInt("item_id");
_price = rset.getInt("price");
final int count = rset.getInt("count");
final int currentCount = rset.getInt("currentCount");
final int time = rset.getInt("time");
final L2ItemInstance buyItem = ItemTable.getInstance().createDummyItem(_itemId);
if (buyItem == null)
{
continue;
}
_itemCount++;
if (count > -1)
{
buyItem.setCountDecrease(true);
}
buyItem.setPriceToSell(_price);
buyItem.setTime(time);
buyItem.setInitCount(count);
if (currentCount > -1)
{
buyItem.setCount(currentCount);
}
else
{
buyItem.setCount(count);
}
buylist.addItem(buyItem);
if (!buylist.isGm() && (buyItem.getReferencePrice() > _price))
{
LOGGER.warning("TradeListTable: Reference price of item " + _itemId + " in buylist " + buylist.getListId() + " higher then sell price.");
}
}
}
catch (Exception e)
{
LOGGER.warning("TradeListTable: Problem with buylist " + buylist.getListId() + ". " + e);
}
if (_itemCount > 0)
{
_lists.put(buylist.getListId(), buylist);
_nextListId = Math.max(_nextListId, buylist.getListId() + 1);
}
else
{
LOGGER.warning("TradeListTable: Empty buylist " + buylist.getListId() + ".");
}
statement.close();
rset.close();
}
rset1.close();
statement1.close();
LOGGER.info("TradeListTable: Loaded " + _lists.size() + " Buylists.");
/*
* Restore Task for reinitialize count of buy item
*/
try
{
int time = 0;
long savetimer = 0;
final long currentMillis = System.currentTimeMillis();
final PreparedStatement statement2 = con.prepareStatement("SELECT DISTINCT time, savetimer FROM " + (custom ? "merchant_buylists" : "merchant_buylists") + " WHERE time <> 0 ORDER BY time");
final ResultSet rset2 = statement2.executeQuery();
while (rset2.next())
{
time = rset2.getInt("time");
savetimer = rset2.getLong("savetimer");
if ((savetimer - currentMillis) > 0)
{
ThreadPoolManager.schedule(new RestoreCount(time), savetimer - System.currentTimeMillis());
}
else
{
ThreadPoolManager.schedule(new RestoreCount(time), 0);
}
}
rset2.close();
statement2.close();
}
catch (Exception e)
{
LOGGER.warning("TradeController: Could not restore Timer for Item count. " + e);
}
}
catch (Exception e)
{
// problem with initializing buylists, go to next one
LOGGER.warning("TradeListTable: Buylists could not be initialized. " + e);
}
}
public void load()
{
load(false); // not custom
load(true); // custom
}
public void reloadAll()
{
_lists.clear();
load();
}
public L2TradeList getBuyList(int listId)
{
if (_lists.containsKey(listId))
{
return _lists.get(listId);
}
return null;
}
public List<L2TradeList> getBuyListByNpcId(int npcId)
{
final List<L2TradeList> lists = new ArrayList<>();
for (L2TradeList list : _lists.values())
{
if (list.isGm())
{
continue;
}
/** if (npcId == list.getNpcId()) **/
lists.add(list);
}
return lists;
}
protected void restoreCount(int time)
{
if (_lists == null)
{
return;
}
for (L2TradeList list : _lists.values())
{
list.restoreCount(time);
}
}
protected void dataTimerSave(int time)
{
final long timerSave = System.currentTimeMillis() + ((long) time * 3600000); // 60*60*1000
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("UPDATE merchant_buylists SET savetimer =? WHERE time =?");
statement.setLong(1, timerSave);
statement.setInt(2, time);
statement.executeUpdate();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("TradeController: Could not update Timer save in Buylist. " + e);
}
}
public void dataCountStore()
{
if (_lists == null)
{
return;
}
int listId;
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
PreparedStatement statement;
for (L2TradeList list : _lists.values())
{
if (list == null)
{
continue;
}
listId = list.getListId();
for (L2ItemInstance Item : list.getItems())
{
if (Item.getCount() < Item.getInitCount()) // needed?
{
statement = con.prepareStatement("UPDATE merchant_buylists SET currentCount=? WHERE item_id=? AND shop_id=?");
statement.setInt(1, Item.getCount());
statement.setInt(2, Item.getItemId());
statement.setInt(3, listId);
statement.executeUpdate();
statement.close();
}
}
}
}
catch (Exception e)
{
LOGGER.warning("TradeController: Could not store Count Item. " + e);
}
}
}

View File

@@ -0,0 +1,750 @@
/*
* 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.datatables.xml;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.model.L2Augmentation;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jmobius.gameserver.skills.Stats;
/**
* This class manages the augmentation data and can also create new augmentations.
* @author durgus
*/
public class AugmentationData
{
private static final Logger LOGGER = Logger.getLogger(AugmentationData.class.getName());
// =========================================================
private static AugmentationData _instance;
public static final AugmentationData getInstance()
{
if (_instance == null)
{
_instance = new AugmentationData();
}
return _instance;
}
// =========================================================
// Data Field
// stats
private static final int STAT_START = 1;
private static final int STAT_END = 14560;
private static final int STAT_BLOCKSIZE = 3640;
// private static final int STAT_NUMBEROF_BLOCKS = 4;
private static final int STAT_SUBBLOCKSIZE = 91;
// private static final int STAT_NUMBEROF_SUBBLOCKS = 40;
// skills
private static final int BLUE_START = 14561;
// private static final int PURPLE_START = 14578;
// private static final int RED_START = 14685;
private static final int SKILLS_BLOCKSIZE = 178;
// basestats
private static final int BASESTAT_STR = 16341;
private static final int BASESTAT_CON = 16342;
private static final int BASESTAT_INT = 16343;
private static final int BASESTAT_MEN = 16344;
private final List<augmentationStat> _augmentationStats[];
private final Map<Integer, ArrayList<augmentationSkill>> _blueSkills;
private final Map<Integer, ArrayList<augmentationSkill>> _purpleSkills;
private final Map<Integer, ArrayList<augmentationSkill>> _redSkills;
// =========================================================
// Constructor
@SuppressWarnings("unchecked")
private AugmentationData()
{
LOGGER.info("Initializing AugmentationData.");
_augmentationStats = new ArrayList[4];
_augmentationStats[0] = new ArrayList<>();
_augmentationStats[1] = new ArrayList<>();
_augmentationStats[2] = new ArrayList<>();
_augmentationStats[3] = new ArrayList<>();
_blueSkills = new HashMap<>();
_purpleSkills = new HashMap<>();
_redSkills = new HashMap<>();
for (int i = 1; i <= 10; i++)
{
_blueSkills.put(i, new ArrayList<augmentationSkill>());
_purpleSkills.put(i, new ArrayList<augmentationSkill>());
_redSkills.put(i, new ArrayList<augmentationSkill>());
}
load();
// Use size*4: since theres 4 blocks of stat-data with equivalent size
LOGGER.info("AugmentationData: Loaded: " + (_augmentationStats[0].size() * 4) + " augmentation stats.");
if (Config.DEBUG)
{
for (int i = 1; i <= 10; i++)
{
LOGGER.info("AugmentationData: Loaded: " + _blueSkills.get(i).size() + " blue, " + _purpleSkills.get(i).size() + " purple and " + _redSkills.get(i).size() + " red skills for lifeStoneLevel " + i);
}
}
}
public static void reload()
{
_instance = null;
getInstance();
}
// =========================================================
// Nested Class
public class augmentationSkill
{
private final int _skillId;
private final int _maxSkillLevel;
private final int _augmentationSkillId;
public augmentationSkill(int skillId, int maxSkillLevel, int augmentationSkillId)
{
_skillId = skillId;
_maxSkillLevel = maxSkillLevel;
_augmentationSkillId = augmentationSkillId;
}
public L2Skill getSkill(int level)
{
if (level > _maxSkillLevel)
{
return SkillTable.getInstance().getInfo(_skillId, _maxSkillLevel);
}
return SkillTable.getInstance().getInfo(_skillId, level);
}
public int getAugmentationSkillId()
{
return _augmentationSkillId;
}
}
public class augmentationStat
{
private final Stats _stat;
private final int _singleSize;
private final int _combinedSize;
private final float _singleValues[];
private final float _combinedValues[];
public augmentationStat(Stats stat, float sValues[], float cValues[])
{
_stat = stat;
_singleSize = sValues.length;
_singleValues = sValues;
_combinedSize = cValues.length;
_combinedValues = cValues;
}
public int getSingleStatSize()
{
return _singleSize;
}
public int getCombinedStatSize()
{
return _combinedSize;
}
public float getSingleStatValue(int i)
{
if ((i >= _singleSize) || (i < 0))
{
return _singleValues[_singleSize - 1];
}
return _singleValues[i];
}
public float getCombinedStatValue(int i)
{
if ((i >= _combinedSize) || (i < 0))
{
return _combinedValues[_combinedSize - 1];
}
return _combinedValues[i];
}
public Stats getStat()
{
return _stat;
}
}
// =========================================================
// Method - Private
private final void load()
{
// Load the skillmap
// Note: the skillmap data is only used when generating new augmentations
// the client expects a different id in order to display the skill in the
// items description...
try
{
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
int badAugmantData = 0;
File file = new File(Config.DATAPACK_ROOT + "/data/stats/augmentation/augmentation_skillmap.xml");
if (!file.exists())
{
if (Config.DEBUG)
{
LOGGER.info("The augmentation skillmap file is missing.");
}
return;
}
Document doc = factory.newDocumentBuilder().parse(file);
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("augmentation".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
int skillId = 0;
final int augmentationId = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
String type = "blue";
int skillLvL = 0;
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("skillId".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
skillId = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
}
else if ("skillLevel".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
skillLvL = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
}
else if ("type".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
type = attrs.getNamedItem("val").getNodeValue();
}
}
if (skillId == 0)
{
if (Config.DEBUG)
{
LOGGER.warning("Bad skillId in augmentation_skillmap.xml in the augmentationId:" + augmentationId);
}
badAugmantData++;
continue;
}
else if (skillLvL == 0)
{
if (Config.DEBUG)
{
LOGGER.warning("Bad skillLevel in augmentation_skillmap.xml in the augmentationId:" + augmentationId);
}
badAugmantData++;
continue;
}
int k = 1;
while ((augmentationId - (k * SKILLS_BLOCKSIZE)) >= BLUE_START)
{
k++;
}
if (type.equalsIgnoreCase("blue"))
{
_blueSkills.get(k).add(new augmentationSkill(skillId, skillLvL, augmentationId));
}
else if (type.equalsIgnoreCase("purple"))
{
_purpleSkills.get(k).add(new augmentationSkill(skillId, skillLvL, augmentationId));
}
else
{
_redSkills.get(k).add(new augmentationSkill(skillId, skillLvL, augmentationId));
}
}
}
}
}
if (badAugmantData != 0)
{
LOGGER.info("AugmentationData: " + badAugmantData + " bad skill(s) were skipped.");
}
}
catch (Exception e)
{
LOGGER.warning("Error parsing augmentation_skillmap.xml. " + e);
return;
}
// Load the stats from xml
for (int i = 1; i < 5; i++)
{
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT + "/data/stats/augmentation/augmentation_stats" + i + ".xml");
if (!file.exists())
{
if (Config.DEBUG)
{
LOGGER.info("The augmentation stat data file " + i + " is missing.");
}
return;
}
Document doc = factory.newDocumentBuilder().parse(file);
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("stat".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
String statName = attrs.getNamedItem("name").getNodeValue();
float soloValues[] = null, combinedValues[] = null;
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("table".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
String tableName = attrs.getNamedItem("name").getNodeValue();
final StringTokenizer data = new StringTokenizer(cd.getFirstChild().getNodeValue());
final List<Float> array = new ArrayList<>();
while (data.hasMoreTokens())
{
array.add(Float.parseFloat(data.nextToken()));
}
if (tableName.equalsIgnoreCase("#soloValues"))
{
soloValues = new float[array.size()];
int x = 0;
for (float value : array)
{
soloValues[x++] = value;
}
}
else
{
combinedValues = new float[array.size()];
int x = 0;
for (float value : array)
{
combinedValues[x++] = value;
}
}
}
}
// store this stat
_augmentationStats[(i - 1)].add(new augmentationStat(Stats.valueOfXml(statName), soloValues, combinedValues));
}
}
}
}
}
catch (Exception e)
{
LOGGER.warning("Error parsing augmentation_stats" + i + ".xml. " + e);
return;
}
}
}
// =========================================================
// Properties - Public
/**
* Generate a new random augmentation
* @param item
* @param lifeStoneLevel
* @param lifeStoneGrade
* @return L2Augmentation
*/
public L2Augmentation generateRandomAugmentation(L2ItemInstance item, int lifeStoneLevel, int lifeStoneGrade)
{
// Note that stat12 stands for stat 1 AND 2 (same for stat34 ;p )
// this is because a value can contain up to 2 stat modifications
// (there are two short values packed in one integer value, meaning 4 stat modifications at max)
// for more info take a look at getAugStatsById(...)
// Note: lifeStoneGrade: (0 means low grade, 3 top grade)
// First: determine whether we will add a skill/baseStatModifier or not because this determine which color could be the result
int skill_Chance = 0;
int stat34 = 0;
boolean generateSkill = false;
int resultColor = 0;
boolean generateGlow = false;
switch (lifeStoneGrade)
{
case 0:
{
skill_Chance = Config.AUGMENTATION_NG_SKILL_CHANCE;
if (Rnd.get(1, 100) <= Config.AUGMENTATION_NG_GLOW_CHANCE)
{
generateGlow = true;
}
break;
}
case 1:
{
skill_Chance = Config.AUGMENTATION_MID_SKILL_CHANCE;
if (Rnd.get(1, 100) <= Config.AUGMENTATION_MID_GLOW_CHANCE)
{
generateGlow = true;
}
break;
}
case 2:
{
skill_Chance = Config.AUGMENTATION_HIGH_SKILL_CHANCE;
if (Rnd.get(1, 100) <= Config.AUGMENTATION_HIGH_GLOW_CHANCE)
{
generateGlow = true;
}
break;
}
case 3:
{
skill_Chance = Config.AUGMENTATION_TOP_SKILL_CHANCE;
if (Rnd.get(1, 100) <= Config.AUGMENTATION_TOP_GLOW_CHANCE)
{
generateGlow = true;
}
}
}
if (Rnd.get(1, 100) <= skill_Chance)
{
generateSkill = true;
}
else if (Rnd.get(1, 100) <= Config.AUGMENTATION_BASESTAT_CHANCE)
{
stat34 = Rnd.get(BASESTAT_STR, BASESTAT_MEN);
}
// Second: decide which grade the augmentation result is going to have:
// 0:yellow, 1:blue, 2:purple, 3:red
// The chances used here are most likely custom,
// whats known is: u can also get a red result from a normal grade lifeStone
// however I will make it so that a higher grade lifeStone will more likely result in a
// higher grade augmentation... and the augmentation result will at least have the grade
// of the life stone
// Second: Calculate the subblock offset for the choosen color,
// and the level of the lifeStone
// whats known is: you cant have yellow with skill(or baseStatModifier)
// noGrade stone can not have glow, mid only with skill, high has a chance(custom), top allways glow
if ((stat34 == 0) && !generateSkill)
{
resultColor = Rnd.get(0, 100);
if (resultColor <= ((15 * lifeStoneGrade) + 40))
{
resultColor = 1;
}
else
{
resultColor = 0;
}
}
else
{
resultColor = Rnd.get(0, 100);
if ((resultColor <= ((10 * lifeStoneGrade) + 5)) || (stat34 != 0))
{
resultColor = 3;
}
else if (resultColor <= ((10 * lifeStoneGrade) + 10))
{
resultColor = 1;
}
else
{
resultColor = 2;
}
}
// is neither a skill nor basestat used for stat34? then generate a normal stat
int stat12 = 0;
if ((stat34 == 0) && !generateSkill)
{
final int temp = Rnd.get(2, 3);
final int colorOffset = (resultColor * 10 * STAT_SUBBLOCKSIZE) + (temp * STAT_BLOCKSIZE) + 1;
int offset = ((lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE) + colorOffset;
stat34 = Rnd.get(offset, (offset + STAT_SUBBLOCKSIZE) - 1);
if (generateGlow && (lifeStoneGrade >= 2))
{
offset = ((lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE) + ((temp - 2) * STAT_BLOCKSIZE) + (lifeStoneGrade * 10 * STAT_SUBBLOCKSIZE) + 1;
}
else
{
offset = ((lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE) + ((temp - 2) * STAT_BLOCKSIZE) + (Rnd.get(0, 1) * 10 * STAT_SUBBLOCKSIZE) + 1;
}
stat12 = Rnd.get(offset, (offset + STAT_SUBBLOCKSIZE) - 1);
}
else
{
int offset;
if (!generateGlow)
{
offset = ((lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE) + (Rnd.get(0, 1) * STAT_BLOCKSIZE) + 1;
}
else
{
offset = ((lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE) + (Rnd.get(0, 1) * STAT_BLOCKSIZE) + (((lifeStoneGrade + resultColor) / 2) * 10 * STAT_SUBBLOCKSIZE) + 1;
}
stat12 = Rnd.get(offset, (offset + STAT_SUBBLOCKSIZE) - 1);
}
// generate a skill if neccessary
L2Skill skill = null;
if (generateSkill)
{
augmentationSkill temp = null;
switch (resultColor)
{
case 1: // blue skill
{
temp = _blueSkills.get(lifeStoneLevel).get(Rnd.get(0, _blueSkills.get(lifeStoneLevel).size() - 1));
skill = temp.getSkill(lifeStoneLevel);
stat34 = temp.getAugmentationSkillId();
break;
}
case 2: // purple skill
{
temp = _purpleSkills.get(lifeStoneLevel).get(Rnd.get(0, _purpleSkills.get(lifeStoneLevel).size() - 1));
skill = temp.getSkill(lifeStoneLevel);
stat34 = temp.getAugmentationSkillId();
break;
}
case 3: // red skill
{
temp = _redSkills.get(lifeStoneLevel).get(Rnd.get(0, _redSkills.get(lifeStoneLevel).size() - 1));
skill = temp.getSkill(lifeStoneLevel);
stat34 = temp.getAugmentationSkillId();
break;
}
}
}
if (Config.DEBUG)
{
LOGGER.info("Augmentation success: stat12=" + stat12 + "; stat34=" + stat34 + "; resultColor=" + resultColor + "; level=" + lifeStoneLevel + "; grade=" + lifeStoneGrade);
}
return new L2Augmentation(item, ((stat34 << 16) + stat12), skill, true);
}
public class AugStat
{
private final Stats _stat;
private final float _value;
public AugStat(Stats stat, float value)
{
_stat = stat;
_value = value;
}
public Stats getStat()
{
return _stat;
}
public float getValue()
{
return _value;
}
}
/**
* Returns the stat and basestat boni for a given augmentation id
* @param augmentationId
* @return
*/
public List<AugStat> getAugStatsById(int augmentationId)
{
final List<AugStat> temp = new ArrayList<>();
// An augmentation id contains 2 short vaues so we gotta seperate them here
// both values contain a number from 1-16380, the first 14560 values are stats
// the 14560 stats are devided into 4 blocks each holding 3640 values
// each block contains 40 subblocks holding 91 stat values
// the first 13 values are so called Solo-stats and they have the highest stat increase possible
// after the 13 Solo-stats come 78 combined stats (thats every possible combination of the 13 solo stats)
// the first 12 combined stats (14-26) is the stat 1 combined with stat 2-13
// the next 11 combined stats then are stat 2 combined with stat 3-13 and so on...
// to get the idea have a look @ optiondata_client-e.dat - thats where the data came from :)
final int stats[] = new int[2];
stats[0] = 0x0000FFFF & augmentationId;
stats[1] = augmentationId >> 16;
for (int i = 0; i < 2; i++)
{
// its a stat
if ((stats[i] >= STAT_START) && (stats[i] <= STAT_END))
{
int block = 0;
while (stats[i] > STAT_BLOCKSIZE)
{
stats[i] -= STAT_BLOCKSIZE;
block++;
}
int subblock = 0;
while (stats[i] > STAT_SUBBLOCKSIZE)
{
stats[i] -= STAT_SUBBLOCKSIZE;
subblock++;
}
if (stats[i] < 14) // solo stat
{
final augmentationStat as = _augmentationStats[block].get((stats[i] - 1));
temp.add(new AugStat(as.getStat(), as.getSingleStatValue(subblock)));
}
else
// twin stat
{
stats[i] -= 13; // rescale to 0 (if first of first combined block)
int x = 12; // next combi block has 12 stats
int rescales = 0; // number of rescales done
while (stats[i] > x)
{
stats[i] -= x;
x--;
rescales++;
}
// get first stat
augmentationStat as = _augmentationStats[block].get(rescales);
if (rescales == 0)
{
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(subblock)));
}
else
{
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue((subblock * 2) + 1)));
}
// get 2nd stat
as = _augmentationStats[block].get(rescales + stats[i]);
if (as.getStat() == Stats.CRITICAL_DAMAGE)
{
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(subblock)));
}
else
{
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(subblock * 2)));
}
}
}
// its a base stat
else if ((stats[i] >= BASESTAT_STR) && (stats[i] <= BASESTAT_MEN))
{
switch (stats[i])
{
case BASESTAT_STR:
{
temp.add(new AugStat(Stats.STAT_STR, 1.0f));
break;
}
case BASESTAT_CON:
{
temp.add(new AugStat(Stats.STAT_CON, 1.0f));
break;
}
case BASESTAT_INT:
{
temp.add(new AugStat(Stats.STAT_INT, 1.0f));
break;
}
case BASESTAT_MEN:
{
temp.add(new AugStat(Stats.STAT_MEN, 1.0f));
break;
}
}
}
}
return temp;
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.datatables.xml;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
/**
* Based on mrTJO's implementation.
* @author Zoey76
*/
public class ExperienceData
{
private static Logger LOGGER = Logger.getLogger(ExperienceData.class.getName());
private byte MAX_LEVEL;
private byte MAX_PET_LEVEL;
private final Map<Integer, Long> _expTable = new HashMap<>();
private ExperienceData()
{
loadData();
}
private void loadData()
{
final File xml = new File(Config.DATAPACK_ROOT, "data/stats/experience.xml");
if (!xml.exists())
{
LOGGER.warning(getClass().getSimpleName() + ": experience.xml not found!");
return;
}
Document doc = null;
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
try
{
doc = factory.newDocumentBuilder().parse(xml);
}
catch (Exception e)
{
LOGGER.warning("Could not parse experience.xml: " + e.getMessage());
return;
}
final Node table = doc.getFirstChild();
final NamedNodeMap tableAttr = table.getAttributes();
MAX_LEVEL = (byte) (Byte.parseByte(tableAttr.getNamedItem("maxLevel").getNodeValue()) + 1);
MAX_PET_LEVEL = (byte) (Byte.parseByte(tableAttr.getNamedItem("maxPetLevel").getNodeValue()) + 1);
_expTable.clear();
NamedNodeMap attrs;
Integer level;
Long exp;
for (Node experience = table.getFirstChild(); experience != null; experience = experience.getNextSibling())
{
if (experience.getNodeName().equals("experience"))
{
attrs = experience.getAttributes();
level = Integer.valueOf(attrs.getNamedItem("level").getNodeValue());
exp = Long.valueOf(attrs.getNamedItem("tolevel").getNodeValue());
_expTable.put(level, exp);
}
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _expTable.size() + " levels");
LOGGER.info(getClass().getSimpleName() + ": Max Player Level is: " + (MAX_LEVEL - 1));
LOGGER.info(getClass().getSimpleName() + ": Max Pet Level is: " + (MAX_PET_LEVEL - 1));
}
public long getExpForLevel(int level)
{
return _expTable.get(level);
}
public byte getMaxLevel()
{
return MAX_LEVEL;
}
public byte getMaxPetLevel()
{
return MAX_PET_LEVEL;
}
public static ExperienceData getInstance()
{
return SingletonHolder._instance;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ExperienceData _instance = new ExperienceData();
}
}

View File

@@ -0,0 +1,379 @@
/*
* 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.datatables.xml;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPoolManager;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.datatables.sql.L2PetDataTable;
import com.l2jmobius.gameserver.engines.DocumentEngine;
import com.l2jmobius.gameserver.engines.Item;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2ItemInstance.ItemLocation;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2RaidBossInstance;
import com.l2jmobius.gameserver.templates.item.L2Armor;
import com.l2jmobius.gameserver.templates.item.L2EtcItem;
import com.l2jmobius.gameserver.templates.item.L2Item;
import com.l2jmobius.gameserver.templates.item.L2Weapon;
/**
* This class ...
* @version $Revision: 1.9.2.6.2.9 $ $Date: 2005/04/02 15:57:34 $
*/
public class ItemTable
{
private static final Logger LOGGER = Logger.getLogger(ItemTable.class.getName());
private static final Logger _logItems = Logger.getLogger("item");
private L2Item[] _allTemplates;
private final Map<Integer, L2EtcItem> _etcItems;
private final Map<Integer, L2Armor> _armors;
private final Map<Integer, L2Weapon> _weapons;
private static final Map<String, Integer> _crystalTypes = new HashMap<>();
static
{
_crystalTypes.put("s", L2Item.CRYSTAL_S);
_crystalTypes.put("a", L2Item.CRYSTAL_A);
_crystalTypes.put("b", L2Item.CRYSTAL_B);
_crystalTypes.put("c", L2Item.CRYSTAL_C);
_crystalTypes.put("d", L2Item.CRYSTAL_D);
_crystalTypes.put("none", L2Item.CRYSTAL_NONE);
}
/**
* Returns instance of ItemTable
* @return ItemTable
*/
public static ItemTable getInstance()
{
return SingletonHolder._instance;
}
/**
* Returns a new object Item
* @return
*/
public Item newItem()
{
return new Item();
}
/**
* Constructor.
*/
private ItemTable()
{
_etcItems = new HashMap<>();
_armors = new HashMap<>();
_weapons = new HashMap<>();
load();
}
private void load()
{
int highest = 0;
_armors.clear();
_etcItems.clear();
_weapons.clear();
for (L2Item item : DocumentEngine.getInstance().loadItems())
{
if (highest < item.getItemId())
{
highest = item.getItemId();
}
if (item instanceof L2EtcItem)
{
_etcItems.put(item.getItemId(), (L2EtcItem) item);
}
else if (item instanceof L2Armor)
{
_armors.put(item.getItemId(), (L2Armor) item);
}
else
{
_weapons.put(item.getItemId(), (L2Weapon) item);
}
}
buildFastLookupTable(highest);
}
/**
* Builds a variable in which all items are putting in in function of their ID.
* @param size
*/
private void buildFastLookupTable(int size)
{
// Create a FastLookUp Table called _allTemplates of size : value of the highest item ID
LOGGER.info("Highest item id used:" + size);
_allTemplates = new L2Item[size + 1];
// Insert armor item in Fast Look Up Table
for (L2Armor item : _armors.values())
{
_allTemplates[item.getItemId()] = item;
}
// Insert weapon item in Fast Look Up Table
for (L2Weapon item : _weapons.values())
{
_allTemplates[item.getItemId()] = item;
}
// Insert etcItem item in Fast Look Up Table
for (L2EtcItem item : _etcItems.values())
{
_allTemplates[item.getItemId()] = item;
}
}
/**
* Returns the item corresponding to the item ID
* @param id : int designating the item
* @return L2Item
*/
public L2Item getTemplate(int id)
{
if (id >= _allTemplates.length)
{
return null;
}
return _allTemplates[id];
}
/**
* Create the L2ItemInstance corresponding to the Item Identifier and quantitiy add logs the activity.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Create and Init the L2ItemInstance corresponding to the Item Identifier and quantity</li>
* <li>Add the L2ItemInstance object to _allObjects of L2world</li>
* <li>Logs Item creation according to LOGGER settings</li><BR>
* <BR>
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
public L2ItemInstance createItem(String process, int itemId, int count, L2PcInstance actor, L2Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
// create loot schedule also if autoloot is enabled
if (process.equalsIgnoreCase("loot")/* && !Config.AUTO_LOOT */)
{
ScheduledFuture<?> itemLootShedule;
long delay = 0;
// if in CommandChannel and was killing a World/RaidBoss
if ((reference instanceof L2GrandBossInstance) || (reference instanceof L2RaidBossInstance))
{
if ((((L2Attackable) reference).getFirstCommandChannelAttacked() != null) && ((L2Attackable) reference).getFirstCommandChannelAttacked().meetRaidWarCondition(reference))
{
item.setOwnerId(((L2Attackable) reference).getFirstCommandChannelAttacked().getChannelLeader().getObjectId());
delay = 300000;
}
else
{
delay = 15000;
item.setOwnerId(actor.getObjectId());
}
}
else
{
item.setOwnerId(actor.getObjectId());
delay = 15000;
}
itemLootShedule = ThreadPoolManager.schedule(new resetOwner(item), delay);
item.setItemLootShedule(itemLootShedule);
}
if (Config.DEBUG)
{
LOGGER.info("ItemTable: Item created oid: " + item.getObjectId() + " itemid: " + itemId);
}
// Add the L2ItemInstance object to _allObjects of L2world
L2World.getInstance().storeObject(item);
// Set Item parameters
if (item.isStackable() && (count > 1))
{
item.setCount(count);
}
if (Config.LOG_ITEMS)
{
final LogRecord record = new LogRecord(Level.INFO, "CREATE:" + process);
record.setLoggerName("item");
record.setParameters(new Object[]
{
item,
actor,
reference
});
_logItems.log(record);
}
return item;
}
public L2ItemInstance createItem(String process, int itemId, int count, L2PcInstance actor)
{
return createItem(process, itemId, count, actor, null);
}
/**
* Returns a dummy (fr = factice) item.<BR>
* <BR>
* <U><I>Concept :</I></U><BR>
* Dummy item is created by setting the ID of the object in the world at null value
* @param itemId : int designating the item
* @return L2ItemInstance designating the dummy item created
*/
public L2ItemInstance createDummyItem(int itemId)
{
final L2Item item = getTemplate(itemId);
if (item == null)
{
return null;
}
L2ItemInstance temp = new L2ItemInstance(0, item);
try
{
temp = new L2ItemInstance(0, itemId);
}
catch (ArrayIndexOutOfBoundsException e)
{
// this can happen if the item templates were not initialized
}
if (temp.getItem() == null)
{
LOGGER.warning("ItemTable: Item Template missing for Id: " + itemId);
}
return temp;
}
/**
* Destroys the L2ItemInstance.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Sets L2ItemInstance parameters to be unusable</li>
* <li>Removes the L2ItemInstance object to _allObjects of L2world</li>
* <li>Logs Item delettion according to LOGGER settings</li><BR>
* <BR>
* @param process : String Identifier of process triggering this action
* @param item
* @param actor : L2PcInstance Player requesting the item destroy
* @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
*/
public void destroyItem(String process, L2ItemInstance item, L2PcInstance actor, L2Object reference)
{
synchronized (item)
{
item.setCount(0);
item.setOwnerId(0);
item.setLocation(ItemLocation.VOID);
item.setLastChange(L2ItemInstance.REMOVED);
L2World.getInstance().removeObject(item);
IdFactory.getInstance().releaseId(item.getObjectId());
// if it's a pet control item, delete the pet as well
if (L2PetDataTable.isPetItem(item.getItemId()))
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final PreparedStatement statement = con.prepareStatement("DELETE FROM pets WHERE item_obj_id=?");
statement.setInt(1, item.getObjectId());
statement.execute();
statement.close();
}
catch (Exception e)
{
LOGGER.warning("Could not delete pet objectid " + e);
}
}
}
}
public void reload()
{
load();
}
protected class resetOwner implements Runnable
{
L2ItemInstance _item;
public resetOwner(L2ItemInstance item)
{
_item = item;
}
@Override
public void run()
{
_item.setOwnerId(0);
_item.setItemLootShedule(null);
}
}
public Set<Integer> getAllArmorsId()
{
return _armors.keySet();
}
public Set<Integer> getAllWeaponsId()
{
return _weapons.keySet();
}
public int getArraySize()
{
return _allTemplates.length;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ItemTable _instance = new ItemTable();
}
}

View File

@@ -0,0 +1,591 @@
/*
* 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.datatables.xml;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.instancemanager.ArenaManager;
import com.l2jmobius.gameserver.instancemanager.FishingZoneManager;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.instancemanager.OlympiadStadiaManager;
import com.l2jmobius.gameserver.instancemanager.TownManager;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.L2WorldRegion;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.form.ZoneCuboid;
import com.l2jmobius.gameserver.model.zone.form.ZoneCylinder;
import com.l2jmobius.gameserver.model.zone.form.ZoneNPoly;
import com.l2jmobius.gameserver.model.zone.type.L2ArenaZone;
import com.l2jmobius.gameserver.model.zone.type.L2BigheadZone;
import com.l2jmobius.gameserver.model.zone.type.L2BossZone;
import com.l2jmobius.gameserver.model.zone.type.L2CastleTeleportZone;
import com.l2jmobius.gameserver.model.zone.type.L2CastleZone;
import com.l2jmobius.gameserver.model.zone.type.L2ClanHallZone;
import com.l2jmobius.gameserver.model.zone.type.L2CustomZone;
import com.l2jmobius.gameserver.model.zone.type.L2DamageZone;
import com.l2jmobius.gameserver.model.zone.type.L2DerbyTrackZone;
import com.l2jmobius.gameserver.model.zone.type.L2EffectZone;
import com.l2jmobius.gameserver.model.zone.type.L2FishingZone;
import com.l2jmobius.gameserver.model.zone.type.L2FortZone;
import com.l2jmobius.gameserver.model.zone.type.L2JailZone;
import com.l2jmobius.gameserver.model.zone.type.L2MotherTreeZone;
import com.l2jmobius.gameserver.model.zone.type.L2NoHqZone;
import com.l2jmobius.gameserver.model.zone.type.L2NoLandingZone;
import com.l2jmobius.gameserver.model.zone.type.L2NoStoreZone;
import com.l2jmobius.gameserver.model.zone.type.L2OlympiadStadiumZone;
import com.l2jmobius.gameserver.model.zone.type.L2PeaceZone;
import com.l2jmobius.gameserver.model.zone.type.L2PoisonZone;
import com.l2jmobius.gameserver.model.zone.type.L2SwampZone;
import com.l2jmobius.gameserver.model.zone.type.L2TownZone;
import com.l2jmobius.gameserver.model.zone.type.L2WaterZone;
/**
* This class manages the augmentation data and can also create new augmentations.
* @author durgus
*/
public class ZoneData
{
private static final Logger LOGGER = Logger.getLogger(ZoneData.class.getName());
// =========================================================
private static ZoneData _instance;
public static final ZoneData getInstance()
{
if (_instance == null)
{
_instance = new ZoneData();
}
return _instance;
}
// =========================================================
// Data Field
// =========================================================
// Constructor
public ZoneData()
{
LOGGER.info("Loading zones...");
load();
}
// reload
public void reload()
{
synchronized (_instance)
{
_instance = null;
_instance = new ZoneData();
}
}
// =========================================================
// Method - Private
private final void load()
{
int zoneCount = 0;
// Get the world regions
final L2WorldRegion[][] worldRegions = L2World.getInstance().getAllWorldRegions();
boolean done = false;
// Load the zone xml
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT + "/data/zones/zone.xml");
if (!file.exists())
{
if (Config.DEBUG)
{
LOGGER.info("The zone.xml file is missing.");
}
}
else
{
Document doc = factory.newDocumentBuilder().parse(file);
int effect_zone_id = 150000; // FIXME Temporally workaround to avoid zone.xml modification
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("zone".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
int zoneId = -1;
if (attrs.getNamedItem("id") != null)
{
zoneId = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
}
final int minZ = Integer.parseInt(attrs.getNamedItem("minZ").getNodeValue());
final int maxZ = Integer.parseInt(attrs.getNamedItem("maxZ").getNodeValue());
String zoneType = attrs.getNamedItem("type").getNodeValue();
String zoneShape = attrs.getNamedItem("shape").getNodeValue();
// Create the zone
L2ZoneType temp = null;
switch (zoneType)
{
case "FishingZone":
{
temp = new L2FishingZone(zoneId);
break;
}
case "ClanHallZone":
{
temp = new L2ClanHallZone(zoneId);
break;
}
case "PeaceZone":
{
temp = new L2PeaceZone(zoneId);
break;
}
case "Town":
{
temp = new L2TownZone(zoneId);
break;
}
case "OlympiadStadium":
{
temp = new L2OlympiadStadiumZone(zoneId);
break;
}
case "CastleZone":
{
temp = new L2CastleZone(zoneId);
break;
}
case "FortZone":
{
temp = new L2FortZone(zoneId);
break;
}
case "DamageZone":
{
temp = new L2DamageZone(zoneId);
break;
}
case "Arena":
{
temp = new L2ArenaZone(zoneId);
break;
}
case "MotherTree":
{
temp = new L2MotherTreeZone(zoneId);
break;
}
case "BigheadZone":
{
temp = new L2BigheadZone(zoneId);
break;
}
case "NoLandingZone":
{
temp = new L2NoLandingZone(zoneId);
break;
}
case "NoStoreZone":
{
temp = new L2NoStoreZone(zoneId);
break;
}
case "JailZone":
{
temp = new L2JailZone(zoneId);
break;
}
case "DerbyTrackZone":
{
temp = new L2DerbyTrackZone(zoneId);
break;
}
case "WaterZone":
{
temp = new L2WaterZone(zoneId);
break;
}
case "NoHqZone":
{
temp = new L2NoHqZone(zoneId);
break;
}
case "BossZone":
{
int boss_id = -1;
try
{
boss_id = Integer.parseInt(attrs.getNamedItem("bossId").getNodeValue());
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
temp = new L2BossZone(zoneId, boss_id);
break;
}
/*
* else if(zoneType.equals("SkillZone")) { temp = new L2SkillZone(zoneId); }
*/
case "EffectZone":
{
zoneId = effect_zone_id;
effect_zone_id++;
temp = new L2EffectZone(zoneId);
break;
}
case "PoisonZone":
{
temp = new L2PoisonZone(zoneId);
break;
}
case "CastleTeleportZone":
{
temp = new L2CastleTeleportZone(zoneId);
break;
}
case "CustomZone":
{
temp = new L2CustomZone(zoneId);
break;
}
case "SwampZone":
{
temp = new L2SwampZone(zoneId);
break;
}
}
// Check for unknown type
if (temp == null)
{
LOGGER.warning("ZoneData: No such zone type: " + zoneType);
continue;
}
// get the zone shape from file if any
int[][] coords = null;
int[] point;
final List<int[]> rs = new ArrayList<>();
// loading from XML first
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("node".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
point = new int[2];
point[0] = Integer.parseInt(attrs.getNamedItem("X").getNodeValue());
point[1] = Integer.parseInt(attrs.getNamedItem("Y").getNodeValue());
rs.add(point);
}
}
coords = rs.toArray(new int[rs.size()][]);
if ((coords == null) || (coords.length == 0)) // check on database
{
// Get the zone shape from sql or from file if not defined into sql
try
{
PreparedStatement statement = null;
// Set the correct query
statement = con.prepareStatement("SELECT x,y FROM zone_vertices WHERE id=? ORDER BY 'order' ASC ");
statement.setInt(1, zoneId);
ResultSet rset = statement.executeQuery();
// Create this zone. Parsing for cuboids is a bit different than for other polygons
// cuboids need exactly 2 points to be defined. Other polygons need at least 3 (one per vertex)
switch (zoneShape)
{
case "Cuboid":
{
final int[] x =
{
0,
0
};
final int[] y =
{
0,
0
};
boolean successfulLoad = true;
for (int i = 0; i < 2; i++)
{
if (rset.next())
{
x[i] = rset.getInt("x");
y[i] = rset.getInt("y");
}
else
{
LOGGER.warning("ZoneData: Missing cuboid vertex in sql data for zone: " + zoneId);
statement.close();
rset.close();
successfulLoad = false;
break;
}
}
if (successfulLoad)
{
temp.setZone(new ZoneCuboid(x[0], x[1], y[0], y[1], minZ, maxZ));
}
else
{
continue;
}
break;
}
case "NPoly":
{
List<Integer> fl_x = new ArrayList<>();
final List<Integer> fl_y = new ArrayList<>();
// Load the rest
while (rset.next())
{
fl_x.add(rset.getInt("x"));
fl_y.add(rset.getInt("y"));
}
// An nPoly needs to have at least 3 vertices
if ((fl_x.size() == fl_y.size()) && (fl_x.size() > 2))
{
// Create arrays
final int[] aX = new int[fl_x.size()];
final int[] aY = new int[fl_y.size()];
// This runs only at server startup so dont complain :>
for (int i = 0; i < fl_x.size(); i++)
{
aX[i] = fl_x.get(i);
aY[i] = fl_y.get(i);
}
// Create the zone
temp.setZone(new ZoneNPoly(aX, aY, minZ, maxZ));
}
else
{
LOGGER.warning("ZoneData: Bad sql data for zone: " + zoneId);
statement.close();
rset.close();
continue;
}
break;
}
default:
{
LOGGER.warning("ZoneData: Unknown shape: " + zoneShape);
statement.close();
rset.close();
continue;
}
}
statement.close();
rset.close();
}
catch (Exception e)
{
LOGGER.warning("ZoneData: Failed to load zone coordinates: " + e);
}
}
else // Create this zone. Parsing for cuboids is a
// bit different than for other polygons
// cuboids need exactly 2 points to be defined.
// Other polygons need at least 3 (one per
// vertex)
if (zoneShape.equalsIgnoreCase("Cuboid"))
{
if (coords.length == 2)
{
temp.setZone(new ZoneCuboid(coords[0][0], coords[1][0], coords[0][1], coords[1][1], minZ, maxZ));
}
else
{
LOGGER.warning("ZoneData: Missing cuboid vertex in sql data for zone: " + zoneId);
continue;
}
}
else if (zoneShape.equalsIgnoreCase("NPoly"))
{
// nPoly needs to have at least 3 vertices
if (coords.length > 2)
{
final int[] aX = new int[coords.length];
final int[] aY = new int[coords.length];
for (int i = 0; i < coords.length; i++)
{
aX[i] = coords[i][0];
aY[i] = coords[i][1];
}
temp.setZone(new ZoneNPoly(aX, aY, minZ, maxZ));
}
else
{
LOGGER.warning("ZoneData: Bad data for zone: " + zoneId);
continue;
}
}
else if (zoneShape.equalsIgnoreCase("Cylinder"))
{
// A Cylinder zone requires a center point
// at x,y and a radius
attrs = d.getAttributes();
final int zoneRad = Integer.parseInt(attrs.getNamedItem("rad").getNodeValue());
if ((coords.length == 1) && (zoneRad > 0))
{
temp.setZone(new ZoneCylinder(coords[0][0], coords[0][1], minZ, maxZ, zoneRad));
}
else
{
LOGGER.warning("ZoneData: Bad data for zone: " + zoneId);
continue;
}
}
else
{
LOGGER.warning("ZoneData: Unknown shape: " + zoneShape);
continue;
}
// Check for aditional parameters
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("stat".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
String name = attrs.getNamedItem("name").getNodeValue();
String val = attrs.getNamedItem("val").getNodeValue();
temp.setParameter(name, val);
}
if ("spawn".equalsIgnoreCase(cd.getNodeName()))
{
temp.setSpawnLocs(cd);
}
}
// Skip checks for fishing zones & add to fishing zone manager
if (temp instanceof L2FishingZone)
{
FishingZoneManager.getInstance().addFishingZone((L2FishingZone) temp);
continue;
}
if (temp instanceof L2WaterZone)
{
FishingZoneManager.getInstance().addWaterZone((L2WaterZone) temp);
}
// Register the zone into any world region it intersects with...
// currently 11136 test for each zone :>
int ax, ay, bx, by;
for (int x = 0; x < worldRegions.length; x++)
{
for (int y = 0; y < worldRegions[x].length; y++)
{
ax = (x - L2World.OFFSET_X) << L2World.SHIFT_BY;
bx = ((x + 1) - L2World.OFFSET_X) << L2World.SHIFT_BY;
ay = (y - L2World.OFFSET_Y) << L2World.SHIFT_BY;
by = ((y + 1) - L2World.OFFSET_Y) << L2World.SHIFT_BY;
if (temp.getZone().intersectsRectangle(ax, bx, ay, by))
{
if (Config.DEBUG)
{
LOGGER.info("Zone (" + zoneId + ") added to: " + x + " " + y);
}
worldRegions[x][y].addZone(temp);
}
}
}
// Special managers for arenas, towns...
if (temp instanceof L2ArenaZone)
{
ArenaManager.getInstance().addArena((L2ArenaZone) temp);
}
else if (temp instanceof L2TownZone)
{
TownManager.getInstance().addTown((L2TownZone) temp);
}
else if (temp instanceof L2OlympiadStadiumZone)
{
OlympiadStadiaManager.getInstance().addStadium((L2OlympiadStadiumZone) temp);
}
else if (temp instanceof L2BossZone)
{
GrandBossManager.getInstance().addZone((L2BossZone) temp);
}
// Increase the counter
zoneCount++;
}
}
}
}
done = true;
}
}
catch (Exception e)
{
LOGGER.warning("Error while loading zones. " + e);
}
if (done)
{
GrandBossManager.getInstance().initZones();
}
LOGGER.info("Done: loaded " + zoneCount + " zones.");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
/*
* 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.engines;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.templates.item.L2Item;
/**
* @author mkizub
*/
public class DocumentEngine
{
protected static final Logger LOGGER = Logger.getLogger(DocumentEngine.class.getName());
private final List<File> _itemFiles = new ArrayList<>();
private final List<File> _skillFiles = new ArrayList<>();
public static DocumentEngine getInstance()
{
return SingletonHolder._instance;
}
private DocumentEngine()
{
hashFiles("data/stats/items", _itemFiles);
hashFiles("data/stats/skills", _skillFiles);
}
private void hashFiles(String dirname, List<File> hash)
{
final File dir = new File(Config.DATAPACK_ROOT, dirname);
if (!dir.exists())
{
LOGGER.info("Dir " + dir.getAbsolutePath() + " not exists");
return;
}
final File[] files = dir.listFiles();
for (File f : files)
{
if (f.getName().endsWith(".xml"))
{
if (!f.getName().startsWith("custom"))
{
hash.add(f);
}
}
}
final File customfile = new File(Config.DATAPACK_ROOT, dirname + "/custom.xml");
if (customfile.exists())
{
hash.add(customfile);
}
}
public List<L2Skill> loadSkills(File file)
{
if (file == null)
{
LOGGER.warning("Skill file not found.");
return null;
}
final DocumentSkill doc = new DocumentSkill(file);
doc.parse();
return doc.getSkills();
}
public void loadAllSkills(Map<Integer, L2Skill> allSkills)
{
int count = 0;
for (File file : _skillFiles)
{
final List<L2Skill> s = loadSkills(file);
if (s == null)
{
continue;
}
for (L2Skill skill : s)
{
allSkills.put(SkillTable.getSkillHashCode(skill), skill);
count++;
}
}
LOGGER.info("SkillsEngine: Loaded " + count + " Skill templates from XML files.");
}
/**
* Return created items
* @return List of {@link L2Item}
*/
public List<L2Item> loadItems()
{
List<L2Item> list = new ArrayList<>();
for (File f : _itemFiles)
{
DocumentItem document = new DocumentItem(f);
document.parse();
list.addAll(document.getItemList());
}
return list;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final DocumentEngine _instance = new DocumentEngine();
}
}

View File

@@ -0,0 +1,435 @@
/*
* 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.engines;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.gameserver.templates.item.L2Armor;
import com.l2jmobius.gameserver.templates.item.L2ArmorType;
import com.l2jmobius.gameserver.templates.item.L2EtcItem;
import com.l2jmobius.gameserver.templates.item.L2EtcItemType;
import com.l2jmobius.gameserver.templates.item.L2Item;
import com.l2jmobius.gameserver.templates.item.L2Weapon;
import com.l2jmobius.gameserver.templates.item.L2WeaponType;
/**
* @author mkizub, JIV
*/
final class DocumentItem extends DocumentBase
{
private Item _currentItem = null;
private final List<L2Item> _itemsInFile = new ArrayList<>();
private static final Map<String, Integer> _slots = new HashMap<>();
static
{
_slots.put("chest", L2Item.SLOT_CHEST);
_slots.put("fullarmor", L2Item.SLOT_FULL_ARMOR);
_slots.put("head", L2Item.SLOT_HEAD);
_slots.put("hair", L2Item.SLOT_HAIR);
_slots.put("face", L2Item.SLOT_FACE);
_slots.put("dhair", L2Item.SLOT_DHAIR);
_slots.put("underwear", L2Item.SLOT_UNDERWEAR);
_slots.put("back", L2Item.SLOT_BACK);
_slots.put("neck", L2Item.SLOT_NECK);
_slots.put("legs", L2Item.SLOT_LEGS);
_slots.put("feet", L2Item.SLOT_FEET);
_slots.put("gloves", L2Item.SLOT_GLOVES);
_slots.put("chest,legs", L2Item.SLOT_CHEST | L2Item.SLOT_LEGS);
_slots.put("rhand", L2Item.SLOT_R_HAND);
_slots.put("lhand", L2Item.SLOT_L_HAND);
_slots.put("lrhand", L2Item.SLOT_LR_HAND);
_slots.put("rear,lear", L2Item.SLOT_R_EAR | L2Item.SLOT_L_EAR);
_slots.put("rfinger,lfinger", L2Item.SLOT_R_FINGER | L2Item.SLOT_L_FINGER);
_slots.put("none", L2Item.SLOT_NONE);
_slots.put("wolf", L2Item.SLOT_WOLF); // for wolf
_slots.put("hatchling", L2Item.SLOT_HATCHLING); // for hatchling
_slots.put("strider", L2Item.SLOT_STRIDER); // for strider
_slots.put("babypet", L2Item.SLOT_BABYPET); // for babypet
}
private static final Map<String, L2WeaponType> _weaponTypes = new HashMap<>();
static
{
_weaponTypes.put("blunt", L2WeaponType.BLUNT);
_weaponTypes.put("bow", L2WeaponType.BOW);
_weaponTypes.put("dagger", L2WeaponType.DAGGER);
_weaponTypes.put("dual", L2WeaponType.DUAL);
_weaponTypes.put("dualfist", L2WeaponType.DUALFIST);
_weaponTypes.put("etc", L2WeaponType.ETC);
_weaponTypes.put("fist", L2WeaponType.FIST);
_weaponTypes.put("none", L2WeaponType.NONE); // these are shields!
_weaponTypes.put("pole", L2WeaponType.POLE);
_weaponTypes.put("sword", L2WeaponType.SWORD);
_weaponTypes.put("bigsword", L2WeaponType.BIGSWORD); // Two-Handed Swords
_weaponTypes.put("pet", L2WeaponType.PET); // Pet Weapon
_weaponTypes.put("rod", L2WeaponType.ROD); // Fishing Rods
_weaponTypes.put("bigblunt", L2WeaponType.BIGBLUNT); // Two handed blunt
}
private static final Map<String, L2ArmorType> _armorTypes = new HashMap<>();
static
{
_armorTypes.put("none", L2ArmorType.NONE);
_armorTypes.put("light", L2ArmorType.LIGHT);
_armorTypes.put("heavy", L2ArmorType.HEAVY);
_armorTypes.put("magic", L2ArmorType.MAGIC);
_armorTypes.put("pet", L2ArmorType.PET);
}
public DocumentItem(File file)
{
super(file);
}
@Override
protected StatsSet getStatsSet()
{
return _currentItem.set;
}
@Override
protected String getTableValue(String name)
{
return _tables.get(name)[_currentItem.currentLevel];
}
@Override
protected String getTableValue(String name, int idx)
{
return _tables.get(name)[idx - 1];
}
@Override
protected void parseDocument(Document doc)
{
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("item".equalsIgnoreCase(d.getNodeName()))
{
try
{
_currentItem = new Item();
parseItem(d);
_itemsInFile.add(_currentItem.item);
resetTable();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Cannot create item " + _currentItem.id, e);
}
}
}
}
}
}
protected void parseItem(Node n)
{
int itemId = Integer.parseInt(n.getAttributes().getNamedItem("id").getNodeValue());
String className = n.getAttributes().getNamedItem("type").getNodeValue();
String itemName = n.getAttributes().getNamedItem("name").getNodeValue();
_currentItem.id = itemId;
_currentItem.name = itemName;
_currentItem.set = new StatsSet();
_currentItem.set.set("item_id", itemId);
_currentItem.set.set("name", itemName);
Node first = n.getFirstChild();
for (n = first; n != null; n = n.getNextSibling())
{
// No tables in item xmls.
// if ("table".equals(n.getNodeName()))
// {
// if (_currentItem.item != null)
// {
// throw new IllegalStateException("Item created but table node found! Item " + itemId);
// }
// parseTable(n);
// }
// else
if ("set".equals(n.getNodeName()))
{
if (_currentItem.item != null)
{
throw new IllegalStateException("Item created but set node found! Item " + itemId);
}
parseBeanSet(n, _currentItem.set, 1);
}
// Handled bellow, after item type is set.
// else if ("for".equals(n.getNodeName()))
// {
// makeItem();
// parseTemplate(n, _currentItem.item);
// }
}
if (className.equals("Weapon"))
{
_currentItem.type = _weaponTypes.get(_currentItem.set.getString("weapon_type"));
// lets see if this is a shield
if (_currentItem.type == L2WeaponType.NONE)
{
_currentItem.set.set("type1", L2Item.TYPE1_SHIELD_ARMOR);
_currentItem.set.set("type2", L2Item.TYPE2_SHIELD_ARMOR);
}
else
{
_currentItem.set.set("type1", L2Item.TYPE1_WEAPON_RING_EARRING_NECKLACE);
_currentItem.set.set("type2", L2Item.TYPE2_WEAPON);
}
if (_currentItem.type == L2WeaponType.PET)
{
_currentItem.set.set("type1", L2Item.TYPE1_WEAPON_RING_EARRING_NECKLACE);
switch (_currentItem.set.getString("bodypart"))
{
case "wolf":
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_WOLF);
break;
}
case "hatchling":
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_HATCHLING);
break;
}
case "babypet":
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_BABY);
break;
}
default:
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_STRIDER);
break;
}
}
_currentItem.set.set("bodypart", L2Item.SLOT_R_HAND);
}
}
else if (className.equals("Armor"))
{
_currentItem.type = _armorTypes.get(_currentItem.set.getString("armor_type"));
final int bodypart = _slots.get(_currentItem.set.getString("bodypart"));
if ((bodypart == L2Item.SLOT_NECK) || (bodypart == L2Item.SLOT_HAIR) || (bodypart == L2Item.SLOT_FACE) || (bodypart == L2Item.SLOT_DHAIR) || ((bodypart & L2Item.SLOT_L_EAR) != 0) || ((bodypart & L2Item.SLOT_L_FINGER) != 0))
{
_currentItem.set.set("type1", L2Item.TYPE1_WEAPON_RING_EARRING_NECKLACE);
_currentItem.set.set("type2", L2Item.TYPE2_ACCESSORY);
}
else
{
_currentItem.set.set("type1", L2Item.TYPE1_SHIELD_ARMOR);
_currentItem.set.set("type2", L2Item.TYPE2_SHIELD_ARMOR);
}
if (_currentItem.type == L2ArmorType.PET)
{
_currentItem.set.set("type1", L2Item.TYPE1_SHIELD_ARMOR);
switch (_currentItem.set.getString("bodypart"))
{
case "wolf":
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_WOLF);
break;
}
case "hatchling":
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_HATCHLING);
break;
}
case "babypet":
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_BABY);
break;
}
default:
{
_currentItem.set.set("type2", L2Item.TYPE2_PET_STRIDER);
break;
}
}
_currentItem.set.set("bodypart", L2Item.SLOT_CHEST);
}
}
else
{
_currentItem.set.set("type1", L2Item.TYPE1_ITEM_QUESTITEM_ADENA);
_currentItem.set.set("type2", L2Item.TYPE2_OTHER);
final String itemType = _currentItem.set.getString("item_type");
switch (itemType)
{
case "none":
{
_currentItem.type = L2EtcItemType.OTHER; // only for default
break;
}
case "castle_guard":
{
_currentItem.type = L2EtcItemType.SCROLL; // dummy
break;
}
case "pet_collar":
{
_currentItem.type = L2EtcItemType.PET_COLLAR;
break;
}
case "potion":
{
_currentItem.type = L2EtcItemType.POTION;
break;
}
case "recipe":
{
_currentItem.type = L2EtcItemType.RECEIPE;
break;
}
case "scroll":
{
_currentItem.type = L2EtcItemType.SCROLL;
break;
}
case "seed":
{
_currentItem.type = L2EtcItemType.SEED;
break;
}
case "shot":
{
_currentItem.type = L2EtcItemType.SHOT;
break;
}
case "spellbook":
{
_currentItem.type = L2EtcItemType.SPELLBOOK; // Spellbook, Amulet, Blueprint
break;
}
case "herb":
{
_currentItem.type = L2EtcItemType.HERB;
break;
}
case "arrow":
{
_currentItem.type = L2EtcItemType.ARROW;
_currentItem.set.set("bodypart", L2Item.SLOT_L_HAND);
break;
}
case "quest":
{
_currentItem.type = L2EtcItemType.QUEST;
_currentItem.set.set("type2", L2Item.TYPE2_QUEST);
break;
}
case "lure":
{
_currentItem.type = L2EtcItemType.OTHER;
_currentItem.set.set("bodypart", L2Item.SLOT_L_HAND);
break;
}
default:
{
_currentItem.type = L2EtcItemType.OTHER;
break;
}
}
final String consume = _currentItem.set.getString("consume_type");
switch (consume)
{
case "asset":
{
_currentItem.type = L2EtcItemType.MONEY;
_currentItem.set.set("stackable", true);
_currentItem.set.set("type2", L2Item.TYPE2_MONEY);
break;
}
case "stackable":
{
_currentItem.set.set("stackable", true);
break;
}
default:
{
_currentItem.set.set("stackable", false);
break;
}
}
}
for (n = first; n != null; n = n.getNextSibling())
{
if ("for".equals(n.getNodeName()))
{
makeItem();
parseTemplate(n, _currentItem.item);
}
}
// bah! in this point item doesn't have to be still created
makeItem();
}
private void makeItem()
{
if (_currentItem.item != null)
{
return; // item is already created
}
if (_currentItem.type instanceof L2ArmorType)
{
_currentItem.item = new L2Armor((L2ArmorType) _currentItem.type, _currentItem.set);
}
else if (_currentItem.type instanceof L2WeaponType)
{
_currentItem.item = new L2Weapon((L2WeaponType) _currentItem.type, _currentItem.set);
}
else if (_currentItem.type instanceof L2EtcItemType)
{
_currentItem.item = new L2EtcItem((L2EtcItemType) _currentItem.type, _currentItem.set);
}
else
{
throw new Error("Unknown item type for " + _currentItem.set.getInteger("item_id") + " " + _currentItem.type);
}
}
public List<L2Item> getItemList()
{
return _itemsInFile;
}
}

View File

@@ -0,0 +1,420 @@
/*
* 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.engines;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.L2Skill.SkillType;
import com.l2jmobius.gameserver.skills.conditions.Condition;
import com.l2jmobius.gameserver.templates.StatsSet;
/**
* @author mkizub
*/
final class DocumentSkill extends DocumentBase
{
public class Skill
{
public int id;
public String name;
public StatsSet[] sets;
public StatsSet[] enchsets1;
public StatsSet[] enchsets2;
public int currentLevel;
public List<L2Skill> skills = new ArrayList<>();
public List<L2Skill> currentSkills = new ArrayList<>();
}
private Skill _currentSkill;
private final List<L2Skill> _skillsInFile = new ArrayList<>();
DocumentSkill(File file)
{
super(file);
}
private void setCurrentSkill(Skill skill)
{
_currentSkill = skill;
}
@Override
protected StatsSet getStatsSet()
{
return _currentSkill.sets[_currentSkill.currentLevel];
}
protected List<L2Skill> getSkills()
{
return _skillsInFile;
}
@Override
protected String getTableValue(String name)
{
try
{
return _tables.get(name)[_currentSkill.currentLevel];
}
catch (RuntimeException e)
{
LOGGER.warning("Error in table: " + name + " of Skill Id " + _currentSkill.id + " " + e);
return "";
}
}
@Override
protected String getTableValue(String name, int idx)
{
try
{
return _tables.get(name)[idx - 1];
}
catch (RuntimeException e)
{
LOGGER.warning("wrong level count in skill Id " + _currentSkill.id + " " + e);
return "";
}
}
@Override
protected void parseDocument(Document doc)
{
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("skill".equalsIgnoreCase(d.getNodeName()))
{
setCurrentSkill(new Skill());
parseSkill(d);
_skillsInFile.addAll(_currentSkill.skills);
resetTable();
}
}
}
else if ("skill".equalsIgnoreCase(n.getNodeName()))
{
setCurrentSkill(new Skill());
parseSkill(n);
_skillsInFile.addAll(_currentSkill.skills);
}
}
}
protected void parseSkill(Node n)
{
final NamedNodeMap attrs = n.getAttributes();
int enchantLevels1 = 0;
int enchantLevels2 = 0;
final int skillId = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
final String skillName = attrs.getNamedItem("name").getNodeValue();
final String levels = attrs.getNamedItem("levels").getNodeValue();
final int lastLvl = Integer.parseInt(levels);
if (attrs.getNamedItem("enchantLevels1") != null)
{
enchantLevels1 = Integer.parseInt(attrs.getNamedItem("enchantLevels1").getNodeValue());
}
if (attrs.getNamedItem("enchantLevels2") != null)
{
enchantLevels2 = Integer.parseInt(attrs.getNamedItem("enchantLevels2").getNodeValue());
}
_currentSkill.id = skillId;
_currentSkill.name = skillName;
_currentSkill.sets = new StatsSet[lastLvl];
_currentSkill.enchsets1 = new StatsSet[enchantLevels1];
_currentSkill.enchsets2 = new StatsSet[enchantLevels2];
for (int i = 0; i < lastLvl; i++)
{
_currentSkill.sets[i] = new StatsSet();
_currentSkill.sets[i].set("skill_id", _currentSkill.id);
_currentSkill.sets[i].set("level", i + 1);
_currentSkill.sets[i].set("name", _currentSkill.name);
}
if (_currentSkill.sets.length != lastLvl)
{
throw new RuntimeException("Skill id=" + skillId + " number of levels missmatch, " + lastLvl + " levels expected");
}
final Node first = n.getFirstChild();
for (n = first; n != null; n = n.getNextSibling())
{
if ("table".equalsIgnoreCase(n.getNodeName()))
{
parseTable(n);
}
}
for (int i = 1; i <= lastLvl; i++)
{
for (n = first; n != null; n = n.getNextSibling())
{
if ("set".equalsIgnoreCase(n.getNodeName()))
{
parseBeanSet(n, _currentSkill.sets[i - 1], i);
}
}
}
for (int i = 0; i < enchantLevels1; i++)
{
_currentSkill.enchsets1[i] = new StatsSet();
_currentSkill.enchsets1[i].set("skill_id", _currentSkill.id);
// currentSkill.enchsets1[i] = currentSkill.sets[currentSkill.sets.length-1];
_currentSkill.enchsets1[i].set("level", i + 101);
_currentSkill.enchsets1[i].set("name", _currentSkill.name);
// currentSkill.enchsets1[i].set("skillType", "NOTDONE");
for (n = first; n != null; n = n.getNextSibling())
{
if ("set".equalsIgnoreCase(n.getNodeName()))
{
parseBeanSet(n, _currentSkill.enchsets1[i], _currentSkill.sets.length);
}
}
for (n = first; n != null; n = n.getNextSibling())
{
if ("enchant1".equalsIgnoreCase(n.getNodeName()))
{
parseBeanSet(n, _currentSkill.enchsets1[i], i + 1);
}
}
}
if (_currentSkill.enchsets1.length != enchantLevels1)
{
throw new RuntimeException("Skill id=" + skillId + " number of levels missmatch, " + enchantLevels1 + " levels expected");
}
for (int i = 0; i < enchantLevels2; i++)
{
_currentSkill.enchsets2[i] = new StatsSet();
// currentSkill.enchsets2[i] = currentSkill.sets[currentSkill.sets.length-1];
_currentSkill.enchsets2[i].set("skill_id", _currentSkill.id);
_currentSkill.enchsets2[i].set("level", i + 141);
_currentSkill.enchsets2[i].set("name", _currentSkill.name);
// currentSkill.enchsets2[i].set("skillType", "NOTDONE");
for (n = first; n != null; n = n.getNextSibling())
{
if ("set".equalsIgnoreCase(n.getNodeName()))
{
parseBeanSet(n, _currentSkill.enchsets2[i], _currentSkill.sets.length);
}
}
for (n = first; n != null; n = n.getNextSibling())
{
if ("enchant2".equalsIgnoreCase(n.getNodeName()))
{
parseBeanSet(n, _currentSkill.enchsets2[i], i + 1);
}
}
}
if (_currentSkill.enchsets2.length != enchantLevels2)
{
throw new RuntimeException("Skill id=" + skillId + " number of levels missmatch, " + enchantLevels2 + " levels expected");
}
makeSkills();
for (int i = 0; i < lastLvl; i++)
{
_currentSkill.currentLevel = i;
for (n = first; n != null; n = n.getNextSibling())
{
if ("cond".equalsIgnoreCase(n.getNodeName()))
{
final Condition condition = parseCondition(n.getFirstChild(), _currentSkill.currentSkills.get(i));
final Node msg = n.getAttributes().getNamedItem("msg");
if ((condition != null) && (msg != null))
{
condition.setMessage(msg.getNodeValue());
}
_currentSkill.currentSkills.get(i).attach(condition, false);
}
if ("for".equalsIgnoreCase(n.getNodeName()))
{
parseTemplate(n, _currentSkill.currentSkills.get(i));
}
}
}
for (int i = lastLvl; i < (lastLvl + enchantLevels1); i++)
{
_currentSkill.currentLevel = i - lastLvl;
boolean found = false;
for (n = first; n != null; n = n.getNextSibling())
{
if ("enchant1cond".equalsIgnoreCase(n.getNodeName()))
{
found = true;
final Condition condition = parseCondition(n.getFirstChild(), _currentSkill.currentSkills.get(i));
final Node msg = n.getAttributes().getNamedItem("msg");
if ((condition != null) && (msg != null))
{
condition.setMessage(msg.getNodeValue());
}
_currentSkill.currentSkills.get(i).attach(condition, false);
}
if ("enchant1for".equalsIgnoreCase(n.getNodeName()))
{
found = true;
parseTemplate(n, _currentSkill.currentSkills.get(i));
}
}
// If none found, the enchanted skill will take effects from maxLvL of norm skill
if (!found)
{
_currentSkill.currentLevel = lastLvl - 1;
for (n = first; n != null; n = n.getNextSibling())
{
if ("cond".equalsIgnoreCase(n.getNodeName()))
{
final Condition condition = parseCondition(n.getFirstChild(), _currentSkill.currentSkills.get(i));
final Node msg = n.getAttributes().getNamedItem("msg");
if ((condition != null) && (msg != null))
{
condition.setMessage(msg.getNodeValue());
}
_currentSkill.currentSkills.get(i).attach(condition, false);
}
if ("for".equalsIgnoreCase(n.getNodeName()))
{
parseTemplate(n, _currentSkill.currentSkills.get(i));
}
}
}
}
for (int i = lastLvl + enchantLevels1; i < (lastLvl + enchantLevels1 + enchantLevels2); i++)
{
boolean found = false;
_currentSkill.currentLevel = i - lastLvl - enchantLevels1;
for (n = first; n != null; n = n.getNextSibling())
{
if ("enchant2cond".equalsIgnoreCase(n.getNodeName()))
{
found = true;
final Condition condition = parseCondition(n.getFirstChild(), _currentSkill.currentSkills.get(i));
final Node msg = n.getAttributes().getNamedItem("msg");
if ((condition != null) && (msg != null))
{
condition.setMessage(msg.getNodeValue());
}
_currentSkill.currentSkills.get(i).attach(condition, false);
}
if ("enchant2for".equalsIgnoreCase(n.getNodeName()))
{
found = true;
parseTemplate(n, _currentSkill.currentSkills.get(i));
}
}
// If none found, the enchanted skill will take effects from maxLvL of norm skill
if (!found)
{
_currentSkill.currentLevel = lastLvl - 1;
for (n = first; n != null; n = n.getNextSibling())
{
if ("cond".equalsIgnoreCase(n.getNodeName()))
{
final Condition condition = parseCondition(n.getFirstChild(), _currentSkill.currentSkills.get(i));
final Node msg = n.getAttributes().getNamedItem("msg");
if ((condition != null) && (msg != null))
{
condition.setMessage(msg.getNodeValue());
}
_currentSkill.currentSkills.get(i).attach(condition, false);
}
if ("for".equalsIgnoreCase(n.getNodeName()))
{
parseTemplate(n, _currentSkill.currentSkills.get(i));
}
}
}
}
_currentSkill.skills.addAll(_currentSkill.currentSkills);
}
private void makeSkills()
{
int count = 0;
_currentSkill.currentSkills = new ArrayList<>(_currentSkill.sets.length + _currentSkill.enchsets1.length + _currentSkill.enchsets2.length);
for (int i = 0; i < _currentSkill.sets.length; i++)
{
try
{
_currentSkill.currentSkills.add(i, _currentSkill.sets[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.sets[i]));
count++;
}
catch (Exception e)
{
LOGGER.warning("Skill id=" + _currentSkill.sets[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.sets[i]).getDisplayId() + "level" + _currentSkill.sets[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.sets[i]).getLevel() + " " + e);
}
}
int _count = count;
for (int i = 0; i < _currentSkill.enchsets1.length; i++)
{
try
{
_currentSkill.currentSkills.add(_count + i, _currentSkill.enchsets1[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.enchsets1[i]));
count++;
}
catch (Exception e)
{
LOGGER.warning("Skill id=" + _currentSkill.enchsets1[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.enchsets1[i]).getDisplayId() + " level=" + _currentSkill.enchsets1[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.enchsets1[i]).getLevel() + " " + e);
}
}
_count = count;
for (int i = 0; i < _currentSkill.enchsets2.length; i++)
{
try
{
_currentSkill.currentSkills.add(_count + i, _currentSkill.enchsets2[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.enchsets2[i]));
count++;
}
catch (Exception e)
{
LOGGER.warning("Skill id=" + _currentSkill.enchsets2[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.enchsets2[i]).getDisplayId() + " level=" + _currentSkill.enchsets2[i].getEnum("skillType", SkillType.class).makeSkill(_currentSkill.enchsets2[i]).getLevel() + " " + e);
}
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.engines;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.gameserver.templates.item.L2Item;
/**
* This class ...
* @author luisantonioa
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
*/
public class Item
{
public int id;
public Enum<?> type;
public String name;
public StatsSet set;
public int currentLevel;
public L2Item item;
}

View File

@@ -0,0 +1,558 @@
/*
* 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.geodata;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.datatables.csv.DoorTable;
import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jmobius.gameserver.geodata.geodriver.GeoDriver;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.actor.position.Location;
import com.l2jmobius.gameserver.util.GeoUtils;
import com.l2jmobius.gameserver.util.LinePointIterator;
import com.l2jmobius.gameserver.util.LinePointIterator3D;
/**
* @author -Nemesiss-, HorridoJoho
*/
public class GeoData
{
protected static final Logger LOGGER = Logger.getLogger(GeoData.class.getName());
private static final String FILE_NAME_FORMAT = "%d_%d.l2j";
private static final int ELEVATED_SEE_OVER_DISTANCE = 2;
private static final int MAX_SEE_OVER_HEIGHT = 48;
private static final int SPAWN_Z_DELTA_LIMIT = 100;
private final GeoDriver _driver = new GeoDriver();
protected GeoData()
{
int loadedRegions = 0;
try
{
for (int regionX = L2World.TILE_X_MIN; regionX <= L2World.TILE_X_MAX; regionX++)
{
for (int regionY = L2World.TILE_Y_MIN; regionY <= L2World.TILE_Y_MAX; regionY++)
{
final Path geoFilePath = Config.GEODATA_PATH.resolve(String.format(FILE_NAME_FORMAT, regionX, regionY));
final Boolean loadFile = Config.GEODATA_REGIONS.get(regionX + "_" + regionY);
if (loadFile != null)
{
if (loadFile)
{
LOGGER.info(getClass().getSimpleName() + ": Loading " + geoFilePath.getFileName() + "...");
_driver.loadRegion(geoFilePath, regionX, regionY);
loadedRegions++;
}
}
else if (Config.TRY_LOAD_UNSPECIFIED_REGIONS && Files.exists(geoFilePath))
{
try
{
LOGGER.info(getClass().getSimpleName() + ": Loading " + geoFilePath.getFileName() + "...");
_driver.loadRegion(geoFilePath, regionX, regionY);
loadedRegions++;
}
catch (Exception e)
{
LOGGER.warning(getClass().getSimpleName() + ": Failed to load " + geoFilePath.getFileName() + "! " + e);
}
}
}
}
}
catch (Exception e)
{
LOGGER.warning(getClass().getSimpleName() + ": Failed to load geodata! " + e);
System.exit(1);
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + loadedRegions + " regions.");
}
public boolean hasGeoPos(int geoX, int geoY)
{
return _driver.hasGeoPos(geoX, geoY);
}
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return _driver.checkNearestNswe(geoX, geoY, worldZ, nswe);
}
public boolean checkNearestNsweAntiCornerCut(int geoX, int geoY, int worldZ, int nswe)
{
boolean can = true;
if ((nswe & Cell.NSWE_NORTH_EAST) == Cell.NSWE_NORTH_EAST)
{
// can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.NORTH);
can = checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_EAST) && checkNearestNswe(geoX + 1, geoY, worldZ, Cell.NSWE_NORTH);
}
if (can && ((nswe & Cell.NSWE_NORTH_WEST) == Cell.NSWE_NORTH_WEST))
{
// can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.NORTH);
can = checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_WEST) && checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_NORTH);
}
if (can && ((nswe & Cell.NSWE_SOUTH_EAST) == Cell.NSWE_SOUTH_EAST))
{
// can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.SOUTH);
can = checkNearestNswe(geoX, geoY + 1, worldZ, Cell.NSWE_EAST) && checkNearestNswe(geoX + 1, geoY, worldZ, Cell.NSWE_SOUTH);
}
if (can && ((nswe & Cell.NSWE_SOUTH_WEST) == Cell.NSWE_SOUTH_WEST))
{
// can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.SOUTH);
can = checkNearestNswe(geoX, geoY + 1, worldZ, Cell.NSWE_WEST) && checkNearestNswe(geoX - 1, geoY, worldZ, Cell.NSWE_SOUTH);
}
return can && checkNearestNswe(geoX, geoY, worldZ, nswe);
}
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _driver.getNearestZ(geoX, geoY, worldZ);
}
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return _driver.getNextLowerZ(geoX, geoY, worldZ);
}
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return _driver.getNextHigherZ(geoX, geoY, worldZ);
}
public int getGeoX(int worldX)
{
return _driver.getGeoX(worldX);
}
public int getGeoY(int worldY)
{
return _driver.getGeoY(worldY);
}
public int getGeoZ(int worldZ)
{
return _driver.getGeoZ(worldZ);
}
public int getWorldX(int geoX)
{
return _driver.getWorldX(geoX);
}
public int getWorldY(int geoY)
{
return _driver.getWorldY(geoY);
}
public int getWorldZ(int geoZ)
{
return _driver.getWorldZ(geoZ);
}
// ///////////////////
// L2J METHODS
/**
* Gets the height.
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @return the height
*/
public int getHeight(int x, int y, int z)
{
return getNearestZ(getGeoX(x), getGeoY(y), z);
}
/**
* Gets the spawn height.
* @param x the x coordinate
* @param y the y coordinate
* @param z the the z coordinate
* @return the spawn height
*/
public int getSpawnHeight(int x, int y, int z)
{
final int geoX = getGeoX(x);
final int geoY = getGeoY(y);
if (!hasGeoPos(geoX, geoY))
{
return z;
}
final int nextLowerZ = getNextLowerZ(geoX, geoY, z + 100);
return Math.abs(nextLowerZ - z) <= SPAWN_Z_DELTA_LIMIT ? nextLowerZ : z;
}
/**
* Gets the spawn height.
* @param location the location
* @return the spawn height
*/
public int getSpawnHeight(Location location)
{
return getSpawnHeight(location.getX(), location.getY(), location.getZ());
}
/**
* Can see target. Doors as target always return true. Checks doors between.
* @param cha the character
* @param target the target
* @return {@code true} if the character can see the target (LOS), {@code false} otherwise
*/
public boolean canSeeTarget(L2Object cha, L2Object target)
{
if (target instanceof L2DoorInstance)
{
// can always see doors :o
return true;
}
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), target.getX(), target.getY(), target.getZ());
}
private int getLosGeoZ(int prevX, int prevY, int prevGeoZ, int curX, int curY, int nswe)
{
if ((((nswe & Cell.NSWE_NORTH) != 0) && ((nswe & Cell.NSWE_SOUTH) != 0)) || (((nswe & Cell.NSWE_WEST) != 0) && ((nswe & Cell.NSWE_EAST) != 0)))
{
throw new RuntimeException("Multiple directions!");
}
if (checkNearestNsweAntiCornerCut(prevX, prevY, prevGeoZ, nswe))
{
return getNearestZ(curX, curY, prevGeoZ);
}
return getNextHigherZ(curX, curY, prevGeoZ);
}
/**
* Can see target. Does not check doors between.
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param tx the target's x coordinate
* @param ty the target's y coordinate
* @param tz the target's z coordinate
* @return {@code true} if there is line of sight between the given coordinate sets, {@code false} otherwise
*/
public boolean canSeeTarget(int x, int y, int z, int tx, int ty, int tz)
{
int geoX = getGeoX(x);
int geoY = getGeoY(y);
int tGeoX = getGeoX(tx);
int tGeoY = getGeoY(ty);
z = getNearestZ(geoX, geoY, z);
tz = getNearestZ(tGeoX, tGeoY, tz);
// fastpath
if ((geoX == tGeoX) && (geoY == tGeoY))
{
if (hasGeoPos(tGeoX, tGeoY))
{
return z == tz;
}
return true;
}
if (tz > z)
{
int tmp = tx;
tx = x;
x = tmp;
tmp = ty;
ty = y;
y = tmp;
tmp = tz;
tz = z;
z = tmp;
tmp = tGeoX;
tGeoX = geoX;
geoX = tmp;
tmp = tGeoY;
tGeoY = geoY;
geoY = tmp;
}
final LinePointIterator3D pointIter = new LinePointIterator3D(geoX, geoY, z, tGeoX, tGeoY, tz);
// first point is guaranteed to be available, skip it, we can always see our own position
pointIter.next();
int prevX = pointIter.x();
int prevY = pointIter.y();
final int prevZ = pointIter.z();
int prevGeoZ = prevZ;
int ptIndex = 0;
while (pointIter.next())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
if ((curX == prevX) && (curY == prevY))
{
continue;
}
final int beeCurZ = pointIter.z();
int curGeoZ = prevGeoZ;
// check if the position has geodata
if (hasGeoPos(curX, curY))
{
final int beeCurGeoZ = getNearestZ(curX, curY, beeCurZ);
final int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY); // .computeDirection(prevX, prevY, curX, curY);
curGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, curX, curY, nswe);
int maxHeight;
if (ptIndex < ELEVATED_SEE_OVER_DISTANCE)
{
maxHeight = z + MAX_SEE_OVER_HEIGHT;
}
else
{
maxHeight = beeCurZ + MAX_SEE_OVER_HEIGHT;
}
boolean canSeeThrough = false;
if ((curGeoZ <= maxHeight) && (curGeoZ <= beeCurGeoZ))
{
if ((nswe & Cell.NSWE_NORTH_EAST) == Cell.NSWE_NORTH_EAST)
{
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_EAST);
final int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Cell.NSWE_NORTH);
canSeeThrough = (northGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
}
else if ((nswe & Cell.NSWE_NORTH_WEST) == Cell.NSWE_NORTH_WEST)
{
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_WEST);
final int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Cell.NSWE_NORTH);
canSeeThrough = (northGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
}
else if ((nswe & Cell.NSWE_SOUTH_EAST) == Cell.NSWE_SOUTH_EAST)
{
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_EAST);
final int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Cell.NSWE_SOUTH);
canSeeThrough = (southGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
}
else if ((nswe & Cell.NSWE_SOUTH_WEST) == Cell.NSWE_SOUTH_WEST)
{
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_WEST);
final int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Cell.NSWE_SOUTH);
canSeeThrough = (southGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
}
else
{
canSeeThrough = true;
}
}
if (!canSeeThrough)
{
return false;
}
}
prevX = curX;
prevY = curY;
prevGeoZ = curGeoZ;
++ptIndex;
}
return true;
}
/**
* Move check.
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param tx the target's x coordinate
* @param ty the target's y coordinate
* @param tz the target's z coordinate
* @return the last Location (x,y,z) where player can walk - just before wall
*/
public Location moveCheck(int x, int y, int z, int tx, int ty, int tz)
{
final int geoX = getGeoX(x);
final int geoY = getGeoY(y);
z = getNearestZ(geoX, geoY, z);
final int tGeoX = getGeoX(tx);
final int tGeoY = getGeoY(ty);
tz = getNearestZ(tGeoX, tGeoY, tz);
if (DoorTable.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz))
{
return new Location(x, y, getHeight(x, y, z));
}
final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
// first point is guaranteed to be available
pointIter.next();
int prevX = pointIter.x();
int prevY = pointIter.y();
int prevZ = z;
while (pointIter.next())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
final int curZ = getNearestZ(curX, curY, prevZ);
if (hasGeoPos(prevX, prevY))
{
final int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY);
if (!checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, nswe))
{
// can't move, return previous location
return new Location(getWorldX(prevX), getWorldY(prevY), prevZ);
}
}
prevX = curX;
prevY = curY;
prevZ = curZ;
}
if (hasGeoPos(prevX, prevY) && (prevZ != tz))
{
// different floors, return start location
return new Location(x, y, z);
}
return new Location(tx, ty, tz);
}
/**
* Checks if its possible to move from one location to another.
* @param fromX the X coordinate to start checking from
* @param fromY the Y coordinate to start checking from
* @param fromZ the Z coordinate to start checking from
* @param toX the X coordinate to end checking at
* @param toY the Y coordinate to end checking at
* @param toZ the Z coordinate to end checking at
* @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
*/
public boolean canMove(int fromX, int fromY, int fromZ, int toX, int toY, int toZ)
{
final int geoX = getGeoX(fromX);
final int geoY = getGeoY(fromY);
fromZ = getNearestZ(geoX, geoY, fromZ);
final int tGeoX = getGeoX(toX);
final int tGeoY = getGeoY(toY);
toZ = getNearestZ(tGeoX, tGeoY, toZ);
if (DoorTable.getInstance().checkIfDoorsBetween(fromX, fromY, fromZ, toX, toY, toZ))
{
return false;
}
final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
// first point is guaranteed to be available
pointIter.next();
int prevX = pointIter.x();
int prevY = pointIter.y();
int prevZ = fromZ;
while (pointIter.next())
{
final int curX = pointIter.x();
final int curY = pointIter.y();
final int curZ = getNearestZ(curX, curY, prevZ);
if (hasGeoPos(prevX, prevY))
{
final int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY);
if (!checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, nswe))
{
return false;
}
}
prevX = curX;
prevY = curY;
prevZ = curZ;
}
if (hasGeoPos(prevX, prevY) && (prevZ != toZ))
{
// different floors
return false;
}
return true;
}
/**
* Checks if its possible to move from one location to another.
* @param from the {@code WorldObject} to start checking from
* @param toX the X coordinate to end checking at
* @param toY the Y coordinate to end checking at
* @param toZ the Z coordinate to end checking at
* @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
*/
public boolean canMove(L2Object from, int toX, int toY, int toZ)
{
return canMove(from.getX(), from.getY(), from.getZ(), toX, toY, toZ);
}
/**
* Checks if its possible to move from one location to another.
* @param from the {@code WorldObject} to start checking from
* @param to the {@code WorldObject} to end checking at
* @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
*/
public boolean canMove(L2Object from, L2Object to)
{
return canMove(from, to.getX(), to.getY(), to.getZ());
}
/**
* Checks the specified position for available geodata.
* @param x the X coordinate
* @param y the Y coordinate
* @return {@code true} if there is geodata for the given coordinates, {@code false} otherwise
*/
public boolean hasGeo(int x, int y)
{
return hasGeoPos(getGeoX(x), getGeoY(y));
}
public static GeoData getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final GeoData _instance = new GeoData();
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.geodata.geodriver;
/**
* @author HorridoJoho
*/
public final class Cell
{
/** East NSWE flag */
public static final byte NSWE_EAST = 1 << 0;
/** West NSWE flag */
public static final byte NSWE_WEST = 1 << 1;
/** South NSWE flag */
public static final byte NSWE_SOUTH = 1 << 2;
/** North NSWE flag */
public static final byte NSWE_NORTH = 1 << 3;
/** North-East NSWE flags */
public static final byte NSWE_NORTH_EAST = NSWE_NORTH | NSWE_EAST;
/** North-West NSWE flags */
public static final byte NSWE_NORTH_WEST = NSWE_NORTH | NSWE_WEST;
/** South-East NSWE flags */
public static final byte NSWE_SOUTH_EAST = NSWE_SOUTH | NSWE_EAST;
/** South-West NSWE flags */
public static final byte NSWE_SOUTH_WEST = NSWE_SOUTH | NSWE_WEST;
/** All directions NSWE flags */
public static final byte NSWE_ALL = NSWE_EAST | NSWE_WEST | NSWE_SOUTH | NSWE_NORTH;
private Cell()
{
}
}

View File

@@ -0,0 +1,189 @@
/*
* 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.geodata.geodriver;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Path;
import java.util.concurrent.atomic.AtomicReferenceArray;
import com.l2jmobius.gameserver.geodata.geodriver.regions.NullRegion;
import com.l2jmobius.gameserver.geodata.geodriver.regions.Region;
/**
* @author HorridoJoho
*/
public final class GeoDriver
{
// world dimensions: 1048576 * 1048576 = 1099511627776
private static final int WORLD_MIN_X = -655360;
private static final int WORLD_MAX_X = 393215;
private static final int WORLD_MIN_Y = -589824;
private static final int WORLD_MAX_Y = 458751;
private static final int WORLD_MIN_Z = -16384;
private static final int WORLD_MAX_Z = 16384;
/** Regions in the world on the x axis */
public static final int GEO_REGIONS_X = 32;
/** Regions in the world on the y axis */
public static final int GEO_REGIONS_Y = 32;
/** Region in the world */
public static final int GEO_REGIONS = GEO_REGIONS_X * GEO_REGIONS_Y;
/** Blocks in the world on the x axis */
public static final int GEO_BLOCKS_X = GEO_REGIONS_X * IRegion.REGION_BLOCKS_X;
/** Blocks in the world on the y axis */
public static final int GEO_BLOCKS_Y = GEO_REGIONS_Y * IRegion.REGION_BLOCKS_Y;
/** Blocks in the world */
public static final int GEO_BLOCKS = GEO_REGIONS * IRegion.REGION_BLOCKS;
/** Cells in the world on the x axis */
public static final int GEO_CELLS_X = GEO_BLOCKS_X * IBlock.BLOCK_CELLS_X;
/** Cells in the world in the y axis */
public static final int GEO_CELLS_Y = GEO_BLOCKS_Y * IBlock.BLOCK_CELLS_Y;
/** Cells in the world in the z axis */
public static final int GEO_CELLS_Z = (Math.abs(WORLD_MIN_Z) + Math.abs(WORLD_MAX_Z)) / 16;
/** The regions array */
private final AtomicReferenceArray<IRegion> _regions = new AtomicReferenceArray<>(GEO_REGIONS);
public GeoDriver()
{
for (int i = 0; i < _regions.length(); i++)
{
_regions.set(i, NullRegion.INSTANCE);
}
}
private void checkGeoX(int geoX)
{
if ((geoX < 0) || (geoX >= GEO_CELLS_X))
{
throw new IllegalArgumentException();
}
}
private void checkGeoY(int geoY)
{
if ((geoY < 0) || (geoY >= GEO_CELLS_Y))
{
throw new IllegalArgumentException();
}
}
private void checkGeoZ(int geoZ)
{
if ((geoZ < 0) || (geoZ >= GEO_CELLS_Z))
{
throw new IllegalArgumentException();
}
}
private IRegion getRegion(int geoX, int geoY)
{
checkGeoX(geoX);
checkGeoY(geoY);
return _regions.get(((geoX / IRegion.REGION_CELLS_X) * GEO_REGIONS_Y) + (geoY / IRegion.REGION_CELLS_Y));
}
public void loadRegion(Path filePath, int regionX, int regionY) throws IOException
{
final int regionOffset = (regionX * GEO_REGIONS_Y) + regionY;
try (RandomAccessFile raf = new RandomAccessFile(filePath.toFile(), "r"))
{
_regions.set(regionOffset, new Region(raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length()).load().order(ByteOrder.LITTLE_ENDIAN)));
}
}
public void unloadRegion(int regionX, int regionY)
{
_regions.set((regionX * GEO_REGIONS_Y) + regionY, NullRegion.INSTANCE);
}
public boolean hasGeoPos(int geoX, int geoY)
{
return getRegion(geoX, geoY).hasGeo();
}
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return getRegion(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe);
}
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return getRegion(geoX, geoY).getNearestZ(geoX, geoY, worldZ);
}
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return getRegion(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ);
}
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return getRegion(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ);
}
public int getGeoX(int worldX)
{
if ((worldX < WORLD_MIN_X) || (worldX > WORLD_MAX_X))
{
throw new IllegalArgumentException();
}
return (worldX - WORLD_MIN_X) / 16;
}
public int getGeoY(int worldY)
{
if ((worldY < WORLD_MIN_Y) || (worldY > WORLD_MAX_Y))
{
throw new IllegalArgumentException();
}
return (worldY - WORLD_MIN_Y) / 16;
}
public int getGeoZ(int worldZ)
{
if ((worldZ < WORLD_MIN_Z) || (worldZ > WORLD_MAX_Z))
{
throw new IllegalArgumentException();
}
return (worldZ - WORLD_MIN_Z) / 16;
}
public int getWorldX(int geoX)
{
checkGeoX(geoX);
return (geoX * 16) + WORLD_MIN_X + 8;
}
public int getWorldY(int geoY)
{
checkGeoY(geoY);
return (geoY * 16) + WORLD_MIN_Y + 8;
}
public int getWorldZ(int geoZ)
{
checkGeoZ(geoZ);
return (geoZ * 16) + WORLD_MIN_Z + 8;
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.geodata.geodriver;
/**
* @author HorridoJoho
*/
public interface IBlock
{
int TYPE_FLAT = 0;
int TYPE_COMPLEX = 1;
int TYPE_MULTILAYER = 2;
/** Cells in a block on the x axis */
int BLOCK_CELLS_X = 8;
/** Cells in a block on the y axis */
int BLOCK_CELLS_Y = 8;
/** Cells in a block */
int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y;
boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe);
int getNearestZ(int geoX, int geoY, int worldZ);
int getNextLowerZ(int geoX, int geoY, int worldZ);
int getNextHigherZ(int geoX, int geoY, int worldZ);
}

View File

@@ -0,0 +1,47 @@
/*
* 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.geodata.geodriver;
/**
* @author HorridoJoho
*/
public interface IRegion
{
/** Blocks in a region on the x axis. */
int REGION_BLOCKS_X = 256;
/** Blocks in a region on the y axis. */
int REGION_BLOCKS_Y = 256;
/** Blocks in a region. */
int REGION_BLOCKS = REGION_BLOCKS_X * REGION_BLOCKS_Y;
/** Cells in a region on the x axis. */
int REGION_CELLS_X = REGION_BLOCKS_X * IBlock.BLOCK_CELLS_X;
/** Cells in a regioin on the y axis. */
int REGION_CELLS_Y = REGION_BLOCKS_Y * IBlock.BLOCK_CELLS_Y;
/** Cells in a region. */
int REGION_CELLS = REGION_CELLS_X * REGION_CELLS_Y;
boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe);
int getNearestZ(int geoX, int geoY, int worldZ);
int getNextLowerZ(int geoX, int geoY, int worldZ);
int getNextHigherZ(int geoX, int geoY, int worldZ);
boolean hasGeo();
}

View File

@@ -0,0 +1,79 @@
/*
* 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.geodata.geodriver.blocks;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
/**
* @author HorridoJoho
*/
public final class ComplexBlock implements IBlock
{
private final short[] _data;
public ComplexBlock(ByteBuffer bb)
{
_data = new short[IBlock.BLOCK_CELLS];
for (int cellOffset = 0; cellOffset < IBlock.BLOCK_CELLS; cellOffset++)
{
_data[cellOffset] = bb.getShort();
}
}
private short _getCellData(int geoX, int geoY)
{
return _data[((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y)];
}
private byte _getCellNSWE(int geoX, int geoY)
{
return (byte) (_getCellData(geoX, geoY) & 0x000F);
}
private int _getCellHeight(int geoX, int geoY)
{
return (short) (_getCellData(geoX, geoY) & 0x0FFF0) >> 1;
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return (_getCellNSWE(geoX, geoY) & nswe) == nswe;
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _getCellHeight(geoX, geoY);
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
final int cellHeight = _getCellHeight(geoX, geoY);
return cellHeight <= worldZ ? cellHeight : worldZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
final int cellHeight = _getCellHeight(geoX, geoY);
return cellHeight >= worldZ ? cellHeight : worldZ;
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.geodata.geodriver.blocks;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
/**
* @author HorridoJoho
*/
public class FlatBlock implements IBlock
{
private final short _height;
public FlatBlock(ByteBuffer bb)
{
_height = bb.getShort();
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return true;
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _height;
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return _height <= worldZ ? _height : worldZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return _height >= worldZ ? _height : worldZ;
}
}

View File

@@ -0,0 +1,186 @@
/*
* 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.geodata.geodriver.blocks;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
/**
* @author HorridoJoho
*/
public class MultilayerBlock implements IBlock
{
private final byte[] _data;
/**
* Initializes a new instance of this block reading the specified buffer.
* @param bb the buffer
*/
public MultilayerBlock(ByteBuffer bb)
{
final int start = bb.position();
for (int blockCellOffset = 0; blockCellOffset < IBlock.BLOCK_CELLS; blockCellOffset++)
{
final byte nLayers = bb.get();
if ((nLayers <= 0) || (nLayers > 125))
{
throw new RuntimeException("L2JGeoDriver: Geo file corrupted! Invalid layers count!");
}
bb.position(bb.position() + (nLayers * 2));
}
_data = new byte[bb.position() - start];
bb.position(start);
bb.get(_data);
}
private short _getNearestLayer(int geoX, int geoY, int worldZ)
{
final int startOffset = _getCellDataOffset(geoX, geoY);
final byte nLayers = _data[startOffset];
final int endOffset = startOffset + 1 + (nLayers * 2);
// 1 layer at least was required on loading so this is set at least once on the loop below
int nearestDZ = 0;
short nearestData = 0;
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
{
final short layerData = _extractLayerData(offset);
final int layerZ = _extractLayerHeight(layerData);
if (layerZ == worldZ)
{
// exact z
return layerData;
}
final int layerDZ = Math.abs(layerZ - worldZ);
if ((offset == (startOffset + 1)) || (layerDZ < nearestDZ))
{
nearestDZ = layerDZ;
nearestData = layerData;
}
}
return nearestData;
}
private int _getCellDataOffset(int geoX, int geoY)
{
final int cellLocalOffset = ((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y);
int cellDataOffset = 0;
// move index to cell, we need to parse on each request, OR we parse on creation and save indexes
for (int i = 0; i < cellLocalOffset; i++)
{
cellDataOffset += 1 + (_data[cellDataOffset] * 2);
}
// now the index points to the cell we need
return cellDataOffset;
}
private short _extractLayerData(int dataOffset)
{
return (short) ((_data[dataOffset] & 0xFF) | (_data[dataOffset + 1] << 8));
}
private int _getNearestNSWE(int geoX, int geoY, int worldZ)
{
return _extractLayerNswe(_getNearestLayer(geoX, geoY, worldZ));
}
private int _extractLayerNswe(short layer)
{
return (byte) (layer & 0x000F);
}
private int _extractLayerHeight(short layer)
{
layer = (short) (layer & 0x0fff0);
return layer >> 1;
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return (_getNearestNSWE(geoX, geoY, worldZ) & nswe) == nswe;
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return _extractLayerHeight(_getNearestLayer(geoX, geoY, worldZ));
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
final int startOffset = _getCellDataOffset(geoX, geoY);
final byte nLayers = _data[startOffset];
final int endOffset = startOffset + 1 + (nLayers * 2);
int lowerZ = Integer.MIN_VALUE;
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
{
final short layerData = _extractLayerData(offset);
final int layerZ = _extractLayerHeight(layerData);
if (layerZ == worldZ)
{
// exact z
return layerZ;
}
if ((layerZ < worldZ) && (layerZ > lowerZ))
{
lowerZ = layerZ;
}
}
return lowerZ == Integer.MIN_VALUE ? worldZ : lowerZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
final int startOffset = _getCellDataOffset(geoX, geoY);
final byte nLayers = _data[startOffset];
final int endOffset = startOffset + 1 + (nLayers * 2);
int higherZ = Integer.MAX_VALUE;
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
{
final short layerData = _extractLayerData(offset);
final int layerZ = _extractLayerHeight(layerData);
if (layerZ == worldZ)
{
// exact z
return layerZ;
}
if ((layerZ > worldZ) && (layerZ < higherZ))
{
higherZ = layerZ;
}
}
return higherZ == Integer.MAX_VALUE ? worldZ : higherZ;
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.geodata.geodriver.regions;
import com.l2jmobius.gameserver.geodata.geodriver.IRegion;
/**
* @author HorridoJoho
*/
public final class NullRegion implements IRegion
{
public static final NullRegion INSTANCE = new NullRegion();
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return true;
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return worldZ;
}
@Override
public boolean hasGeo()
{
return false;
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.geodata.geodriver.regions;
import java.nio.ByteBuffer;
import com.l2jmobius.gameserver.geodata.geodriver.IBlock;
import com.l2jmobius.gameserver.geodata.geodriver.IRegion;
import com.l2jmobius.gameserver.geodata.geodriver.blocks.ComplexBlock;
import com.l2jmobius.gameserver.geodata.geodriver.blocks.FlatBlock;
import com.l2jmobius.gameserver.geodata.geodriver.blocks.MultilayerBlock;
/**
* @author HorridoJoho
*/
public final class Region implements IRegion
{
private final IBlock[] _blocks = new IBlock[IRegion.REGION_BLOCKS];
public Region(ByteBuffer bb)
{
for (int blockOffset = 0; blockOffset < IRegion.REGION_BLOCKS; blockOffset++)
{
final int blockType = bb.get();
switch (blockType)
{
case IBlock.TYPE_FLAT:
{
_blocks[blockOffset] = new FlatBlock(bb);
break;
}
case IBlock.TYPE_COMPLEX:
{
_blocks[blockOffset] = new ComplexBlock(bb);
break;
}
case IBlock.TYPE_MULTILAYER:
{
_blocks[blockOffset] = new MultilayerBlock(bb);
break;
}
default:
{
throw new RuntimeException("Invalid block type " + blockType + "!");
}
}
}
}
private IBlock getBlock(int geoX, int geoY)
{
return _blocks[(((geoX / IBlock.BLOCK_CELLS_X) % IRegion.REGION_BLOCKS_X) * IRegion.REGION_BLOCKS_Y) + ((geoY / IBlock.BLOCK_CELLS_Y) % IRegion.REGION_BLOCKS_Y)];
}
@Override
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
{
return getBlock(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe);
}
@Override
public int getNearestZ(int geoX, int geoY, int worldZ)
{
return getBlock(geoX, geoY).getNearestZ(geoX, geoY, worldZ);
}
@Override
public int getNextLowerZ(int geoX, int geoY, int worldZ)
{
return getBlock(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ);
}
@Override
public int getNextHigherZ(int geoX, int geoY, int worldZ)
{
return getBlock(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ);
}
@Override
public boolean hasGeo()
{
return true;
}
}

View File

@@ -0,0 +1,121 @@
/*
* 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.geodata.geoeditorcon;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Logger;
import com.l2jmobius.Config;
public class GeoEditorListener extends Thread
{
protected static final Logger LOGGER = Logger.getLogger(GeoEditorListener.class.getName());
private static final int PORT = Config.GEOEDITOR_PORT;
private static final class SingletonHolder
{
protected static final GeoEditorListener INSTANCE = new GeoEditorListener();
}
public static GeoEditorListener getInstance()
{
return SingletonHolder.INSTANCE;
}
private ServerSocket _serverSocket;
private GeoEditorThread _geoEditor;
protected GeoEditorListener()
{
try
{
_serverSocket = new ServerSocket(PORT);
}
catch (IOException e)
{
LOGGER.warning("Error creating geoeditor listener! " + e);
System.exit(1);
}
start();
LOGGER.info("GeoEditorListener Initialized.");
}
public GeoEditorThread getThread()
{
return _geoEditor;
}
public String getStatus()
{
if ((_geoEditor != null) && _geoEditor.isWorking())
{
return "Geoeditor connected.";
}
return "Geoeditor not connected.";
}
@Override
public void run()
{
Socket connection = null;
try
{
while (true)
{
connection = _serverSocket.accept();
if ((_geoEditor != null) && _geoEditor.isWorking())
{
LOGGER.warning("Geoeditor already connected!");
connection.close();
continue;
}
LOGGER.info("Received geoeditor connection from: " + connection.getInetAddress().getHostAddress());
_geoEditor = new GeoEditorThread(connection);
_geoEditor.start();
}
}
catch (Exception e)
{
LOGGER.warning("GeoEditorListener: " + e);
try
{
if (connection != null)
{
connection.close();
}
}
catch (Exception e2)
{
}
}
finally
{
try
{
_serverSocket.close();
}
catch (IOException io)
{
LOGGER.warning(io.getMessage());
}
LOGGER.warning("GeoEditorListener Closed!");
}
}
}

View File

@@ -0,0 +1,284 @@
/*
* 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.geodata.geoeditorcon;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
public class GeoEditorThread extends Thread
{
protected static final Logger LOGGER = Logger.getLogger(GeoEditorThread.class.getName());
private boolean _working = false;
private int _mode = 0; // 0 - don't send coords, 1 - send each
// validateposition from client, 2 - send in
// intervals of _sendDelay ms.
private int _sendDelay = 1000; // default - once in second
private final Socket _geSocket;
private OutputStream _out;
private final List<L2PcInstance> _gms;
public GeoEditorThread(Socket ge)
{
_geSocket = ge;
_working = true;
_gms = new ArrayList<>();
}
@Override
public void interrupt()
{
try
{
_geSocket.close();
}
catch (Exception e)
{
}
super.interrupt();
}
@Override
public void run()
{
try
{
_out = _geSocket.getOutputStream();
int timer = 0;
while (_working)
{
if (!isConnected())
{
_working = false;
}
if ((_mode == 2) && (timer > _sendDelay))
{
for (L2PcInstance gm : _gms)
{
if (gm.isOnline() == 1)
{
sendGmPosition(gm);
}
else
{
_gms.remove(gm);
}
}
timer = 0;
}
try
{
sleep(100);
if (_mode == 2)
{
timer += 100;
}
}
catch (Exception e)
{
}
}
}
catch (SocketException e)
{
LOGGER.warning("GeoEditor disconnected. " + e);
}
catch (Exception e)
{
LOGGER.warning(e.getMessage());
}
finally
{
try
{
_geSocket.close();
}
catch (Exception e)
{
}
_working = false;
}
}
public void sendGmPosition(int gx, int gy, short z)
{
if (!isConnected())
{
return;
}
try
{
synchronized (_out)
{
writeC(0x0b); // length 11 bytes!
writeC(0x01); // Cmd = save cell;
writeD(gx); // Global coord X;
writeD(gy); // Global coord Y;
writeH(z); // Coord Z;
_out.flush();
}
}
catch (SocketException e)
{
LOGGER.warning("GeoEditor disconnected. " + e);
_working = false;
}
catch (Exception e)
{
LOGGER.warning(e.getMessage());
try
{
_geSocket.close();
}
catch (Exception ex)
{
}
_working = false;
}
}
public void sendGmPosition(L2PcInstance _gm)
{
sendGmPosition(_gm.getX(), _gm.getY(), (short) _gm.getZ());
}
public void sendPing()
{
if (!isConnected())
{
return;
}
try
{
synchronized (_out)
{
writeC(0x01); // length 1 byte!
writeC(0x02); // Cmd = ping (dummy packet for connection test);
_out.flush();
}
}
catch (SocketException e)
{
LOGGER.warning("GeoEditor disconnected. " + e);
_working = false;
}
catch (Exception e)
{
LOGGER.warning(e.getMessage() + e);
try
{
_geSocket.close();
}
catch (Exception ex)
{
}
_working = false;
}
}
private void writeD(int value) throws IOException
{
_out.write(value & 0xff);
_out.write((value >> 8) & 0xff);
_out.write((value >> 16) & 0xff);
_out.write((value >> 24) & 0xff);
}
private void writeH(int value) throws IOException
{
_out.write(value & 0xff);
_out.write((value >> 8) & 0xff);
}
private void writeC(int value) throws IOException
{
_out.write(value & 0xff);
}
public void setMode(int value)
{
_mode = value;
}
public void setTimer(int value)
{
if (value < 500)
{
_sendDelay = 500; // maximum - 2 times per second!
}
else if (value > 60000)
{
_sendDelay = 60000; // Minimum - 1 time per minute.
}
else
{
_sendDelay = value;
}
}
public void addGM(L2PcInstance gm)
{
if (!_gms.contains(gm))
{
_gms.add(gm);
}
}
public void removeGM(L2PcInstance gm)
{
if (_gms.contains(gm))
{
_gms.remove(gm);
}
}
public boolean isSend(L2PcInstance gm)
{
return (_mode == 1) && _gms.contains(gm);
}
private boolean isConnected()
{
return _geSocket.isConnected() && !_geSocket.isClosed();
}
public boolean isWorking()
{
sendPing();
return _working;
}
public int getMode()
{
return _mode;
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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.geodata.pathfinding;
public abstract class AbstractNode<T extends AbstractNodeLoc>
{
private T _loc;
private AbstractNode<T> _parent;
public AbstractNode(T loc)
{
_loc = loc;
}
public void setParent(AbstractNode<T> p)
{
_parent = p;
}
public AbstractNode<T> getParent()
{
return _parent;
}
public T getLoc()
{
return _loc;
}
public void setLoc(T l)
{
_loc = l;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = (prime * result) + ((_loc == null) ? 0 : _loc.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof AbstractNode))
{
return false;
}
final AbstractNode<?> other = (AbstractNode<?>) obj;
if (_loc == null)
{
if (other._loc != null)
{
return false;
}
}
else if (!_loc.equals(other._loc))
{
return false;
}
return true;
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.geodata.pathfinding;
/**
* @author -Nemesiss-
*/
public abstract class AbstractNodeLoc
{
public abstract int getX();
public abstract int getY();
public abstract int getZ();
public abstract int getNodeX();
public abstract int getNodeY();
}

View File

@@ -0,0 +1,210 @@
/*
* 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.geodata.pathfinding;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.geodata.pathfinding.cellnodes.CellPathFinding;
import com.l2jmobius.gameserver.geodata.pathfinding.geonodes.GeoPathFinding;
import com.l2jmobius.gameserver.model.L2World;
/**
* @author -Nemesiss-
*/
public abstract class PathFinding
{
public static PathFinding getInstance()
{
if (Config.PATHFINDING == 1)
{
// Higher Memory Usage, Smaller Cpu Usage
return GeoPathFinding.getInstance();
}
// Cell pathfinding, calculated directly from geodata files
return CellPathFinding.getInstance();
}
public abstract boolean pathNodesExist(short regionoffset);
public abstract List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, boolean playable);
// @formatter:off
/*
public List<AbstractNodeLoc> search(AbstractNode start, AbstractNode end, int instanceId)
{
// The simplest grid-based pathfinding.
// Drawback is not having higher cost for diagonal movement (means funny routes)
// Could be optimized e.g. not to calculate backwards as far as forwards.
// List of Visited Nodes
LinkedList<AbstractNode> visited = new LinkedList<AbstractNode>();
// List of Nodes to Visit
LinkedList<AbstractNode> to_visit = new LinkedList<AbstractNode>();
to_visit.add(start);
int i = 0;
while (i < 800)
{
AbstractNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end)) //path found!
return constructPath(node, instanceId);
else
{
i++;
visited.add(node);
node.attachNeighbors();
Node[] neighbors = node.getNeighbors();
if (neighbors == null)
continue;
for (Node n : neighbors)
{
if (!visited.contains(n) && !to_visit.contains(n))
{
n.setParent(node);
to_visit.add(n);
}
}
}
}
//No Path found
return null;
}
*/
/*
public List<AbstractNodeLoc> searchAStar(Node start, Node end, int instanceId)
{
// Not operational yet?
int start_x = start.getLoc().getX();
int start_y = start.getLoc().getY();
int end_x = end.getLoc().getX();
int end_y = end.getLoc().getY();
//List of Visited Nodes
FastNodeList visited = new FastNodeList(800);//TODO! Add limit to cfg
// List of Nodes to Visit
BinaryNodeHeap to_visit = new BinaryNodeHeap(800);
to_visit.add(start);
int i = 0;
while (i < 800)//TODO! Add limit to cfg
{
AbstractNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end)) //path found!
return constructPath(node, instanceId);
else
{
visited.add(node);
node.attachNeighbors();
for (Node n : node.getNeighbors())
{
if (!visited.contains(n) && !to_visit.contains(n))
{
i++;
n.setParent(node);
n.setCost(Math.abs(start_x - n.getLoc().getNodeX()) + Math.abs(start_y - n.getLoc().getNodeY())
+ Math.abs(end_x - n.getLoc().getNodeX()) + Math.abs(end_y - n.getLoc().getNodeY()));
to_visit.add(n);
}
}
}
}
//No Path found
return null;
}
*/
// @formatter:on
/**
* Convert geodata position to pathnode position
* @param geo_pos
* @return pathnode position
*/
public short getNodePos(int geo_pos)
{
return (short) (geo_pos >> 3); // OK?
}
/**
* Convert node position to pathnode block position
* @param node_pos
* @return pathnode block position (0...255)
*/
public short getNodeBlock(int node_pos)
{
return (short) (node_pos % 256);
}
public byte getRegionX(int node_pos)
{
return (byte) ((node_pos >> 8) + L2World.TILE_X_MIN);
}
public byte getRegionY(int node_pos)
{
return (byte) ((node_pos >> 8) + L2World.TILE_Y_MIN);
}
public short getRegionOffset(byte rx, byte ry)
{
return (short) ((rx << 5) + ry);
}
/**
* Convert pathnode x to World x position
* @param node_x rx
* @return
*/
public int calculateWorldX(short node_x)
{
return L2World.MAP_MIN_X + (node_x * 128) + 48;
}
/**
* Convert pathnode y to World y position
* @param node_y
* @return
*/
public int calculateWorldY(short node_y)
{
return L2World.MAP_MIN_Y + (node_y * 128) + 48;
}
public String[] getStat()
{
return null;
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.geodata.pathfinding.cellnodes;
import com.l2jmobius.gameserver.geodata.pathfinding.AbstractNode;
public class CellNode extends AbstractNode<NodeLoc>
{
private CellNode _next = null;
private boolean _isInUse = true;
private float _cost = -1000;
public CellNode(NodeLoc loc)
{
super(loc);
}
public boolean isInUse()
{
return _isInUse;
}
public void setInUse()
{
_isInUse = true;
}
public CellNode getNext()
{
return _next;
}
public void setNext(CellNode next)
{
_next = next;
}
public float getCost()
{
return _cost;
}
public void setCost(double cost)
{
_cost = (float) cost;
}
public void free()
{
setParent(null);
_cost = -1000;
_isInUse = false;
_next = null;
}
}

View File

@@ -0,0 +1,361 @@
/*
* 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.geodata.pathfinding.cellnodes;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import com.l2jmobius.Config;
/**
* @author DS Credits to Diamond
*/
public class CellNodeBuffer
{
private static final int MAX_ITERATIONS = 3500;
private final ReentrantLock _lock = new ReentrantLock();
private final int _mapSize;
private final CellNode[][] _buffer;
private int _baseX = 0;
private int _baseY = 0;
private int _targetX = 0;
private int _targetY = 0;
private int _targetZ = 0;
private long _timeStamp = 0;
private long _lastElapsedTime = 0;
private CellNode _current = null;
public CellNodeBuffer(int size)
{
_mapSize = size;
_buffer = new CellNode[_mapSize][_mapSize];
}
public final boolean lock()
{
return _lock.tryLock();
}
public final CellNode findPath(int x, int y, int z, int tx, int ty, int tz)
{
_timeStamp = System.currentTimeMillis();
_baseX = x + ((tx - x - _mapSize) / 2); // middle of the line (x,y) - (tx,ty)
_baseY = y + ((ty - y - _mapSize) / 2); // will be in the center of the buffer
_targetX = tx;
_targetY = ty;
_targetZ = tz;
_current = getNode(x, y, z);
_current.setCost(getCost(x, y, z, Config.HIGH_WEIGHT));
for (int count = 0; count < MAX_ITERATIONS; count++)
{
if ((_current.getLoc().getNodeX() == _targetX) && (_current.getLoc().getNodeY() == _targetY) && (Math.abs(_current.getLoc().getZ() - _targetZ) < 64))
{
return _current; // found
}
getNeighbors();
if (_current.getNext() == null)
{
return null; // no more ways
}
_current = _current.getNext();
}
return null;
}
public final void free()
{
_current = null;
CellNode node;
for (int i = 0; i < _mapSize; i++)
{
for (int j = 0; j < _mapSize; j++)
{
node = _buffer[i][j];
if (node != null)
{
node.free();
}
}
}
_lock.unlock();
_lastElapsedTime = System.currentTimeMillis() - _timeStamp;
}
public final long getElapsedTime()
{
return _lastElapsedTime;
}
public final List<CellNode> debugPath()
{
final List<CellNode> result = new LinkedList<>();
for (CellNode n = _current; n.getParent() != null; n = (CellNode) n.getParent())
{
result.add(n);
n.setCost(-n.getCost());
}
for (int i = 0; i < _mapSize; i++)
{
for (int j = 0; j < _mapSize; j++)
{
final CellNode n = _buffer[i][j];
if ((n == null) || !n.isInUse() || (n.getCost() <= 0))
{
continue;
}
result.add(n);
}
}
return result;
}
private void getNeighbors()
{
if (!_current.getLoc().canGoAll())
{
return;
}
final int x = _current.getLoc().getNodeX();
final int y = _current.getLoc().getNodeY();
final int z = _current.getLoc().getZ();
CellNode nodeE = null;
CellNode nodeS = null;
CellNode nodeW = null;
CellNode nodeN = null;
// East
if (_current.getLoc().canGoEast())
{
nodeE = addNode(x + 1, y, z, false);
}
// South
if (_current.getLoc().canGoSouth())
{
nodeS = addNode(x, y + 1, z, false);
}
// West
if (_current.getLoc().canGoWest())
{
nodeW = addNode(x - 1, y, z, false);
}
// North
if (_current.getLoc().canGoNorth())
{
nodeN = addNode(x, y - 1, z, false);
}
if (Config.ADVANCED_DIAGONAL_STRATEGY)
{
// SouthEast
if ((nodeE != null) && (nodeS != null))
{
if (nodeE.getLoc().canGoSouth() && nodeS.getLoc().canGoEast())
{
addNode(x + 1, y + 1, z, true);
}
}
// SouthWest
if ((nodeS != null) && (nodeW != null))
{
if (nodeW.getLoc().canGoSouth() && nodeS.getLoc().canGoWest())
{
addNode(x - 1, y + 1, z, true);
}
}
// NorthEast
if ((nodeN != null) && (nodeE != null))
{
if (nodeE.getLoc().canGoNorth() && nodeN.getLoc().canGoEast())
{
addNode(x + 1, y - 1, z, true);
}
}
// NorthWest
if ((nodeN != null) && (nodeW != null))
{
if (nodeW.getLoc().canGoNorth() && nodeN.getLoc().canGoWest())
{
addNode(x - 1, y - 1, z, true);
}
}
}
}
private CellNode getNode(int x, int y, int z)
{
final int aX = x - _baseX;
if ((aX < 0) || (aX >= _mapSize))
{
return null;
}
final int aY = y - _baseY;
if ((aY < 0) || (aY >= _mapSize))
{
return null;
}
CellNode result = _buffer[aX][aY];
if (result == null)
{
result = new CellNode(new NodeLoc(x, y, z));
_buffer[aX][aY] = result;
}
else if (!result.isInUse())
{
result.setInUse();
// reinit node if needed
if (result.getLoc() != null)
{
result.getLoc().set(x, y, z);
}
else
{
result.setLoc(new NodeLoc(x, y, z));
}
}
return result;
}
private CellNode addNode(int x, int y, int z, boolean diagonal)
{
final CellNode newNode = getNode(x, y, z);
if (newNode == null)
{
return null;
}
if (newNode.getCost() >= 0)
{
return newNode;
}
final int geoZ = newNode.getLoc().getZ();
final int stepZ = Math.abs(geoZ - _current.getLoc().getZ());
float weight = diagonal ? Config.DIAGONAL_WEIGHT : Config.LOW_WEIGHT;
if (!newNode.getLoc().canGoAll() || (stepZ > 16))
{
weight = Config.HIGH_WEIGHT;
}
else if (isHighWeight(x + 1, y, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
else if (isHighWeight(x - 1, y, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
else if (isHighWeight(x, y + 1, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
else if (isHighWeight(x, y - 1, geoZ))
{
weight = Config.MEDIUM_WEIGHT;
}
newNode.setParent(_current);
newNode.setCost(getCost(x, y, geoZ, weight));
CellNode node = _current;
int count = 0;
while ((node.getNext() != null) && (count < (MAX_ITERATIONS * 4)))
{
count++;
if (node.getNext().getCost() > newNode.getCost())
{
// insert node into a chain
newNode.setNext(node.getNext());
break;
}
node = node.getNext();
}
if (count == (MAX_ITERATIONS * 4))
{
System.err.println("Pathfinding: too long loop detected, cost:" + newNode.getCost());
}
node.setNext(newNode); // add last
return newNode;
}
private boolean isHighWeight(int x, int y, int z)
{
final CellNode result = getNode(x, y, z);
if (result == null)
{
return true;
}
if (!result.getLoc().canGoAll())
{
return true;
}
if (Math.abs(result.getLoc().getZ() - z) > 16)
{
return true;
}
return false;
}
private double getCost(int x, int y, int z, float weight)
{
final int dX = x - _targetX;
final int dY = y - _targetY;
final int dZ = z - _targetZ;
// Math.abs(dx) + Math.abs(dy) + Math.abs(dz) / 16
double result = Math.sqrt((dX * dX) + (dY * dY) + ((dZ * dZ) / 256.0));
if (result > weight)
{
result += weight;
}
if (result > Float.MAX_VALUE)
{
result = Float.MAX_VALUE;
}
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More