View difference between Paste ID: PhLZmNi0 and EDi98ZR2
SHOW: | | - or go back to the newest paste.
1
### Eclipse Workspace Patch 1.0
2
#P aCis
3
diff --git aCis_data/data/html/default/29061.htm aCis_data/data/html/default/29061.htm
4
new file mode 100644
5
index 0000000..ab9388d
6
--- /dev/null
7
+++ aCis_data/data/html/default/29061.htm
8
@@ -0,0 +1,3 @@
9
+<html><body>Teleportation Cubic:<br>
10
+<a action="bypass -h npc_%objectId%_Quest GrandBossTeleporter">Exit the Last Imperial Tomb</a><br>
11
+</body></html>
12
diff --git aCis_data/data/html/default/32011.htm aCis_data/data/html/default/32011.htm
13
index 2341448..1c7c641 100644
14
--- aCis_data/data/html/default/32011.htm
15
+++ aCis_data/data/html/default/32011.htm
16
@@ -1,7 +1,7 @@
17
 <html><body>
18
 I feel an invisible barrier... Some sort of Magic Force Field has been put in place...<br>
19
 ...? The guide of the Imperial mausoleum seems to have something to say.<br><br>
20
-<a action="bypass -h npc_%objectId%_Quest FinalEmperialTomb">Enter the Magic Force Field</a><br>
21
+<a action="bypass -h npc_%objectId%_Quest GrandBossTeleporter">Enter the Magic Force Field</a><br>
22
 <a action="bypass -h npc_%objectId%_Chat 1">Listen to Imperial Tomb Guide</a><br>
23
 <a action="bypass -h npc_%objectId%_Quest">Quest</a>
24
 </body></html>
25
\ No newline at end of file
26
diff --git aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-01.htm aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-01.htm
27
new file mode 100644
28
index 0000000..ef3f436
29
--- /dev/null
30
+++ aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-01.htm
31
@@ -0,0 +1,2 @@
32
+<html><body>There is nothing beyond the Magic Force Field. Come back later.<br>(You may not enter because Frintezza is not inside the Imperial Tomb.)
33
+</body></html>
34
\ No newline at end of file
35
diff --git aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-02.htm aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-02.htm
36
new file mode 100644
37
index 0000000..7904d4e
38
--- /dev/null
39
+++ aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-02.htm
40
@@ -0,0 +1,3 @@
41
+<html><body>There is big battle beyond the Magic Force Field. Come back later.<br>
42
+(You may not enter becouse someone is already in a battle with Frintezza.)
43
+</body></html>
44
\ No newline at end of file
45
diff --git aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-03.htm aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-03.htm
46
new file mode 100644
47
index 0000000..2e5ec6f
48
--- /dev/null
49
+++ aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-03.htm
50
@@ -0,0 +1 @@
51
+<html><body>No reaction. Contact must be initiated by the Command Channel Leader.</body></html>
52
\ No newline at end of file
53
diff --git aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-04.htm aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-04.htm
54
new file mode 100644
55
index 0000000..9fd5d88
56
--- /dev/null
57
+++ aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-04.htm
58
@@ -0,0 +1 @@
59
+<html><body>Your command channel needs to have at least 2 parties and a maximum of 5.</body></html>
60
\ No newline at end of file
61
diff --git aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-05.htm aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-05.htm
62
new file mode 100644
63
index 0000000..1c29d9e
64
--- /dev/null
65
+++ aCis_data/data/html/script/teleport/GrandBossTeleporter/32011-05.htm
66
@@ -0,0 +1 @@
67
+<html><body>You dont have required item.</body></html>
68
\ No newline at end of file
69
diff --git aCis_data/data/xml/items/8100-8199.xml aCis_data/data/xml/items/8100-8199.xml
70
index 79540e3..eafa3ac 100644
71
--- aCis_data/data/xml/items/8100-8199.xml
72
+++ aCis_data/data/xml/items/8100-8199.xml
73
@@ -1566,6 +1566,7 @@
74
 		<set name="material" val="GOLD" />
75
 		<set name="weight" val="3" />
76
 		<set name="is_stackable" val="true" />
77
+		<set name="handler" val="ItemSkills" />
78
 		<set name="item_skill" val="2234-1" />
79
 	</item>
80
 	<item id="8193" type="EtcItem" name="Fisherman's Potion - Green">
81
diff --git aCis_data/data/xml/items/8500-8599.xml aCis_data/data/xml/items/8500-8599.xml
82
index 95d3e27..ae2dcf5 100644
83
--- aCis_data/data/xml/items/8500-8599.xml
84
+++ aCis_data/data/xml/items/8500-8599.xml
85
@@ -549,6 +549,7 @@
86
 		<set name="material" val="GOLD" />
87
 		<set name="weight" val="3" />
88
 		<set name="is_stackable" val="true" />
89
+		<set name="handler" val="ItemSkills" />
90
 		<set name="item_skill" val="2276-1" />
91
 	</item>
92
 	<item id="8557" type="Armor" name="Blue Party Hat">
93
diff --git aCis_data/data/xml/npcs/29000-29999.xml aCis_data/data/xml/npcs/29000-29999.xml
94
index 40f963f..a8f62b3 100644
95
--- aCis_data/data/xml/npcs/29000-29999.xml
96
+++ aCis_data/data/xml/npcs/29000-29999.xml
97
@@ -2317,7 +2317,7 @@
98
 		</skills>
99
 	</npc>
100
 	<npc id="29045" name="Frintezza" title="">
101
-		<set name="level" val="90"/>
102
+		<set name="level" val="85"/>
103
 		<set name="radius" val="45"/>
104
 		<set name="height" val="42.7"/>
105
 		<set name="rHand" val="0"/>
106
@@ -2338,7 +2338,7 @@
107
 		<set name="str" val="60"/>
108
 		<set name="int" val="76"/>
109
 		<set name="dex" val="73"/>
110
-		<set name="wit" val="70"/>
111
+		<set name="wit" val="30"/>
112
 		<set name="con" val="57"/>
113
 		<set name="men" val="80"/>
114
 		<set name="corpseTime" val="7"/>
115
@@ -2352,7 +2352,7 @@
116
 		</skills>
117
 	</npc>
118
 	<npc id="29046" name="Scarlet van Halisha" title="">
119
-		<set name="level" val="85"/>
120
+		<set name="level" val="80"/>
121
 		<set name="radius" val="45"/>
122
 		<set name="height" val="90.7"/>
123
 		<set name="rHand" val="8204"/>
124
@@ -2387,7 +2387,7 @@
125
 		</skills>
126
 	</npc>
127
 	<npc id="29047" name="Scarlet van Halisha" title="">
128
-		<set name="level" val="90"/>
129
+		<set name="level" val="85"/>
130
 		<set name="radius" val="92"/>
131
 		<set name="height" val="112.8"/>
132
 		<set name="rHand" val="8222"/>
133
diff --git aCis_data/data/xml/scripts.xml aCis_data/data/xml/scripts.xml
134
index 3e38b21..e44c739 100644
135
--- aCis_data/data/xml/scripts.xml
136
+++ aCis_data/data/xml/scripts.xml
137
@@ -366,7 +366,7 @@
138
 	<script path="script.ai.boss.Benom"/>
139
 	<script path="script.ai.boss.Core"/>
140
 	<script path="script.ai.boss.DrChaos"/>
141
-<!-- 	<script path="script.ai.boss.Frintezza"/> -->
142
+ 	<script path="script.ai.boss.Frintezza"/>
143
 	<script path="script.ai.boss.Gordon"/>
144
 <!-- 	<script path="script.ai.boss.IceFairySirra"/> -->
145
 	<script path="script.ai.boss.Orfen"/>
146
diff --git aCis_data/data/xml/skills/5000-5099.xml aCis_data/data/xml/skills/5000-5099.xml
147
index b958bd0..d268c96 100644
148
--- aCis_data/data/xml/skills/5000-5099.xml
149
+++ aCis_data/data/xml/skills/5000-5099.xml
150
@@ -104,22 +104,25 @@
151
 		<set name="target" val="SELF" />
152
 	</skill>
153
     <skill id="5008" levels="5" name="Frintezza's Songs">
154
-		<table name="#aggroPoints"> 100 100 100 0 0 </table>
155
+		<table name="#aggroPoints"> 100 100 110 0 0 </table>
156
 		<table name="#isDebuff"> false false false true true </table>
157
 		<table name="#isMagic"> true false false true true </table>
158
 		<table name="#power"> 3 0 0 10 10 </table>
159
-		<table name="#skillType"> HEAL_PERCENT DUMMY BUFF DEBUFF STUN </table>
160
+		<table name="#skillType"> HEAL_PERCENT BUFF BUFF DEBUFF STUN </table>
161
 		<table name="#stackOrder"> 0 0 1 1 1 </table>
162
 		<table name="#stackType"> none none ultimate_buff heal_effect_down stun </table>
163
 		<table name="#attackAndSpeed"> 1 1 1.2 1 1 </table>
164
-		<table name="#time"> 0 0 5 5 5 </table>
165
+		<table name="#time"> 0 30 30 15 8 </table>
166
 		<table name="#gainHp"> 1 1 1 0.5 1 </table>
167
 		<table name="#lvlDepend"> 0 0 0 1 1 </table>
168
-		<table name="#effectname1"> Buff Buff Buff Buff Stun </table>
169
-		<table name="#effectname2"> Buff Buff Buff Buff Cancel </table>
170
+		<table name="#effectname1"> Buff Buff Buff Debuff DanceStun </table><!-- EffectDanceStun.java -->
171
+		<table name="#effectname2"> Buff Buff Buff Buff Stun </table>
172
 		<table name="#effectPower"> 0 0 0 0 20 </table>
173
-		<table name="#effectType"> BUFF BUFF BUFF BUFF CANCEL </table>
174
+		<table name="#effectType"> BUFF BUFF BUFF DEBUFF STUN </table>
175
+		<table name="#effectRange"> 6000 6000 6000 -1 -1 </table>
176
 		<table name="#maxNegated"> 0 0 0 0 10 </table>
177
+		<table name="#target"> SELF SELF SELF AURA AURA </table>
178
+		<table name="#skillRadius"> -1 -1 -1 8000 8000 </table>
179
 		<set name="aggroPoints" val="#aggroPoints" />
180
 		<set name="isDebuff" val="#isDebuff" />
181
 		<set name="isMagic" val="#isMagic" />
182
@@ -127,9 +130,11 @@
183
 		<set name="magicLvl" val="85" />
184
 		<set name="maxNegated" val="#maxNegated" />
185
 		<set name="operateType" val="ACTIVE" />
186
+		<set name="effectRange" val="#effectRange" />
187
 		<set name="power" val="#power" />
188
 		<set name="skillType" val="#skillType" />
189
-		<set name="target" val="SELF" />
190
+		<set name="target" val="#target" />
191
+		<set name="skillRadius" val="#skillRadius" />
192
 		<for>
193
 			<effect name="#effectname1" time="#time" val="0" stackOrder="1" stackType="#stackType">
194
 				<mul stat="pAtk" val="#attackAndSpeed" />
195
@@ -139,7 +144,7 @@
196
 				<add stat="runSpd" val="#attackAndSpeed" />
197
 				<mul stat="gainHp" val="#gainHp" />
198
 			</effect>
199
-			<effect name="#effectname2" noicon="1" val="0" effectPower="#effectPower" effectType="#effectType" />
200
+			<effect name="#effectname2" val="0" effectPower="#effectPower" effectType="#effectType" />
201
 		</for>
202
 	</skill>
203
 	<skill id="5009" levels="1" name="Frintezza's Ghostly Fighter">
204
@@ -170,6 +175,8 @@
205
 	<skill id="5011" levels="1" name="Frintezza's Bomber Ghost">
206
 		<set name="element" val="DARK" />
207
 		<set name="hitTime" val="1000" />
208
+		<set name="coolTime" val="2000" />
209
+		<set name="isMagic" val="false" />
210
 		<set name="isSuicideAttack" val="true" />
211
 		<set name="magicLvl" val="85" />
212
 		<set name="operateType" val="ACTIVE" />
213
@@ -223,12 +230,14 @@
214
 		<set name="target" val="FRONT_AREA" />
215
 	</skill>
216
 	<skill id="5015" levels="6" name="Frintezza's Daemon Charge">
217
+		<table name="#baseCritRate"> 10 12 12 10 12 12 </table>
218
 		<table name="#coolTime"> 0 0 0 1500 1500 1500 </table>
219
 		<table name="#radius"> 400 500 700 400 500 700 </table>
220
 		<table name="#power"> 48761 52970 68074 48761 52970 68074 </table>
221
-		<set name="castRange" val="150" />
222
+		<set name="baseCritRate" val="#baseCritRate" />
223
+		<set name="castRange" val="250" />
224
 		<set name="coolTime" val="#coolTime" />
225
-		<set name="effectRange" val="650" />
226
+		<set name="effectRange" val="925" />
227
 		<set name="element" val="DARK" />
228
 		<set name="flyRadius" val="#radius" />
229
 		<set name="flyType" val="CHARGE" />
230
@@ -239,6 +248,10 @@
231
 		<set name="skillRadius" val="#radius" />
232
 		<set name="skillType" val="PDAM" />
233
 		<set name="target" val="FRONT_AREA" />
234
+		<set name="flyCourse" val="180" />
235
+		<for>
236
+			<effect self="1" name="Warp" val="0" noicon="1" />
237
+		</for>
238
 	</skill>
239
 	<skill id="5016" levels="1" name="Yoke of Scarlet">
240
 		<set name="castRange" val="500" />
241
@@ -254,7 +267,7 @@
242
 		<set name="skillType" val="PARALYZE" />
243
 		<set name="target" val="AREA" />
244
 		<for>
245
-			<effect name="Paralyze" time="20" val="0" abnormal="floatroot" stackOrder="1" stackType="paralyze" />
246
+			<effect name="FloatStun" time="15" val="0" stackOrder="1" stackType="stun" abnormal="floatroot" effectPower="80" effectType="STUN" />
247
 		</for>
248
 	</skill>
249
 	<skill id="5017" levels="1" name="Frintezza's Daemon Morph">
250
@@ -278,6 +291,7 @@
251
 		<set name="coolTime" val="1000" />
252
 		<set name="element" val="DARK" />
253
 		<set name="hitTime" val="7000" />
254
+		<set name="isMagic" val="false" />
255
 		<set name="magicLvl" val="85" />
256
 		<set name="operateType" val="ACTIVE" />
257
 		<set name="power" val="#power" />
258
diff --git aCis_data/data/xml/zones/BossZone.xml aCis_data/data/xml/zones/BossZone.xml
259
index 8dddd01..e620733 100644
260
--- aCis_data/data/xml/zones/BossZone.xml
261
+++ aCis_data/data/xml/zones/BossZone.xml
262
@@ -109,12 +109,10 @@
263
 		<node x="26846" y="-8117"/>
264
 		<node x="28231" y="-8163"/>
265
 	</zone>
266
-	<zone id="110012" shape="NPoly" minZ="-5200" maxZ="-4680"><!-- Frintezza -->
267
-		<stat name="InvadeTime" val="1800000"/>
268
-		<node x="172031" y="-90127"/>
269
-		<node x="176428" y="-90089"/>
270
-		<node x="176428" y="-74051"/>
271
-		<node x="172057" y="-74108"/>
272
+	<zone id="110012" shape="Cuboid" minZ="-5150" maxZ="-4000"><!-- Frintezza -->
273
+		<stat name="InvadeTime" val="1800000" />
274
+		<node x="172176" y="-74106" />
275
+		<node x="176284" y="-90033" />
276
 	</zone>
277
 	<zone id="110013" shape="NPoly" minZ="-5136" maxZ="864"><!-- Ice Fairy 1 -->
278
 		<stat name="InvadeTime" val="1800000"/>
279
diff --git aCis_data/data/xml/zones/ScriptZone.xml aCis_data/data/xml/zones/ScriptZone.xml
280
index e0dbb43..8962e1b 100644
281
--- aCis_data/data/xml/zones/ScriptZone.xml
282
+++ aCis_data/data/xml/zones/ScriptZone.xml
283
@@ -22,4 +22,8 @@
284
 		<node x="88759" y="-108195"/>
285
 		<node x="88677" y="-108275"/>
286
 	</zone>
287
+	<zone id="100004" shape="Cuboid" minZ="-5140" maxZ="-2319"> <!-- Frintezza.java# Frintezza's Concert Hall -->
288
+		<node x="172176" y="-86081" />
289
+		<node x="176284" y="-90033" />
290
+	</zone>
291
 </list>
292
\ No newline at end of file
293
diff --git aCis_game/java/net/sf/l2j/gameserver/handler/chathandlers/ChatAll.java aCis_game/java/net/sf/l2j/gameserver/handler/chathandlers/ChatAll.java
294
index a707ce5..28c1129 100644
295
--- aCis_game/java/net/sf/l2j/gameserver/handler/chathandlers/ChatAll.java
296
+++ aCis_game/java/net/sf/l2j/gameserver/handler/chathandlers/ChatAll.java
297
@@ -1,5 +1,6 @@
298
 package net.sf.l2j.gameserver.handler.chathandlers;
299
 
300
+import net.sf.l2j.gameserver.data.xml.ScriptData;
301
 import net.sf.l2j.gameserver.enums.FloodProtector;
302
 import net.sf.l2j.gameserver.enums.SayType;
303
 import net.sf.l2j.gameserver.handler.IChatHandler;
304
@@ -18,7 +19,14 @@
305
 	{
306
 		if (!player.getClient().performAction(FloodProtector.GLOBAL_CHAT))
307
 			return;
308
-		
309
+
310
+		if (player.isGM())
311
+			if (text.equalsIgnoreCase(".frintezza"))
312
+			{
313
+				ScriptData.getInstance().getQuest("Frintezza").startQuestTimer("start", null, null, 1000);
314
+				return;
315
+			}
316
+	
317
 		final CreatureSay cs = new CreatureSay(player, type, text);
318
 		for (Player knownPlayer : player.getKnownTypeInRadius(Player.class, 1250))
319
 			knownPlayer.sendPacket(cs);
320
diff --git aCis_game/java/net/sf/l2j/gameserver/model/actor/Npc.java aCis_game/java/net/sf/l2j/gameserver/model/actor/Npc.java
321
index 23723ee..728cf87 100644
322
--- aCis_game/java/net/sf/l2j/gameserver/model/actor/Npc.java
323
+++ aCis_game/java/net/sf/l2j/gameserver/model/actor/Npc.java
324
@@ -1486,4 +1486,15 @@
325
 	{
326
 		startRandomAnimationTimer();
327
 	}
328
+	private boolean isFlying = false;
329
+	@Override
330
+	public boolean isFlying()
331
+	{
332
+		return isFlying;
333
+	}
334
+	
335
+	public void setIsFlying(boolean a)
336
+	{
337
+		isFlying = a;
338
+	}
339
 }
340
\ No newline at end of file
341
diff --git aCis_game/java/net/sf/l2j/gameserver/scripting/script/ai/boss/Frintezza.java aCis_game/java/net/sf/l2j/gameserver/scripting/script/ai/boss/Frintezza.java
342
new file mode 100644
343
index 0000000..472c122
344
--- /dev/null
345
+++ aCis_game/java/net/sf/l2j/gameserver/scripting/script/ai/boss/Frintezza.java
346
@@ -0,0 +1,1167 @@
347
+package net.sf.l2j.gameserver.scripting.script.ai.boss;
348
+
349
+import java.util.List;
350
+import java.util.Map;
351
+import java.util.concurrent.ConcurrentHashMap;
352
+import java.util.concurrent.CopyOnWriteArrayList;
353
+
354
+import net.sf.l2j.commons.data.StatSet;
355
+import net.sf.l2j.commons.math.MathUtil;
356
+import net.sf.l2j.commons.random.Rnd;
357
+
358
+import net.sf.l2j.Config;
359
+import net.sf.l2j.gameserver.data.manager.GrandBossManager;
360
+import net.sf.l2j.gameserver.data.manager.ZoneManager;
361
+import net.sf.l2j.gameserver.data.xml.DoorData;
362
+import net.sf.l2j.gameserver.enums.SayType;
363
+import net.sf.l2j.gameserver.enums.skills.FlyType;
364
+import net.sf.l2j.gameserver.model.actor.Creature;
365
+import net.sf.l2j.gameserver.model.actor.Npc;
366
+import net.sf.l2j.gameserver.model.actor.Player;
367
+import net.sf.l2j.gameserver.model.actor.instance.GrandBoss;
368
+import net.sf.l2j.gameserver.model.actor.instance.Monster;
369
+import net.sf.l2j.gameserver.model.holder.IntIntHolder;
370
+import net.sf.l2j.gameserver.model.location.Location;
371
+import net.sf.l2j.gameserver.model.zone.type.BossZone;
372
+import net.sf.l2j.gameserver.model.zone.type.ScriptZone;
373
+import net.sf.l2j.gameserver.network.SystemMessageId;
374
+import net.sf.l2j.gameserver.network.serverpackets.AbstractNpcInfo.NpcInfo;
375
+import net.sf.l2j.gameserver.network.serverpackets.CreatureSay;
376
+import net.sf.l2j.gameserver.network.serverpackets.Earthquake;
377
+import net.sf.l2j.gameserver.network.serverpackets.ExShowScreenMessage;
378
+import net.sf.l2j.gameserver.network.serverpackets.ExShowScreenMessage.SMPOS;
379
+import net.sf.l2j.gameserver.network.serverpackets.FlyToLocation;
380
+import net.sf.l2j.gameserver.network.serverpackets.L2GameServerPacket;
381
+import net.sf.l2j.gameserver.network.serverpackets.MagicSkillCanceled;
382
+import net.sf.l2j.gameserver.network.serverpackets.MagicSkillUse;
383
+import net.sf.l2j.gameserver.network.serverpackets.NpcSay;
384
+import net.sf.l2j.gameserver.network.serverpackets.SocialAction;
385
+import net.sf.l2j.gameserver.network.serverpackets.SpecialCamera;
386
+import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
387
+import net.sf.l2j.gameserver.network.serverpackets.ValidateLocation;
388
+import net.sf.l2j.gameserver.scripting.script.ai.AttackableAIScript;
389
+import net.sf.l2j.gameserver.skills.AbstractEffect;
390
+import net.sf.l2j.gameserver.skills.L2Skill;
391
+
392
+public class Frintezza extends AttackableAIScript
393
+{
394
+	private static final ScriptZone FRINTEZZA_LAIR = ZoneManager.getInstance().getZoneById(100004, ScriptZone.class);
395
+	private static final BossZone lastImperialTomp = ZoneManager.getInstance().getZoneById(110012, BossZone.class);
396
+	
397
+	public static final int FRINTEZZA = 29045;
398
+	private static final int SCARLET1 = 29046;
399
+	private static final int SCARLET2 = 29047;
400
+	
401
+	private static final int ALARM_DEVICE = 18328;
402
+	private static final int CHOIR_CAPTAIN = 18334;
403
+	private static final int CHOIR_PRAYER = 18339;
404
+	
405
+	// Frintezza Status Tracking :
406
+	public static final byte DORMANT = 0; // No one has entered yet. Entry is unlocked
407
+	public static final byte WAITING = 1; // Someone has entered, triggering a 35 minute window for additional people to enter before he unleashes his attack. Entry is unlocked
408
+	public static final byte FIGHTING = 2; // Frintezza is engaged in battle, annihilating his foes. Entry is locked
409
+	public static final byte DEAD = 3; // Frintezza has been killed. Entry is locked
410
+	
411
+	private Player _actualVictim; // Actual target of Scarlet.
412
+	private static long _lastAttackTime = 0;
413
+	private static int _killMobs = 0;
414
+
415
+	private static GrandBoss scarlet, frintezza;
416
+
417
+	private final List<Npc> _dummys = new CopyOnWriteArrayList<>();
418
+	private final List<Monster> demons = new CopyOnWriteArrayList<>();
419
+	private final Map<Monster, Integer> portraits = new ConcurrentHashMap<>();
420
+	private final List<Npc> _mobs = new CopyOnWriteArrayList<>();
421
+
422
+	//features unconfirmed retail
423
+	// Cinematic initial and Alarm Device open doors
424
+	private static boolean not_confirmed = true;
425
+
426
+	// Skills
427
+	private static final int DEWDROP_OF_DESTRUCTION_SKILL_ID = 2276;
428
+	private static final int BREAKING_ARROW_SKILL_ID = 2234;
429
+	private static final IntIntHolder Bomber_Ghost = new IntIntHolder(5011, 1);
430
+	
431
+	private L2Skill songEffect = null;
432
+	private static int[][] scarletSkills;
433
+	
434
+	// Items
435
+	//private static final int FRINTEZZA_SCROLL = 8073; // Frintezza's Magic Force Field Removal Scroll.
436
+	//http://legacy.lineage2.com/news/chronicle5_07.html
437
+	private static final int DEWDROP_OF_DESTRUCTION = 8556; // Dewdrop of Destruction
438
+	// Clicking the Dewdrop of Destruction will make the portrait disappear. It will disappear when one enters the Last Imperial Sepulcher.
439
+	private static final int BREAKING_ARROW = 8192; // Breaking Arrow
440
+	// Double-click the arrow to temporarily stop Frintezza's musical performance. This gets deleted when one enters the Tomb of the Last Emperor.
441
+	
442
+	protected static final int[][] PORTRAIT_GHOST =
443
+	{
444
+		{29048, 175833, -87165, -5126, 35048, 175833, -87165, -5100, 35048},
445
+		{29048, 172634, -87165, -5126, 57730, 172634, -87165, -5100, 57730},
446
+		{29049, 175876, -88713, -5126, 28205, 175876, -88713, -5100, 28205},
447
+		{29049, 172608, -88702, -5126, 64817, 172608, -88702, -5100, 64817}
448
+	};
449
+	
450
+	protected static final int[][] DUMMY_SPAWNS =
451
+	{
452
+		{29052, 174240, -89805, -5022, 16048},
453
+		{29052, 174232, -88020, -5110, 16384},
454
+		{29052, 172450, -87890, -5100, 16048},
455
+		{29052, 176012, -87890, -5100, 16048},
456
+		{29053, 174232, -88020, -5110, 16384}
457
+	};
458
+	
459
+    private static final int[][] ROOM1_SPAWN =
460
+    {
461
+            { 18328,172894,-76019,-5107,243 },
462
+            { 18328,174095,-77279,-5107,16216 },
463
+            { 18328,174111,-74833,-5107,49043 },
464
+            { 18328,175344,-76042,-5107,32847 },
465
+            { 18330,173489,-76227,-5134,63565 },
466
+            { 18330,173498,-75724,-5107,58498 },
467
+            { 18330,174365,-76745,-5107,22424 },
468
+            { 18330,174570,-75584,-5107,31968 },
469
+            { 18330,174613,-76179,-5107,31471 },
470
+            { 18332,173620,-75981,-5107,4588 },
471
+            { 18332,173630,-76340,-5107,62454 },
472
+            { 18332,173755,-75613,-5107,57892 },
473
+            { 18332,173823,-76688,-5107,2411 },
474
+            { 18332,174000,-75411,-5107,54718 },
475
+            { 18332,174487,-75555,-5107,33861 },
476
+            { 18332,174517,-76471,-5107,21893 },
477
+            { 18332,174576,-76122,-5107,31176 },
478
+            { 18332,174600,-75841,-5134,35927 }
479
+    };
480
+    //	Hall Keeper Captain
481
+	private static final int[][] ROOM1_CAPTAIN =
482
+	{
483
+		{ 18329,173481,-76043,-5107,61312 },
484
+		{ 18329,173539,-75678,-5107,59524 },
485
+		{ 18329,173584,-76386,-5107,3041 },
486
+		{ 18329,173773,-75420,-5107,51115 },
487
+		{ 18329,173777,-76650,-5107,12588 },
488
+		{ 18329,174585,-76510,-5107,21704 },
489
+		{ 18329,174623,-75571,-5107,40141 },
490
+		{ 18329,174744,-76240,-5107,29202 },
491
+		{ 18329,174769,-75895,-5107,29572 }
492
+	};
493
+	//	Hall Keeper Suicidal Soldier
494
+	private static final int[][] ROOM1_SUICIDAL_SOLDIER =
495
+	{
496
+		{ 18333,173861,-76011,-5107,383 },
497
+		{ 18333,173872,-76461,-5107,8041 },
498
+		{ 18333,173898,-75668,-5107,51856 },
499
+		{ 18333,174422,-75689,-5107,42878 },
500
+		{ 18333,174460,-76355,-5107,27311 },
501
+		{ 18333,174483,-76041,-5107,30947 }
502
+	};
503
+	//	Hall Keeper Guard
504
+	private static final int[][] ROOM1_GUARD =
505
+	{
506
+		{ 18331,173515,-76184,-5107,6971 },
507
+		{ 18331,173516,-75790,-5134,3142 },
508
+		{ 18331,173696,-76675,-5107,6757 },
509
+		{ 18331,173766,-75502,-5134,60827 },
510
+		{ 18331,174473,-75321,-5107,37147 },
511
+		{ 18331,174493,-76505,-5107,34503 },
512
+		{ 18331,174568,-75654,-5134,41661 },
513
+		{ 18331,174584,-76263,-5107,31729 }
514
+	};
515
+	//	Dark Choir Player
516
+	private static final int[][] ROOM2_SPAWN =
517
+	{
518
+		{ 18339,173892,-81592,-5123,50849 },
519
+		{ 18339,173958,-81820,-5123,7459 },
520
+		{ 18339,174128,-81805,-5150,21495 },
521
+		{ 18339,174245,-81566,-5123,41760 }
522
+	};
523
+	private static final int[][] ROOM2_SPAWN2 =
524
+	{
525
+		{ 18334,173264,-81529,-5072,1646 },
526
+		{ 18334,173265,-81656,-5072,441 },
527
+		{ 18334,173267,-81889,-5072,0 },
528
+		{ 18334,173271,-82015,-5072,65382 },
529
+		{ 18334,174867,-81655,-5073,32537 },
530
+		{ 18334,174868,-81890,-5073,32768 },
531
+		{ 18334,174869,-81485,-5073,32315 },
532
+		{ 18334,174871,-82017,-5073,33007 },
533
+		{ 18335,173074,-80817,-5107,8353 },
534
+		{ 18335,173128,-82702,-5107,5345 },
535
+		{ 18335,173181,-82544,-5107,65135 },
536
+		{ 18335,173191,-80981,-5107,6947 },
537
+		{ 18335,174859,-80889,-5134,24103 },
538
+		{ 18335,174924,-82666,-5107,38710 },
539
+		{ 18335,174947,-80733,-5107,22449 },
540
+		{ 18335,175096,-82724,-5107,42205 },
541
+		{ 18336,173435,-80512,-5107,65215 },
542
+		{ 18336,173440,-82948,-5107,417 },
543
+		{ 18336,173443,-83120,-5107,1094 },
544
+		{ 18336,173463,-83064,-5107,286 },
545
+		{ 18336,173465,-80453,-5107,174 },
546
+		{ 18336,173465,-83006,-5107,2604 },
547
+		{ 18336,173468,-82889,-5107,316 },
548
+		{ 18336,173469,-80570,-5107,65353 },
549
+		{ 18336,173469,-80628,-5107,166 },
550
+		{ 18336,173492,-83121,-5107,394 },
551
+		{ 18336,173493,-80683,-5107,0 },
552
+		{ 18336,173497,-80510,-5134,417 },
553
+		{ 18336,173499,-82947,-5107,0 },
554
+		{ 18336,173521,-83063,-5107,316 },
555
+		{ 18336,173523,-82889,-5107,128 },
556
+		{ 18336,173524,-80627,-5134,65027 },
557
+		{ 18336,173524,-83007,-5107,0 },
558
+		{ 18336,173526,-80452,-5107,64735 },
559
+		{ 18336,173527,-80569,-5134,65062 },
560
+		{ 18336,174602,-83122,-5107,33104 },
561
+		{ 18336,174604,-82949,-5107,33184 },
562
+		{ 18336,174609,-80514,-5107,33234 },
563
+		{ 18336,174609,-80684,-5107,32851 },
564
+		{ 18336,174629,-80627,-5107,33346 },
565
+		{ 18336,174632,-80570,-5107,32896 },
566
+		{ 18336,174632,-83066,-5107,32768 },
567
+		{ 18336,174635,-82893,-5107,33594 },
568
+		{ 18336,174636,-80456,-5107,32065 },
569
+		{ 18336,174639,-83008,-5107,33057 },
570
+		{ 18336,174660,-80512,-5107,33057 },
571
+		{ 18336,174661,-83121,-5107,32768 },
572
+		{ 18336,174663,-82948,-5107,32768 },
573
+		{ 18336,174664,-80685,-5107,32676 },
574
+		{ 18336,174687,-83008,-5107,32520 },
575
+		{ 18336,174691,-83066,-5107,32961 },
576
+		{ 18336,174692,-80455,-5107,33202 },
577
+		{ 18336,174692,-80571,-5107,32768 },
578
+		{ 18336,174693,-80630,-5107,32994 },
579
+		{ 18336,174693,-82889,-5107,32622 },
580
+		{ 18337,172837,-82382,-5107,58363 },
581
+		{ 18337,172867,-81123,-5107,64055 },
582
+		{ 18337,172883,-82495,-5107,64764 },
583
+		{ 18337,172916,-81033,-5107,7099 },
584
+		{ 18337,172940,-82325,-5107,58998 },
585
+		{ 18337,172946,-82435,-5107,58038 },
586
+		{ 18337,172971,-81198,-5107,14768 },
587
+		{ 18337,172992,-81091,-5107,9438 },
588
+		{ 18337,173032,-82365,-5107,59041 },
589
+		{ 18337,173064,-81125,-5107,5827 },
590
+		{ 18337,175014,-81173,-5107,26398 },
591
+		{ 18337,175061,-82374,-5107,43290 },
592
+		{ 18337,175096,-81080,-5107,24719 },
593
+		{ 18337,175169,-82453,-5107,37672 },
594
+		{ 18337,175172,-80972,-5107,32315 },
595
+		{ 18337,175174,-82328,-5107,41760 },
596
+		{ 18337,175197,-81157,-5107,27617 },
597
+		{ 18337,175245,-82547,-5107,40275 },
598
+		{ 18337,175249,-81075,-5107,28435 },
599
+		{ 18337,175292,-82432,-5107,42225 },
600
+		{ 18338,173014,-82628,-5107,11874 },
601
+		{ 18338,173033,-80920,-5107,10425 },
602
+		{ 18338,173095,-82520,-5107,49152 },
603
+		{ 18338,173115,-80986,-5107,9611 },
604
+		{ 18338,173144,-80894,-5107,5345 },
605
+		{ 18338,173147,-82602,-5107,51316 },
606
+		{ 18338,174912,-80825,-5107,24270 },
607
+		{ 18338,174935,-80899,-5107,18061 },
608
+		{ 18338,175016,-82697,-5107,39533 },
609
+		{ 18338,175041,-80834,-5107,25420 },
610
+		{ 18338,175071,-82549,-5107,39163 },
611
+		{ 18338,175154,-82619,-5107,36345 }
612
+	};
613
+	
614
+	public Frintezza()
615
+	{
616
+		super("ai/boss");
617
+		
618
+		StatSet info = GrandBossManager.getInstance().getStatSet(FRINTEZZA);
619
+		if (GrandBossManager.getInstance().getBossStatus(FRINTEZZA) == DEAD)
620
+		{
621
+			long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
622
+			if (temp > 0)
623
+				startQuestTimer("frintezza_unlock", null, null, temp);
624
+			else
625
+				GrandBossManager.getInstance().setBossStatus(FRINTEZZA, DORMANT);
626
+		}
627
+		else if (GrandBossManager.getInstance().getBossStatus(FRINTEZZA) != DORMANT)
628
+			GrandBossManager.getInstance().setBossStatus(FRINTEZZA, DORMANT);
629
+	}
630
+	
631
+	@Override
632
+	protected void registerNpcs()
633
+	{
634
+		addAttackId(SCARLET1,  SCARLET2, FRINTEZZA, 29048, 29049);
635
+		addSpawnId(FRINTEZZA, SCARLET1, SCARLET2, ALARM_DEVICE, CHOIR_CAPTAIN);
636
+		addKillId(SCARLET2, 29048, 29049, 29050, 29051, ALARM_DEVICE, 18329, 18330, 18331, 18332, 18333, CHOIR_CAPTAIN, 18335, 18336, 18337, 18338, CHOIR_PRAYER);
637
+		addSkillSeeId(29050, 29051);
638
+		addSpellFinishedId(FRINTEZZA, 29050, 29051);
639
+		addExitZoneId(100004);
640
+	}
641
+
642
+	@Override
643
+	public String onSpawn(Npc npc)
644
+	{
645
+		switch(npc.getNpcId())
646
+		{
647
+			case ALARM_DEVICE:
648
+			case CHOIR_CAPTAIN:
649
+				if (not_confirmed)
650
+					lastImperialTomp.broadcastPacket(new NpcSay(npc.getObjectId(), SayType.SHOUT, npc.getNpcId() == ALARM_DEVICE ? "Intruders! Sound the alarm!" : "How dare you ruin the performance of the Dark Choir... Unforgivable!"));
651
+				npc.setIsImmobilized(true);
652
+				npc.disableCoreAi(true);
653
+				break;
654
+			case FRINTEZZA:
655
+			case SCARLET1:
656
+			case SCARLET2:
657
+				npc.disableCoreAi(true);
658
+				break;
659
+		}
660
+		return super.onSpawn(npc);
661
+	}
662
+
663
+	@Override
664
+	public String onTimer(String event, Npc npc, Player player)
665
+	{
666
+		if (event.equalsIgnoreCase("start"))
667
+		{
668
+			broadcastPacket(new Earthquake(getKnownInside(), 45, 27, false));
669
+			clean(WAITING);
670
+			dropTimers();
671
+			startQuestTimer("beginning", null, null, 4000);
672
+		}
673
+		else if (event.equalsIgnoreCase("beginning")) //TODO: beginning
674
+		{
675
+			startQuestTimer("camera_00", null, null, 29000);
676
+			startQuestTimer("camera_01", null, null, 30000);
677
+			startQuestTimer("camera_02", null, null, 31000); //100
678
+			startQuestTimer("camera_03", null, null, 37500); //6500
679
+			startQuestTimer("camera_04", null, null, 38400); //900
680
+			startQuestTimer("camera_05", null, null, 42400); //4000 ex - cam5b 
681
+			startQuestTimer("camera_06", null, null, 43750); //1350
682
+			startQuestTimer("camera_07", null, null, 51750); //7000
683
+			startQuestTimer("camera_08", null, null, 52150); //1000
684
+			startQuestTimer("camera_09", null, null, 54150); //2000
685
+			startQuestTimer("camera_10", null, null, 58650); //4500
686
+			startQuestTimer("camera_11", null, null, 59350); //700
687
+			startQuestTimer("camera_12", null, null, 60650); //1300 -15
688
+			startQuestTimer("camera_13", null, null, 62150); //1500 -16
689
+			startQuestTimer("camera_14", null, null, 69650); //7500 -17
690
+			startQuestTimer("camera_15", null, null, 79150); //9500 -16 //79350//200
691
+			startQuestTimer("camera_16", null, null, 81750); //2400 //81550 //81150
692
+			startQuestTimer("camera_17", null, null, 84150); //5000
693
+			startQuestTimer("camera_18", null, null, 84850); //6300 -85450 -throw_up
694
+			startQuestTimer("camera_19", null, null, 87650); //3500
695
+			startQuestTimer("camera_20", null, null, 89650); //2000
696
+			startQuestTimer("camera_21", null, null, 92650); //3000
697
+			startQuestTimer("camera_22", null, null, 94650); //2000
698
+		}
699
+		else if (event.equalsIgnoreCase("despawn"))
700
+		{
701
+			if (GrandBossManager.getInstance().getBossStatus(FRINTEZZA) == FIGHTING && (System.currentTimeMillis() - _lastAttackTime) >= 900000)
702
+			{
703
+				clean(DORMANT);
704
+				dropTimers();
705
+			}
706
+		}
707
+		else if (event.equalsIgnoreCase("camera_00")) //TODO: camera 00
708
+		{
709
+			for (int[] loc : DUMMY_SPAWNS)
710
+			{
711
+				Npc dummy = addSpawn(loc[0], loc[1], loc[2], loc[3], loc[4], false, 62650, false);
712
+				dummy.setIsImmobilized(true);
713
+				dummy.setIsParalyzed(true);
714
+				dummy.disableCoreAi(true);
715
+				_dummys.add(dummy);
716
+			}
717
+			_dummys.get(2).setIsFlying(true);
718
+			_dummys.get(3).setIsFlying(true);
719
+			_dummys.get(1).setCollisionHeight(600);
720
+			setPrepareRoom(true);
721
+		}
722
+		else if (event.equalsIgnoreCase("camera_01"))
723
+		{
724
+			GrandBossManager.getInstance().setBossStatus(FRINTEZZA, FIGHTING);
725
+			frintezza = (GrandBoss) addSpawn(FRINTEZZA, 174240, -89805, -5022, 16048, false, 0, false);
726
+			frintezza.setInvul(true);
727
+			frintezza.decayMe();
728
+		}
729
+		else if (event.equalsIgnoreCase("camera_02"))
730
+		{
731
+			for (int[] ghosts : PORTRAIT_GHOST)
732
+			{
733
+				Monster demon = (Monster) addSpawn(ghosts[0] + 2, ghosts[5], ghosts[6], ghosts[7], ghosts[8], false, 0, false);
734
+				demon.setIsImmobilized(true);
735
+				demon.disableAllSkills();
736
+				demons.add(demon);
737
+			}
738
+			frintezza.spawnMe();
739
+			_dummys.get(1).decayMe();
740
+			broadcastPacket(new NpcInfo(_dummys.get(1), null));
741
+			GrandBossManager.getInstance().addBoss(frintezza);
742
+			broadcastPacket(new SpecialCamera(_dummys.get(1).getObjectId(), 0, 75, -89, 0, 100, 0, 0, 1, 0), new SpecialCamera(_dummys.get(1).getObjectId(), 0, 75, -89, 0, 100, 0, 0, 1, 0), new ValidateLocation(frintezza), new SpecialCamera(_dummys.get(1).getObjectId(), 300, 90, -10, 6500, 7000, 0, 0, 1, 0));
743
+		}
744
+		else if (event.equalsIgnoreCase("camera_03"))
745
+			broadcastPacket(new SpecialCamera(_dummys.get(0).getObjectId(), 1800, 90, 8, 6500, 7000, 0, 0, 1, 0));
746
+		else if (event.equalsIgnoreCase("camera_04"))
747
+			broadcastPacket(new SpecialCamera(_dummys.get(0).getObjectId(), 140, 90, 10, 2500, 4500, 0, 0, 1, 0));
748
+		else if (event.equalsIgnoreCase("camera_05"))
749
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 40, 75, -10, 0, 1000, 0, 0, 1, 0), new SpecialCamera(frintezza.getObjectId(), 40, 75, -10, 0, 12000, 0, 0, 1, 0));
750
+		else if (event.equalsIgnoreCase("camera_06"))
751
+			broadcastPacket(new SocialAction(frintezza, 2));
752
+		else if (event.equalsIgnoreCase("camera_07"))
753
+			{}//broadcastPacket(new SocialAction(demons.get(1), 1), new SocialAction(demons.get(3), 1)); // TODO: 1 y 3
754
+		else if (event.equalsIgnoreCase("camera_08"))
755
+		{
756
+			broadcastPacket(new SocialAction(demons.get(1), 1), new SocialAction(demons.get(3), 1), new SocialAction(demons.get(0), 1), new SocialAction(demons.get(2), 1));
757
+			_dummys.get(2).instantTeleportTo(172450, -87890, -5100, 0);
758
+			_dummys.get(3).instantTeleportTo(176012, -87890, -5100, 0);
759
+			boolean locX = getKnownInside().getX() < 174232;
760
+			broadcastPacket(new SpecialCamera(_dummys.get(locX ? 2 : 3).getObjectId(), 1000, locX ? 118 : 62, 0, 0, 1000, 0, 0, 1, 0), new SpecialCamera(_dummys.get(locX ? 2 : 3).getObjectId(), 1000, locX ? 118 : 62, 0, 0, 10000, 0, 0, 1, 0));
761
+		}
762
+		else if (event.equalsIgnoreCase("camera_09"))
763
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 240, 90, 0, 0, 1000, 0, 0, 1, 0), new SpecialCamera(frintezza.getObjectId(), 240, 90, 25, 5500, 10000, 0, 0, 1, 0), new SocialAction(frintezza, 3));
764
+		else if (event.equalsIgnoreCase("camera_10"))
765
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 100, 195, 35, 0, 10000, 0, 0, 1, 0));
766
+		else if (event.equalsIgnoreCase("camera_11"))
767
+		{
768
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 100, 195, 35, 0, 10000, 0, 0, 1, 0));
769
+			if (not_confirmed)
770
+				playFrintezzaMelody();
771
+		}
772
+		else if (event.equalsIgnoreCase("camera_12"))
773
+		{
774
+			scarlet = (GrandBoss) addSpawn(SCARLET1, 174232, -88020, -5110, 16384, false, 0, true);
775
+			scarlet.setRightHandItemId(8204);
776
+			scarlet.decayMe();
777
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 120, 180, 45, 1500, 10000, 0, 0, 1, 0));
778
+			if (!not_confirmed)
779
+				playFrintezzaMelody();
780
+		}
781
+		else if (event.equalsIgnoreCase("camera_13"))
782
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 520, 135, 45, 8000, 10000, 0, 0, 1, 0));
783
+		else if (event.equalsIgnoreCase("camera_14"))
784
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 1500, 110, 25, 10000, 13000, 0, 0, 1, 0));
785
+		else if (event.equalsIgnoreCase("camera_15"))
786
+			broadcastPacket(new SpecialCamera(_dummys.get(1).getObjectId(), 930, 160, -20, 0, 1000, 0, 0, 1, 0), new MagicSkillUse(_dummys.get(4), _dummys.get(4), 5004, 1, 5800, 0), new SpecialCamera(_dummys.get(1).getObjectId(), 600, 180, -25, 0, 10000, 0, 0, 1, 0));
787
+		else if (event.equalsIgnoreCase("camera_16"))
788
+			scarlet.spawnMe();
789
+		else if (event.equalsIgnoreCase("camera_17"))
790
+			broadcastPacket(new SocialAction(_dummys.get(4), 3), new SpecialCamera(_dummys.get(4).getObjectId(), 800, 180, 10, 1000, 10000, 0, 0, 1, 0));
791
+		else if (event.equalsIgnoreCase("camera_18")) // TODO: throw_up
792
+			throwUp(_dummys.get(4), 500, SystemMessage.getSystemMessage(SystemMessageId.YOU_FEEL_S1_EFFECT).addSkillName(5004, 1));
793
+		else if (event.equalsIgnoreCase("camera_19"))
794
+			broadcastPacket(new SpecialCamera(_dummys.get(4).getObjectId(), 300, 60, 8, 0, 10000, 0, 0, 1, 0));
795
+		else if (event.equalsIgnoreCase("camera_20"))
796
+			broadcastPacket(new SpecialCamera(scarlet.getObjectId(), 500, 90, 10, 1000, 5000, 0, 0, 1, 0), new SpecialCamera(scarlet.getObjectId(), 500, 90, 10, 3000, 5000, 0, 0, 1, 0));
797
+		else if (event.equalsIgnoreCase("camera_21"))
798
+		{
799
+			for (int i = 0; i < PORTRAIT_GHOST.length; i++)
800
+			{
801
+				Monster portrait = (Monster) addSpawn(PORTRAIT_GHOST[i][0], PORTRAIT_GHOST[i][1], PORTRAIT_GHOST[i][2], PORTRAIT_GHOST[i][3], PORTRAIT_GHOST[i][4], false, 0, false);
802
+				//portrait.setIsFlying(true);
803
+				portrait.setIsImmobilized(true);
804
+				portrait.disableCoreAi(true);
805
+				portraits.put(portrait, i);
806
+			}
807
+			if (!_dummys.isEmpty())
808
+			{
809
+				for (Npc n : _dummys)
810
+					deleteNpc(n);
811
+				_dummys.clear();
812
+			}
813
+		}
814
+		else if (event.equalsIgnoreCase("camera_22")) //TODO: camera_22
815
+		{
816
+			roomTasks();
817
+			setPrepareRoom(false);
818
+			frintezza.setInvul(false);
819
+			startQuestTimerAtFixedRate("spawn_minion", null, null, 20000);
820
+		}
821
+		else if (event.equalsIgnoreCase("spawn_minion")) //TODO: spawn_minion
822
+		{
823
+			if (frintezza != null && !frintezza.isDead() && !portraits.isEmpty())
824
+			{
825
+				if (!frintezza.isInvul())
826
+					for (int i : portraits.values())
827
+					{
828
+						if (demons.size() > 24)
829
+							break;
830
+						Monster demon = (Monster) addSpawn(PORTRAIT_GHOST[i][0] + 2, PORTRAIT_GHOST[i][5], PORTRAIT_GHOST[i][6], PORTRAIT_GHOST[i][7], PORTRAIT_GHOST[i][8], false, 0, false);
831
+						demon.setMinion(true);
832
+						demon.forceRunStance();
833
+						demons.add(demon);
834
+						demon.disableSkill(Bomber_Ghost.getSkill(), -1); // Bomb
835
+						startQuestTimer("action", demon, null, 200);
836
+					}
837
+			}
838
+			else 
839
+				cancelQuestTimers("spawn_minion");
840
+		}
841
+		else if (event.equalsIgnoreCase("end_camera"))
842
+			npc.setInvul(false);
843
+		else if (event.equalsIgnoreCase("first_morph_01")) //TODO: first_morph
844
+		{
845
+			npc.stopSkillEffects(5008);
846
+			setPrepareRoom(true);
847
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 250, calcCameraAngle(npc), 12, 2000, 15000, 0, 0, 1, 0));
848
+		}
849
+		else if (event.equalsIgnoreCase("first_morph_02"))
850
+		{
851
+			broadcastPacket(new SocialAction(npc, 1));
852
+			npc.setRightHandItemId(7903);
853
+		}
854
+		else if (event.equalsIgnoreCase("first_morph_03"))
855
+			daemonMorph(npc, 1);
856
+		else if (event.equalsIgnoreCase("second_morph_01"))
857
+		{
858
+			setPrepareRoom(true);
859
+			broadcastPacket(new SocialAction(frintezza, 4));
860
+		}
861
+		else if (event.equalsIgnoreCase("second_morph_02"))
862
+		{
863
+			broadcastPacket(new SpecialCamera(frintezza.getObjectId(), 250, 120, 15, 0, 1000, 0, 0, 1, 0), new SpecialCamera(frintezza.getObjectId(), 250, 120, 15, 0, 10000, 0, 0, 1, 0));
864
+			npc.setIsImmobilized(true);
865
+		}
866
+		else if (event.equalsIgnoreCase("second_morph_03"))
867
+		{
868
+			playFrintezzaMelody();
869
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 500, 70, 15, 3000, 10000, 0, 0, 1, 0));
870
+		}
871
+		else if (event.equalsIgnoreCase("second_morph_04"))
872
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 2500, 90, 12, 6000, 10000, 0, 0, 1, 0));
873
+		else if (event.equalsIgnoreCase("second_morph_05"))
874
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 250, calcCameraAngle(npc), 12, 0, 1000, 0, 0, 1, 0), new SpecialCamera(npc.getObjectId(), 250, calcCameraAngle(npc), 12, 0, 10000, 0, 0, 1, 0));
875
+		else if (event.equalsIgnoreCase("second_morph_06"))
876
+		{
877
+			npc.doDie(npc);
878
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 450, calcCameraAngle(npc), 14, 8000, 8000, 0, 0, 1, 0));
879
+			scarlet = null;
880
+		}
881
+		else if (event.equalsIgnoreCase("second_morph_07"))
882
+			deleteNpc(npc);
883
+		else if (event.equalsIgnoreCase("second_morph_08"))
884
+		{
885
+			scarlet = (GrandBoss) addSpawn(SCARLET2, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), false, 0, false);
886
+			broadcastPacket(new SpecialCamera(scarlet.getObjectId(), 450, calcCameraAngle(npc), 12, 500, 14000, 0, 0, 1, 0));
887
+		}
888
+		else if (event.equalsIgnoreCase("second_morph_09"))
889
+			daemonMorph(scarlet, 2);
890
+		else if (event.equalsIgnoreCase("start_room"))
891
+			setPrepareRoom(false);
892
+		else if (event.equalsIgnoreCase("die_01")) //TODO: die_01
893
+			npc.doDie(npc);
894
+		else if (event.equalsIgnoreCase("die_02"))
895
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 100, 120, 5, 0, 7000, 0, 0, 1, 0), new SpecialCamera(npc.getObjectId(), 100, 90, 5, 5000, 15000, 0, 0, 1, 0));
896
+		else if (event.equalsIgnoreCase("die_03"))
897
+		{
898
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 900, 90, 25, 7000, 10000, 0, 0, 1, 0));
899
+			addSpawn(29061, 174232, -88020, -5114, 16384, false, 900000, false);
900
+			startQuestTimer("remove_players", null, null, 900000);
901
+		}
902
+		else if (event.equalsIgnoreCase("die_04"))
903
+		{
904
+			cancelQuestTimers("spawn_minion");
905
+			clean(DEAD);
906
+			long respawnTime = (long) Config.SPAWN_INTERVAL_FRINTEZZA + Rnd.get(-Config.RANDOM_SPAWN_TIME_FRINTEZZA, Config.RANDOM_SPAWN_TIME_FRINTEZZA);
907
+			respawnTime *= 3600000;
908
+			startQuestTimer("frintezza_unlock", npc, null, respawnTime);
909
+			// also save the respawn time so that the info is maintained past reboots
910
+			StatSet info = GrandBossManager.getInstance().getStatSet(FRINTEZZA);
911
+			info.set("respawn_time", System.currentTimeMillis() + respawnTime);
912
+			GrandBossManager.getInstance().setStatSet(FRINTEZZA, info);
913
+		}
914
+		else if (event.equalsIgnoreCase("songs_play")) //TODO: play song
915
+			callSongAI();
916
+		else if (event.equalsIgnoreCase("skill_task")) //TODO: skill_task
917
+		{
918
+			if (npc.isInvul() || npc.getCast().isCastingNow() || npc.isDead() || frintezza.isInvul())
919
+				return super.onTimer(event, npc, player);
920
+			
921
+			final L2Skill skill = getRandomSkill();
922
+			int rnd = Rnd.get(10);
923
+
924
+			if (_actualVictim == null || _actualVictim.isDead() || !npc.knows(_actualVictim) || npc.getScriptValue() != 1 && !npc.isMoving() || rnd == 0 && npc.isMoving())
925
+				_actualVictim = getRandomPlayer(npc);
926
+			if (_actualVictim == null)
927
+				return super.onTimer(event, npc, player);
928
+			
929
+			int range = skill.getCastRange();
930
+			if (_actualVictim.isMoving())
931
+	        	range = range * 80 / 100;
932
+			if (MathUtil.checkIfInRange((int) (range + npc.getCollisionRadius()), npc, _actualVictim, true))
933
+			{
934
+				npc.getAI().tryToIdle(); //.getAI().setIntention(CtrlIntention.IDLE);
935
+				npc.getAI().tryToCast(_actualVictim, skill); // npc.doCast(skill); npc.setTarget(_actualVictim);
936
+				npc.setScriptValue(0);
937
+				if (rnd < 0) // 90% he decides to reconsiders his new target.
938
+					_actualVictim = null;
939
+			}
940
+			else 
941
+			{
942
+				npc.forceRunStance();
943
+				npc.setScriptValue(1);
944
+				npc.getAI().tryToMoveTo(new Location(_actualVictim.getX(), _actualVictim.getY(), _actualVictim.getZ()), null);//npc.getAI().setIntention(CtrlIntention.FOLLOW, _actualVictim, null);
945
+			}
946
+		}
947
+		else if (event.equalsIgnoreCase("songs_effect"))
948
+		{
949
+			if (scarlet == null || frintezza == null || scarlet.isDead() || scarlet.isInvul() || frintezza.isDead() || frintezza.isInvul() || songEffect == null)
950
+				return super.onTimer(event, npc, player);
951
+			
952
+			if (frintezza.getScriptValue() == 1)
953
+				frintezza.getCast().doCast(songEffect, songEffect.getLevel() < 4 ? getKnownInside() : scarlet, null);
954
+			else
955
+				cancelQuestTimers("songs_effect");
956
+		}
957
+		else if (event.equalsIgnoreCase("end_song")) // Stop effect song
958
+			npc.setScriptValue(3);
959
+		else if (event.equalsIgnoreCase("timeNextSong")) // BreakingArrow - time next song
960
+			npc.setScriptValue(0);
961
+		else if (event.equalsIgnoreCase("action"))
962
+			broadcastPacket(new SocialAction(npc, 1));
963
+		else if (event.equalsIgnoreCase("frintezza_unlock"))
964
+			GrandBossManager.getInstance().setBossStatus(FRINTEZZA, DORMANT);
965
+		else if (event.equalsIgnoreCase("waiting"))
966
+		{
967
+			startQuestTimer("close", npc, null, 2700);
968
+			startQuestTimer("beginning", null, null, 3000);//_LastImperialTomp.broadcastPacket(new Earthquake(174232, -88020, -5116, 45, 27));
969
+			for (Creature cha : lastImperialTomp.getKnownTypeInside(Player.class))
970
+				if (cha instanceof Player)
971
+					cha.broadcastPacket(new Earthquake(cha, 45, 27, false)); //174232, -88020, -5116, 45, 27));
972
+		}
973
+		else if (event.equalsIgnoreCase("room1_spawn"))
974
+			for (int[] loc : ROOM1_SPAWN)
975
+	            _mobs.add(addSpawn(loc[0], loc[1], loc[2], loc[3], loc[4], false, 0, false));
976
+		else if (event.equalsIgnoreCase("room1_spawn2"))
977
+			for (int[] loc : ROOM1_CAPTAIN)
978
+				_mobs.add(addSpawn(loc[0], loc[1], loc[2], loc[3], loc[4], false, 0, false));
979
+		else if (event.equalsIgnoreCase("room1_spawn3"))
980
+			for (int[] loc : ROOM1_SUICIDAL_SOLDIER)
981
+				_mobs.add(addSpawn(loc[0], loc[1], loc[2], loc[3], loc[4], false, 0, false));
982
+		else if (event.equalsIgnoreCase("room1_spawn4"))
983
+			for (int[] loc : ROOM1_GUARD)
984
+				_mobs.add(addSpawn(loc[0], loc[1], loc[2], loc[3], loc[4], false, 0, false));
985
+		else if (event.equalsIgnoreCase("room2_spawn"))
986
+			for (int[] loc : ROOM2_SPAWN)
987
+				_mobs.add(addSpawn(loc[0], loc[1], loc[2], loc[3], loc[4], false, 0, false));
988
+		else if (event.equalsIgnoreCase("room2_spawn2"))
989
+			for (int[] loc : ROOM2_SPAWN2)
990
+				_mobs.add(addSpawn(loc[0], loc[1], loc[2], loc[3], loc[4], false, 0, false));
991
+		else if (event.equalsIgnoreCase("mobs_del"))
992
+		{
993
+			for (Npc mob : _mobs)
994
+				if (mob != null)
995
+					mob.deleteMe();
996
+			_mobs.clear();
997
+		}
998
+		else if (event.equalsIgnoreCase("clean"))
999
+			_killMobs = 0;
1000
+		else if (event.equalsIgnoreCase("close"))
1001
+		{
1002
+			for (int i = 25150051; i <= 25150058; i++)
1003
+				openCloseDoor(false, i);
1004
+			
1005
+			for (int i = 25150061; i <= 25150070; i++)
1006
+				openCloseDoor(false, i);
1007
+
1008
+			openCloseDoor(false, 25150042, 25150043, 25150045, 25150046);
1009
+		}
1010
+		else if (event.equalsIgnoreCase("enter"))
1011
+		{
1012
+			startQuestTimer("clean", null, null, 100);
1013
+			startQuestTimer("close", null, null, 100);
1014
+			startQuestTimer("room1_spawn", null, null, 4000);
1015
+			startQuestTimer("room_final", null, null, 2100000); // 35min
1016
+		}
1017
+		else if (event.equalsIgnoreCase("room_final"))
1018
+		{
1019
+			lastImperialTomp.broadcastPacket(new CreatureSay(npc.getObjectId(), SayType.SHOUT, npc.getName(), "Exceeded his time limit, challenge failed!"));
1020
+			startQuestTimer("remove_players", null, null, 0);
1021
+			
1022
+			cancelQuestTimers("waiting");
1023
+			startQuestTimer("clean", null, null, 1000);
1024
+			startQuestTimer("close", null, null, 1000);
1025
+			startQuestTimer("mobs_del", null, null, 1000);
1026
+
1027
+			GrandBossManager.getInstance().setBossStatus(Frintezza.FRINTEZZA, Frintezza.DORMANT);
1028
+		}
1029
+		else if (event.equalsIgnoreCase("remove_players"))
1030
+			lastImperialTomp.oustAllPlayers();
1031
+		
1032
+		return super.onTimer(event, npc, player);
1033
+	}
1034
+	
1035
+	private static void playFrintezzaMelody()
1036
+	{
1037
+		// frintezza.getCast().doCast(Frintezza_Melody.getSkill(), frintezza, null); // frintezza.getAI().tryToCast(frintezza, Frintezza_Melody.getSkill());
1038
+		L2Skill skill = new IntIntHolder(5006, 1).getSkill(); // If tryToCast or doCast is used in the last acis, it looks like a speen run, Frintezza's casting stats are wrong?
1039
+		broadcastPacket(new MagicSkillUse(frintezza, frintezza, skill.getId(), skill.getLevel(), skill.getHitTime(), skill.getReuseDelay()));
1040
+	}
1041
+
1042
+	private void callSongAI()
1043
+	{
1044
+		if (frintezza == null || frintezza.isDead() || frintezza.isInvul() || frintezza.getScriptValue() == 1)
1045
+			return;
1046
+		else if (frintezza.getScriptValue() == 0)
1047
+		{
1048
+			boolean isRequiem = getState() == 3 && scarlet != null && scarlet.getStatus().getHp() < scarlet.getStatus().getMaxHp() * 0.6 && 100 < Rnd.get(80);
1049
+			// new song play
1050
+			int rnd = Rnd.get(100);
1051
+			for (FrintezzaSong song : FRINTEZZA_SONG_LIST)
1052
+			{
1053
+				int songLvl = song.skill.getSkill().getLevel();
1054
+				if (rnd < song.chance || isRequiem && songLvl == 1)
1055
+				{
1056
+					L2Skill dummySkill = song.skill.getSkill();
1057
+					songEffect = song.effectSkill.getSkill();
1058
+					int hitTime = dummySkill.getHitTime();
1059
+					broadcastPacket(new ExShowScreenMessage(1, -1, SMPOS.TOP_CENTER, false, 0, 0, 0, true, 4000, false, song.songName));
1060
+					broadcastPacket(new MagicSkillUse(frintezza, frintezza, dummySkill.getId(), songLvl, hitTime, dummySkill.getReuseDelay()));
1061
+					startQuestTimer("songs_effect", scarlet, null, 10000);
1062
+					startQuestTimer("endSong", frintezza, null, hitTime);
1063
+					startQuestTimer("timeNextSong", frintezza, null, hitTime + Rnd.get(10000, 15000)/*Rnd.get(30000, 120000)*/);
1064
+					frintezza.setScriptValue(1);
1065
+					return;
1066
+				}
1067
+			}
1068
+		}
1069
+		else if (frintezza.getScriptValue() == 2)
1070
+		{
1071
+			frintezza.setScriptValue(3);
1072
+			startQuestTimer("timeNextSong", frintezza, null, Rnd.get(30000, 120000));
1073
+		}
1074
+	}
1075
+
1076
+	@Override
1077
+	public String onAttack(Npc npc, Creature attacker, int damage, L2Skill skill)
1078
+	{
1079
+		if (GrandBossManager.getInstance().getBossStatus(FRINTEZZA) != FIGHTING || npc.isInvul())
1080
+			return null;
1081
+		
1082
+		if (!FRINTEZZA_LAIR.isInsideZone(attacker))
1083
+		{
1084
+			attacker.teleportTo(150037 + Rnd.get(500), -57720 + Rnd.get(500), -2976, 0);
1085
+			return null;
1086
+		}
1087
+		if (npc.getNpcId() != FRINTEZZA && !FRINTEZZA_LAIR.isInsideZone(npc) || npc.getX() < 171932 || npc.getX() > 176532 || npc.getY() < -90320 || npc.getY() > -85720 || npc.getZ() < -5130)
1088
+		{
1089
+			npc.enableAllSkills();
1090
+			npc.setIsImmobilized(false);
1091
+			npc.teleportTo(174232, -88020, -5116, 0);
1092
+			return null;
1093
+		}
1094
+
1095
+		switch (npc.getNpcId())
1096
+		{
1097
+			// When Dewdrop of Destruction is used on Portraits they suicide.
1098
+			case 29048:
1099
+			case 29049:
1100
+			if (skill != null && (skill.getId() == DEWDROP_OF_DESTRUCTION_SKILL_ID))
1101
+				if (attacker.getTarget() == npc)
1102
+					npc.doDie(attacker);
1103
+			break;
1104
+			case 29050:
1105
+			case 29051:
1106
+				double hp = npc.getStatus().getHp();
1107
+				double mm = npc.getStatus().getMaxHp() * 0.10;
1108
+				if (hp >= mm && hp - damage > 0 && hp - damage < mm)
1109
+					npc.enableSkill(Bomber_Ghost.getSkill());
1110
+				break;
1111
+			case FRINTEZZA:
1112
+				if (skill != null && skill.getId() == BREAKING_ARROW_SKILL_ID)
1113
+				{
1114
+					npc.setScriptValue(2);
1115
+					npc.abortAll(true);
1116
+					npc.getAI().tryToIdle();
1117
+					getKnownInside().stopSkillEffects(5008);
1118
+					if (scarlet != null)
1119
+						scarlet.stopSkillEffects(5008);
1120
+					broadcastPacket(new MagicSkillCanceled(frintezza.getObjectId()));
1121
+				}
1122
+				npc.getStatus().setHp(npc.getStatus().getMaxHp(), true);
1123
+				break;
1124
+			case SCARLET1:
1125
+				synchronized (this)
1126
+				{
1127
+					taskCameraMorph(getState(), npc);
1128
+					break;
1129
+				}
1130
+		}
1131
+		_lastAttackTime = System.currentTimeMillis();
1132
+		return super.onAttack(npc, attacker, damage, skill);
1133
+	}
1134
+
1135
+	@Override
1136
+	public String onSpellFinished(Npc npc, Player player, L2Skill skill)
1137
+	{
1138
+		if (skill.isSuicideAttack() && npc.getNpcId() != FRINTEZZA)
1139
+			this.onKill(npc, null);
1140
+		return super.onSpellFinished(npc, player, skill);
1141
+	}
1142
+
1143
+	@Override
1144
+	public String onKill(Npc npc, Creature killer)
1145
+	{
1146
+		int StatusBoss = GrandBossManager.getInstance().getBossStatus(FRINTEZZA);
1147
+		if (StatusBoss == FIGHTING)
1148
+		{
1149
+			if (npc.getNpcId() == SCARLET2)
1150
+				taskCameraMorph(getState(), npc);
1151
+			if (portraits.containsKey(npc))
1152
+				portraits.remove(npc);
1153
+			if (demons.contains(npc))
1154
+				demons.remove(npc);
1155
+			return null;
1156
+		}
1157
+		else if (StatusBoss == WAITING)
1158
+		{
1159
+			switch(npc.getNpcId())
1160
+			{
1161
+				case 18329:
1162
+				case 18330:
1163
+				case 18331:
1164
+				case 18332:
1165
+				case 18333:
1166
+					if (Rnd.get(100) < 10)
1167
+						killer.getInventory().addItem("Quest", DEWDROP_OF_DESTRUCTION, 1, null, null);
1168
+					break;
1169
+				case ALARM_DEVICE:
1170
+					if (Rnd.get(100) < 33)
1171
+						killer.getInventory().addItem("Quest", DEWDROP_OF_DESTRUCTION, 1, null, null);
1172
+					_killMobs++;
1173
+					
1174
+					if (not_confirmed)
1175
+						if (_killMobs <= 3 && Rnd.get(100) < _killMobs * 5) // 5% chance first alarm, 10% in the second alarm
1176
+							for (int i = 25150051; i <= 25150058; i++)
1177
+								openCloseDoor(true, i);
1178
+					if (_killMobs == 1)
1179
+						startQuestTimer("room1_spawn2", npc, null, 200);
1180
+					if (_killMobs == 2)
1181
+						startQuestTimer("room1_spawn3", npc, null, 200);
1182
+					if (_killMobs == 3)
1183
+						startQuestTimer("room1_spawn4", npc, null, 200);
1184
+					if (_killMobs == 4)
1185
+					{
1186
+						for (int i = 25150051; i <= 25150058; i++)
1187
+							openCloseDoor(true, i);
1188
+						startQuestTimer("mobs_del", npc, null, 100);
1189
+						startQuestTimer("room2_spawn", npc, null, 200);
1190
+						
1191
+						openCloseDoor(true, 25150042, 25150043); //, 25150045, 25150046
1192
+					}
1193
+					break;
1194
+				case 18339:
1195
+					if (_killMobs <= 6)
1196
+						_killMobs++;
1197
+					if (_killMobs == 6)
1198
+					{
1199
+						openCloseDoor(false, 25150042, 25150043, 25150045, 25150046);
1200
+						for (int i = 25150061; i <= 25150070; i++)
1201
+							openCloseDoor(true, i);
1202
+							
1203
+						startQuestTimer("room2_spawn2", npc, null, 1000);
1204
+					}
1205
+					break;
1206
+				case 18334:
1207
+					if (Rnd.get(100) < 33)
1208
+						killer.getInventory().addItem("Quest", BREAKING_ARROW, 1, null, null); // Breaking Arrow
1209
+					if (_killMobs <= 14)
1210
+						_killMobs++;
1211
+					if (_killMobs == 14)
1212
+					{
1213
+				    	startQuestTimer("mobs_del", npc, null, 100);
1214
+						
1215
+						openCloseDoor(true, 25150045, 25150046);
1216
+						startQuestTimer("waiting", npc, null, Config.WAIT_TIME_FRINTEZZA * 3);
1217
+						cancelQuestTimers("room_final");
1218
+						startQuestTimer("clean", npc, null, 1000);
1219
+					}
1220
+					break;
1221
+			}
1222
+			return null;
1223
+		}
1224
+		return super.onKill(npc, killer);
1225
+	}
1226
+	
1227
+	private static void openCloseDoor(boolean open, int... doorIds)
1228
+	{
1229
+		for (int doorId : doorIds)
1230
+			if (open)
1231
+				DoorData.getInstance().getDoor(doorId).openMe();
1232
+			else
1233
+				DoorData.getInstance().getDoor(doorId).closeMe();
1234
+	}
1235
+	
1236
+	private static L2Skill getRandomSkill() //TODO: getRandomSkill()
1237
+	{
1238
+		int[][] FIRST_SCARLET_SKILLS = 
1239
+		{
1240
+			{ 5014, 1, 100}, // Frintezza's Daemon Attack 1
1241
+			{ 5015, 1, 5  }, // Frintezza's Daemon Charge 1
1242
+			{ 5015, 4, 5  }, // Frintezza's Daemon Charge 4
1243
+		};
1244
+		int[][] SECOND_SCARLET_SKILLS = 
1245
+		{
1246
+			{ 5014, 2, 100}, // Frintezza's Daemon Attack
1247
+			{ 5015, 2, 5  }, // Frintezza's Daemon Charge 2
1248
+			{ 5015, 5, 5  }, // Frintezza's Daemon Charge 5
1249
+			{ 5018, 1, 10 }, // Frintezza's Daemon Field 1
1250
+			{ 5016, 1, 10 }, // Yoke of Scarlet
1251
+		};
1252
+		int[][] THIRD_SCARLET_SKILLS = 
1253
+		{
1254
+			{ 5014, 3, 100}, // Frintezza's Daemon Attack
1255
+			{ 5015, 3, 5  }, // Frintezza's Daemon Charge 3
1256
+			{ 5015, 6, 5  }, // Frintezza's Daemon Charge 6
1257
+			{ 5018, 2, 10 }, // Frintezza's Daemon Field 2
1258
+			{ 5019, 1, 10 }, // Frintezza's Daemon Drain
1259
+			{ 5016, 1, 10 }, // Yoke of Scarlet
1260
+		};
1261
+		int skillLvl = getState();
1262
+		if (skillLvl == 1)
1263
+			scarletSkills = FIRST_SCARLET_SKILLS;
1264
+		else if (skillLvl == 2)
1265
+			scarletSkills = SECOND_SCARLET_SKILLS;
1266
+		else if (skillLvl == 3)
1267
+			scarletSkills = THIRD_SCARLET_SKILLS;
1268
+		
1269
+		int rnd = Rnd.get(100);
1270
+		for (int i = scarletSkills.length; --i >= 0;)
1271
+		{
1272
+			int[] sk = scarletSkills[i];
1273
+			int chance = sk[2];
1274
+			if ((rnd -= chance) <= 0)
1275
+				return new IntIntHolder(sk[0], sk[1]).getSkill();
1276
+		}
1277
+		return null;
1278
+	}
1279
+	
1280
+	private static int calcCameraAngle(Creature npc)
1281
+	{
1282
+		final int heading = npc.getHeading();
1283
+		return Math.abs((heading < 32768 ? 180 : 540) - (int)(heading / 182.044444444));
1284
+	}
1285
+	
1286
+	private static void throwUp(Creature attacker, final double range, SystemMessage msg)
1287
+	{
1288
+		final int mx = attacker.getX(), my = attacker.getY();
1289
+		for (Creature target : FRINTEZZA_LAIR.getKnownTypeInside(Creature.class))//.getCharactersInside())
1290
+		{
1291
+			if (target == attacker)
1292
+				continue;
1293
+			if (target instanceof Npc && ((Npc) target).getNpcId() >= 29045 && ((Npc) target).getNpcId() <= 29053)
1294
+				continue;
1295
+			double dx = target.getX() - mx;
1296
+			double dy = target.getY() - my;
1297
+			if (dx == 0 && dy == 0)
1298
+				dx = dy = range / 2;
1299
+			double aa = range / Math.sqrt(dx * dx + dy * dy);
1300
+			if (aa > 1.0)
1301
+			{
1302
+				int x = mx + (int) (dx * aa);
1303
+				int y = my + (int) (dy * aa);
1304
+				int z = target.getZ();
1305
+
1306
+				target.abortAll(true); //cha.abortAttack(); //cha.abortCast();
1307
+				target.getAI().tryToIdle(); //target.getAI().setIntention(CtrlIntention.IDLE);
1308
+				
1309
+				target.broadcastPacket(new FlyToLocation(target, x, y, z, FlyType.THROW_UP));
1310
+				target.setXYZ(x, y, z);
1311
+				target.getPosition().setHeading(MathUtil.calculateHeadingFrom(x, y, mx, my));
1312
+				target.broadcastPacket(new ValidateLocation(target));
1313
+				if (msg != null)
1314
+					target.sendPacket(msg);
1315
+				if (target instanceof Player)
1316
+					((Player) target).standUp();
1317
+			}
1318
+		}
1319
+	}
1320
+	
1321
+	private static class FrintezzaSong
1322
+	{
1323
+		public IntIntHolder skill;
1324
+		public IntIntHolder effectSkill;
1325
+		public String songName;
1326
+		public int chance;
1327
+		
1328
+		public FrintezzaSong(IntIntHolder sk, IntIntHolder esk, String sn, int ch)
1329
+		{
1330
+			skill = sk;
1331
+			effectSkill = esk;
1332
+			songName = sn;
1333
+			chance = ch;
1334
+		}
1335
+	}
1336
+	
1337
+	private final FrintezzaSong[] FRINTEZZA_SONG_LIST =
1338
+	{
1339
+		new FrintezzaSong(new IntIntHolder(5007, 1), new IntIntHolder(5008, 1), "Requiem of Hatred", 5),
1340
+		new FrintezzaSong(new IntIntHolder(5007, 2), new IntIntHolder(5008, 2), "Rondo of Solitude", 50),
1341
+		new FrintezzaSong(new IntIntHolder(5007, 3), new IntIntHolder(5008, 3), "Frenetic Toccata", 70),
1342
+		new FrintezzaSong(new IntIntHolder(5007, 4), new IntIntHolder(5008, 4), "Fugue of Jubilation", 90),
1343
+		new FrintezzaSong(new IntIntHolder(5007, 5), new IntIntHolder(5008, 5), "Hypnotic Mazurka", 100),
1344
+	};
1345
+	
1346
+	private static void broadcastPacket(L2GameServerPacket... packets)
1347
+	{
1348
+		for (L2GameServerPacket packet : packets)
1349
+			FRINTEZZA_LAIR.broadcastPacket(packet);
1350
+	}
1351
+	
1352
+	private void daemonMorph(Npc npc, int stage)
1353
+	{
1354
+		npc.setCollisionHeight(stage == 1 ? 110 : 130);
1355
+		broadcastPacket(new SocialAction(npc, stage == 1 ? 4 : 2));
1356
+		final IntIntHolder Daemon_Morph = new IntIntHolder(5017, 1);
1357
+		npc.getCast().doCast(Daemon_Morph.getSkill(), npc, null);
1358
+		broadcastPacket(new NpcInfo(npc, null));
1359
+		roomTasks();
1360
+	}
1361
+	
1362
+	private void setPrepareRoom(boolean move)
1363
+	{
1364
+		for (Creature cha : FRINTEZZA_LAIR.getKnownTypeInside(Creature.class))
1365
+		{
1366
+			if (cha != null)
1367
+			{
1368
+				if (frintezza != cha || frintezza == null)
1369
+					cha.setInvul(move);
1370
+				if (move)
1371
+				{
1372
+					cha.getAI().tryToIdle();
1373
+					cha.abortAll(true);
1374
+					if (frintezza != null)
1375
+					{
1376
+						if (move)
1377
+							cha.setInvul(true);
1378
+						dropTimers();
1379
+						frintezza.setScriptValue(1);
1380
+						broadcastPacket(new MagicSkillCanceled(frintezza.getObjectId()));
1381
+					}
1382
+				}
1383
+				if (!(cha instanceof GrandBoss))
1384
+				{
1385
+					if (move)
1386
+					{
1387
+						cha.disableAllSkills();
1388
+						if (cha instanceof Monster)
1389
+							cha.forceRunStance();//cha.setRunning(true);
1390
+					}
1391
+					else
1392
+						cha.enableAllSkills();
1393
+					cha.setIsImmobilized(move);
1394
+					cha.setIsParalyzed(move);
1395
+				}
1396
+			}
1397
+		}
1398
+	}
1399
+	
1400
+	private void roomTasks()
1401
+	{
1402
+		_lastAttackTime = System.currentTimeMillis();
1403
+		startQuestTimerAtFixedRate("songs_play", frintezza, null, 5000);
1404
+		startQuestTimerAtFixedRate("skill_task", scarlet, null, 2500);
1405
+		startQuestTimerAtFixedRate("spawn_minion", null, null, 20000);
1406
+		startQuestTimer("despawn", scarlet, null, 60000);
1407
+		frintezza.setScriptValue(0);
1408
+	}
1409
+	
1410
+	private static void deleteNpc(Npc... npcs)
1411
+	{
1412
+		for (Npc npc : npcs)
1413
+		{
1414
+			if (npc != null)
1415
+				npc.deleteMe();
1416
+			npc = null;
1417
+		}
1418
+	}
1419
+	
1420
+	private void clean(int status)
1421
+	{
1422
+		if (!demons.isEmpty())
1423
+			for (Npc mobs : demons)
1424
+				deleteNpc(mobs);
1425
+		if (!portraits.isEmpty())
1426
+			for (Monster portrait : portraits.keySet())
1427
+				deleteNpc(portrait);
1428
+		deleteNpc(scarlet, frintezza);
1429
+		demons.clear();
1430
+		portraits.clear();
1431
+		GrandBossManager.getInstance().setBossStatus(FRINTEZZA, status);
1432
+		
1433
+		_lastAttackTime = 0;
1434
+		songEffect = null;
1435
+	}
1436
+	
1437
+	private static int getState()
1438
+	{
1439
+		final IntIntHolder Daemon_Morph = new IntIntHolder(5017, 1);
1440
+		if (scarlet != null)
1441
+		{
1442
+			if (scarlet.getNpcId() == SCARLET2)
1443
+				return 3;
1444
+			AbstractEffect[] effects = scarlet.getAllEffects();
1445
+			if (effects.length != 0)
1446
+				for (AbstractEffect e : effects)
1447
+					if (e.getSkill() == Daemon_Morph.getSkill())
1448
+						return 2;
1449
+			return 1;
1450
+		}
1451
+		return 0;
1452
+	}
1453
+	
1454
+	private void dropTimers()
1455
+	{
1456
+		cancelQuestTimers("despawn");
1457
+		cancelQuestTimers("spawn_minion");
1458
+		cancelQuestTimers("skill_task");
1459
+		cancelQuestTimers("songs_play");
1460
+		cancelQuestTimers("songs_effect");
1461
+		cancelQuestTimers("end_song");
1462
+		cancelQuestTimers("timeNextSong");
1463
+	}
1464
+	
1465
+	private void taskCameraMorph(int state, Npc npc)
1466
+	{
1467
+		if (frintezza.isInvul())
1468
+			return;
1469
+		final double hpRatio = npc.getStatus().getHp() / npc.getStatus().getMaxHp();
1470
+		if (state == 1 && hpRatio < 0.75)
1471
+		{
1472
+			setPrepareRoom(true);
1473
+			startQuestTimer("first_morph_01", npc, null, 1100);
1474
+			startQuestTimer("first_morph_02", npc, null, 4100);
1475
+			startQuestTimer("first_morph_03", npc, null, 8100);
1476
+			startQuestTimer("start_room", npc, null, 11100);
1477
+			startQuestTimer("end_camera", frintezza, null, 14100);
1478
+		}
1479
+		else if (state == 2 && hpRatio < 0.5)
1480
+		{
1481
+			setPrepareRoom(true);
1482
+			startQuestTimer("second_morph_01", npc, null, 2000);
1483
+			startQuestTimer("second_morph_02", npc, null, 2100);
1484
+			startQuestTimer("second_morph_03", frintezza, null, 6300);
1485
+			startQuestTimer("second_morph_04", frintezza, null, 9300);
1486
+			startQuestTimer("second_morph_05", npc, null, 12300);
1487
+			startQuestTimer("second_morph_06", npc, null, 12800);
1488
+			startQuestTimer("second_morph_07", npc, null, 19050);
1489
+			startQuestTimer("second_morph_08", npc, null, 20000);
1490
+			startQuestTimer("second_morph_09", npc, null, 28100);
1491
+			startQuestTimer("start_room", npc, null, 34100);
1492
+			startQuestTimer("end_camera", frintezza, null, 37100);
1493
+		}
1494
+		if (state == 3 && npc.getNpcId() == SCARLET2)
1495
+		{
1496
+			setPrepareRoom(true);
1497
+			broadcastPacket(new SpecialCamera(npc.getObjectId(), 300, calcCameraAngle(npc) - 180, 5, 0, 7000, 0, 0, 1, 0), new SpecialCamera(npc.getObjectId(), 200, calcCameraAngle(npc), 85, 4000, 10000, 0, 0, 1, 0));
1498
+			startQuestTimer("die_01", frintezza, null, 7400);
1499
+			startQuestTimer("die_02", frintezza, null, 7500);
1500
+			startQuestTimer("die_03", frintezza, null, 14500);
1501
+			startQuestTimer("die_04", frintezza, null, 22500);
1502
+			startQuestTimer("start_room", frintezza, null, 21500);
1503
+		}
1504
+	}
1505
+	
1506
+	private static Creature getKnownInside()
1507
+	{
1508
+		for (Creature ch : FRINTEZZA_LAIR.getKnownTypeInside(Creature.class))
1509
+			if (ch instanceof Player)
1510
+				return ch;
1511
+		return null;
1512
+	}
1513
+}
1514
\ No newline at end of file
1515
diff --git aCis_game/java/net/sf/l2j/gameserver/scripting/script/teleport/GrandBossTeleporter.java aCis_game/java/net/sf/l2j/gameserver/scripting/script/teleport/GrandBossTeleporter.java
1516
index cee8e32..c6de41b 100644
1517
--- aCis_game/java/net/sf/l2j/gameserver/scripting/script/teleport/GrandBossTeleporter.java
1518
+++ aCis_game/java/net/sf/l2j/gameserver/scripting/script/teleport/GrandBossTeleporter.java
1519
@@ -12,11 +12,14 @@
1520
 import net.sf.l2j.gameserver.data.xml.ScriptData;
1521
 import net.sf.l2j.gameserver.model.actor.Npc;
1522
 import net.sf.l2j.gameserver.model.actor.Player;
1523
+import net.sf.l2j.gameserver.model.group.CommandChannel;
1524
+import net.sf.l2j.gameserver.model.group.Party;
1525
 import net.sf.l2j.gameserver.model.location.Location;
1526
 import net.sf.l2j.gameserver.model.zone.type.BossZone;
1527
 import net.sf.l2j.gameserver.scripting.Quest;
1528
 import net.sf.l2j.gameserver.scripting.script.ai.boss.Antharas;
1529
 import net.sf.l2j.gameserver.scripting.script.ai.boss.Baium;
1530
+import net.sf.l2j.gameserver.scripting.script.ai.boss.Frintezza;
1531
 import net.sf.l2j.gameserver.scripting.script.ai.boss.Sailren;
1532
 import net.sf.l2j.gameserver.scripting.script.ai.boss.Valakas;
1533
 
1534
@@ -47,6 +50,18 @@
1535
 		new Location(115488, 22096, -5168)
1536
 	};
1537
 	
1538
+	private static final Location[] FRINTEZZA_IN =
1539
+	{
1540
+		new Location(174102, -76039, -5105),
1541
+		new Location(173235, -76884, -5105),
1542
+		new Location(175003, -76933, -5105),
1543
+		new Location(174196, -76190, -5105),
1544
+		new Location(174013, -76120, -5105),
1545
+		new Location(173263, -75161, -5105)
1546
+		};
1547
+	
1548
+	private static final Location FRINTEZZA_OUT = new Location(150037, -57720, -2976);
1549
+	
1550
 	private static final Location SAILREN_IN = new Location(27333, -6835, -1970);
1551
 	private static final Location[] SAILREN_OUT =
1552
 	{
1553
@@ -62,7 +77,7 @@
1554
 		super(-1, "teleport");
1555
 		
1556
 		addFirstTalkId(29055, 31862);
1557
-		addTalkId(13001, 29055, 31859, 31384, 31385, 31540, 31686, 31687, 31759, 31862, 32107, 32109);
1558
+		addTalkId(13001, 29055, 31859, 31384, 31385, 31540, 31686, 31687, 31759, 31862, 32107, 32109, 32011, 29061);
1559
 	}
1560
 	
1561
 	@Override
1562
@@ -169,6 +184,10 @@
1563
 						htmltext = "13001-03.htm";
1564
 				}
1565
 				break;
1566
+				
1567
+			case 29061:
1568
+				player.teleportTo(FRINTEZZA_OUT.getX() + Rnd.get(500), FRINTEZZA_OUT.getY() + Rnd.get(500), FRINTEZZA_OUT.getZ(), 0);
1569
+				break;
1570
 			
1571
 			case 31859:
1572
 				player.teleportTo(79800 + Rnd.get(600), 151200 + Rnd.get(1100), -3534, 0);
1573
@@ -232,7 +251,88 @@
1574
 			case 31759:
1575
 				player.teleportTo(150037, -57720, -2976, 250);
1576
 				break;
1577
-			
1578
+				
1579
+			case 32011:
1580
+				status = GrandBossManager.getInstance().getBossStatus(Frintezza.FRINTEZZA);
1581
+				if (status == Frintezza.DORMANT)
1582
+				{
1583
+					final BossZone tomb = ZoneManager.getInstance().getZoneById(110012, BossZone.class);
1584
+					if (player.isGM())
1585
+					{
1586
+						ScriptData.getInstance().getQuest("Frintezza").startQuestTimer("enter", null, player, 1000);
1587
+						GrandBossManager.getInstance().setBossStatus(Frintezza.FRINTEZZA, Frintezza.WAITING);
1588
+						byte locCycle = 0;
1589
+						final List<Player> party = player.getParty().getMembers();
1590
+						if (player.getParty() != null)
1591
+						{
1592
+							for (Player member : party)
1593
+							{
1594
+								if (tomb != null)
1595
+								{
1596
+									tomb.allowPlayerEntry(member, 30);
1597
+									member.teleportTo(FRINTEZZA_IN[locCycle], 100);
1598
+								}
1599
+								locCycle++;
1600
+								if (locCycle >= 6)
1601
+									locCycle = 1;
1602
+							}
1603
+						}
1604
+						else 
1605
+							player.teleportTo(FRINTEZZA_IN[locCycle], 100);
1606
+						break;
1607
+					}
1608
+					if ((!player.isInParty() || !player.getParty().isLeader(player)) || (player.getParty().getCommandChannel() == null) || (player.getParty().getCommandChannel().getLeader() != player))
1609
+						htmltext = "32011-03.htm";
1610
+					else if (player.getParty().getCommandChannel().getParties().size() < 2 || player.getParty().getCommandChannel().getParties().size() > 5)
1611
+						htmltext = "32011-04.htm";
1612
+					else
1613
+					{
1614
+						if (!player.destroyItemByItemId("Quest", 8073, 1, player, true))
1615
+							return "32011-05.htm";
1616
+
1617
+						byte locCycle = 0;
1618
+						ScriptData.getInstance().getQuest("Frintezza").startQuestTimer("enter", null, player, 1000);
1619
+						GrandBossManager.getInstance().setBossStatus(Frintezza.FRINTEZZA, Frintezza.WAITING);
1620
+						
1621
+						if (player.getParty() != null)
1622
+						{
1623
+							CommandChannel CommandChannel = player.getParty().getCommandChannel();
1624
+							if (CommandChannel != null)
1625
+								for (Party party : CommandChannel.getParties())
1626
+								{
1627
+									if (party == null)
1628
+										continue;
1629
+									for (Player member : party.getMembers())
1630
+									{
1631
+										if (member == null || member.getStatus().getLevel() < 74 || !MathUtil.checkIfInRange(700, npc, member, true))
1632
+											continue;
1633
+										if (CommandChannel.getMembersCount() > 45)
1634
+										{
1635
+											member.sendMessage("The number of challenges have been full, so can not enter.");
1636
+											break;
1637
+										}
1638
+										
1639
+										if (tomb != null)
1640
+										{
1641
+											tomb.allowPlayerEntry(member, 30);
1642
+											member.teleportTo(FRINTEZZA_IN[locCycle], 100);
1643
+										}
1644
+										member.destroyItemByItemId(getName(), 8556, member.getInventory().getItemCount(8556, -1), null, true);
1645
+										member.destroyItemByItemId(getName(), 8192, member.getInventory().getItemCount(8192, -1), null, true);
1646
+									}
1647
+									locCycle++;
1648
+									if (locCycle >= 6)
1649
+										locCycle = 1;
1650
+								}
1651
+						}
1652
+					}
1653
+				}
1654
+				if (status == Frintezza.DEAD)
1655
+					htmltext = "32011-01.htm";
1656
+				else
1657
+					htmltext = "32011-02.htm";
1658
+				break;
1659
+				
1660
 			case 32107:
1661
 				player.teleportTo(Rnd.get(SAILREN_OUT), 100);
1662
 				break;
1663
diff --git aCis_game/java/net/sf/l2j/gameserver/skills/effects/EffectDanceStun.java aCis_game/java/net/sf/l2j/gameserver/skills/effects/EffectDanceStun.java
1664
new file mode 100644
1665
index 0000000..8a6a80a
1666
--- /dev/null
1667
+++ aCis_game/java/net/sf/l2j/gameserver/skills/effects/EffectDanceStun.java
1668
@@ -0,0 +1,74 @@
1669
+/*
1670
+ * This program is free software: you can redistribute it and/or modify it under
1671
+ * the terms of the GNU General Public License as published by the Free Software
1672
+ * Foundation, either version 3 of the License, or (at your option) any later
1673
+ * version.
1674
+ * 
1675
+ * This program is distributed in the hope that it will be useful, but WITHOUT
1676
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1677
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1678
+ * details.
1679
+ * 
1680
+ * You should have received a copy of the GNU General Public License along with
1681
+ * this program. If not, see <http://www.gnu.org/licenses/>.
1682
+ */
1683
+package net.sf.l2j.gameserver.skills.effects;
1684
+
1685
+import net.sf.l2j.gameserver.enums.skills.AbnormalEffect;
1686
+import net.sf.l2j.gameserver.enums.skills.EffectType;
1687
+import net.sf.l2j.gameserver.model.actor.Creature;
1688
+import net.sf.l2j.gameserver.skills.AbstractEffect;
1689
+import net.sf.l2j.gameserver.skills.L2Skill;
1690
+
1691
+/**
1692
+ * Copy from http://www.l2jserver.com/forum/viewtopic.php?f=69&t=13999
1693
+ * @author KKnD
1694
+ */
1695
+public class EffectDanceStun extends AbstractEffect
1696
+{
1697
+	public EffectDanceStun(EffectTemplate template, L2Skill skill, Creature effected, Creature effector)
1698
+	{
1699
+		super(template, skill, effected, effector);
1700
+	}
1701
+	
1702
+	@Override
1703
+	public EffectType getEffectType()
1704
+	{
1705
+		return EffectType.STUN;
1706
+	}
1707
+	
1708
+	/** Notify started */
1709
+	@Override
1710
+	public boolean onStart()
1711
+	{
1712
+		if (getEffected().isStunned() || getEffected().isImmobilized())
1713
+			return false;
1714
+		int e = getEffected().getAbnormalEffect();
1715
+		if ((e & AbnormalEffect.FLOATING_ROOT.getMask()) != 0 || (e & AbnormalEffect.DANCE_STUNNED.getMask()) != 0)
1716
+			return false;
1717
+
1718
+		// Abort attack, cast and move.
1719
+		getEffected().abortAll(false);
1720
+		
1721
+		getEffected().startAbnormalEffect(AbnormalEffect.DANCE_STUNNED);
1722
+		getEffected().setIsImmobilized(true);
1723
+		getEffected().disableAllSkills();
1724
+		return true;
1725
+	}
1726
+	
1727
+	/** Notify exited */
1728
+	@Override
1729
+	public void onExit()
1730
+	{
1731
+		getEffected().stopAbnormalEffect(AbnormalEffect.DANCE_STUNNED);
1732
+		getEffected().setIsImmobilized(false);
1733
+		getEffected().enableAllSkills();
1734
+	}
1735
+	
1736
+	@Override
1737
+	public boolean onActionTime()
1738
+	{
1739
+		// just stop this effect
1740
+		return false;
1741
+	}
1742
+}
1743
\ No newline at end of file
1744
diff --git aCis_game/java/net/sf/l2j/gameserver/skills/effects/EffectFloatStun.java aCis_game/java/net/sf/l2j/gameserver/skills/effects/EffectFloatStun.java
1745
new file mode 100644
1746
index 0000000..221b06e
1747
--- /dev/null
1748
+++ aCis_game/java/net/sf/l2j/gameserver/skills/effects/EffectFloatStun.java
1749
@@ -0,0 +1,59 @@
1750
+package net.sf.l2j.gameserver.skills.effects;
1751
+
1752
+import net.sf.l2j.gameserver.enums.skills.AbnormalEffect;
1753
+import net.sf.l2j.gameserver.enums.skills.EffectType;
1754
+import net.sf.l2j.gameserver.model.actor.Creature;
1755
+import net.sf.l2j.gameserver.skills.AbstractEffect;
1756
+import net.sf.l2j.gameserver.skills.L2Skill;
1757
+
1758
+/**
1759
+ * Copy from EffectDanceStun.java
1760
+ */
1761
+public class EffectFloatStun extends AbstractEffect
1762
+{
1763
+	public EffectFloatStun(EffectTemplate template, L2Skill skill, Creature effected, Creature effector)
1764
+	{
1765
+		super(template, skill, effected, effector);
1766
+	}
1767
+	
1768
+	@Override
1769
+	public EffectType getEffectType()
1770
+	{
1771
+		return EffectType.STUN;
1772
+	}
1773
+	
1774
+	@Override
1775
+	public boolean onStart()
1776
+	{
1777
+		if (getEffected().isStunned() || getEffected().isImmobilized())
1778
+			return false;
1779
+		int e = getEffected().getAbnormalEffect();
1780
+		if ((e & AbnormalEffect.FLOATING_ROOT.getMask()) != 0 || (e & AbnormalEffect.DANCE_STUNNED.getMask()) != 0)
1781
+			return false;
1782
+
1783
+		// Abort attack, cast and move.
1784
+		getEffected().abortAll(false);
1785
+		
1786
+		getEffected().getAI().tryToIdle();
1787
+		
1788
+		getEffected().startAbnormalEffect(AbnormalEffect.FLOATING_ROOT);
1789
+		getEffected().setIsImmobilized(true);
1790
+		getEffected().disableAllSkills();
1791
+		return true;
1792
+	}
1793
+	
1794
+	@Override
1795
+	public void onExit()
1796
+	{
1797
+		getEffected().stopAbnormalEffect(AbnormalEffect.FLOATING_ROOT);
1798
+		getEffected().setIsImmobilized(false);
1799
+		getEffected().enableAllSkills();
1800
+	}
1801
+	
1802
+	@Override
1803
+	public boolean onActionTime()
1804
+	{
1805
+		// just stop this effect
1806
+		return false;
1807
+	}
1808
+}
1809
\ No newline at end of file
1810