· 9 years ago · Jan 06, 2017, 07:34 PM
1### Eclipse Workspace Patch 1.0
2#P L2jFrozen_GameServer
3Index: head-src/com/l2jfrozen/gameserver/Shutdown.java
4===================================================================
5--- head-src/com/l2jfrozen/gameserver/Shutdown.java (revision 412)
6+++ head-src/com/l2jfrozen/gameserver/Shutdown.java (working copy)
7@@ -24,6 +24,7 @@
8 import com.l2jfrozen.Config;
9 import com.l2jfrozen.gameserver.controllers.GameTimeController;
10 import com.l2jfrozen.gameserver.controllers.TradeController;
11+import com.l2jfrozen.gameserver.datatables.BufferTable;
12 import com.l2jfrozen.gameserver.datatables.OfflineTradeTable;
13 import com.l2jfrozen.gameserver.managers.AutoSaveManager;
14 import com.l2jfrozen.gameserver.managers.CastleManorManager;
15@@ -708,6 +709,8 @@
16 // Save all global (non-player specific) Quest data that needs to persist after reboot
17 if(!Config.ALT_DEV_NO_QUESTS)
18 QuestManager.getInstance().save();
19+
20+ BufferTable.getInstance().onServerShutdown();
21
22 //Save items on ground before closing
23 if(Config.SAVE_DROPPED_ITEM)
24Index: head-src/com/l2jfrozen/gameserver/model/holder/IntIntHolder.java
25===================================================================
26--- head-src/com/l2jfrozen/gameserver/model/holder/IntIntHolder.java (revision 0)
27+++ head-src/com/l2jfrozen/gameserver/model/holder/IntIntHolder.java (working copy)
28@@ -0,0 +1,67 @@
29+/*
30+ * This program is free software: you can redistribute it and/or modify it under
31+ * the terms of the GNU General Public License as published by the Free Software
32+ * Foundation, either version 3 of the License, or (at your option) any later
33+ * version.
34+ *
35+ * This program is distributed in the hope that it will be useful, but WITHOUT
36+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
37+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
38+ * details.
39+ *
40+ * You should have received a copy of the GNU General Public License along with
41+ * this program. If not, see <http://www.gnu.org/licenses/>.
42+ */
43+package com.l2jfrozen.gameserver.model.holder;
44+
45+import com.l2jfrozen.gameserver.datatables.SkillTable;
46+import com.l2jfrozen.gameserver.model.L2Skill;
47+
48+/**
49+ * A generic int/int container.
50+ */
51+public class IntIntHolder
52+{
53+ private int _id;
54+ private int _value;
55+
56+ public IntIntHolder(int id, int value)
57+ {
58+ _id = id;
59+ _value = value;
60+ }
61+
62+ public int getId()
63+ {
64+ return _id;
65+ }
66+
67+ public int getValue()
68+ {
69+ return _value;
70+ }
71+
72+ public void setId(int id)
73+ {
74+ _id = id;
75+ }
76+
77+ public void setValue(int value)
78+ {
79+ _value = value;
80+ }
81+
82+ /**
83+ * @return the L2Skill associated to the id/value.
84+ */
85+ public final L2Skill getSkill()
86+ {
87+ return SkillTable.getInstance().getInfo(_id, _value);
88+ }
89+
90+ @Override
91+ public String toString()
92+ {
93+ return getClass().getSimpleName() + ": Id: " + _id + ", Value: " + _value;
94+ }
95+}
96\ No newline at end of file
97Index: head-src/com/l2jfrozen/gameserver/model/actor/instance/L2SchemeInstance.java
98===================================================================
99--- head-src/com/l2jfrozen/gameserver/model/actor/instance/L2SchemeInstance.java (revision 0)
100+++ head-src/com/l2jfrozen/gameserver/model/actor/instance/L2SchemeInstance.java (working copy)
101@@ -0,0 +1,483 @@
102+/*
103+ * This program is free software; you can redistribute it and/or modify
104+ * it under the terms of the GNU General Public License as published by
105+ * the Free Software Foundation; either version 2, or (at your option)
106+ * any later version.
107+ *
108+ * This program is distributed in the hope that it will be useful,
109+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
110+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111+ * GNU General Public License for more details.
112+ *
113+ * You should have received a copy of the GNU General Public License
114+ * along with this program; if not, write to the Free Software
115+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
116+ * 02111-1307, USA.
117+ *
118+ * http://www.gnu.org/copyleft/gpl.html
119+ */
120+package com.l2jfrozen.gameserver.model.actor.instance;
121+
122+import java.util.ArrayList;
123+import java.util.List;
124+import java.util.Map;
125+import java.util.StringTokenizer;
126+
127+import com.l2jfrozen.Config;
128+import com.l2jfrozen.gameserver.datatables.BufferTable;
129+import com.l2jfrozen.gameserver.datatables.SkillTable;
130+import com.l2jfrozen.gameserver.model.L2Character;
131+import com.l2jfrozen.gameserver.model.L2Summon;
132+import com.l2jfrozen.gameserver.network.serverpackets.NpcHtmlMessage;
133+import com.l2jfrozen.gameserver.templates.L2NpcTemplate;
134+import com.l2jfrozen.util.StringUtil;
135+
136+public class L2SchemeInstance extends L2NpcInstance
137+{
138+ public L2SchemeInstance(int objectId, L2NpcTemplate template)
139+ {
140+ super(objectId, template);
141+ }
142+
143+ @Override
144+ public void onBypassFeedback(L2PcInstance player, String command)
145+ {
146+ StringTokenizer st = new StringTokenizer(command, " ");
147+ String currentCommand = st.nextToken();
148+
149+ if (currentCommand.startsWith("menu"))
150+ {
151+ final NpcHtmlMessage html = new NpcHtmlMessage(0);
152+ html.setFile(getHtmlPath(getNpcId(), 0));
153+ html.replace("%objectId%", getObjectId());
154+ player.sendPacket(html);
155+ }
156+ else if (currentCommand.startsWith("cleanup"))
157+ {
158+ player.stopAllEffects();
159+
160+ final L2Summon summon = player.getPet();
161+ if (summon != null)
162+ summon.stopAllEffects();
163+
164+ final NpcHtmlMessage html = new NpcHtmlMessage(0);
165+ html.setFile(getHtmlPath(getNpcId(), 0));
166+ html.replace("%objectId%", getObjectId());
167+ player.sendPacket(html);
168+ }
169+ else if (currentCommand.startsWith("heal"))
170+ {
171+ player.setCurrentHpMp(player.getMaxHp(), player.getMaxMp());
172+ player.setCurrentCp(player.getMaxCp());
173+
174+ final L2Summon summon = player.getPet();
175+ if (summon != null)
176+ summon.setCurrentHpMp(summon.getMaxHp(), summon.getMaxMp());
177+
178+ final NpcHtmlMessage html = new NpcHtmlMessage(0);
179+ html.setFile(getHtmlPath(getNpcId(), 0));
180+ html.replace("%objectId%", getObjectId());
181+ player.sendPacket(html);
182+ }
183+ else if (currentCommand.startsWith("support"))
184+ {
185+ showGiveBuffsWindow(player, st.nextToken());
186+ }
187+ else if (currentCommand.startsWith("givebuffs"))
188+ {
189+ final String targetType = st.nextToken();
190+ final String schemeName = st.nextToken();
191+ final int cost = Integer.parseInt(st.nextToken());
192+
193+ final L2Character target = (targetType.equalsIgnoreCase("pet")) ? player.getPet() : player;
194+ if (target == null)
195+ player.sendMessage("You don't have a pet.");
196+ else if (cost == 0 || player.reduceAdena("NPC Buffer", cost, this, true))
197+ {
198+ for (int skillId : BufferTable.getInstance().getScheme(player.getObjectId(), schemeName))
199+ SkillTable.getInstance().getInfo(skillId, SkillTable.getInstance().getMaxLevel(skillId, 0)).getEffects(this, target);
200+ }
201+ showGiveBuffsWindow(player, targetType);
202+ }
203+ else if (currentCommand.startsWith("editschemes"))
204+ {
205+ showEditSchemeWindow(player, st.nextToken(), st.nextToken());
206+ }
207+ else if (currentCommand.startsWith("skill"))
208+ {
209+ final String groupType = st.nextToken();
210+ final String schemeName = st.nextToken();
211+
212+ final int skillId = Integer.parseInt(st.nextToken());
213+
214+ final List<Integer> skills = BufferTable.getInstance().getScheme(player.getObjectId(), schemeName);
215+
216+ if (currentCommand.startsWith("skillselect") && !schemeName.equalsIgnoreCase("none"))
217+ {
218+ if (skills.size() < Config.BUFFER_MAX_SKILLS)
219+ skills.add(skillId);
220+ else
221+ player.sendMessage("This scheme has reached the maximum amount of buffs.");
222+ }
223+ else if (currentCommand.startsWith("skillunselect"))
224+ skills.remove(Integer.valueOf(skillId));
225+
226+ showEditSchemeWindow(player, groupType, schemeName);
227+ }
228+ else if (currentCommand.startsWith("manageschemes"))
229+ {
230+ showManageSchemeWindow(player);
231+ }
232+ else if (currentCommand.startsWith("createscheme"))
233+ {
234+ try
235+ {
236+ final String schemeName = st.nextToken();
237+ if (schemeName.length() > 14)
238+ {
239+ player.sendMessage("Scheme's name must contain up to 14 chars. Spaces are trimmed.");
240+ showManageSchemeWindow(player);
241+ return;
242+ }
243+
244+ final Map<String, ArrayList<Integer>> schemes = BufferTable.getInstance().getPlayerSchemes(player.getObjectId());
245+ if (schemes != null)
246+ {
247+ if (schemes.size() == Config.BUFFER_MAX_SCHEMES)
248+ {
249+ player.sendMessage("Maximum schemes amount is already reached.");
250+ showManageSchemeWindow(player);
251+ return;
252+ }
253+
254+ if (schemes.containsKey(schemeName))
255+ {
256+ player.sendMessage("The scheme name already exists.");
257+ showManageSchemeWindow(player);
258+ return;
259+ }
260+ }
261+
262+ BufferTable.getInstance().setScheme(player.getObjectId(), schemeName.trim(), new ArrayList<Integer>());
263+ showManageSchemeWindow(player);
264+ }
265+ catch (Exception e)
266+ {
267+ player.sendMessage("Scheme's name must contain up to 14 chars. Spaces are trimmed.");
268+ showManageSchemeWindow(player);
269+ }
270+ }
271+ else if (currentCommand.startsWith("deletescheme"))
272+ {
273+ try
274+ {
275+ final String schemeName = st.nextToken();
276+ final Map<String, ArrayList<Integer>> schemes = BufferTable.getInstance().getPlayerSchemes(player.getObjectId());
277+
278+ if (schemes != null && schemes.containsKey(schemeName))
279+ schemes.remove(schemeName);
280+ }
281+ catch (Exception e)
282+ {
283+ player.sendMessage("This scheme name is invalid.");
284+ }
285+ showManageSchemeWindow(player);
286+ }
287+ else if (currentCommand.startsWith("clearscheme"))
288+ {
289+ try
290+ {
291+ final String schemeName = st.nextToken();
292+ final Map<String, ArrayList<Integer>> schemes = BufferTable.getInstance().getPlayerSchemes(player.getObjectId());
293+
294+ if (schemes != null && schemes.containsKey(schemeName))
295+ schemes.get(schemeName).clear();
296+ }
297+ catch (Exception e)
298+ {
299+ player.sendMessage("This scheme name is invalid.");
300+ }
301+ showManageSchemeWindow(player);
302+ }
303+
304+ super.onBypassFeedback(player, command);
305+ }
306+
307+ @Override
308+ public String getHtmlPath(int npcId, int val)
309+ {
310+ String filename = "";
311+ if (val == 0)
312+ filename = "" + npcId;
313+ else
314+ filename = npcId + "-" + val;
315+
316+ return "data/html/mods/buffer/" + filename + ".htm";
317+ }
318+
319+ /**
320+ * Sends an html packet to player with Give Buffs menu info for player and pet, depending on targetType parameter {player, pet}
321+ * @param player : The player to make checks on.
322+ * @param targetType : a String used to define if the player or his pet must be used as target.
323+ */
324+ private void showGiveBuffsWindow(L2PcInstance player, String targetType)
325+ {
326+ final StringBuilder sb = new StringBuilder(200);
327+
328+ final Map<String, ArrayList<Integer>> schemes = BufferTable.getInstance().getPlayerSchemes(player.getObjectId());
329+ if (schemes == null || schemes.isEmpty())
330+ sb.append("<font color=\"LEVEL\">You haven't defined any scheme, please go to 'Manage my schemes' and create at least one valid scheme.</font>");
331+ else
332+ {
333+ for (Map.Entry<String, ArrayList<Integer>> scheme : schemes.entrySet())
334+ {
335+ final int cost = getFee(scheme.getValue());
336+ StringUtil.append(sb, "<font color=\"LEVEL\"><a action=\"bypass -h npc_%objectId%_givebuffs ", targetType, " ", scheme.getKey(), " ", cost, "\">", scheme.getKey(), " (", scheme.getValue().size(), " skill(s))</a>", ((cost > 0) ? " - Adena cost: " + cost : ""), "</font><br1>");
337+ }
338+ }
339+
340+ final NpcHtmlMessage html = new NpcHtmlMessage(0);
341+ html.setFile(getHtmlPath(getNpcId(), 1));
342+ html.replace("%schemes%", sb.toString());
343+ html.replace("%targettype%", (targetType.equalsIgnoreCase("pet") ? " <a action=\"bypass -h npc_%objectId%_support player\">yourself</a> | your pet" : "yourself | <a action=\"bypass -h npc_%objectId%_support pet\">your pet</a>"));
344+ html.replace("%objectId%", getObjectId());
345+ player.sendPacket(html);
346+ }
347+
348+ /**
349+ * Sends an html packet to player with Manage scheme menu info. This allows player to create/delete/clear schemes
350+ * @param player : The player to make checks on.
351+ */
352+ private void showManageSchemeWindow(L2PcInstance player)
353+ {
354+ final StringBuilder sb = new StringBuilder(200);
355+
356+ final Map<String, ArrayList<Integer>> schemes = BufferTable.getInstance().getPlayerSchemes(player.getObjectId());
357+ if (schemes == null || schemes.isEmpty())
358+ sb.append("<font color=\"LEVEL\">You haven't created any scheme.</font>");
359+ else
360+ {
361+ sb.append("<table>");
362+ for (Map.Entry<String, ArrayList<Integer>> scheme : schemes.entrySet())
363+ StringUtil.append(sb, "<tr><td width=140>", scheme.getKey(), " (", scheme.getValue().size(), " skill(s))</td><td width=60><button value=\"Clear\" action=\"bypass -h npc_%objectId%_clearscheme ", scheme.getKey(), "\" width=55 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td><td width=60><button value=\"Drop\" action=\"bypass -h npc_%objectId%_deletescheme ", scheme.getKey(), "\" width=55 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr>");
364+
365+ sb.append("</table>");
366+ }
367+
368+ final NpcHtmlMessage html = new NpcHtmlMessage(0);
369+ html.setFile(getHtmlPath(getNpcId(), 2));
370+ html.replace("%schemes%", sb.toString());
371+ html.replace("%max_schemes%", Config.BUFFER_MAX_SCHEMES);
372+ html.replace("%objectId%", getObjectId());
373+ player.sendPacket(html);
374+ }
375+
376+ /**
377+ * This sends an html packet to player with Edit Scheme Menu info. This allows player to edit each created scheme (add/delete skills)
378+ * @param player : The player to make checks on.
379+ * @param groupType : The group of skills to select.
380+ * @param schemeName : The scheme to make check.
381+ */
382+ private void showEditSchemeWindow(L2PcInstance player, String groupType, String schemeName)
383+ {
384+ final NpcHtmlMessage html = new NpcHtmlMessage(0);
385+
386+ if (schemeName.equalsIgnoreCase("none"))
387+ html.setFile(getHtmlPath(getNpcId(), 3));
388+ else
389+ {
390+ if (groupType.equalsIgnoreCase("none"))
391+ html.setFile(getHtmlPath(getNpcId(), 4));
392+ else
393+ {
394+ html.setFile(getHtmlPath(getNpcId(), 5));
395+ html.replace("%skilllistframe%", getGroupSkillList(player, groupType, schemeName));
396+ }
397+ html.replace("%schemename%", schemeName);
398+ html.replace("%myschemeframe%", getPlayerSchemeSkillList(player, groupType, schemeName));
399+ html.replace("%typesframe%", getTypesFrame(groupType, schemeName));
400+ }
401+ html.replace("%schemes%", getPlayerSchemes(player, schemeName));
402+ html.replace("%objectId%", getObjectId());
403+ player.sendPacket(html);
404+ }
405+
406+ /**
407+ * @param player : The player to make checks on.
408+ * @param schemeName : The name to don't link (previously clicked).
409+ * @return a String listing player's schemes. The scheme currently on selection isn't linkable.
410+ */
411+ private static String getPlayerSchemes(L2PcInstance player, String schemeName)
412+ {
413+ final Map<String, ArrayList<Integer>> schemes = BufferTable.getInstance().getPlayerSchemes(player.getObjectId());
414+ if (schemes == null || schemes.isEmpty())
415+ return "Please create at least one scheme.";
416+
417+ final StringBuilder sb = new StringBuilder(200);
418+ sb.append("<table>");
419+
420+ for (Map.Entry<String, ArrayList<Integer>> scheme : schemes.entrySet())
421+ {
422+ if (schemeName.equalsIgnoreCase(scheme.getKey()))
423+ StringUtil.append(sb, "<tr><td width=200>", scheme.getKey(), " (<font color=\"LEVEL\">", scheme.getValue().size(), "</font> / ", Config.BUFFER_MAX_SKILLS, " skill(s))</td></tr>");
424+ else
425+ StringUtil.append(sb, "<tr><td width=200><a action=\"bypass -h npc_%objectId%_editschemes none ", scheme.getKey(), "\">", scheme.getKey(), " (", scheme.getValue().size(), " / ", Config.BUFFER_MAX_SKILLS, " skill(s))</a></td></tr>");
426+ }
427+
428+ sb.append("</table>");
429+
430+ return sb.toString();
431+ }
432+
433+ /**
434+ * @param player : The player to make checks on.
435+ * @param groupType : The group of skills to select.
436+ * @param schemeName : The scheme to make check.
437+ * @return a String representing skills available to selection for a given groupType.
438+ */
439+ private static String getGroupSkillList(L2PcInstance player, String groupType, String schemeName)
440+ {
441+ final List<Integer> skills = new ArrayList<>();
442+ for (int skillId : BufferTable.getSkillsIdsByType(groupType))
443+ {
444+ if (BufferTable.getInstance().getSchemeContainsSkill(player.getObjectId(), schemeName, skillId))
445+ continue;
446+
447+ skills.add(skillId);
448+ }
449+
450+ if (skills.isEmpty())
451+ return "That group doesn't contain any skills.";
452+
453+ final StringBuilder sb = new StringBuilder(500);
454+
455+ sb.append("<table>");
456+ int count = 0;
457+ for (int skillId : skills)
458+ {
459+ if (BufferTable.getInstance().getSchemeContainsSkill(player.getObjectId(), schemeName, skillId))
460+ continue;
461+
462+ if (count == 0)
463+ sb.append("<tr>");
464+
465+ if (skillId < 100)
466+ StringUtil.append(sb, "<td><button action=\"bypass -h npc_%objectId%_skillselect ", groupType, " ", schemeName, " ", skillId, "\" width=32 height=32 back=\"icon.skill00", skillId, "\" fore=\"icon.skill00", skillId, "\"></td>");
467+ else if (skillId < 1000)
468+ StringUtil.append(sb, "<td><button action=\"bypass -h npc_%objectId%_skillselect ", groupType, " ", schemeName, " ", skillId, "\" width=32 height=32 back=\"icon.skill0", skillId, "\" fore=\"icon.skill0", skillId, "\"></td>");
469+ else
470+ StringUtil.append(sb, "<td><button action=\"bypass -h npc_%objectId%_skillselect ", groupType, " ", schemeName, " ", skillId, "\" width=32 height=32 back=\"icon.skill", skillId, "\" fore=\"icon.skill", skillId, "\"></td>");
471+
472+ count++;
473+ if (count == 6)
474+ {
475+ sb.append("</tr>");
476+ count = 0;
477+ }
478+ }
479+
480+ if (!sb.toString().endsWith("</tr>"))
481+ sb.append("</tr>");
482+
483+ sb.append("</table>");
484+
485+ return sb.toString();
486+ }
487+
488+ /**
489+ * @param player : The player to make checks on.
490+ * @param groupType : The group of skills to select.
491+ * @param schemeName : The scheme to make check.
492+ * @return a String representing a given scheme's content.
493+ */
494+ private static String getPlayerSchemeSkillList(L2PcInstance player, String groupType, String schemeName)
495+ {
496+ final List<Integer> skills = BufferTable.getInstance().getScheme(player.getObjectId(), schemeName);
497+ if (skills.isEmpty())
498+ return "That scheme is empty.";
499+
500+ final StringBuilder sb = new StringBuilder(500);
501+ sb.append("<table>");
502+ int count = 0;
503+
504+ for (int sk : skills)
505+ {
506+ if (count == 0)
507+ sb.append("<tr>");
508+
509+ if (sk < 100)
510+ StringUtil.append(sb, "<td><button action=\"bypass -h npc_%objectId%_skillunselect ", groupType, " ", schemeName, " ", sk, "\" width=32 height=32 back=\"icon.skill00", sk, "\" fore=\"icon.skill00", sk, "\"></td>");
511+ else if (sk < 1000)
512+ StringUtil.append(sb, "<td><button action=\"bypass -h npc_%objectId%_skillunselect ", groupType, " ", schemeName, " ", sk, "\" width=32 height=32 back=\"icon.skill0", sk, "\" fore=\"icon.skill0", sk, "\"></td>");
513+ else
514+ StringUtil.append(sb, "<td><button action=\"bypass -h npc_%objectId%_skillunselect ", groupType, " ", schemeName, " ", sk, "\" width=32 height=32 back=\"icon.skill", sk, "\" fore=\"icon.skill", sk, "\"></td>");
515+
516+ count++;
517+ if (count == 6)
518+ {
519+ sb.append("</tr>");
520+ count = 0;
521+ }
522+ }
523+
524+ if (!sb.toString().endsWith("<tr>"))
525+ sb.append("<tr>");
526+
527+ sb.append("</table>");
528+
529+ return sb.toString();
530+ }
531+
532+ /**
533+ * @param groupType : The group of skills to select.
534+ * @param schemeName : The scheme to make check.
535+ * @return a string representing all groupTypes availables. The group currently on selection isn't linkable.
536+ */
537+ private static String getTypesFrame(String groupType, String schemeName)
538+ {
539+ final StringBuilder sb = new StringBuilder(500);
540+ sb.append("<table>");
541+
542+ int count = 0;
543+ for (String s : BufferTable.getSkillTypes())
544+ {
545+ if (count == 0)
546+ sb.append("<tr>");
547+
548+ if (groupType.equalsIgnoreCase(s))
549+ StringUtil.append(sb, "<td width=65>", s, "</td>");
550+ else
551+ StringUtil.append(sb, "<td width=65><a action=\"bypass -h npc_%objectId%_editschemes ", s, " ", schemeName, "\">", s, "</a></td>");
552+
553+ count++;
554+ if (count == 4)
555+ {
556+ sb.append("</tr>");
557+ count = 0;
558+ }
559+ }
560+
561+ if (!sb.toString().endsWith("</tr>"))
562+ sb.append("</tr>");
563+
564+ sb.append("</table>");
565+
566+ return sb.toString();
567+ }
568+
569+ /**
570+ * @param list : A list of skill ids.
571+ * @return a global fee for all skills contained in list.
572+ */
573+ private static int getFee(ArrayList<Integer> list)
574+ {
575+ if (Config.BUFFER_STATIC_BUFF_COST >= 0)
576+ return (list.size() * Config.BUFFER_STATIC_BUFF_COST);
577+
578+ int fee = 0;
579+ for (int sk : list)
580+ fee += Config.BUFFER_BUFFLIST.get(sk).getValue();
581+
582+ return fee;
583+ }
584+}
585\ No newline at end of file
586Index: head-src/com/l2jfrozen/gameserver/GameServer.java
587===================================================================
588--- head-src/com/l2jfrozen/gameserver/GameServer.java (revision 412)
589+++ head-src/com/l2jfrozen/gameserver/GameServer.java (working copy)
590@@ -41,6 +41,7 @@
591 import com.l2jfrozen.gameserver.controllers.GameTimeController;
592 import com.l2jfrozen.gameserver.controllers.RecipeController;
593 import com.l2jfrozen.gameserver.controllers.TradeController;
594+import com.l2jfrozen.gameserver.datatables.BufferTable;
595 import com.l2jfrozen.gameserver.datatables.GmListTable;
596 import com.l2jfrozen.gameserver.datatables.HeroSkillTable;
597 import com.l2jfrozen.gameserver.datatables.NobleSkillTable;
598@@ -530,6 +531,8 @@
599
600 Util.printSection("Custom Mods");
601
602+ BufferTable.getInstance();
603+
604 if (Config.L2JMOD_ALLOW_WEDDING || Config.ALLOW_AWAY_STATUS || Config.PCB_ENABLE)
605 {
606 if (Config.L2JMOD_ALLOW_WEDDING)
607Index: head-src/com/l2jfrozen/util/StringUtil.java
608===================================================================
609--- head-src/com/l2jfrozen/util/StringUtil.java (revision 412)
610+++ head-src/com/l2jfrozen/util/StringUtil.java (working copy)
611@@ -311,4 +311,15 @@
612 TextBuilder.recycle(sbString);
613 return result;
614 }
615+
616+ /**
617+ * Appends objects to an existing StringBuilder.
618+ * @param sb : the StringBuilder to edit.
619+ * @param content : parameters to append.
620+ */
621+ public static void append(StringBuilder sb, Object... content)
622+ {
623+ for (Object obj : content)
624+ sb.append((obj == null) ? null : obj.toString());
625+ }
626 }
627Index: head-src/com/l2jfrozen/gameserver/datatables/BufferTable.java
628===================================================================
629--- head-src/com/l2jfrozen/gameserver/datatables/BufferTable.java (revision 0)
630+++ head-src/com/l2jfrozen/gameserver/datatables/BufferTable.java (working copy)
631@@ -0,0 +1,263 @@
632+/*
633+ * This program is free software; you can redistribute it and/or modify
634+ * it under the terms of the GNU General Public License as published by
635+ * the Free Software Foundation; either version 2, or (at your option)
636+ * any later version.
637+ *
638+ * This program is distributed in the hope that it will be useful,
639+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
640+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
641+ * GNU General Public License for more details.
642+ *
643+ * You should have received a copy of the GNU General Public License
644+ * along with this program; if not, write to the Free Software
645+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
646+ * 02111-1307, USA.
647+ *
648+ * http://www.gnu.org/copyleft/gpl.html
649+ */
650+package com.l2jfrozen.gameserver.datatables;
651+
652+import java.sql.Connection;
653+import java.sql.PreparedStatement;
654+import java.sql.ResultSet;
655+import java.util.ArrayList;
656+import java.util.Collections;
657+import java.util.HashMap;
658+import java.util.List;
659+import java.util.Map;
660+import java.util.concurrent.ConcurrentHashMap;
661+import java.util.logging.Logger;
662+
663+import com.l2jfrozen.Config;
664+import com.l2jfrozen.gameserver.model.holder.BuffSkillHolder;
665+import com.l2jfrozen.util.CloseUtil;
666+import com.l2jfrozen.util.StringUtil;
667+import com.l2jfrozen.util.database.L2DatabaseFactory;
668+
669+/**
670+ * This class stores players' buff schemes into _schemesTable.
671+ * @author House, Tryskell
672+ */
673+public class BufferTable
674+{
675+ private static final Logger _log = Logger.getLogger(BufferTable.class.getName());
676+
677+ private static final Map<Integer, HashMap<String, ArrayList<Integer>>> _schemesTable = new ConcurrentHashMap<>();
678+
679+ private static final String LOAD_SCHEMES = "SELECT * FROM buffer_schemes";
680+ private static final String DELETE_SCHEMES = "TRUNCATE TABLE buffer_schemes";
681+ private static final String INSERT_SCHEME = "INSERT INTO buffer_schemes (object_id, scheme_name, skills) VALUES (?,?,?)";
682+
683+ public static BufferTable getInstance()
684+ {
685+ return SingletonHolder._instance;
686+ }
687+
688+ public BufferTable()
689+ {
690+ int count = 0;
691+
692+ try (Connection con = L2DatabaseFactory.getInstance().getConnection())
693+ {
694+ PreparedStatement st = con.prepareStatement(LOAD_SCHEMES);
695+ ResultSet rs = st.executeQuery();
696+
697+ while (rs.next())
698+ {
699+ final int objectId = rs.getInt("object_id");
700+
701+ final String schemeName = rs.getString("scheme_name");
702+ final String[] skills = rs.getString("skills").split(",");
703+
704+ ArrayList<Integer> schemeList = new ArrayList<>();
705+ for (String skill : skills)
706+ {
707+ // Don't feed the skills list if the config is reached, or if the list is empty.
708+ if (skill.isEmpty() || schemeList.size() >= Config.BUFFER_MAX_SKILLS)
709+ break;
710+
711+ schemeList.add(Integer.valueOf(skill));
712+ }
713+ setScheme(objectId, schemeName, schemeList);
714+ count++;
715+ }
716+
717+ rs.close();
718+ st.close();
719+ }
720+ catch (Exception e)
721+ {
722+ _log.warning("BufferTable: Failed to load buff schemes : " + e);
723+ }
724+ _log.info("BufferTable: Loaded " + count + " players schemes.");
725+ }
726+
727+ /**
728+ * Do necessary task when server is shutting down or restarting:<br>
729+ * <li>Clears DataBase</li> <li>Saves new info</li>
730+ */
731+ public void onServerShutdown()
732+ {
733+ clearDB();
734+ saveSchemes();
735+ }
736+
737+ public void clearDB()
738+ {
739+ if (_schemesTable.isEmpty())
740+ return;
741+
742+ Connection con = null;
743+ try
744+ {
745+ con = L2DatabaseFactory.getInstance().getConnection(false);
746+ for (Map.Entry<Integer, HashMap<String, ArrayList<Integer>>> player : _schemesTable.entrySet())
747+ {
748+ PreparedStatement statement = con.prepareStatement(DELETE_SCHEMES);
749+ statement.setInt(1, player.getKey());
750+ statement.execute();
751+ }
752+ }
753+ catch (Exception e)
754+ {
755+ if(Config.ENABLE_ALL_EXCEPTIONS)
756+ e.printStackTrace();
757+
758+ _log.warning("CharSchemesTable: Error while trying to delete schemes");
759+ }
760+ finally
761+ {
762+ CloseUtil.close(con);
763+ }
764+ }
765+
766+ public void saveSchemes()
767+ {
768+ if (_schemesTable.isEmpty())
769+ return;
770+
771+ try (Connection con = L2DatabaseFactory.getInstance().getConnection())
772+ {
773+ // Delete all entries from database.
774+ PreparedStatement st = con.prepareStatement(DELETE_SCHEMES);
775+ st.execute();
776+ st.close();
777+
778+ st = con.prepareStatement(INSERT_SCHEME);
779+
780+ // Save _schemesTable content.
781+ for (Map.Entry<Integer, HashMap<String, ArrayList<Integer>>> player : _schemesTable.entrySet())
782+ {
783+ for (Map.Entry<String, ArrayList<Integer>> scheme : player.getValue().entrySet())
784+ {
785+ // Build a String composed of skill ids seperated by a ",".
786+ final StringBuilder sb = new StringBuilder();
787+ for (int skillId : scheme.getValue())
788+ StringUtil.append(sb, skillId, ",");
789+
790+ // Delete the last "," : must be called only if there is something to delete !
791+ if (sb.length() > 0)
792+ sb.setLength(sb.length() - 1);
793+
794+ st.setInt(1, player.getKey());
795+ st.setString(2, scheme.getKey());
796+ st.setString(3, sb.toString());
797+ st.executeUpdate();
798+ st.clearParameters();
799+ }
800+ }
801+ st.close();
802+ }
803+ catch (Exception e)
804+ {
805+ _log.warning("BufferTable: Error while saving schemes : " + e);
806+ }
807+ }
808+
809+ public void setScheme(int playerId, String schemeName, ArrayList<Integer> list)
810+ {
811+ if (!_schemesTable.containsKey(playerId))
812+ _schemesTable.put(playerId, new HashMap<String, ArrayList<Integer>>());
813+ else if (_schemesTable.get(playerId).size() >= Config.BUFFER_MAX_SCHEMES)
814+ return;
815+
816+ _schemesTable.get(playerId).put(schemeName, list);
817+ }
818+
819+ /**
820+ * @param playerId : The player objectId to check.
821+ * @return the list of schemes for a given player.
822+ */
823+ public Map<String, ArrayList<Integer>> getPlayerSchemes(int playerId)
824+ {
825+ return _schemesTable.get(playerId);
826+ }
827+
828+ /**
829+ * @param playerId : The player objectId to check.
830+ * @param schemeName : The scheme name to check.
831+ * @return the List holding skills for the given scheme name and player, or null (if scheme or player isn't registered).
832+ */
833+ public List<Integer> getScheme(int playerId, String schemeName)
834+ {
835+ if (_schemesTable.get(playerId) == null || _schemesTable.get(playerId).get(schemeName) == null)
836+ return Collections.emptyList();
837+
838+ return _schemesTable.get(playerId).get(schemeName);
839+ }
840+
841+ /**
842+ * @param playerId : The player objectId to check.
843+ * @param schemeName : The scheme name to check.
844+ * @param skillId : The skill id to check.
845+ * @return true if the skill is already registered on the scheme, or false otherwise.
846+ */
847+ public boolean getSchemeContainsSkill(int playerId, String schemeName, int skillId)
848+ {
849+ final List<Integer> skills = getScheme(playerId, schemeName);
850+ if (skills.isEmpty())
851+ return false;
852+
853+ for (int id : skills)
854+ {
855+ if (id == skillId)
856+ return true;
857+ }
858+ return false;
859+ }
860+
861+ /**
862+ * @param groupType : The type of skills to return.
863+ * @return a list of skills ids based on the given groupType.
864+ */
865+ public static List<Integer> getSkillsIdsByType(String groupType)
866+ {
867+ List<Integer> skills = new ArrayList<>();
868+ for (BuffSkillHolder skill : Config.BUFFER_BUFFLIST.values())
869+ {
870+ if (skill.getType().equalsIgnoreCase(groupType))
871+ skills.add(skill.getId());
872+ }
873+ return skills;
874+ }
875+
876+ /**
877+ * @return a list of all buff types available.
878+ */
879+ public static List<String> getSkillTypes()
880+ {
881+ List<String> skillTypes = new ArrayList<>();
882+ for (BuffSkillHolder skill : Config.BUFFER_BUFFLIST.values())
883+ {
884+ if (!skillTypes.contains(skill.getType()))
885+ skillTypes.add(skill.getType());
886+ }
887+ return skillTypes;
888+ }
889+
890+ private static class SingletonHolder
891+ {
892+ protected static final BufferTable _instance = new BufferTable();
893+ }
894+}
895\ No newline at end of file
896Index: head-src/com/l2jfrozen/gameserver/model/holder/BuffSkillHolder.java
897===================================================================
898--- head-src/com/l2jfrozen/gameserver/model/holder/BuffSkillHolder.java (revision 0)
899+++ head-src/com/l2jfrozen/gameserver/model/holder/BuffSkillHolder.java (working copy)
900@@ -0,0 +1,35 @@
901+/*
902+ * This program is free software: you can redistribute it and/or modify it under
903+ * the terms of the GNU General Public License as published by the Free Software
904+ * Foundation, either version 3 of the License, or (at your option) any later
905+ * version.
906+ *
907+ * This program is distributed in the hope that it will be useful, but WITHOUT
908+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
909+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
910+ * details.
911+ *
912+ * You should have received a copy of the GNU General Public License along with
913+ * this program. If not, see <http://www.gnu.org/licenses/>.
914+ */
915+package com.l2jfrozen.gameserver.model.holder;
916+
917+/**
918+ * A container used for schemes buffer.
919+ */
920+public final class BuffSkillHolder extends IntIntHolder
921+{
922+ private final String _type;
923+
924+ public BuffSkillHolder(int id, int price, String type)
925+ {
926+ super(id, price);
927+
928+ _type = type;
929+ }
930+
931+ public final String getType()
932+ {
933+ return _type;
934+ }
935+}
936\ No newline at end of file
937Index: head-src/com/l2jfrozen/Config.java
938===================================================================
939--- head-src/com/l2jfrozen/Config.java (revision 412)
940+++ head-src/com/l2jfrozen/Config.java (working copy)
941@@ -45,6 +45,7 @@
942 import javolution.util.FastMap;
943
944 import com.l2jfrozen.gameserver.model.entity.olympiad.OlympiadPeriod;
945+import com.l2jfrozen.gameserver.model.holder.BuffSkillHolder;
946 import com.l2jfrozen.gameserver.util.FloodProtectorConfig;
947 import com.l2jfrozen.loginserver.LoginController;
948 import com.l2jfrozen.util.StringUtil;
949@@ -1312,8 +1313,12 @@
950 public static byte BASE_SUBCLASS_LEVEL;
951 public static byte MAX_SUBCLASS_LEVEL;
952
953 public static String DISABLE_BOW_CLASSES_STRING;
954 public static FastList<Integer> DISABLE_BOW_CLASSES = new FastList<>();
955+ /** Buffer */
956+ public static int BUFFER_MAX_SCHEMES;
957+ public static int BUFFER_MAX_SKILLS;
958+ public static int BUFFER_STATIC_BUFF_COST;
959+ public static String BUFFER_BUFFS;
960+ public static Map<Integer, BuffSkillHolder> BUFFER_BUFFLIST;
961
962 //============================================================
963 public static void loadAltConfig()
964@@ -1542,7 +1547,18 @@
965
966 ALLOWED_SUBCLASS = Integer.parseInt(altSettings.getProperty("AllowedSubclass", "3"));
967 BASE_SUBCLASS_LEVEL = Byte.parseByte(altSettings.getProperty("BaseSubclassLevel", "40"));
968 MAX_SUBCLASS_LEVEL = Byte.parseByte(altSettings.getProperty("MaxSubclassLevel", "81"));
969+
970+ BUFFER_MAX_SCHEMES = Integer.parseInt(altSettings.getProperty("BufferMaxSchemesPerChar", "4"));
971+ BUFFER_MAX_SKILLS = Integer.parseInt(altSettings.getProperty("BufferMaxSkillsPerScheme", "24"));
972+ BUFFER_STATIC_BUFF_COST = Integer.parseInt(altSettings.getProperty("BufferStaticCostPerBuff", "-1"));
973+ BUFFER_BUFFS = altSettings.getProperty("BufferBuffs");
974+ BUFFER_BUFFLIST = new HashMap<>();
975+ for (String skillInfo : BUFFER_BUFFS.split(";"))
976+ {
977+ final String[] infos = skillInfo.split(",");
978+ BUFFER_BUFFLIST.put(Integer.valueOf(infos[0]), new BuffSkillHolder(Integer.valueOf(infos[0]), Integer.valueOf(infos[1]), infos[2]));
979+ }
980 }
981 catch(Exception e)
982 {
983Index: config/head/altsettings.properties
984===================================================================
985--- config/head/altsettings.properties (revision 412)
986+++ config/head/altsettings.properties (working copy)
987@@ -344,6 +344,24 @@
988 # Default: 81
989 MaxSubclassLevel = 81
990+
991+#=============================================================
992+# Buffer
993+#=============================================================
994+# Maximum number of available schemes per player.
995+BufferMaxSchemesPerChar = 4
996+# Maximum number of buffs per scheme.
997+BufferMaxSkillsPerScheme = 24
998+# Static cost of buffs ; override skills price if different of -1.
999+BufferStaticCostPerBuff = -1
1000+# The list of buffs, under a skillId,buffPrice,groupType format.
1001+BufferBuffs = 264,0,Songs;265,0,Songs;266,0,Songs;267,0,Songs;268,0,Songs;269,0,Songs;270,0,Songs;304,0,Songs;305,0,Songs;306,0,Songs;308,0,Songs;349,0,Songs;363,0,Songs;364,0,Songs;271,0,Dances;272,0,Dances;273,0,Dances;274,0,Dances;275,0,Dances;276,0,Dances;277,0,Dances;309,0,Dances;310,0,Dances;311,0,Dances;1002,0,Warcryer;1006,0,Warcryer;1007,0,Warcryer;1009,0,Warcryer;1308,0,Warcryer;1309,0,Warcryer;1310,0,Warcryer;1362,0,Warcryer;1390,0,Warcryer;1391,0,Warcryer;1413,0,Warcryer;1416,0,Overlord;1003,0,Overlord;1004,0,Overlord;1005,0,Overlord;1008,0,Overlord;1249,0,Overlord;1364,0,Overlord;1365,0,Overlord;1032,0,Prophet;1033,0,Prophet;1035,0,Prophet;1036,0,Prophet;1040,0,Prophet;1043,0,Prophet;1044,0,Prophet;1045,0,Prophet;1048,0,Prophet;1059,0,Shillen_Elder;1062,0,Prophet;1068,0,Prophet;1073,0,Elder;1077,0,Shillen_Elder;1078,0,Shillen_Elder;1085,0,Prophet;1086,0,Prophet;1087,0,Elder;1182,0,Elder;1189,0,Shillen_Elder;1191,0,Prophet;1204,0,Prophet;1242,0,Shillen_Elder;1243,0,Prophet;1259,0,Elder;1268,0,Shillen_Elder;1303,0,Shillen_Elder;1304,0,Elder;1352,0,Elder;1353,0,Elder;1354,0,Elder;1388,0,Shillen_Elder;1389,0,Shillen_Elder;1392,0,Prophet;1393,0,Elder;1397,0,Elder;1355,0,Elder;1356,0,Prophet;1357,0,Shillen_Elder;1363,0,Warcryer;1414,0,Overlord
1002+
1003#P L2jFrozen_DataPack
1004Index: sql/buffer_schemes.sql
1005===================================================================
1006--- sql/buffer_schemes.sql (revision 0)
1007+++ sql/buffer_schemes.sql (working copy)
1008@@ -0,0 +1,5 @@
1009+CREATE TABLE IF NOT EXISTS `buffer_schemes` (
1010+ `object_id` INT UNSIGNED NOT NULL DEFAULT '0',
1011+ `scheme_name` VARCHAR(16) NOT NULL DEFAULT 'default',
1012+ `skills` VARCHAR(200) NOT NULL
1013+);
1014\ No newline at end of file