/*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*/
package silentium.scripts.ai;
import silentium.commons.utils.Rnd;
import silentium.gameserver.ai.CtrlIntention;
import silentium.gameserver.instancemanager.GrandBossManager;
import silentium.gameserver.model.L2CharPosition;
import silentium.gameserver.model.L2Object;
import silentium.gameserver.model.actor.L2Npc;
import silentium.gameserver.model.actor.instance.L2GrandBossInstance;
import silentium.gameserver.model.actor.instance.L2PcInstance;
import silentium.gameserver.model.quest.Quest;
import silentium.gameserver.network.serverpackets.PlaySound;
import silentium.gameserver.network.serverpackets.SocialAction;
import silentium.gameserver.network.serverpackets.SpecialCamera;
import silentium.gameserver.scripting.ScriptFile;
import silentium.gameserver.templates.StatsSet;
import silentium.gameserver.utils.Util;
import java.util.Collection;
/**
* Dr. Chaos is a boss @ Pavel's Ruins. Some things to know :
* <ul>
* <li>As a mad scientist, he thinks all are spies, and for so if you stand too much longer near him you're considered as an
* "assassin from Black Anvil Guild".</li>
* <li>You can chat with him, but if you try too much he will become angry.</li>
* <li>That adaptation sends a decent cinematic made with the different social actions too.</li>
* <li>The status of the RB is saved under GBs table, in order to retrieve the state if server restarts.</li>
* <li>The spawn of the different NPCs (Dr. Chaos / War golem) is handled by that script aswell.</li>
* </ul>
*
* @author Kerberos, Tryskell.
*/
public class DrChaos extends Quest implements ScriptFile {
private static final int DOCTOR_CHAOS = 32033;
private static final int CHAOS_GOLEM = 25512;
private long _lastAttackVsGolem = 0;
private int _pissedOffTimer;
// Dr. Chaos status tracking
private static final byte NORMAL = 0; // Dr. Chaos is in NPC form.
private static final byte CRAZY = 1; // Dr. Chaos entered on golem form.
private static final byte DEAD = 2; // Dr. Chaos has been killed and has not yet spawned.
public static void onLoad() {
new DrChaos(-1, "DrChaos", "DrChaos", "ai");
}
public DrChaos(final int scriptId, final String name, final String dname, final String path) {
super(scriptId, name, dname, path);
addFirstTalkId(DOCTOR_CHAOS); // Different HTMs following actual humor.
addSpawnId(DOCTOR_CHAOS); // Timer activation at 30sec + paranoia activity.
addKillId(CHAOS_GOLEM); // Message + despawn.
addAttackActId(CHAOS_GOLEM); // Random messages when he attacks.
final StatsSet info = GrandBossManager.getInstance().getStatsSet(CHAOS_GOLEM);
final int status = GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM);
// Load the reset date and time for Dr. Chaos from DB.
if (status == DEAD) {
final long temp = info.getLong("respawn_time") - System.currentTimeMillis();
if (temp > 0)
startQuestTimer("reset_drchaos", temp, null, null);
else {
// The time has already expired while the server was offline. Delete the saved time and
// immediately spawn Dr. Chaos. Also the state need to be changed for NORMAL
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0);
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, NORMAL);
}
}
// Spawn the war golem.
else if (status == CRAZY) {
final int loc_x = info.getInteger("loc_x");
final int loc_y = info.getInteger("loc_y");
final int loc_z = info.getInteger("loc_z");
final int heading = info.getInteger("heading");
final int hp = info.getInteger("currentHP");
final int mp = info.getInteger("currentMP");
final L2GrandBossInstance golem = (L2GrandBossInstance) addSpawn(CHAOS_GOLEM, loc_x, loc_y, loc_z, heading, false, 0);
GrandBossManager.getInstance().addBoss(golem);
final L2Npc _golem = golem;
_golem.setCurrentHpMp(hp, mp);
_golem.setRunning();
// start monitoring Dr. Chaos's inactivity
_lastAttackVsGolem = System.currentTimeMillis();
startQuestTimer("golem_despawn", 60000, _golem, null, true);
}
// Spawn the regular NPC.
else
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0);
}
@Override
public String onAdvEvent(final String event, L2Npc npc, final L2PcInstance player) {
if ("reset_drchaos".equalsIgnoreCase(event)) {
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, NORMAL);
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0);
}
// despawn the live Dr. Chaos after 30 minutes of inactivity
else if ("golem_despawn".equalsIgnoreCase(event) && npc != null) {
if (npc.getNpcId() == CHAOS_GOLEM) {
if (_lastAttackVsGolem + 1800000 < System.currentTimeMillis()) {
// Despawn the war golem.
npc.deleteMe();
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0); // spawn Dr. Chaos
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, NORMAL); // mark Dr. Chaos is not crazy any more
cancelQuestTimer("golem_despawn", npc, null);
}
}
} else if ("1".equalsIgnoreCase(event)) {
npc.broadcastPacket(new SocialAction(npc, 2));
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 1, -200, 15, 5500, 13500, 0, 0, 1, 0));
} else if ("2".equalsIgnoreCase(event))
npc.broadcastPacket(new SocialAction(npc, 3));
else if ("3".equalsIgnoreCase(event))
npc.broadcastPacket(new SocialAction(npc, 1));
else if ("4".equalsIgnoreCase(event)) {
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 1, -150, 10, 3500, 5000, 0, 0, 1, 0));
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(95928, -110671, -3340, 0));
} else if ("5".equalsIgnoreCase(event)) {
// Delete Dr. Chaos && spawn the war golem.
npc.deleteMe();
final L2GrandBossInstance golem = (L2GrandBossInstance) addSpawn(CHAOS_GOLEM, 96080, -110822, -3343, 0, false, 0);
GrandBossManager.getInstance().addBoss(golem);
// The "npc" variable attribution is now for the golem.
npc = golem;
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 30, 200, 20, 6000, 8000, 0, 0, 1, 0));
npc.broadcastPacket(new SocialAction(npc, 1));
npc.broadcastPacket(new PlaySound(1, "Rm03_A", 0, 0, 0, 0, 0));
// start monitoring Dr. Chaos's inactivity
_lastAttackVsGolem = System.currentTimeMillis();
startQuestTimer("golem_despawn", 60000, npc, null, true);
}
// Check every sec if someone is in range, if found, launch one task to decrease the timer.
else if ("paranoia_activity".equalsIgnoreCase(event)) {
if (GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM) == NORMAL) {
final Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
for (final L2Object obj : objs) {
if (obj instanceof L2PcInstance && Util.checkIfInShortRadius(500, npc, obj, true)) {
if (((L2PcInstance) obj).isDead())
continue;
_pissedOffTimer -= 1;
// Make him speak.
if (_pissedOffTimer == 15)
npc.broadcastNpcSay("How dare you trespass into my territory! Have you no fear?");
// That was "too much" for that time.
if (_pissedOffTimer <= 0)
crazyMidgetBecomesAngry(npc);
}
}
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onFirstTalk(final L2Npc npc, final L2PcInstance player) {
String htmltext = "";
if (GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM) == NORMAL) {
_pissedOffTimer -= 1 + Rnd.get(5); // remove 1-5 secs.
if (_pissedOffTimer > 20 && _pissedOffTimer <= 30)
htmltext = "<html><body>Doctor Chaos:<br>What?! Who are you? How did you come here?<br>You really look suspicious... Aren't those filthy members of Black Anvil guild send you? No? Mhhhhh... I don't trust you!</body></html>";
else if (_pissedOffTimer > 10 && _pissedOffTimer <= 20)
htmltext = "<html><body>Doctor Chaos:<br>Why are you standing here? Don't you see it's a private propertie? Don't look at him with those eyes... Did you smile?! Don't make fun of me! He will ... destroy ... you ... if you continue!</body></html>";
else if (_pissedOffTimer > 0 && _pissedOffTimer <= 10)
htmltext = "<html><body>Doctor Chaos:<br>I know why you are here, traitor! He discovered your plans! You are assassin ... sent by the Black Anvil guild! But you won't kill the Emperor of Evil!</body></html>";
else if (_pissedOffTimer <= 0) // That was "too much" for that time.
crazyMidgetBecomesAngry(npc);
}
return htmltext;
}
@Override
public String onSpawn(final L2Npc npc) {
// 30 seconds timer at initialization.
_pissedOffTimer = 30;
// Initialization of the paranoia.
startQuestTimer("paranoia_activity", 1000, npc, null, true);
return null;
}
@Override
public String onKill(final L2Npc npc, final L2PcInstance player, final boolean isPet) {
cancelQuestTimer("golem_despawn", npc, null);
npc.broadcastNpcSay("Urggh! You will pay dearly for this insult.");
// "lock" Dr. Chaos for regular RB time (12H fixed + 24H random)
final long respawnTime = 43200000 + Rnd.get(86400000);
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, DEAD);
startQuestTimer("reset_drchaos", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
final StatsSet info = GrandBossManager.getInstance().getStatsSet(CHAOS_GOLEM);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(CHAOS_GOLEM, info);
return null;
}
@Override
public String onAttackAct(final L2Npc npc, final L2PcInstance victim) {
final int chance = Rnd.get(300);
// Choose a message from 3 choices (1/100)
if (chance < 3) {
String message = "";
switch (chance) {
case 0:
message = "Bwah-ha-ha! Your doom is at hand! Behold the Ultra Secret Super Weapon!";
break;
case 1:
message = "Foolish, insignificant creatures! How dare you challenge me!";
break;
default:
message = "I see that none will challenge me now!";
break;
}
// Make him speak.
npc.broadcastNpcSay(message);
}
return null;
}
/**
* Launches the complete animation.
*
* @param npc the midget.
* @param player the victim.
*/
private void crazyMidgetBecomesAngry(final L2Npc npc) {
if (GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM) == NORMAL) {
// Set the status to "crazy".
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, CRAZY);
// Cancels the paranoia timer.
cancelQuestTimer("paranoia_activity", npc, null);
// Makes the NPC moves near the Strange Box speaking.
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(96323, -110914, -3328, 0));
npc.broadcastNpcSay("Fools! Why haven't you fled yet? Prepare to learn a lesson!");
// Delayed animation timers.
startQuestTimer("1", 2000, npc, null); // 2 secs, time to launch dr.C anim 2. Cam 1 on.
startQuestTimer("2", 4000, npc, null); // 2,5 secs, time to launch dr.C anim 3.
startQuestTimer("3", 6500, npc, null); // 6 secs, time to launch dr.C anim 1.
startQuestTimer("4", 12500, npc, null); // 4,5 secs to make the NPC moves to the grotto. Cam 2 on.
startQuestTimer("5", 17000, npc, null); // 4 secs for golem spawn, and golem anim. Cam 3 on.
}
}
}