View difference between Paste ID: H0PRGqgh and q0piKWJQ
SHOW: | | - or go back to the newest paste.
1
diff --git a/config/CustomMods/BossSettings.ini b/config/CustomMods/BossSettings.ini
2
index 1190422..729b563 100644
3
--- a/config/CustomMods/BossSettings.ini
4
+++ b/config/CustomMods/BossSettings.ini
5
@@ -1,4 +1,23 @@
6
+#=============================================================
7
+#                       Custom settings
8
+#=============================================================
9
+# Limit of displayed raid boss per page
10
+# Default: 15
11
+RaidBossInfoPageLimit = 15
12
+
13
+# Limit of displayed drop per page
14
+# Default: 15, Max 18
15
+RaidBossDropPageLimit = 18
16
+
17
+# Displayed date format for dead raid boss
18
+# Default: (MMM dd, HH:mm)
19
+RaidBossDateFormat = (MMM dd, HH:mm)
20
+
21
+# Displayed raid boss
22
+# Syntax: bossId,bossId, ...
23
+RaidBossIds = 25325,29001
24
+
25
 #=============================================================
26
 #                             Bosses
27
 #=============================================================
28
 
29
diff --git a/java/net/sf/l2j/Config.java b/java/net/sf/l2j/Config.java
30
index 61cacdf..53f4314 100644
31
--- a/java/net/sf/l2j/Config.java
32
+++ b/java/net/sf/l2j/Config.java
33
@@ -85,6 +85,12 @@
34
 	public static boolean ALLOW_DUALBOX;
35
 	public static int ALLOWED_BOXES;
36
 	public static boolean ALLOW_DUALBOX_OLY;
37
+	/** Raid info*/
38
+	public static int RAID_BOSS_INFO_PAGE_LIMIT;
39
+	public static int RAID_BOSS_DROP_PAGE_LIMIT;
40
+	public static String RAID_BOSS_DATE_FORMAT;
41
+	public static String RAID_BOSS_IDS;
42
+	public static List<Integer> LIST_RAID_BOSS_IDS;
43
 	/** Clan Hall function */
44
 	public static boolean PVP_SAME_IP;
45
     public static boolean PVP_SUMON;
46
@@ -1084,6 +1090,16 @@
47
 	private static final void loadBoss()
48
 	{
49
 		final ExProperties Boss = initProperties(BOSSESETTIGNS);
50
+		RAID_BOSS_INFO_PAGE_LIMIT = Integer.parseInt(Boss.getProperty("RaidBossInfoPageLimit", "15"));
51
+		RAID_BOSS_DROP_PAGE_LIMIT = Integer.parseInt(Boss.getProperty("RaidBossDropPageLimit", "15"));
52
+		RAID_BOSS_DATE_FORMAT = Boss.getProperty("RaidBossDateFormat", "MMM dd, HH:mm");
53
+		RAID_BOSS_IDS = Boss.getProperty("RaidBossIds", "0,0");
54
+		LIST_RAID_BOSS_IDS = new ArrayList<>();
55
+		for (String val : RAID_BOSS_IDS.split(","))
56
+		{
57
+			int npcId = Integer.parseInt(val);
58
+			LIST_RAID_BOSS_IDS.add(npcId);
59
+		}
60
 		RAID_HP_REGEN_MULTIPLIER = Boss.getProperty("RaidHpRegenMultiplier", 1.);
61
 		RAID_MP_REGEN_MULTIPLIER = Boss.getProperty("RaidMpRegenMultiplier", 1.);
62
 		RAID_DEFENCE_MULTIPLIER = Boss.getProperty("RaidDefenceMultiplier", 1.);
63
diff --git a/java/net/sf/l2j/gameserver/GameServer.java b/java/net/sf/l2j/gameserver/GameServer.java
64
index 33aa989..fb95657 100644
65
--- a/java/net/sf/l2j/gameserver/GameServer.java
66
+++ b/java/net/sf/l2j/gameserver/GameServer.java
67
@@ -39,6 +39,7 @@
68
 import net.sf.l2j.gameserver.data.manager.LotteryManager;
69
 import net.sf.l2j.gameserver.data.manager.PartyMatchRoomManager;
70
 import net.sf.l2j.gameserver.data.manager.PetitionManager;
71
+import net.sf.l2j.gameserver.data.manager.RaidBossInfoManager;
72
 import net.sf.l2j.gameserver.data.manager.RaidBossManager;
73
 import net.sf.l2j.gameserver.data.manager.RaidPointManager;
74
 import net.sf.l2j.gameserver.data.manager.SevenSignsManager;
75
@@ -57,6 +58,7 @@
76
 import net.sf.l2j.gameserver.data.xml.FishData;
77
 import net.sf.l2j.gameserver.data.xml.HennaData;
78
 import net.sf.l2j.gameserver.data.xml.HerbDropData;
79
+import net.sf.l2j.gameserver.data.xml.IconTable;
80
 import net.sf.l2j.gameserver.data.xml.InstantTeleportData;
81
 import net.sf.l2j.gameserver.data.xml.ItemData;
82
 import net.sf.l2j.gameserver.data.xml.MapRegionData;
83
@@ -218,6 +220,8 @@
84
 		RandomAnimationTaskManager.getInstance();
85
 		ShadowItemTaskManager.getInstance();
86
 		WaterTaskManager.getInstance();
87
+		RaidBossInfoManager.getInstance();
88
+		IconTable.getInstance();
89
 		
90
 		StringUtil.printSection("Auto Spawns");
91
 		AutoSpawnTable.getInstance();
92
diff --git a/java/net/sf/l2j/gameserver/data/manager/GrandBossManager.java b/java/net/sf/l2j/gameserver/data/manager/GrandBossManager.java
93
index 8055a66..64f5c5a 100644
94
--- a/java/net/sf/l2j/gameserver/data/manager/GrandBossManager.java
95
+++ b/java/net/sf/l2j/gameserver/data/manager/GrandBossManager.java
96
@@ -10,6 +10,7 @@
97
 import net.sf.l2j.commons.logging.CLogger;
98
 import net.sf.l2j.commons.pool.ConnectionPool;
99
 
100
+import net.sf.l2j.Config;
101
 import net.sf.l2j.gameserver.data.xml.NpcData;
102
 import net.sf.l2j.gameserver.model.actor.instance.GrandBoss;
103
 
104
@@ -106,6 +107,8 @@
105
 	public void setStatSet(int bossId, StatSet info)
106
 	{
107
 		_sets.put(bossId, info);
108
+		if (Config.LIST_RAID_BOSS_IDS.contains(bossId))
109
+		RaidBossInfoManager.getInstance().updateRaidBossInfo(bossId, info.getLong("respawn_time"));
110
 		
111
 		updateDb(bossId, false);
112
 	}
113
diff --git a/java/net/sf/l2j/gameserver/data/manager/RaidBossInfoManager.java b/java/net/sf/l2j/gameserver/data/manager/RaidBossInfoManager.java
114
new file mode 100644
115
index 0000000..79f77ea
116
--- /dev/null
117
+++ b/java/net/sf/l2j/gameserver/data/manager/RaidBossInfoManager.java
118
@@ -0,0 +1,71 @@
119
+package net.sf.l2j.gameserver.data.manager;
120
+
121
+import java.sql.Connection;
122
+import java.sql.PreparedStatement;
123
+import java.sql.ResultSet;
124
+import java.util.Map;
125
+import java.util.concurrent.ConcurrentHashMap;
126
+import java.util.logging.Logger;
127
+
128
+import net.sf.l2j.commons.pool.ConnectionPool;
129
+
130
+import net.sf.l2j.Config;
131
+
132
+public class RaidBossInfoManager
133
+{
134
+	private static final Logger _log = Logger.getLogger(RaidBossInfoManager.class.getName());
135
+	private final Map<Integer, Long> _raidBosses;
136
+
137
+	protected RaidBossInfoManager()
138
+	{
139
+		_raidBosses = new ConcurrentHashMap<>();
140
+		load();
141
+	}
142
+	
143
+	public void load()
144
+	{
145
+		try (Connection con = ConnectionPool.getConnection();
146
+			PreparedStatement statement = con.prepareStatement("SELECT boss_id, respawn_time FROM grandboss_data UNION SELECT boss_id, respawn_time FROM raidboss_spawnlist ORDER BY boss_id"))
147
+		{
148
+			try (ResultSet rs = statement.executeQuery())
149
+			{
150
+				while (rs.next())
151
+				{
152
+					int bossId = rs.getInt("boss_id");
153
+					if (Config.LIST_RAID_BOSS_IDS.contains(bossId))
154
+						_raidBosses.put(bossId, rs.getLong("respawn_time"));
155
+		
156
+					/*if (Config.LIST_RAID_BOSS_IDS2.contains(bossId))
157
+						_raidBosses.put(bossId, rs.getLong("respawn_time"));
158
+					if (Config.LIST_RAID_BOSS_IDS3.contains(bossId))
159
+						_raidBosses.put(bossId, rs.getLong("respawn_time"));*/
160
+				}
161
+			}
162
+		}
163
+		catch (Exception e)
164
+		{
165
+			_log.warning("Exception: RaidBossInfoManager load: " + e);
166
+		}
167
+		_log.info("RaidBossInfoManager: Loaded " + _raidBosses.size() + " instances.");
168
+	}
169
+	
170
+	public void updateRaidBossInfo(int bossId, long respawnTime)
171
+	{
172
+		_raidBosses.put(bossId, respawnTime);
173
+	}
174
+	
175
+	public long getRaidBossRespawnTime(int bossId)
176
+	{
177
+		return _raidBosses.get(bossId);
178
+	}
179
+	
180
+	public static RaidBossInfoManager getInstance()
181
+	{
182
+		return SingletonHolder._instance;
183
+	}
184
+	
185
+	private static class SingletonHolder
186
+	{
187
+		protected static final RaidBossInfoManager _instance = new RaidBossInfoManager();
188
+	}
189
+}
190
\ No newline at end of file
191
diff --git a/java/net/sf/l2j/gameserver/data/xml/IconTable.java b/java/net/sf/l2j/gameserver/data/xml/IconTable.java
192
new file mode 100644
193
index 0000000..08bbfec
194
--- /dev/null
195
+++ b/java/net/sf/l2j/gameserver/data/xml/IconTable.java
196
@@ -0,0 +1,96 @@
197
+/*
198
+ * This program is free software: you can redistribute it and/or modify it under
199
+ * the terms of the GNU General Public License as published by the Free Software
200
+ * Foundation, either version 3 of the License, or (at your option) any later
201
+ * version.
202
+ * 
203
+ * This program is distributed in the hope that it will be useful, but WITHOUT
204
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
205
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
206
+ * details.
207
+ * 
208
+ * You should have received a copy of the GNU General Public License along with
209
+ * this program. If not, see <http://www.gnu.org/licenses/>.
210
+ */
211
+package net.sf.l2j.gameserver.data.xml;
212
+
213
+import java.io.File;
214
+import java.util.Map;
215
+import java.util.concurrent.ConcurrentHashMap;
216
+import java.util.logging.Level;
217
+import java.util.logging.Logger;
218
+
219
+import net.sf.l2j.gameserver.xmlfactory.XMLDocumentFactory;
220
+
221
+import org.w3c.dom.Document;
222
+import org.w3c.dom.NamedNodeMap;
223
+import org.w3c.dom.Node;
224
+/**
225
+ * 
226
+ * @author Sarada
227
+ *
228
+ */
229
+public class IconTable
230
+{
231
+       private static final Logger _log = Logger.getLogger(IconTable.class.getName());
232
+      
233
+       private static Map<Integer, String> _icons = new ConcurrentHashMap<>();
234
+      
235
+       public static final IconTable getInstance()
236
+       {
237
+               return SingletonHolder._instance;
238
+       }
239
+      
240
+       protected IconTable()
241
+       {
242
+               
243
+               load();
244
+       }
245
+       
246
+       private static void load()
247
+       {
248
+    	   try
249
+    	   {
250
+			File f = new File("./data/xml/icons.xml");
251
+			Document doc = XMLDocumentFactory.getInstance().loadDocument(f);
252
+			
253
+			Node n = doc.getFirstChild();
254
+			for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
255
+			{
256
+				if (d.getNodeName().equalsIgnoreCase("icon"))
257
+				{
258
+					NamedNodeMap attrs = d.getAttributes();
259
+					
260
+					int itemId = Integer.valueOf(attrs.getNamedItem("itemId").getNodeValue());
261
+					String iconName = attrs.getNamedItem("iconName").getNodeValue();
262
+					
263
+					if (itemId == 0 && itemId < 0)
264
+					{
265
+						_log.log(Level.WARNING, "Icon Table: itemId=\"" + itemId + "\" is not item ID, Ignoring it!");
266
+						continue;
267
+					}					
268
+					_icons.put(itemId, iconName);
269
+				}
270
+			}
271
+		}
272
+		catch (Exception e)
273
+		{
274
+			_log.log(Level.WARNING, "Icon Table: Error loading from database: " + e.getMessage(), e);
275
+		}
276
+    	   
277
+		_log.info("Icon Table: Loaded " + _icons.size() + " icons.");
278
+       }
279
+      
280
+       public static String getIcon(int id)
281
+       {
282
+               if (_icons.get(id) == null)
283
+                       return "icon.NOIMAGE";
284
+              
285
+               return _icons.get(id);
286
+       }
287
+      
288
+       private static class SingletonHolder
289
+       {
290
+               protected static final IconTable _instance = new IconTable();
291
+       }
292
+}
293
\ No newline at end of file
294
diff --git a/java/net/sf/l2j/gameserver/model/actor/Npc.java b/java/net/sf/l2j/gameserver/model/actor/Npc.java
295
index 9b5c4fb..17a0088 100644
296
--- a/java/net/sf/l2j/gameserver/model/actor/Npc.java
297
+++ b/java/net/sf/l2j/gameserver/model/actor/Npc.java
298
@@ -3,7 +3,9 @@
299
 import java.text.DateFormat;
300
 import java.util.ArrayList;
301
 import java.util.List;
302
+import java.util.Map;
303
 import java.util.StringTokenizer;
304
+import java.util.concurrent.ConcurrentHashMap;
305
 
306
 import net.sf.l2j.commons.lang.StringUtil;
307
 import net.sf.l2j.commons.pool.ThreadPool;
308
@@ -94,7 +96,19 @@
309
 	private final SiegableHall _siegableHall;
310
 	
311
 	private boolean _isCoreAiDisabled;
312
-	
313
+	protected static final int PAGE_LIMIT = Config.RAID_BOSS_DROP_PAGE_LIMIT;
314
+	protected static final Map<Integer, Integer> LAST_PAGE = new ConcurrentHashMap<>();
315
+	protected static final String[][] MESSAGE =
316
+	{
317
+		{
318
+			"<font color=\"LEVEL\">%player%</font>, are you not afraid?",
319
+			"Be careful <font color=\"LEVEL\">%player%</font>!"
320
+		},
321
+		{
322
+			"Here is the drop list of <font color=\"LEVEL\">%boss%</font>!",
323
+			"Seems that <font color=\"LEVEL\">%boss%</font> has good drops."
324
+		},
325
+	};
326
 	public Npc(int objectId, NpcTemplate template)
327
 	{
328
 		super(objectId, template);
329
diff --git a/java/net/sf/l2j/gameserver/model/actor/instance/RaidBossInfo.java b/java/net/sf/l2j/gameserver/model/actor/instance/RaidBossInfo.java
330
new file mode 100644
331
index 0000000..4a17556
332
--- /dev/null
333
+++ b/java/net/sf/l2j/gameserver/model/actor/instance/RaidBossInfo.java
334
@@ -0,0 +1,328 @@
335
+/*
336
+* This program is free software: you can redistribute it and/or modify it under
337
+* the terms of the GNU General Public License as published by the Free Software
338
+* Foundation, either version 3 of the License, or (at your option) any later
339
+* version.
340
+*
341
+* This program is distributed in the hope that it will be useful, but WITHOUT
342
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
343
+* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
344
+* details.
345
+*
346
+* You should have received a copy of the GNU General Public License along with
347
+* this program. If not, see <http://www.gnu.org/licenses/>.
348
+*/
349
+package net.sf.l2j.gameserver.model.actor.instance;
350
+ 
351
+import java.text.DecimalFormat;
352
+import java.text.SimpleDateFormat;
353
+import java.util.ArrayList;
354
+import java.util.Collections;
355
+import java.util.Date;
356
+import java.util.List;
357
+import java.util.Map;
358
+import java.util.StringTokenizer;
359
+import java.util.concurrent.ConcurrentHashMap;
360
+
361
+import net.sf.l2j.commons.lang.StringUtil;
362
+import net.sf.l2j.commons.random.Rnd;
363
+
364
+import net.sf.l2j.Config;
365
+import net.sf.l2j.gameserver.data.manager.RaidBossInfoManager;
366
+import net.sf.l2j.gameserver.data.xml.IconTable;
367
+import net.sf.l2j.gameserver.data.xml.ItemData;
368
+import net.sf.l2j.gameserver.data.xml.NpcData;
369
+import net.sf.l2j.gameserver.model.actor.Player;
370
+import net.sf.l2j.gameserver.model.actor.template.NpcTemplate;
371
+import net.sf.l2j.gameserver.model.item.DropCategory;
372
+import net.sf.l2j.gameserver.model.item.DropData;
373
+import net.sf.l2j.gameserver.model.item.kind.Item;
374
+import net.sf.l2j.gameserver.network.serverpackets.ActionFailed;
375
+import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage;
376
+
377
+public class RaidBossInfo extends Folk
378
+{
379
+private final Map<Integer, Integer> _lastPage = new ConcurrentHashMap<>();
380
+ 
381
+private final String[][] _messages =
382
+{
383
+{
384
+"<font color=\"LEVEL\">%player%</font>, are you not afraid?",
385
+"Be careful <font color=\"LEVEL\">%player%</font>!"
386
+},
387
+{
388
+"Here is the drop list of <font color=\"LEVEL\">%boss%</font>!",
389
+"Seems that <font color=\"LEVEL\">%boss%</font> has good drops."
390
+},
391
+};
392
+ 
393
+public RaidBossInfo(int objectId, NpcTemplate template)
394
+{
395
+super(objectId, template);
396
+}
397
+ 
398
+@Override
399
+public void showChatWindow(Player player, int val)
400
+{
401
+String name = "data/html/mods/raidbossinfo/" + getNpcId() + ".htm";
402
+if (val != 0)
403
+name = "data/html/mods/raidbossinfo/" + getNpcId() + "-" + val + ".htm";
404
+ 
405
+NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
406
+html.setFile(name);
407
+html.replace("%objectId%", getObjectId());
408
+player.sendPacket(html);
409
+player.sendPacket(ActionFailed.STATIC_PACKET);
410
+}
411
+ 
412
+@Override
413
+public void onBypassFeedback(Player player, String command)
414
+{
415
+StringTokenizer st = new StringTokenizer(command, " ");
416
+String currentCommand = st.nextToken();
417
+ 
418
+if (currentCommand.startsWith("RaidBossInfo"))
419
+{
420
+int pageId = Integer.parseInt(st.nextToken());
421
+_lastPage.put(player.getObjectId(), pageId);
422
+showRaidBossInfo(player, pageId);
423
+}
424
+else if (currentCommand.startsWith("RaidBossDrop"))
425
+{
426
+int bossId = Integer.parseInt(st.nextToken());
427
+int pageId = st.hasMoreTokens() ? Integer.parseInt(st.nextToken()) : 1;
428
+showRaidBossDrop(player, bossId, pageId);
429
+}
430
+ 
431
+super.onBypassFeedback(player, command);
432
+}
433
+ 
434
+private void showRaidBossInfo(Player player, int pageId)
435
+{
436
+List<Integer> infos = new ArrayList<>();
437
+infos.addAll(Config.LIST_RAID_BOSS_IDS);
438
+ 
439
+final int limit = Config.RAID_BOSS_INFO_PAGE_LIMIT;
440
+final int max = infos.size() / limit + (infos.size() % limit == 0 ? 0 : 1);
441
+infos = infos.subList((pageId - 1) * limit, Math.min(pageId * limit, infos.size()));
442
+ 
443
+final StringBuilder sb = new StringBuilder();
444
+sb.append("<html>");
445
+sb.append("<center>");
446
+sb.append("<body>");
447
+sb.append("<table><tr>");
448
+sb.append("<td width=32><img src=Icon.etc_alphabet_b_i00 height=32 width=32></td>");
449
+sb.append("<td width=32><img src=Icon.etc_alphabet_i_i00 height=32 width=32></td>");
450
+sb.append("<td width=32><img src=Icon.etc_alphabet_g_i00 height=32 width=32></td>");
451
+sb.append("<td width=32><img src=Icon.etc_alphabet_b_i00 height=32 width=32></td>");
452
+sb.append("<td width=32><img src=Icon.etc_alphabet_o_i00 height=32 width=32></td>");
453
+sb.append("<td width=32><img src=Icon.etc_alphabet_s_i00 height=32 width=32></td>");
454
+sb.append("<td width=32><img src=Icon.etc_alphabet_s_i00 height=32 width=32></td>");
455
+sb.append("</tr></table><br>");
456
+
457
+sb.append("<img src=\"L2UI.SquareGray\" width=300 height=1>");
458
+sb.append("<table bgcolor=\"000000\" width=\"318\">");
459
+sb.append("<tr><td><center>" + _messages[0][Rnd.get(_messages.length)].replace("%player%", player.getName()) + "</center></td></tr>");
460
+sb.append("<tr><td><center><font color=\"FF8C00\">Raid Boss Infos</font></center></td></tr>");
461
+sb.append("</table>");
462
+sb.append("<img src=\"L2UI.SquareGray\" width=300 height=1>");
463
+
464
+sb.append("<table bgcolor=\"000000\" width=\"318\">");
465
+ 
466
+for (int bossId : infos)
467
+{
468
+final NpcTemplate template = NpcData.getInstance().getTemplate(bossId);
469
+if (template == null)
470
+continue;
471
+ 
472
+String bossName = template.getName();
473
+if (bossName.length() > 23)
474
+bossName = bossName.substring(0, 23) + "...";
475
+ 
476
+final long respawnTime = RaidBossInfoManager.getInstance().getRaidBossRespawnTime(bossId);
477
+if (respawnTime <= System.currentTimeMillis())
478
+{
479
+sb.append("<tr>");
480
+sb.append("<td><a action=\"bypass -h npc_%objectId%_RaidBossDrop " + bossId + "\">" + bossName + "</a></td>");
481
+sb.append("<td><font color=\"9CC300\">Alive</font></td>");
482
+sb.append("</tr>");
483
+}
484
+else
485
+{
486
+sb.append("<tr>");
487
+sb.append("<td width=\"159\" align=\"left\"><a action=\"bypass -h npc_%objectId%_RaidBossDrop " + bossId + "\">" + bossName + "</a></td>");
488
+sb.append("<td width=\"159\" align=\"left\"><font color=\"FB5858\">Dead</font> " + new SimpleDateFormat(Config.RAID_BOSS_DATE_FORMAT).format(new Date(respawnTime)) + "</td>");
489
+sb.append("</tr>");
490
+}
491
+} 
492
+sb.append("</table>");
493
+
494
+sb.append("<img src=\"L2UI.SquareGray\" width=300 height=1>");
495
+
496
+sb.append("<table width=\"300\" cellspacing=\"2\">");
497
+sb.append("<tr>");
498
+for (int x = 0; x < max; x++)
499
+{
500
+	final int pageNr = x + 1;
501
+	if (pageId == pageNr)
502
+		sb.append("<td align=\"center\">" + pageNr + "</td>");
503
+	else
504
+		sb.append("<td align=\"center\"><a action=\"bypass -h npc_%objectId%_RaidBossInfo " + pageNr + "\">" + pageNr + "</a></td>");
505
+}
506
+sb.append("</tr>");
507
+sb.append("</table>");
508
+
509
+sb.append("<img src=\"L2UI.SquareGray\" width=300 height=1>");
510
+
511
+sb.append("<table bgcolor=\"000000\" width=\"350\">");
512
+sb.append("<tr><td><center><a action=\"bypass -h npc_%objectId%_Chat 0\">Return</a></center></td></tr>");
513
+sb.append("</table>");
514
+sb.append("<img src=\"L2UI.SquareGray\" width=300 height=1>");
515
+
516
+
517
+sb.append("</center>");
518
+sb.append("</body>");
519
+sb.append("</html>");
520
+ 
521
+final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
522
+html.setHtml(sb.toString());
523
+html.replace("%name%", getName());
524
+html.replace("%objectId%", getObjectId());
525
+player.sendPacket(html);
526
+}
527
+ 
528
+private void showRaidBossDrop(Player player, int npcId, int page)
529
+{
530
+	final NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
531
+	if (template == null)
532
+		return; 
533
+	
534
+	if (template.getDropData().isEmpty()) 
535
+	{
536
+		player.sendMessage("This target have not drop info.");
537
+		return;
538
+	} 
539
+	
540
+	final List<DropCategory> list = new ArrayList<>();
541
+	template.getDropData().forEach(c -> list.add(c));
542
+	Collections.reverse(list);
543
+	
544
+	int myPage = 1;
545
+	int i = 0;
546
+	int shown = 0;
547
+	boolean hasMore = false;
548
+	
549
+	final StringBuilder sb = new StringBuilder();
550
+	sb.append("<html>");
551
+	sb.append("<center>");
552
+	sb.append("<body>");
553
+	sb.append("<table width=\"256\">");
554
+	sb.append("<tr><td width=\"256\" align=\"center\">%name%</td></tr>");
555
+	sb.append("</table>");
556
+	sb.append("<br>");
557
+	sb.append("<table width=\"256\">");
558
+	sb.append("<tr><td width=\"256\" align=\"left\">" + MESSAGE[1][Rnd.get(MESSAGE.length)].replace("%boss%", template.getName()) + "</td></tr>");
559
+	sb.append("</table>");
560
+	sb.append("<br>");
561
+	sb.append("<table width=\"224\" bgcolor=\"000000\">");
562
+	sb.append("<tr><td width=\"224\" align=\"center\">Raid Boss Drops</td></tr>");
563
+	sb.append("</table>");
564
+	sb.append("<br>");
565
+	
566
+	for (DropCategory cat : list) 
567
+	{
568
+		if (shown == PAGE_LIMIT)
569
+		{
570
+			hasMore = true;
571
+			break;
572
+		} 
573
+		
574
+		for (DropData drop : cat.getAllDrops())
575
+		{
576
+			final double chance = Math.min(100, (((drop.getItemId() == 57) ? drop.getChance() * Config.RATE_DROP_ADENA : drop.getChance() * Config.RATE_DROP_ITEMS) / 10000));
577
+			final Item item = ItemData.getInstance().getTemplate(drop.getItemId());
578
+
579
+			String name = item.getName();
580
+			if (name.startsWith("Recipe: "))
581
+				name = "R: " + name.substring(8);
582
+			
583
+			if (name.length() >= 45)
584
+				name = name.substring(0, 42) + "...";
585
+			
586
+			String percent = null;
587
+			if (chance <= 0.001)
588
+			{
589
+				DecimalFormat df = new DecimalFormat("#.####");
590
+				percent = df.format(chance);
591
+			}
592
+			else if (chance <= 0.01)
593
+			{
594
+				DecimalFormat df = new DecimalFormat("#.###");
595
+				percent = df.format(chance);
596
+			}
597
+			else
598
+			{
599
+				DecimalFormat df = new DecimalFormat("##.##");
600
+				percent = df.format(chance);
601
+			}
602
+			
603
+			if (myPage != page)
604
+			{
605
+				i++;
606
+				if (i == PAGE_LIMIT)
607
+				{
608
+					myPage++;
609
+					i = 0;
610
+				}
611
+				continue;
612
+			}
613
+			
614
+			if (shown == PAGE_LIMIT)
615
+			{
616
+				hasMore = true;
617
+				break;
618
+			}
619
+			
620
+			sb.append(((shown % 2) == 0 ? "<table width=\"280\" bgcolor=\"000000\"><tr>" : "<table width=\"280\"><tr>"));
621
+			sb.append("<td width=44 height=41 align=center><table bgcolor=" + (cat.isSweep() ? "FF00FF" : "FFFFFF") + " cellpadding=6 cellspacing=\"-5\"><tr><td><button width=32 height=32 back=" + IconTable.getIcon(item.getItemId()) + " fore=" + IconTable.getIcon(item.getItemId()) + "></td></tr></table></td>");
622
+			sb.append("<td width=240>" + (cat.isSweep() ? ("<font color=ff00ff>" + name + "</font>") : name) + "<br1><font color=B09878>" + (cat.isSweep() ? "Spoil" : "Drop") + " Chance : " + percent + "%</font></td>");
623
+			sb.append("</tr></table><img src=L2UI.SquareGray width=280 height=1>");
624
+			shown++;
625
+		} 
626
+	} 
627
+
628
+	// Build page footer.
629
+	sb.append("<br><img src=\"L2UI.SquareGray\" width=277 height=1><table width=\"100%\" bgcolor=000000><tr>");
630
+	
631
+	if (page > 1)
632
+		StringUtil.append(sb, "<td align=left width=70><a action=\"bypass -h npc_%objectId%_RaidBossDrop "+ npcId + " ", (page - 1), "\">Previous</a></td>");
633
+	else
634
+		StringUtil.append(sb, "<td align=left width=70>Previous</td>");
635
+	
636
+	StringUtil.append(sb, "<td align=center width=100>Page ", page, "</td>");
637
+	
638
+	if (page < shown)
639
+		StringUtil.append(sb, "<td align=right width=70>" + (hasMore ? "<a action=\"bypass -h npc_%objectId%_RaidBossDrop " + npcId + " " + (page + 1) + "\">Next</a>" : "") + "</td>");
640
+	else
641
+		StringUtil.append(sb, "<td align=right width=70>Next</td>");
642
+	
643
+	sb.append("</tr></table><img src=\"L2UI.SquareGray\" width=277 height=1>");
644
+	sb.append("<br>");
645
+	sb.append("<center>");
646
+	sb.append("<table width=\"160\" cellspacing=\"2\">");
647
+	sb.append("<tr>");											
648
+	sb.append("<td width=\"160\" align=\"center\"><a action=\"bypass -h npc_%objectId%_RaidBossInfo " + _lastPage.get(player.getObjectId()) + "\">Return</a></td>");
649
+	sb.append("</tr>");
650
+	sb.append("</table>");
651
+	sb.append("</center>");
652
+	sb.append("</body>");
653
+	sb.append("</html>");
654
+
655
+	final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
656
+	html.setHtml(sb.toString());
657
+	html.replace("%name%", getName());
658
+	html.replace("%objectId%", getObjectId());
659
+	player.sendPacket(html);
660
+}
661
+
662
+}
663
\ No newline at end of file
664
diff --git a/java/net/sf/l2j/gameserver/model/spawn/BossSpawn.java b/java/net/sf/l2j/gameserver/model/spawn/BossSpawn.java
665
index c7c5a19..0507249 100644
666
--- a/java/net/sf/l2j/gameserver/model/spawn/BossSpawn.java
667
+++ b/java/net/sf/l2j/gameserver/model/spawn/BossSpawn.java
668
@@ -11,6 +11,7 @@
669
 import net.sf.l2j.commons.random.Rnd;
670
 
671
 import net.sf.l2j.Config;
672
+import net.sf.l2j.gameserver.data.manager.RaidBossInfoManager;
673
 import net.sf.l2j.gameserver.enums.BossStatus;
674
 import net.sf.l2j.gameserver.model.World;
675
 import net.sf.l2j.gameserver.model.actor.Npc;
676
@@ -147,6 +148,8 @@
677
 		
678
 		// Refresh the database for this particular boss entry.
679
 		updateOnDb();
680
+		if (Config.LIST_RAID_BOSS_IDS.contains(_spawn.getNpcId()))
681
+		RaidBossInfoManager.getInstance().updateRaidBossInfo(_spawn.getNpcId(), respawnTime);
682
 		
683
 		LOGGER.info("Raid boss: {} - {} ({}h).", _spawn.getNpc().getName(), new SimpleDateFormat("dd-MM-yyyy HH:mm").format(respawnTime), respawnDelay);
684
 	}
685
@@ -175,6 +178,10 @@
686
 		
687
 		// Refresh the database for this particular boss entry.
688
 		updateOnDb();
689
+		
690
+		if (Config.LIST_RAID_BOSS_IDS.contains(npc.getNpcId()))
691
+			RaidBossInfoManager.getInstance().updateRaidBossInfo(npc.getNpcId(), 0);
692
+		
693
 		if (Config.ANNOUNCE_BOSS_ALIVE)
694
 			World.gameAnnounceToOnlinePlayers("Boss: " + npc.getName() + " has spawned in the world!");
695
 		LOGGER.info("{} raid boss has spawned.", npc.getName());
696