diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/db_installer/sql/game/buffer_schemes.sql b/L2J_Mobius_Classic_2.0_Saviors/dist/db_installer/sql/game/buffer_schemes.sql new file mode 100644 index 0000000000..ecc7cb6ed7 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/db_installer/sql/game/buffer_schemes.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS `buffer_schemes` ( + `object_id` INT UNSIGNED NOT NULL DEFAULT '0', + `scheme_name` VARCHAR(16) NOT NULL DEFAULT 'default', + `skills` VARCHAR(200) NOT NULL +); \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/ShemeBuffer.ini b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/ShemeBuffer.ini new file mode 100644 index 0000000000..9087a3df17 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/ShemeBuffer.ini @@ -0,0 +1,10 @@ +#============================================================= +# Buffer +#============================================================= +# Also check data\SchemeBufferSkills.xml + +# Maximum number of available schemes per player. +BufferMaxSchemesPerChar = 4 + +# Static cost of buffs ; override skills price if different of -1. +BufferStaticCostPerBuff = -1 diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/SchemeBufferSkills.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/SchemeBufferSkills.xml new file mode 100644 index 0000000000..dc54a77ef5 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/SchemeBufferSkills.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008-1.htm b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008-1.htm new file mode 100644 index 0000000000..780dc11dbd --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008-1.htm @@ -0,0 +1,14 @@ + +You can create up to %max_schemes% schemes. Is it clear for you? +If not, read until you get it! I can't afford idiots...
+You can register a new scheme filling this form, here! +
+ + + + +

+Here are listed your schemes and their fee.
+%schemes%
+ + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008-2.htm b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008-2.htm new file mode 100644 index 0000000000..620467cf0e --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008-2.htm @@ -0,0 +1,8 @@ + +%schemename% scheme holds %count% buffs.
+
+%typesframe%
+%skilllistframe%
+
+ + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008.htm b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008.htm new file mode 100644 index 0000000000..e092b4456f --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/mods/SchemeBuffer/50008.htm @@ -0,0 +1,8 @@ + +Hello stranger!
+Yup, you're right, I decided to share some of my powerful buffs in order to improve your pew-pew-bum-zap abilities.
+What can I do for you?
+ + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/SchemeBuffer.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/SchemeBuffer.xml new file mode 100644 index 0000000000..222adec5b0 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/SchemeBuffer.xml @@ -0,0 +1,21 @@ + + + + HUMAN + FEMALE + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/SchemeBufferSkills.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/SchemeBufferSkills.xsd new file mode 100644 index 0000000000..91ae871150 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/SchemeBufferSkills.xsd @@ -0,0 +1,32 @@ + + + + + + + Magnus' Chant Siren's Dance Song of Champion + + + + + + Mental Shield Magic Barrier Shield Blessed Body Blessed Soul Empower Berserker Spirit Might Focus Concentration Acumen Haste Agility Wind Walk Guidance Death Whisper Bless Shield Resist Shock Vampiric Rage Wild Magic Advanced Block Elemental Protection Divine Protection Arcane Protection Prophecy of Water Prophecy of Fire Prophecy of Wind Chant of Victory Greater Might Greater Shield War Chant Earth Chant Clarity Dance of the Warrior Dance of Inspiration Dance of the Mystic Dance of Fire Dance of Fury Dance of Concentration Dance of Light Dance of Aqua Guard Dance of Earth Guard Dance of the Vampire Dance of Protection Song of Earth Song of Life Song of Water Song of Warding Song of Wind Song of Hunter Song of Invocation Song of Vitality Song of Vengeance Song of Flame Guard Song of Storm Guard Song of Renewal Song of Meditation + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java index c16a2d120b..80726c414d 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java @@ -133,6 +133,7 @@ public final class Config public static final String CUSTOM_SCREEN_WELCOME_MESSAGE_CONFIG_FILE = "./config/Custom/ScreenWelcomeMessage.ini"; public static final String CUSTOM_SELL_BUFFS_CONFIG_FILE = "./config/Custom/SellBuffs.ini"; public static final String CUSTOM_SERVER_TIME_CONFIG_FILE = "./config/Custom/ServerTime.ini"; + public static final String CUSTOM_SCHEME_BUFFER_CONFIG_FILE = "./config/Custom/ShemeBuffer.ini"; public static final String CUSTOM_STARTING_LOCATION_CONFIG_FILE = "./config/Custom/StartingLocation.ini"; public static final String CUSTOM_VOTE_REWARD_CONFIG_FILE = "./config/Custom/VoteReward.ini"; public static final String CUSTOM_WALKER_BOT_PROTECTION_CONFIG_FILE = "./config/Custom/WalkerBotProtection.ini"; @@ -1008,6 +1009,8 @@ public final class Config public static boolean OFFLINE_FAME; public static boolean STORE_OFFLINE_TRADE_IN_REALTIME; public static boolean DISPLAY_SERVER_TIME; + public static int BUFFER_MAX_SCHEMES; + public static int BUFFER_STATIC_BUFF_COST; public static boolean WELCOME_MESSAGE_ENABLED; public static String WELCOME_MESSAGE_TEXT; public static int WELCOME_MESSAGE_TIME; @@ -2769,6 +2772,12 @@ public final class Config DISPLAY_SERVER_TIME = ServerTime.getBoolean("DisplayServerTime", false); + // Load SchemeBuffer config file (if exists) + final PropertiesParser SchemeBuffer = new PropertiesParser(CUSTOM_SCHEME_BUFFER_CONFIG_FILE); + + BUFFER_MAX_SCHEMES = SchemeBuffer.getInt("BufferMaxSchemesPerChar", 4); + BUFFER_STATIC_BUFF_COST = SchemeBuffer.getInt("BufferStaticCostPerBuff", -1); + // Load StartingLocation config file (if exists) final PropertiesParser StartingLocation = new PropertiesParser(CUSTOM_STARTING_LOCATION_CONFIG_FILE); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java index 7316defa0d..289496a640 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java @@ -97,6 +97,7 @@ import com.l2jmobius.gameserver.data.xml.impl.VariationData; import com.l2jmobius.gameserver.datatables.BotReportTable; import com.l2jmobius.gameserver.datatables.EventDroplist; import com.l2jmobius.gameserver.datatables.ItemTable; +import com.l2jmobius.gameserver.datatables.SchemeBufferTable; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.ConditionHandler; import com.l2jmobius.gameserver.handler.DailyMissionHandler; @@ -317,6 +318,7 @@ public class GameServer StaticObjectData.getInstance(); ItemAuctionManager.getInstance(); CastleManager.getInstance().loadInstances(); + SchemeBufferTable.getInstance(); GrandBossManager.getInstance(); EventDroplist.getInstance(); CommissionManager.getInstance(); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/Shutdown.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/Shutdown.java index dbaf36b403..39b43e46dc 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/Shutdown.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/Shutdown.java @@ -26,6 +26,7 @@ import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.data.sql.impl.ClanTable; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; import com.l2jmobius.gameserver.datatables.BotReportTable; +import com.l2jmobius.gameserver.datatables.SchemeBufferTable; import com.l2jmobius.gameserver.instancemanager.CastleManorManager; import com.l2jmobius.gameserver.instancemanager.CeremonyOfChaosManager; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; @@ -521,6 +522,10 @@ public class Shutdown extends Thread GlobalVariablesManager.getInstance().storeMe(); LOGGER.info("Global Variables Manager: Variables saved(" + tc.getEstimatedTimeAndRestartCounter() + "ms)."); + // Schemes save. + SchemeBufferTable.getInstance().saveSchemes(); + LOGGER.info("SchemeBufferTable data has been saved."); + // Save items on ground before closing if (Config.SAVE_DROPPED_ITEM) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/SchemeBufferTable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/SchemeBufferTable.java new file mode 100644 index 0000000000..7b47d8fc45 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/SchemeBufferTable.java @@ -0,0 +1,289 @@ +/* + * 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 . + */ +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.gameserver.model.holders.BuffSkillHolder; + +/** + * This class loads available skills and stores players' buff schemes into _schemesTable. + */ +public class SchemeBufferTable +{ + private static final Logger LOGGER = Logger.getLogger(SchemeBufferTable.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>> _schemesTable = new ConcurrentHashMap<>(); + private final Map _availableBuffs = new LinkedHashMap<>(); + + public SchemeBufferTable() + { + 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 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("SchemeBufferTable: Failed to load buff schemes : " + e); + } + + try + { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(new File("./data/SchemeBufferSkills.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("SchemeBufferTable: Failed to load buff info : " + e); + } + LOGGER.info("SchemeBufferTable: 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>> player : _schemesTable.entrySet()) + { + for (Map.Entry> scheme : player.getValue().entrySet()) + { + // Build a String composed of skill ids seperated by a ",". + final StringBuilder sb = new StringBuilder(); + for (int skillId : scheme.getValue()) + { + sb.append(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("BufferTableScheme: Error while saving schemes : " + e); + } + } + + public void setScheme(int playerId, String schemeName, ArrayList list) + { + if (!_schemesTable.containsKey(playerId)) + { + _schemesTable.put(playerId, new HashMap>()); + } + 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> 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 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 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 getSkillsIdsByType(String groupType) + { + List 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 getSkillTypes() + { + List 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 SchemeBufferTable getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final SchemeBufferTable INSTANCE = new SchemeBufferTable(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/enums/InstanceType.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/enums/InstanceType.java index a918695558..c354fcddb5 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/enums/InstanceType.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/enums/InstanceType.java @@ -83,6 +83,7 @@ public enum InstanceType L2FortDoormenInstance(L2DoormenInstance), // Custom L2ClassMasterInstance(L2NpcInstance), + L2SchemeBufferInstance(L2Npc), L2EventMobInstance(L2Npc); private final InstanceType _parent; diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2SchemeBufferInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2SchemeBufferInstance.java new file mode 100644 index 0000000000..8ed128c7e6 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2SchemeBufferInstance.java @@ -0,0 +1,450 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.model.actor.instance; + +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.SkillData; +import com.l2jmobius.gameserver.datatables.SchemeBufferTable; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.L2Summon; +import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; +import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; + +public class L2SchemeBufferInstance extends L2Npc +{ + private static final int PAGE_LIMIT = 6; + + public L2SchemeBufferInstance(L2NpcTemplate template) + { + super(template); + } + + @Override + public void onBypassFeedback(L2PcInstance player, String command) + { + StringTokenizer st = new StringTokenizer(command, " "); + String currentCommand = st.nextToken(); + + if (currentCommand.startsWith("menu")) + { + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 0)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + else if (currentCommand.startsWith("cleanup")) + { + player.stopAllEffects(); + + final L2Summon summon = player.getPet(); + if (summon != null) + { + summon.stopAllEffects(); + } + + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 0)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + else if (currentCommand.startsWith("heal")) + { + player.setCurrentHpMp(player.getMaxHp(), player.getMaxMp()); + player.setCurrentCp(player.getMaxCp()); + + final L2Summon summon = player.getPet(); + if (summon != null) + { + summon.setCurrentHpMp(summon.getMaxHp(), summon.getMaxMp()); + } + + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 0)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + else if (currentCommand.startsWith("support")) + { + showGiveBuffsWindow(player); + } + else if (currentCommand.startsWith("givebuffs")) + { + final String schemeName = st.nextToken(); + final int cost = Integer.parseInt(st.nextToken()); + + L2Character target = null; + if (st.hasMoreTokens()) + { + final String targetType = st.nextToken(); + if ((targetType != null) && targetType.equalsIgnoreCase("pet")) + { + target = player.getPet(); + } + } + else + { + target = player; + } + + if (target == null) + { + player.sendMessage("You don't have a pet."); + } + else if ((cost == 0) || player.reduceAdena("NPC Buffer", cost, this, true)) + { + for (int skillId : SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName)) + { + SkillData.getInstance().getSkill(skillId, SkillData.getInstance().getMaxLevel(skillId)).applyEffects(this, target); + } + } + } + else if (currentCommand.startsWith("editschemes")) + { + showEditSchemeWindow(player, st.nextToken(), st.nextToken(), Integer.parseInt(st.nextToken())); + } + else if (currentCommand.startsWith("skill")) + { + final String groupType = st.nextToken(); + final String schemeName = st.nextToken(); + + final int skillId = Integer.parseInt(st.nextToken()); + final int page = Integer.parseInt(st.nextToken()); + + final List skills = SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName); + + if (currentCommand.startsWith("skillselect") && !schemeName.equalsIgnoreCase("none")) + { + if (skills.size() < player.getStat().getMaxBuffCount()) + { + skills.add(skillId); + } + else + { + player.sendMessage("This scheme has reached the maximum amount of buffs."); + } + } + else if (currentCommand.startsWith("skillunselect")) + { + skills.remove(Integer.valueOf(skillId)); + } + + showEditSchemeWindow(player, groupType, schemeName, page); + } + else if (currentCommand.startsWith("createscheme")) + { + try + { + final String schemeName = st.nextToken(); + if (schemeName.length() > 14) + { + player.sendMessage("Scheme's name must contain up to 14 chars. Spaces are trimmed."); + return; + } + + final Map> schemes = SchemeBufferTable.getInstance().getPlayerSchemes(player.getObjectId()); + if (schemes != null) + { + if (schemes.size() == Config.BUFFER_MAX_SCHEMES) + { + player.sendMessage("Maximum schemes amount is already reached."); + return; + } + + if (schemes.containsKey(schemeName)) + { + player.sendMessage("The scheme name already exists."); + return; + } + } + + SchemeBufferTable.getInstance().setScheme(player.getObjectId(), schemeName.trim(), new ArrayList()); + showGiveBuffsWindow(player); + } + catch (Exception e) + { + player.sendMessage("Scheme's name must contain up to 14 chars. Spaces are trimmed."); + } + } + else if (currentCommand.startsWith("deletescheme")) + { + try + { + final String schemeName = st.nextToken(); + final Map> schemes = SchemeBufferTable.getInstance().getPlayerSchemes(player.getObjectId()); + + if ((schemes != null) && schemes.containsKey(schemeName)) + { + schemes.remove(schemeName); + } + } + catch (Exception e) + { + player.sendMessage("This scheme name is invalid."); + } + showGiveBuffsWindow(player); + } + } + + @Override + public String getHtmlPath(int npcId, int val) + { + String filename = ""; + if (val == 0) + { + filename = "" + npcId; + } + else + { + filename = npcId + "-" + val; + } + + return "data/html/mods/SchemeBuffer/" + filename + ".htm"; + } + + /** + * Sends an html packet to player with Give Buffs menu info for player and pet, depending on targetType parameter {player, pet} + * @param player : The player to make checks on. + */ + private void showGiveBuffsWindow(L2PcInstance player) + { + final StringBuilder sb = new StringBuilder(200); + + final Map> schemes = SchemeBufferTable.getInstance().getPlayerSchemes(player.getObjectId()); + if ((schemes == null) || schemes.isEmpty()) + { + sb.append("You haven't defined any scheme."); + } + else + { + for (Map.Entry> scheme : schemes.entrySet()) + { + final int cost = getFee(scheme.getValue()); + sb.append("" + scheme.getKey() + " [" + scheme.getValue().size() + " / " + player.getStat().getMaxBuffCount() + "]" + ((cost > 0) ? " - cost: " + NumberFormat.getInstance(Locale.ENGLISH).format(cost) : "") + ""); + sb.append("Use on Me | "); + sb.append("Use on Pet | "); + sb.append("Edit | "); + sb.append("Delete
"); + } + } + + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 1)); + html.replace("%schemes%", sb.toString()); + html.replace("%max_schemes%", Config.BUFFER_MAX_SCHEMES); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + + /** + * This sends an html packet to player with Edit Scheme Menu info. This allows player to edit each created scheme (add/delete skills) + * @param player : The player to make checks on. + * @param groupType : The group of skills to select. + * @param schemeName : The scheme to make check. + * @param page The page. + */ + private void showEditSchemeWindow(L2PcInstance player, String groupType, String schemeName, int page) + { + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + final List schemeSkills = SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName); + + html.setFile(player, getHtmlPath(getId(), 2)); + html.replace("%schemename%", schemeName); + html.replace("%count%", schemeSkills.size() + " / " + player.getStat().getMaxBuffCount()); + html.replace("%typesframe%", getTypesFrame(groupType, schemeName)); + html.replace("%skilllistframe%", getGroupSkillList(player, groupType, schemeName, page)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + + /** + * @param player : The player to make checks on. + * @param groupType : The group of skills to select. + * @param schemeName : The scheme to make check. + * @param page The page. + * @return a String representing skills available to selection for a given groupType. + */ + private String getGroupSkillList(L2PcInstance player, String groupType, String schemeName, int page) + { + // Retrieve the entire skills list based on group type. + List skills = SchemeBufferTable.getInstance().getSkillsIdsByType(groupType); + if (skills.isEmpty()) + { + return "That group doesn't contain any skills."; + } + + // Calculate page number. + final int max = countPagesNumber(skills.size(), PAGE_LIMIT); + if (page > max) + { + page = max; + } + + // Cut skills list up to page number. + skills = skills.subList((page - 1) * PAGE_LIMIT, Math.min(page * PAGE_LIMIT, skills.size())); + + final List schemeSkills = SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName); + final StringBuilder sb = new StringBuilder(skills.size() * 150); + + int row = 0; + for (int skillId : skills) + { + sb.append(((row % 2) == 0 ? "" : "
")); + + if (skillId < 100) + { + if (schemeSkills.contains(skillId)) + { + sb.append(""); + } + else + { + sb.append(""); + } + } + else if (skillId < 1000) + { + if (schemeSkills.contains(skillId)) + { + sb.append(""); + } + else + { + sb.append(""); + } + } + else + { + if (schemeSkills.contains(skillId)) + { + sb.append(""); + } + else + { + sb.append(""); + } + } + + sb.append("
" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "
"); + row++; + } + + // Build page footer. + sb.append("
"); + + if (page > 1) + { + sb.append(""); + } + else + { + sb.append(""); + } + + sb.append(""); + + if (page < max) + { + sb.append(""); + } + else + { + sb.append(""); + } + + sb.append("
PreviousPreviousPage " + page + "NextNext
"); + + return sb.toString(); + } + + /** + * @param groupType : The group of skills to select. + * @param schemeName : The scheme to make check. + * @return a string representing all groupTypes available. The group currently on selection isn't linkable. + */ + private static String getTypesFrame(String groupType, String schemeName) + { + final StringBuilder sb = new StringBuilder(500); + sb.append(""); + + int count = 0; + for (String type : SchemeBufferTable.getInstance().getSkillTypes()) + { + if (count == 0) + { + sb.append(""); + } + + if (groupType.equalsIgnoreCase(type)) + { + sb.append(""); + } + else + { + sb.append(""); + } + + count++; + if (count == 4) + { + sb.append(""); + count = 0; + } + } + + if (!sb.toString().endsWith("")) + { + sb.append(""); + } + + sb.append("
" + type + "" + type + "
"); + + return sb.toString(); + } + + /** + * @param list : A list of skill ids. + * @return a global fee for all skills contained in list. + */ + private static int getFee(ArrayList list) + { + if (Config.BUFFER_STATIC_BUFF_COST > 0) + { + return list.size() * Config.BUFFER_STATIC_BUFF_COST; + } + + int fee = 0; + for (int sk : list) + { + fee += SchemeBufferTable.getInstance().getAvailableBuff(sk).getValue(); + } + + return fee; + } + + private static int countPagesNumber(int objectsSize, int pageSize) + { + return (objectsSize / pageSize) + ((objectsSize % pageSize) == 0 ? 0 : 1); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/BuffSkillHolder.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/BuffSkillHolder.java new file mode 100644 index 0000000000..2e38a43cfb --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/BuffSkillHolder.java @@ -0,0 +1,44 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.model.holders; + +/** + * A container used for schemes buffer. + */ +public final class BuffSkillHolder extends IntIntHolder +{ + private final String _type; + private final String _description; + + public BuffSkillHolder(int id, int price, String type, String description) + { + super(id, price); + + _type = type; + _description = description; + } + + public final String getType() + { + return _type; + } + + public final String getDescription() + { + return _description; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/IntIntHolder.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/IntIntHolder.java new file mode 100644 index 0000000000..22d161aa38 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/IntIntHolder.java @@ -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 . + */ +package com.l2jmobius.gameserver.model.holders; + +import com.l2jmobius.gameserver.data.xml.impl.SkillData; +import com.l2jmobius.gameserver.model.skills.Skill; + +/** + * A generic int/int container. + */ +public class IntIntHolder +{ + private int _id; + private int _value; + + public IntIntHolder(int id, int value) + { + _id = id; + _value = value; + } + + public int getId() + { + return _id; + } + + public int getValue() + { + return _value; + } + + public void setId(int id) + { + _id = id; + } + + public void setValue(int value) + { + _value = value; + } + + /** + * @return the L2Skill associated to the id/value. + */ + public final Skill getSkill() + { + return SkillData.getInstance().getSkill(_id, _value); + } + + @Override + public String toString() + { + return getClass().getSimpleName() + ": Id: " + _id + ", Value: " + _value; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/db_installer/sql/game/buffer_schemes.sql b/L2J_Mobius_Classic_2.0_Zaken/dist/db_installer/sql/game/buffer_schemes.sql new file mode 100644 index 0000000000..ecc7cb6ed7 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/db_installer/sql/game/buffer_schemes.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS `buffer_schemes` ( + `object_id` INT UNSIGNED NOT NULL DEFAULT '0', + `scheme_name` VARCHAR(16) NOT NULL DEFAULT 'default', + `skills` VARCHAR(200) NOT NULL +); \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/config/Custom/ShemeBuffer.ini b/L2J_Mobius_Classic_2.0_Zaken/dist/game/config/Custom/ShemeBuffer.ini new file mode 100644 index 0000000000..9087a3df17 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/config/Custom/ShemeBuffer.ini @@ -0,0 +1,10 @@ +#============================================================= +# Buffer +#============================================================= +# Also check data\SchemeBufferSkills.xml + +# Maximum number of available schemes per player. +BufferMaxSchemesPerChar = 4 + +# Static cost of buffs ; override skills price if different of -1. +BufferStaticCostPerBuff = -1 diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/SchemeBufferSkills.xml b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/SchemeBufferSkills.xml new file mode 100644 index 0000000000..dc54a77ef5 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/SchemeBufferSkills.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008-1.htm b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008-1.htm new file mode 100644 index 0000000000..780dc11dbd --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008-1.htm @@ -0,0 +1,14 @@ + +You can create up to %max_schemes% schemes. Is it clear for you? +If not, read until you get it! I can't afford idiots...
+You can register a new scheme filling this form, here! +
+ + + + +

+Here are listed your schemes and their fee.
+%schemes%
+ + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008-2.htm b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008-2.htm new file mode 100644 index 0000000000..620467cf0e --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008-2.htm @@ -0,0 +1,8 @@ + +%schemename% scheme holds %count% buffs.
+
+%typesframe%
+%skilllistframe%
+
+ + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008.htm b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008.htm new file mode 100644 index 0000000000..e092b4456f --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/mods/SchemeBuffer/50008.htm @@ -0,0 +1,8 @@ + +Hello stranger!
+Yup, you're right, I decided to share some of my powerful buffs in order to improve your pew-pew-bum-zap abilities.
+What can I do for you?
+ + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/stats/npcs/custom/SchemeBuffer.xml b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/stats/npcs/custom/SchemeBuffer.xml new file mode 100644 index 0000000000..222adec5b0 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/stats/npcs/custom/SchemeBuffer.xml @@ -0,0 +1,21 @@ + + + + HUMAN + FEMALE + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/xsd/SchemeBufferSkills.xsd b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/xsd/SchemeBufferSkills.xsd new file mode 100644 index 0000000000..91ae871150 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/xsd/SchemeBufferSkills.xsd @@ -0,0 +1,32 @@ + + + + + + + Magnus' Chant Siren's Dance Song of Champion + + + + + + Mental Shield Magic Barrier Shield Blessed Body Blessed Soul Empower Berserker Spirit Might Focus Concentration Acumen Haste Agility Wind Walk Guidance Death Whisper Bless Shield Resist Shock Vampiric Rage Wild Magic Advanced Block Elemental Protection Divine Protection Arcane Protection Prophecy of Water Prophecy of Fire Prophecy of Wind Chant of Victory Greater Might Greater Shield War Chant Earth Chant Clarity Dance of the Warrior Dance of Inspiration Dance of the Mystic Dance of Fire Dance of Fury Dance of Concentration Dance of Light Dance of Aqua Guard Dance of Earth Guard Dance of the Vampire Dance of Protection Song of Earth Song of Life Song of Water Song of Warding Song of Wind Song of Hunter Song of Invocation Song of Vitality Song of Vengeance Song of Flame Guard Song of Storm Guard Song of Renewal Song of Meditation + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/Config.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/Config.java index b7ed6f6550..69b2000ecc 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/Config.java @@ -133,6 +133,7 @@ public final class Config public static final String CUSTOM_SCREEN_WELCOME_MESSAGE_CONFIG_FILE = "./config/Custom/ScreenWelcomeMessage.ini"; public static final String CUSTOM_SELL_BUFFS_CONFIG_FILE = "./config/Custom/SellBuffs.ini"; public static final String CUSTOM_SERVER_TIME_CONFIG_FILE = "./config/Custom/ServerTime.ini"; + public static final String CUSTOM_SCHEME_BUFFER_CONFIG_FILE = "./config/Custom/ShemeBuffer.ini"; public static final String CUSTOM_STARTING_LOCATION_CONFIG_FILE = "./config/Custom/StartingLocation.ini"; public static final String CUSTOM_VOTE_REWARD_CONFIG_FILE = "./config/Custom/VoteReward.ini"; public static final String CUSTOM_WALKER_BOT_PROTECTION_CONFIG_FILE = "./config/Custom/WalkerBotProtection.ini"; @@ -1012,6 +1013,8 @@ public final class Config public static boolean OFFLINE_FAME; public static boolean STORE_OFFLINE_TRADE_IN_REALTIME; public static boolean DISPLAY_SERVER_TIME; + public static int BUFFER_MAX_SCHEMES; + public static int BUFFER_STATIC_BUFF_COST; public static boolean WELCOME_MESSAGE_ENABLED; public static String WELCOME_MESSAGE_TEXT; public static int WELCOME_MESSAGE_TIME; @@ -2776,6 +2779,12 @@ public final class Config DISPLAY_SERVER_TIME = ServerTime.getBoolean("DisplayServerTime", false); + // Load SchemeBuffer config file (if exists) + final PropertiesParser SchemeBuffer = new PropertiesParser(CUSTOM_SCHEME_BUFFER_CONFIG_FILE); + + BUFFER_MAX_SCHEMES = SchemeBuffer.getInt("BufferMaxSchemesPerChar", 4); + BUFFER_STATIC_BUFF_COST = SchemeBuffer.getInt("BufferStaticCostPerBuff", -1); + // Load StartingLocation config file (if exists) final PropertiesParser StartingLocation = new PropertiesParser(CUSTOM_STARTING_LOCATION_CONFIG_FILE); diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java index 7316defa0d..289496a640 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java @@ -97,6 +97,7 @@ import com.l2jmobius.gameserver.data.xml.impl.VariationData; import com.l2jmobius.gameserver.datatables.BotReportTable; import com.l2jmobius.gameserver.datatables.EventDroplist; import com.l2jmobius.gameserver.datatables.ItemTable; +import com.l2jmobius.gameserver.datatables.SchemeBufferTable; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.ConditionHandler; import com.l2jmobius.gameserver.handler.DailyMissionHandler; @@ -317,6 +318,7 @@ public class GameServer StaticObjectData.getInstance(); ItemAuctionManager.getInstance(); CastleManager.getInstance().loadInstances(); + SchemeBufferTable.getInstance(); GrandBossManager.getInstance(); EventDroplist.getInstance(); CommissionManager.getInstance(); diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/Shutdown.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/Shutdown.java index dbaf36b403..39b43e46dc 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/Shutdown.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/Shutdown.java @@ -26,6 +26,7 @@ import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.data.sql.impl.ClanTable; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; import com.l2jmobius.gameserver.datatables.BotReportTable; +import com.l2jmobius.gameserver.datatables.SchemeBufferTable; import com.l2jmobius.gameserver.instancemanager.CastleManorManager; import com.l2jmobius.gameserver.instancemanager.CeremonyOfChaosManager; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; @@ -521,6 +522,10 @@ public class Shutdown extends Thread GlobalVariablesManager.getInstance().storeMe(); LOGGER.info("Global Variables Manager: Variables saved(" + tc.getEstimatedTimeAndRestartCounter() + "ms)."); + // Schemes save. + SchemeBufferTable.getInstance().saveSchemes(); + LOGGER.info("SchemeBufferTable data has been saved."); + // Save items on ground before closing if (Config.SAVE_DROPPED_ITEM) { diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/datatables/SchemeBufferTable.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/datatables/SchemeBufferTable.java new file mode 100644 index 0000000000..7b47d8fc45 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/datatables/SchemeBufferTable.java @@ -0,0 +1,289 @@ +/* + * 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 . + */ +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.gameserver.model.holders.BuffSkillHolder; + +/** + * This class loads available skills and stores players' buff schemes into _schemesTable. + */ +public class SchemeBufferTable +{ + private static final Logger LOGGER = Logger.getLogger(SchemeBufferTable.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>> _schemesTable = new ConcurrentHashMap<>(); + private final Map _availableBuffs = new LinkedHashMap<>(); + + public SchemeBufferTable() + { + 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 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("SchemeBufferTable: Failed to load buff schemes : " + e); + } + + try + { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(new File("./data/SchemeBufferSkills.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("SchemeBufferTable: Failed to load buff info : " + e); + } + LOGGER.info("SchemeBufferTable: 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>> player : _schemesTable.entrySet()) + { + for (Map.Entry> scheme : player.getValue().entrySet()) + { + // Build a String composed of skill ids seperated by a ",". + final StringBuilder sb = new StringBuilder(); + for (int skillId : scheme.getValue()) + { + sb.append(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("BufferTableScheme: Error while saving schemes : " + e); + } + } + + public void setScheme(int playerId, String schemeName, ArrayList list) + { + if (!_schemesTable.containsKey(playerId)) + { + _schemesTable.put(playerId, new HashMap>()); + } + 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> 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 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 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 getSkillsIdsByType(String groupType) + { + List 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 getSkillTypes() + { + List 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 SchemeBufferTable getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final SchemeBufferTable INSTANCE = new SchemeBufferTable(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/enums/InstanceType.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/enums/InstanceType.java index a918695558..c354fcddb5 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/enums/InstanceType.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/enums/InstanceType.java @@ -83,6 +83,7 @@ public enum InstanceType L2FortDoormenInstance(L2DoormenInstance), // Custom L2ClassMasterInstance(L2NpcInstance), + L2SchemeBufferInstance(L2Npc), L2EventMobInstance(L2Npc); private final InstanceType _parent; diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/actor/instance/L2SchemeBufferInstance.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/actor/instance/L2SchemeBufferInstance.java new file mode 100644 index 0000000000..8ed128c7e6 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/actor/instance/L2SchemeBufferInstance.java @@ -0,0 +1,450 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.model.actor.instance; + +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.SkillData; +import com.l2jmobius.gameserver.datatables.SchemeBufferTable; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.L2Summon; +import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; +import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; + +public class L2SchemeBufferInstance extends L2Npc +{ + private static final int PAGE_LIMIT = 6; + + public L2SchemeBufferInstance(L2NpcTemplate template) + { + super(template); + } + + @Override + public void onBypassFeedback(L2PcInstance player, String command) + { + StringTokenizer st = new StringTokenizer(command, " "); + String currentCommand = st.nextToken(); + + if (currentCommand.startsWith("menu")) + { + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 0)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + else if (currentCommand.startsWith("cleanup")) + { + player.stopAllEffects(); + + final L2Summon summon = player.getPet(); + if (summon != null) + { + summon.stopAllEffects(); + } + + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 0)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + else if (currentCommand.startsWith("heal")) + { + player.setCurrentHpMp(player.getMaxHp(), player.getMaxMp()); + player.setCurrentCp(player.getMaxCp()); + + final L2Summon summon = player.getPet(); + if (summon != null) + { + summon.setCurrentHpMp(summon.getMaxHp(), summon.getMaxMp()); + } + + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 0)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + else if (currentCommand.startsWith("support")) + { + showGiveBuffsWindow(player); + } + else if (currentCommand.startsWith("givebuffs")) + { + final String schemeName = st.nextToken(); + final int cost = Integer.parseInt(st.nextToken()); + + L2Character target = null; + if (st.hasMoreTokens()) + { + final String targetType = st.nextToken(); + if ((targetType != null) && targetType.equalsIgnoreCase("pet")) + { + target = player.getPet(); + } + } + else + { + target = player; + } + + if (target == null) + { + player.sendMessage("You don't have a pet."); + } + else if ((cost == 0) || player.reduceAdena("NPC Buffer", cost, this, true)) + { + for (int skillId : SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName)) + { + SkillData.getInstance().getSkill(skillId, SkillData.getInstance().getMaxLevel(skillId)).applyEffects(this, target); + } + } + } + else if (currentCommand.startsWith("editschemes")) + { + showEditSchemeWindow(player, st.nextToken(), st.nextToken(), Integer.parseInt(st.nextToken())); + } + else if (currentCommand.startsWith("skill")) + { + final String groupType = st.nextToken(); + final String schemeName = st.nextToken(); + + final int skillId = Integer.parseInt(st.nextToken()); + final int page = Integer.parseInt(st.nextToken()); + + final List skills = SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName); + + if (currentCommand.startsWith("skillselect") && !schemeName.equalsIgnoreCase("none")) + { + if (skills.size() < player.getStat().getMaxBuffCount()) + { + skills.add(skillId); + } + else + { + player.sendMessage("This scheme has reached the maximum amount of buffs."); + } + } + else if (currentCommand.startsWith("skillunselect")) + { + skills.remove(Integer.valueOf(skillId)); + } + + showEditSchemeWindow(player, groupType, schemeName, page); + } + else if (currentCommand.startsWith("createscheme")) + { + try + { + final String schemeName = st.nextToken(); + if (schemeName.length() > 14) + { + player.sendMessage("Scheme's name must contain up to 14 chars. Spaces are trimmed."); + return; + } + + final Map> schemes = SchemeBufferTable.getInstance().getPlayerSchemes(player.getObjectId()); + if (schemes != null) + { + if (schemes.size() == Config.BUFFER_MAX_SCHEMES) + { + player.sendMessage("Maximum schemes amount is already reached."); + return; + } + + if (schemes.containsKey(schemeName)) + { + player.sendMessage("The scheme name already exists."); + return; + } + } + + SchemeBufferTable.getInstance().setScheme(player.getObjectId(), schemeName.trim(), new ArrayList()); + showGiveBuffsWindow(player); + } + catch (Exception e) + { + player.sendMessage("Scheme's name must contain up to 14 chars. Spaces are trimmed."); + } + } + else if (currentCommand.startsWith("deletescheme")) + { + try + { + final String schemeName = st.nextToken(); + final Map> schemes = SchemeBufferTable.getInstance().getPlayerSchemes(player.getObjectId()); + + if ((schemes != null) && schemes.containsKey(schemeName)) + { + schemes.remove(schemeName); + } + } + catch (Exception e) + { + player.sendMessage("This scheme name is invalid."); + } + showGiveBuffsWindow(player); + } + } + + @Override + public String getHtmlPath(int npcId, int val) + { + String filename = ""; + if (val == 0) + { + filename = "" + npcId; + } + else + { + filename = npcId + "-" + val; + } + + return "data/html/mods/SchemeBuffer/" + filename + ".htm"; + } + + /** + * Sends an html packet to player with Give Buffs menu info for player and pet, depending on targetType parameter {player, pet} + * @param player : The player to make checks on. + */ + private void showGiveBuffsWindow(L2PcInstance player) + { + final StringBuilder sb = new StringBuilder(200); + + final Map> schemes = SchemeBufferTable.getInstance().getPlayerSchemes(player.getObjectId()); + if ((schemes == null) || schemes.isEmpty()) + { + sb.append("You haven't defined any scheme."); + } + else + { + for (Map.Entry> scheme : schemes.entrySet()) + { + final int cost = getFee(scheme.getValue()); + sb.append("" + scheme.getKey() + " [" + scheme.getValue().size() + " / " + player.getStat().getMaxBuffCount() + "]" + ((cost > 0) ? " - cost: " + NumberFormat.getInstance(Locale.ENGLISH).format(cost) : "") + ""); + sb.append("Use on Me | "); + sb.append("Use on Pet | "); + sb.append("Edit | "); + sb.append("Delete
"); + } + } + + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + html.setFile(player, getHtmlPath(getId(), 1)); + html.replace("%schemes%", sb.toString()); + html.replace("%max_schemes%", Config.BUFFER_MAX_SCHEMES); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + + /** + * This sends an html packet to player with Edit Scheme Menu info. This allows player to edit each created scheme (add/delete skills) + * @param player : The player to make checks on. + * @param groupType : The group of skills to select. + * @param schemeName : The scheme to make check. + * @param page The page. + */ + private void showEditSchemeWindow(L2PcInstance player, String groupType, String schemeName, int page) + { + final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); + final List schemeSkills = SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName); + + html.setFile(player, getHtmlPath(getId(), 2)); + html.replace("%schemename%", schemeName); + html.replace("%count%", schemeSkills.size() + " / " + player.getStat().getMaxBuffCount()); + html.replace("%typesframe%", getTypesFrame(groupType, schemeName)); + html.replace("%skilllistframe%", getGroupSkillList(player, groupType, schemeName, page)); + html.replace("%objectId%", getObjectId()); + player.sendPacket(html); + } + + /** + * @param player : The player to make checks on. + * @param groupType : The group of skills to select. + * @param schemeName : The scheme to make check. + * @param page The page. + * @return a String representing skills available to selection for a given groupType. + */ + private String getGroupSkillList(L2PcInstance player, String groupType, String schemeName, int page) + { + // Retrieve the entire skills list based on group type. + List skills = SchemeBufferTable.getInstance().getSkillsIdsByType(groupType); + if (skills.isEmpty()) + { + return "That group doesn't contain any skills."; + } + + // Calculate page number. + final int max = countPagesNumber(skills.size(), PAGE_LIMIT); + if (page > max) + { + page = max; + } + + // Cut skills list up to page number. + skills = skills.subList((page - 1) * PAGE_LIMIT, Math.min(page * PAGE_LIMIT, skills.size())); + + final List schemeSkills = SchemeBufferTable.getInstance().getScheme(player.getObjectId(), schemeName); + final StringBuilder sb = new StringBuilder(skills.size() * 150); + + int row = 0; + for (int skillId : skills) + { + sb.append(((row % 2) == 0 ? "" : "
")); + + if (skillId < 100) + { + if (schemeSkills.contains(skillId)) + { + sb.append(""); + } + else + { + sb.append(""); + } + } + else if (skillId < 1000) + { + if (schemeSkills.contains(skillId)) + { + sb.append(""); + } + else + { + sb.append(""); + } + } + else + { + if (schemeSkills.contains(skillId)) + { + sb.append(""); + } + else + { + sb.append(""); + } + } + + sb.append("
" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "" + SkillData.getInstance().getSkill(skillId, 1).getName() + "" + SchemeBufferTable.getInstance().getAvailableBuff(skillId).getDescription() + "
"); + row++; + } + + // Build page footer. + sb.append("
"); + + if (page > 1) + { + sb.append(""); + } + else + { + sb.append(""); + } + + sb.append(""); + + if (page < max) + { + sb.append(""); + } + else + { + sb.append(""); + } + + sb.append("
PreviousPreviousPage " + page + "NextNext
"); + + return sb.toString(); + } + + /** + * @param groupType : The group of skills to select. + * @param schemeName : The scheme to make check. + * @return a string representing all groupTypes available. The group currently on selection isn't linkable. + */ + private static String getTypesFrame(String groupType, String schemeName) + { + final StringBuilder sb = new StringBuilder(500); + sb.append(""); + + int count = 0; + for (String type : SchemeBufferTable.getInstance().getSkillTypes()) + { + if (count == 0) + { + sb.append(""); + } + + if (groupType.equalsIgnoreCase(type)) + { + sb.append(""); + } + else + { + sb.append(""); + } + + count++; + if (count == 4) + { + sb.append(""); + count = 0; + } + } + + if (!sb.toString().endsWith("")) + { + sb.append(""); + } + + sb.append("
" + type + "" + type + "
"); + + return sb.toString(); + } + + /** + * @param list : A list of skill ids. + * @return a global fee for all skills contained in list. + */ + private static int getFee(ArrayList list) + { + if (Config.BUFFER_STATIC_BUFF_COST > 0) + { + return list.size() * Config.BUFFER_STATIC_BUFF_COST; + } + + int fee = 0; + for (int sk : list) + { + fee += SchemeBufferTable.getInstance().getAvailableBuff(sk).getValue(); + } + + return fee; + } + + private static int countPagesNumber(int objectsSize, int pageSize) + { + return (objectsSize / pageSize) + ((objectsSize % pageSize) == 0 ? 0 : 1); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/holders/BuffSkillHolder.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/holders/BuffSkillHolder.java new file mode 100644 index 0000000000..2e38a43cfb --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/holders/BuffSkillHolder.java @@ -0,0 +1,44 @@ +/* + * 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 . + */ +package com.l2jmobius.gameserver.model.holders; + +/** + * A container used for schemes buffer. + */ +public final class BuffSkillHolder extends IntIntHolder +{ + private final String _type; + private final String _description; + + public BuffSkillHolder(int id, int price, String type, String description) + { + super(id, price); + + _type = type; + _description = description; + } + + public final String getType() + { + return _type; + } + + public final String getDescription() + { + return _description; + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/holders/IntIntHolder.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/holders/IntIntHolder.java new file mode 100644 index 0000000000..22d161aa38 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/holders/IntIntHolder.java @@ -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 . + */ +package com.l2jmobius.gameserver.model.holders; + +import com.l2jmobius.gameserver.data.xml.impl.SkillData; +import com.l2jmobius.gameserver.model.skills.Skill; + +/** + * A generic int/int container. + */ +public class IntIntHolder +{ + private int _id; + private int _value; + + public IntIntHolder(int id, int value) + { + _id = id; + _value = value; + } + + public int getId() + { + return _id; + } + + public int getValue() + { + return _value; + } + + public void setId(int id) + { + _id = id; + } + + public void setValue(int value) + { + _value = value; + } + + /** + * @return the L2Skill associated to the id/value. + */ + public final Skill getSkill() + { + return SkillData.getInstance().getSkill(_id, _value); + } + + @Override + public String toString() + { + return getClass().getSimpleName() + ": Id: " + _id + ", Value: " + _value; + } +} \ No newline at end of file