Initial changes.

This commit is contained in:
MobiusDevelopment
2019-10-15 21:51:01 +00:00
parent 481a1a019c
commit c7712bbde0
3821 changed files with 2008450 additions and 137785 deletions

View File

@@ -0,0 +1,125 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.BeastFarm;
import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.ListenerRegisterType;
import org.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import org.l2jmobius.gameserver.model.events.annotations.RegisterType;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLogout;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.skills.SkillCaster;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import ai.AbstractNpcAI;
/**
* Baby Pets AI.
* @author St3eT
*/
public class BabyPets extends AbstractNpcAI
{
// NPCs
private static final int[] BABY_PETS =
{
12780, // Baby Buffalo
12781, // Baby Kookaburra
12782, // Baby Cougar
};
// Skills
private static final int HEAL_1 = 4717; // Heal Trick
private static final int HEAL_2 = 4718; // Greater Heal Trick
private BabyPets()
{
addSummonSpawnId(BABY_PETS);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (event.equals("HEAL") && (player != null))
{
final Summon summon = player.getPet();
if (summon != null)
{
if (getRandom(100) <= 25)
{
castHeal(summon, new SkillHolder(HEAL_1, getHealLv(summon)), 80);
}
if (getRandom(100) <= 75)
{
castHeal(summon, new SkillHolder(HEAL_2, getHealLv(summon)), 15);
}
}
else
{
cancelQuestTimer("HEAL", null, player);
}
}
return super.onAdvEvent(event, npc, player);
}
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
@RegisterType(ListenerRegisterType.GLOBAL)
public void OnPlayerLogout(OnPlayerLogout event)
{
cancelQuestTimer("HEAL", null, event.getPlayer());
}
@Override
public void onSummonSpawn(Summon summon)
{
startQuestTimer("HEAL", 5000, null, summon.getOwner(), true);
}
private int getHealLv(Summon summon)
{
final int summonLv = summon.getLevel();
return CommonUtil.constrain(summonLv < 70 ? (summonLv / 10) : (7 + ((summonLv - 70) / 5)), 1, 12);
}
private void castHeal(Summon summon, SkillHolder skill, int maxHpPer)
{
final boolean previousFollowStatus = summon.getFollowStatus();
final PlayerInstance owner = summon.getOwner();
if (!owner.isDead() && (((owner.getCurrentHp() / owner.getMaxHp()) * 100) < maxHpPer) && !summon.isHungry() && SkillCaster.checkUseConditions(summon, skill.getSkill()))
{
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill.getSkill(), owner);
summon.sendPacket(new SystemMessage(SystemMessageId.YOUR_PET_USES_S1).addSkillName(skill.getSkill()));
if (previousFollowStatus != summon.getFollowStatus())
{
summon.setFollowStatus(previousFollowStatus);
}
}
}
public static void main(String[] args)
{
new BabyPets();
}
}

View File

@@ -0,0 +1,488 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.BeastFarm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.SkillData;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.TamedBeastInstance;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.network.serverpackets.NpcInfo;
import ai.AbstractNpcAI;
/**
* Growth-capable mobs: Polymorphing upon successful feeding.<br>
* Updated to Freya.
* @author Fulminus, Gigiikun
*/
public class BeastFarm extends AbstractNpcAI
{
private static final int GOLDEN_SPICE = 15474;
private static final int CRYSTAL_SPICE = 15475;
private static final int SKILL_GOLDEN_SPICE = 9049;
private static final int SKILL_CRYSTAL_SPICE = 9050;
private static final int SKILL_BLESSED_GOLDEN_SPICE = 9051;
private static final int SKILL_BLESSED_CRYSTAL_SPICE = 9052;
private static final int SKILL_SGRADE_GOLDEN_SPICE = 9053;
private static final int SKILL_SGRADE_CRYSTAL_SPICE = 9054;
private static final int[] TAMED_BEASTS =
{
18869,
18870,
18871,
18872
};
private static final int TAME_CHANCE = 20;
protected static final int[] SPECIAL_SPICE_CHANCES =
{
33,
75
};
// all mobs that can eat...
private static final int[] FEEDABLE_BEASTS =
{
// Kookaburras
18873,
18874,
18875,
18876,
18877,
18878,
18879,
// Cougars
18880,
18881,
18882,
18883,
18884,
18885,
18886,
// Buffalos
18887,
18888,
18889,
18890,
18891,
18892,
18893,
// Grendels
18894,
18895,
18896,
18897,
18898,
18899,
18900
};
private static Map<Integer, GrowthCapableMob> GROWTH_CAPABLE_MOBS = new HashMap<>();
private static List<TamedBeast> TAMED_BEAST_DATA = new ArrayList<>();
private final Map<Integer, Integer> _feedInfo = new ConcurrentHashMap<>();
private BeastFarm()
{
addSkillSeeId(FEEDABLE_BEASTS);
addKillId(FEEDABLE_BEASTS);
GrowthCapableMob temp;
// Kookabura
temp = new GrowthCapableMob(100, 0, 18869);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18874);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18875);
temp.addNpcIdForSkillId(SKILL_BLESSED_GOLDEN_SPICE, 18869);
temp.addNpcIdForSkillId(SKILL_BLESSED_CRYSTAL_SPICE, 18869);
temp.addNpcIdForSkillId(SKILL_SGRADE_GOLDEN_SPICE, 18878);
temp.addNpcIdForSkillId(SKILL_SGRADE_CRYSTAL_SPICE, 18879);
GROWTH_CAPABLE_MOBS.put(18873, temp);
temp = new GrowthCapableMob(40, 1, 18869);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18876);
GROWTH_CAPABLE_MOBS.put(18874, temp);
temp = new GrowthCapableMob(40, 1, 18869);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18877);
GROWTH_CAPABLE_MOBS.put(18875, temp);
temp = new GrowthCapableMob(25, 2, 18869);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18878);
GROWTH_CAPABLE_MOBS.put(18876, temp);
temp = new GrowthCapableMob(25, 2, 18869);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18879);
GROWTH_CAPABLE_MOBS.put(18877, temp);
// Cougar
temp = new GrowthCapableMob(100, 0, 18870);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18881);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18882);
temp.addNpcIdForSkillId(SKILL_BLESSED_GOLDEN_SPICE, 18870);
temp.addNpcIdForSkillId(SKILL_BLESSED_CRYSTAL_SPICE, 18870);
temp.addNpcIdForSkillId(SKILL_SGRADE_GOLDEN_SPICE, 18885);
temp.addNpcIdForSkillId(SKILL_SGRADE_CRYSTAL_SPICE, 18886);
GROWTH_CAPABLE_MOBS.put(18880, temp);
temp = new GrowthCapableMob(40, 1, 18870);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18883);
GROWTH_CAPABLE_MOBS.put(18881, temp);
temp = new GrowthCapableMob(40, 1, 18870);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18884);
GROWTH_CAPABLE_MOBS.put(18882, temp);
temp = new GrowthCapableMob(25, 2, 18870);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18885);
GROWTH_CAPABLE_MOBS.put(18883, temp);
temp = new GrowthCapableMob(25, 2, 18870);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18886);
GROWTH_CAPABLE_MOBS.put(18884, temp);
// Buffalo
temp = new GrowthCapableMob(100, 0, 18871);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18888);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18889);
temp.addNpcIdForSkillId(SKILL_BLESSED_GOLDEN_SPICE, 18871);
temp.addNpcIdForSkillId(SKILL_BLESSED_CRYSTAL_SPICE, 18871);
temp.addNpcIdForSkillId(SKILL_SGRADE_GOLDEN_SPICE, 18892);
temp.addNpcIdForSkillId(SKILL_SGRADE_CRYSTAL_SPICE, 18893);
GROWTH_CAPABLE_MOBS.put(18887, temp);
temp = new GrowthCapableMob(40, 1, 18871);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18890);
GROWTH_CAPABLE_MOBS.put(18888, temp);
temp = new GrowthCapableMob(40, 1, 18871);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18891);
GROWTH_CAPABLE_MOBS.put(18889, temp);
temp = new GrowthCapableMob(25, 2, 18871);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18892);
GROWTH_CAPABLE_MOBS.put(18890, temp);
temp = new GrowthCapableMob(25, 2, 18871);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18893);
GROWTH_CAPABLE_MOBS.put(18891, temp);
// Grendel
temp = new GrowthCapableMob(100, 0, 18872);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18895);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18896);
temp.addNpcIdForSkillId(SKILL_BLESSED_GOLDEN_SPICE, 18872);
temp.addNpcIdForSkillId(SKILL_BLESSED_CRYSTAL_SPICE, 18872);
temp.addNpcIdForSkillId(SKILL_SGRADE_GOLDEN_SPICE, 18899);
temp.addNpcIdForSkillId(SKILL_SGRADE_CRYSTAL_SPICE, 18900);
GROWTH_CAPABLE_MOBS.put(18894, temp);
temp = new GrowthCapableMob(40, 1, 18872);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18897);
GROWTH_CAPABLE_MOBS.put(18895, temp);
temp = new GrowthCapableMob(40, 1, 18872);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18898);
GROWTH_CAPABLE_MOBS.put(18896, temp);
temp = new GrowthCapableMob(25, 2, 18872);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18899);
GROWTH_CAPABLE_MOBS.put(18897, temp);
temp = new GrowthCapableMob(25, 2, 18872);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18900);
GROWTH_CAPABLE_MOBS.put(18898, temp);
// Tamed beasts data
TAMED_BEAST_DATA.add(new TamedBeast("%name% of Focus", new SkillHolder(6432, 1), new SkillHolder(6668, 1)));
TAMED_BEAST_DATA.add(new TamedBeast("%name% of Guiding", new SkillHolder(6433, 1), new SkillHolder(6670, 1)));
TAMED_BEAST_DATA.add(new TamedBeast("%name% of Swifth", new SkillHolder(6434, 1), new SkillHolder(6667, 1)));
TAMED_BEAST_DATA.add(new TamedBeast("Berserker %name%", new SkillHolder(6671, 1)));
TAMED_BEAST_DATA.add(new TamedBeast("%name% of Protect", new SkillHolder(6669, 1), new SkillHolder(6672, 1)));
TAMED_BEAST_DATA.add(new TamedBeast("%name% of Vigor", new SkillHolder(6431, 1), new SkillHolder(6666, 1)));
}
public void spawnNext(Npc npc, PlayerInstance player, int nextNpcId, int food)
{
// remove the feedinfo of the mob that got despawned, if any
if (_feedInfo.containsKey(npc.getObjectId()))
{
if (_feedInfo.get(npc.getObjectId()) == player.getObjectId())
{
_feedInfo.remove(npc.getObjectId());
}
}
// despawn the old mob
// TODO: same code? FIXED?
/*
* if (_GrowthCapableMobs.get(npc.getNpcId()).getGrowthLevel() == 0) { npc.deleteMe(); } else {
*/
npc.deleteMe();
// }
// if this is finally a trained mob, then despawn any other trained mobs that the
// player might have and initialize the Tamed Beast.
if (CommonUtil.contains(TAMED_BEASTS, nextNpcId))
{
final TamedBeastInstance nextNpc = new TamedBeastInstance(nextNpcId, player, food, npc.getX(), npc.getY(), npc.getZ(), true);
final TamedBeast beast = TAMED_BEAST_DATA.get(getRandom(TAMED_BEAST_DATA.size()));
String name = beast.getName();
switch (nextNpcId)
{
case 18869:
{
name = name.replace("%name%", "Alpine Kookaburra");
break;
}
case 18870:
{
name = name.replace("%name%", "Alpine Cougar");
break;
}
case 18871:
{
name = name.replace("%name%", "Alpine Buffalo");
break;
}
case 18872:
{
name = name.replace("%name%", "Alpine Grendel");
break;
}
}
nextNpc.setName(name);
nextNpc.broadcastPacket(new NpcInfo(nextNpc));
nextNpc.setRunning();
final SkillData st = SkillData.getInstance();
for (SkillHolder sh : beast.getSkills())
{
nextNpc.addBeastSkill(st.getSkill(sh.getSkillId(), sh.getSkillLevel()));
}
// TODO: Q00020_BringUpWithLove.checkJewelOfInnocence(player);
}
else
{
// if not trained, the newly spawned mob will automatically be agro against its feeder
// (what happened to "never bite the hand that feeds you" anyway?!)
final Attackable nextNpc = (Attackable) addSpawn(nextNpcId, npc);
// register the player in the feedinfo for the mob that just spawned
_feedInfo.put(nextNpc.getObjectId(), player.getObjectId());
nextNpc.setRunning();
nextNpc.addDamageHate(player, 0, 99999);
nextNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player);
player.setTarget(nextNpc);
}
}
@Override
public String onSkillSee(Npc npc, PlayerInstance caster, Skill skill, WorldObject[] targets, boolean isSummon)
{
// this behavior is only run when the target of skill is the passed npc (chest)
// i.e. when the player is attempting to open the chest using a skill
if (!CommonUtil.contains(targets, npc))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// gather some values on local variables
final int npcId = npc.getId();
final int skillId = skill.getId();
// check if the npc and skills used are valid for this script. Exit if invalid.
if (!CommonUtil.contains(FEEDABLE_BEASTS, npcId) || ((skillId != SKILL_GOLDEN_SPICE) && (skillId != SKILL_CRYSTAL_SPICE) && (skillId != SKILL_BLESSED_GOLDEN_SPICE) && (skillId != SKILL_BLESSED_CRYSTAL_SPICE) && (skillId != SKILL_SGRADE_GOLDEN_SPICE) && (skillId != SKILL_SGRADE_CRYSTAL_SPICE)))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// first gather some values on local variables
final int objectId = npc.getObjectId();
int growthLevel = 3; // if a mob is in FEEDABLE_BEASTS but not in _GrowthCapableMobs, then it's at max growth (3)
if (GROWTH_CAPABLE_MOBS.containsKey(npcId))
{
growthLevel = GROWTH_CAPABLE_MOBS.get(npcId).getGrowthLevel();
}
// prevent exploit which allows 2 players to simultaneously raise the same 0-growth beast
// If the mob is at 0th level (when it still listens to all feeders) lock it to the first feeder!
if ((growthLevel == 0) && _feedInfo.containsKey(objectId))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
_feedInfo.put(objectId, caster.getObjectId());
// display the social action of the beast eating the food.
npc.broadcastSocialAction(2);
int food = 0;
if ((skillId == SKILL_GOLDEN_SPICE) || (skillId == SKILL_BLESSED_GOLDEN_SPICE))
{
food = GOLDEN_SPICE;
}
else if ((skillId == SKILL_CRYSTAL_SPICE) || (skillId == SKILL_BLESSED_CRYSTAL_SPICE))
{
food = CRYSTAL_SPICE;
}
// if this pet can't grow, it's all done.
if (GROWTH_CAPABLE_MOBS.containsKey(npcId))
{
// do nothing if this mob doesn't eat the specified food (food gets consumed but has no effect).
final int newNpcId = GROWTH_CAPABLE_MOBS.get(npcId).getLeveledNpcId(skillId);
if (newNpcId == -1)
{
if (growthLevel == 0)
{
_feedInfo.remove(objectId);
npc.setRunning();
((Attackable) npc).addDamageHate(caster, 0, 1);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, caster);
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
else if ((growthLevel > 0) && (_feedInfo.get(objectId) != caster.getObjectId()))
{
// check if this is the same player as the one who raised it from growth 0.
// if no, then do not allow a chance to raise the pet (food gets consumed but has no effect).
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
spawnNext(npc, caster, newNpcId, food);
}
else
{
caster.sendMessage("The beast spit out the feed instead of eating it.");
npc.dropItem(caster, food, 1);
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onKill(Npc npc, PlayerInstance killer, boolean isSummon)
{
// remove the feedinfo of the mob that got killed, if any
if (_feedInfo.containsKey(npc.getObjectId()))
{
_feedInfo.remove(npc.getObjectId());
}
return super.onKill(npc, killer, isSummon);
}
// all mobs that grow by eating
private static class GrowthCapableMob
{
private final int _chance;
private final int _growthLevel;
private final int _tameNpcId;
private final Map<Integer, Integer> _skillSuccessNpcIdList = new ConcurrentHashMap<>();
public GrowthCapableMob(int chance, int growthLevel, int tameNpcId)
{
_chance = chance;
_growthLevel = growthLevel;
_tameNpcId = tameNpcId;
}
public void addNpcIdForSkillId(int skillId, int npcId)
{
_skillSuccessNpcIdList.put(skillId, npcId);
}
public int getGrowthLevel()
{
return _growthLevel;
}
public int getLeveledNpcId(int skillId)
{
if (!_skillSuccessNpcIdList.containsKey(skillId))
{
return -1;
}
else if ((skillId == SKILL_BLESSED_GOLDEN_SPICE) || (skillId == SKILL_BLESSED_CRYSTAL_SPICE) || (skillId == SKILL_SGRADE_GOLDEN_SPICE) || (skillId == SKILL_SGRADE_CRYSTAL_SPICE))
{
if (getRandom(100) < SPECIAL_SPICE_CHANCES[0])
{
if (getRandom(100) < SPECIAL_SPICE_CHANCES[1])
{
return _skillSuccessNpcIdList.get(skillId);
}
else if ((skillId == SKILL_BLESSED_GOLDEN_SPICE) || (skillId == SKILL_SGRADE_GOLDEN_SPICE))
{
return _skillSuccessNpcIdList.get(SKILL_GOLDEN_SPICE);
}
else
{
return _skillSuccessNpcIdList.get(SKILL_CRYSTAL_SPICE);
}
}
return -1;
}
else if ((_growthLevel == 2) && (getRandom(100) < TAME_CHANCE))
{
return _tameNpcId;
}
else if (getRandom(100) < _chance)
{
return _skillSuccessNpcIdList.get(skillId);
}
else
{
return -1;
}
}
}
private static class TamedBeast
{
private final String name;
private final SkillHolder[] sh;
public TamedBeast(String beastName, SkillHolder... holders)
{
name = beastName;
sh = holders;
}
public String getName()
{
return name;
}
public SkillHolder[] getSkills()
{
return sh;
}
}
public static void main(String[] args)
{
new BeastFarm();
}
}

View File

@@ -0,0 +1,600 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.BeastFarm;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.TamedBeastInstance;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.network.NpcStringId;
import ai.AbstractNpcAI;
/**
* Growth-capable mobs: Polymorphing upon successful feeding.
* @author Fulminus
*/
public class FeedableBeasts extends AbstractNpcAI
{
private static final int GOLDEN_SPICE = 6643;
private static final int CRYSTAL_SPICE = 6644;
private static final int SKILL_GOLDEN_SPICE = 2188;
private static final int SKILL_CRYSTAL_SPICE = 2189;
private static final int FOODSKILLDIFF = GOLDEN_SPICE - SKILL_GOLDEN_SPICE;
// Tamed Wild Beasts
private static final int TRAINED_BUFFALO1 = 16013;
private static final int TRAINED_BUFFALO2 = 16014;
private static final int TRAINED_COUGAR1 = 16015;
private static final int TRAINED_COUGAR2 = 16016;
private static final int TRAINED_KOOKABURRA1 = 16017;
private static final int TRAINED_KOOKABURRA2 = 16018;
// private static final int TRAINED_TINY_BABY_BUFFALO = 16020; // TODO: Implement.
// private static final int TRAINED_TINY_BABY_COUGAR = 16022; // TODO: Implement.
// private static final int TRAINED_TINY_BABY_KOOKABURRA = 16024; // TODO: Implement.
// @formatter:off
private static final int[] TAMED_BEASTS =
{
TRAINED_BUFFALO1, TRAINED_BUFFALO2, TRAINED_COUGAR1, TRAINED_COUGAR2, TRAINED_KOOKABURRA1, TRAINED_KOOKABURRA2
};
// all mobs that can eat...
private static final int[] FEEDABLE_BEASTS =
{
TRAINED_BUFFALO1, TRAINED_BUFFALO2, TRAINED_COUGAR1, TRAINED_COUGAR2, TRAINED_KOOKABURRA1, TRAINED_KOOKABURRA2
};
// @formatter:on
private static final Map<Integer, Integer> MAD_COW_POLYMORPH = new HashMap<>(6);
static
{
MAD_COW_POLYMORPH.put(21824, 21468);
MAD_COW_POLYMORPH.put(21825, 21469);
MAD_COW_POLYMORPH.put(21826, 21487);
MAD_COW_POLYMORPH.put(21827, 21488);
MAD_COW_POLYMORPH.put(21828, 21506);
MAD_COW_POLYMORPH.put(21829, 21507);
}
private static final NpcStringId[][] TEXT =
{
{
NpcStringId.WHAT_DID_YOU_JUST_DO_TO_ME,
NpcStringId.ARE_YOU_TRYING_TO_TAME_ME_DON_T_DO_THAT,
NpcStringId.DON_T_GIVE_SUCH_A_THING_YOU_CAN_ENDANGER_YOURSELF,
NpcStringId.YUCK_WHAT_IS_THIS_IT_TASTES_TERRIBLE,
NpcStringId.I_M_HUNGRY_GIVE_ME_A_LITTLE_MORE_PLEASE,
NpcStringId.WHAT_IS_THIS_IS_THIS_EDIBLE,
NpcStringId.DON_T_WORRY_ABOUT_ME,
NpcStringId.THANK_YOU_THAT_WAS_DELICIOUS,
NpcStringId.I_THINK_I_AM_STARTING_TO_LIKE_YOU,
NpcStringId.EEEEEK_EEEEEK
},
{
NpcStringId.DON_T_KEEP_TRYING_TO_TAME_ME_I_DON_T_WANT_TO_BE_TAMED,
NpcStringId.IT_IS_JUST_FOOD_TO_ME_ALTHOUGH_IT_MAY_ALSO_BE_YOUR_HAND,
NpcStringId.IF_I_KEEP_EATING_LIKE_THIS_WON_T_I_BECOME_FAT_CHOMP_CHOMP,
NpcStringId.WHY_DO_YOU_KEEP_FEEDING_ME,
NpcStringId.DON_T_TRUST_ME_I_M_AFRAID_I_MAY_BETRAY_YOU_LATER
},
{
NpcStringId.GRRRRR,
NpcStringId.YOU_BROUGHT_THIS_UPON_YOURSELF,
NpcStringId.I_FEEL_STRANGE_I_KEEP_HAVING_THESE_EVIL_THOUGHTS,
NpcStringId.ALAS_SO_THIS_IS_HOW_IT_ALL_ENDS,
NpcStringId.I_DON_T_FEEL_SO_GOOD_OH_MY_MIND_IS_VERY_TROUBLED
}
};
private static final NpcStringId[] TAMED_TEXT =
{
NpcStringId.S1_SO_WHAT_DO_YOU_THINK_IT_IS_LIKE_TO_BE_TAMED,
NpcStringId.S1_WHENEVER_I_SEE_SPICE_I_THINK_I_WILL_MISS_YOUR_HAND_THAT_USED_TO_FEED_IT_TO_ME,
NpcStringId.S1_DON_T_GO_TO_THE_VILLAGE_I_DON_T_HAVE_THE_STRENGTH_TO_FOLLOW_YOU,
NpcStringId.THANK_YOU_FOR_TRUSTING_ME_S1_I_HOPE_I_WILL_BE_HELPFUL_TO_YOU,
NpcStringId.S1_WILL_I_BE_ABLE_TO_HELP_YOU,
NpcStringId.I_GUESS_IT_S_JUST_MY_ANIMAL_MAGNETISM,
NpcStringId.TOO_MUCH_SPICY_FOOD_MAKES_ME_SWEAT_LIKE_A_BEAST,
NpcStringId.ANIMALS_NEED_LOVE_TOO
};
private final Map<Integer, Integer> _feedInfo = new ConcurrentHashMap<>();
private static Map<Integer, GrowthCapableMob> GROWTH_CAPABLE_MOBS = new HashMap<>();
// all mobs that grow by eating
private static class GrowthCapableMob
{
private final int _growthLevel;
private final int _chance;
private final Map<Integer, int[][]> _spiceToMob = new ConcurrentHashMap<>();
public GrowthCapableMob(int growthLevel, int chance)
{
_growthLevel = growthLevel;
_chance = chance;
}
public void addMobs(int spice, int[][] Mobs)
{
_spiceToMob.put(spice, Mobs);
}
public Integer getMob(int spice, int mobType, int classType)
{
if (_spiceToMob.containsKey(spice))
{
return _spiceToMob.get(spice)[mobType][classType];
}
return null;
}
public Integer getRandomMob(int spice)
{
int[][] temp;
temp = _spiceToMob.get(spice);
final int rand = getRandom(temp[0].length);
return temp[0][rand];
}
public Integer getChance()
{
return _chance;
}
public Integer getGrowthLevel()
{
return _growthLevel;
}
}
private FeedableBeasts()
{
addKillId(FEEDABLE_BEASTS);
addSkillSeeId(FEEDABLE_BEASTS);
// TODO: no grendels?
GrowthCapableMob temp;
//@formatter:off
final int[][] Kookabura_0_Gold = {{ 21452, 21453, 21454, 21455 }};
final int[][] Kookabura_0_Crystal = {{ 21456, 21457, 21458, 21459 }};
final int[][] Kookabura_1_Gold_1= {{ 21460, 21462 }};
final int[][] Kookabura_1_Gold_2 = {{ 21461, 21463 }};
final int[][] Kookabura_1_Crystal_1 = {{ 21464, 21466 }};
final int[][] Kookabura_1_Crystal_2 = {{ 21465, 21467 }};
final int[][] Kookabura_2_1 = {{ 21468, 21824}, { TRAINED_KOOKABURRA1, TRAINED_KOOKABURRA2 }};
final int[][] Kookabura_2_2 = {{ 21469, 21825}, { TRAINED_KOOKABURRA1, TRAINED_KOOKABURRA2 }};
final int[][] Buffalo_0_Gold = {{ 21471, 21472, 21473, 21474 }};
final int[][] Buffalo_0_Crystal = {{ 21475, 21476, 21477, 21478 }};
final int[][] Buffalo_1_Gold_1 = {{ 21479, 21481 }};
final int[][] Buffalo_1_Gold_2 = {{ 21481, 21482 }};
final int[][] Buffalo_1_Crystal_1 = {{ 21483, 21485 }};
final int[][] Buffalo_1_Crystal_2 = {{ 21484, 21486 }};
final int[][] Buffalo_2_1 = {{ 21487, 21826}, {TRAINED_BUFFALO1, TRAINED_BUFFALO2 }};
final int[][] Buffalo_2_2 = {{ 21488, 21827}, {TRAINED_BUFFALO1, TRAINED_BUFFALO2 }};
final int[][] Cougar_0_Gold = {{ 21490, 21491, 21492, 21493 }};
final int[][] Cougar_0_Crystal = {{ 21494, 21495, 21496, 21497 }};
final int[][] Cougar_1_Gold_1 = {{ 21498, 21500 }};
final int[][] Cougar_1_Gold_2 = {{ 21499, 21501 }};
final int[][] Cougar_1_Crystal_1 = {{ 21502, 21504 }};
final int[][] Cougar_1_Crystal_2 = {{ 21503, 21505 }};
final int[][] Cougar_2_1 = {{ 21506, 21828 }, { TRAINED_COUGAR1, TRAINED_COUGAR2 }};
final int[][] Cougar_2_2 = {{ 21507, 21829 }, { TRAINED_COUGAR1, TRAINED_COUGAR2 }};
//@formatter:on
// Alpen Kookabura
temp = new GrowthCapableMob(0, 100);
temp.addMobs(GOLDEN_SPICE, Kookabura_0_Gold);
temp.addMobs(CRYSTAL_SPICE, Kookabura_0_Crystal);
GROWTH_CAPABLE_MOBS.put(21451, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Kookabura_1_Gold_1);
GROWTH_CAPABLE_MOBS.put(21452, temp);
GROWTH_CAPABLE_MOBS.put(21454, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Kookabura_1_Gold_2);
GROWTH_CAPABLE_MOBS.put(21453, temp);
GROWTH_CAPABLE_MOBS.put(21455, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Kookabura_1_Crystal_1);
GROWTH_CAPABLE_MOBS.put(21456, temp);
GROWTH_CAPABLE_MOBS.put(21458, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Kookabura_1_Crystal_2);
GROWTH_CAPABLE_MOBS.put(21457, temp);
GROWTH_CAPABLE_MOBS.put(21459, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Kookabura_2_1);
GROWTH_CAPABLE_MOBS.put(21460, temp);
GROWTH_CAPABLE_MOBS.put(21462, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Kookabura_2_2);
GROWTH_CAPABLE_MOBS.put(21461, temp);
GROWTH_CAPABLE_MOBS.put(21463, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Kookabura_2_1);
GROWTH_CAPABLE_MOBS.put(21464, temp);
GROWTH_CAPABLE_MOBS.put(21466, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Kookabura_2_2);
GROWTH_CAPABLE_MOBS.put(21465, temp);
GROWTH_CAPABLE_MOBS.put(21467, temp);
// Alpen Buffalo
temp = new GrowthCapableMob(0, 100);
temp.addMobs(GOLDEN_SPICE, Buffalo_0_Gold);
temp.addMobs(CRYSTAL_SPICE, Buffalo_0_Crystal);
GROWTH_CAPABLE_MOBS.put(21470, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Buffalo_1_Gold_1);
GROWTH_CAPABLE_MOBS.put(21471, temp);
GROWTH_CAPABLE_MOBS.put(21473, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Buffalo_1_Gold_2);
GROWTH_CAPABLE_MOBS.put(21472, temp);
GROWTH_CAPABLE_MOBS.put(21474, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Buffalo_1_Crystal_1);
GROWTH_CAPABLE_MOBS.put(21475, temp);
GROWTH_CAPABLE_MOBS.put(21477, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Buffalo_1_Crystal_2);
GROWTH_CAPABLE_MOBS.put(21476, temp);
GROWTH_CAPABLE_MOBS.put(21478, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Buffalo_2_1);
GROWTH_CAPABLE_MOBS.put(21479, temp);
GROWTH_CAPABLE_MOBS.put(21481, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Buffalo_2_2);
GROWTH_CAPABLE_MOBS.put(21480, temp);
GROWTH_CAPABLE_MOBS.put(21482, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Buffalo_2_1);
GROWTH_CAPABLE_MOBS.put(21483, temp);
GROWTH_CAPABLE_MOBS.put(21485, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Buffalo_2_2);
GROWTH_CAPABLE_MOBS.put(21484, temp);
GROWTH_CAPABLE_MOBS.put(21486, temp);
// Alpen Cougar
temp = new GrowthCapableMob(0, 100);
temp.addMobs(GOLDEN_SPICE, Cougar_0_Gold);
temp.addMobs(CRYSTAL_SPICE, Cougar_0_Crystal);
GROWTH_CAPABLE_MOBS.put(21489, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Cougar_1_Gold_1);
GROWTH_CAPABLE_MOBS.put(21490, temp);
GROWTH_CAPABLE_MOBS.put(21492, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Cougar_1_Gold_2);
GROWTH_CAPABLE_MOBS.put(21491, temp);
GROWTH_CAPABLE_MOBS.put(21493, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Cougar_1_Crystal_1);
GROWTH_CAPABLE_MOBS.put(21494, temp);
GROWTH_CAPABLE_MOBS.put(21496, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Cougar_1_Crystal_2);
GROWTH_CAPABLE_MOBS.put(21495, temp);
GROWTH_CAPABLE_MOBS.put(21497, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Cougar_2_1);
GROWTH_CAPABLE_MOBS.put(21498, temp);
GROWTH_CAPABLE_MOBS.put(21500, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Cougar_2_2);
GROWTH_CAPABLE_MOBS.put(21499, temp);
GROWTH_CAPABLE_MOBS.put(21501, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Cougar_2_1);
GROWTH_CAPABLE_MOBS.put(21502, temp);
GROWTH_CAPABLE_MOBS.put(21504, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Cougar_2_2);
GROWTH_CAPABLE_MOBS.put(21503, temp);
GROWTH_CAPABLE_MOBS.put(21505, temp);
}
private void spawnNext(Npc npc, int growthLevel, PlayerInstance player, int food)
{
final int npcId = npc.getId();
int nextNpcId = 0;
// find the next mob to spawn, based on the current npcId, growthlevel, and food.
if (growthLevel == 2)
{
// if tamed, the mob that will spawn depends on the class type (fighter/mage) of the player!
if (getRandom(2) == 0)
{
if (player.getClassId().isMage())
{
nextNpcId = GROWTH_CAPABLE_MOBS.get(npcId).getMob(food, 1, 1);
}
else
{
nextNpcId = GROWTH_CAPABLE_MOBS.get(npcId).getMob(food, 1, 0);
}
}
else
{
// if not tamed, there is a small chance that have "mad cow" disease.
// that is a stronger-than-normal animal that attacks its feeder
if (getRandom(5) == 0)
{
nextNpcId = GROWTH_CAPABLE_MOBS.get(npcId).getMob(food, 0, 1);
}
else
{
nextNpcId = GROWTH_CAPABLE_MOBS.get(npcId).getMob(food, 0, 0);
}
}
}
else
{
// all other levels of growth are straight-forward
nextNpcId = GROWTH_CAPABLE_MOBS.get(npcId).getRandomMob(food);
}
// remove the feedinfo of the mob that got despawned, if any
if (_feedInfo.containsKey(npc.getObjectId()))
{
if (_feedInfo.get(npc.getObjectId()) == player.getObjectId())
{
_feedInfo.remove(npc.getObjectId());
}
}
// despawn the old mob
// TODO: same code? FIXED?
// @formatter:off
/*
* if (_GrowthCapableMobs.get(npcId).getGrowthLevel() == 0)
{
npc.deleteMe();
}
else
{
*/
npc.deleteMe();
// }
// @formatter:on
// if this is finally a trained mob, then despawn any other trained mobs that the
// player might have and initialize the Tamed Beast.
if (CommonUtil.contains(TAMED_BEASTS, nextNpcId))
{
for (TamedBeastInstance oldTrained : player.getTrainedBeasts())
{
oldTrained.deleteMe();
}
final TamedBeastInstance nextNpc = new TamedBeastInstance(nextNpcId, player, food - FOODSKILLDIFF, npc.getX(), npc.getY(), npc.getZ());
nextNpc.setRunning();
// TODO: Q00020_BringUpWithLove.checkJewelOfInnocence(player);
// Support for A Grand Plan for Taming Wild Beasts (655) quest.
// Q00655_AGrandPlanForTamingWildBeasts.reward(player, nextNpc); TODO: Replace me?
// also, perform a rare random chat
if (getRandom(20) == 0)
{
final NpcStringId message = NpcStringId.getNpcStringId(getRandom(2024, 2029));
npc.broadcastSay(ChatType.NPC_GENERAL, message, message.getParamCount() > 0 ? player.getName() : null);
}
// @formatter:off
/*
TODO: The tamed beast consumes one golden/crystal spice
every 60 seconds with an initial delay of 60 seconds
if (tamed beast exists and is alive)
{
if (player has 1+ golden/crystal spice)
{
take one golden/crystal spice;
say random NpcString(getRandom(2029, 2038));
}
}
*/
// @formatter:on
}
else
{
// if not trained, the newly spawned mob will automatically be aggro against its feeder
// (what happened to "never bite the hand that feeds you" anyway?!)
final Attackable nextNpc = (Attackable) addSpawn(nextNpcId, npc);
if (MAD_COW_POLYMORPH.containsKey(nextNpcId))
{
startQuestTimer("polymorph Mad Cow", 10000, nextNpc, player);
}
// register the player in the feedinfo for the mob that just spawned
_feedInfo.put(nextNpc.getObjectId(), player.getObjectId());
nextNpc.setRunning();
nextNpc.addDamageHate(player, 0, 99999);
nextNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player);
}
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (event.equalsIgnoreCase("polymorph Mad Cow") && (npc != null) && (player != null))
{
if (MAD_COW_POLYMORPH.containsKey(npc.getId()))
{
// remove the feed info from the previous mob
if (_feedInfo.get(npc.getObjectId()) == player.getObjectId())
{
_feedInfo.remove(npc.getObjectId());
}
// despawn the mad cow
npc.deleteMe();
// spawn the new mob
final Attackable nextNpc = (Attackable) addSpawn(MAD_COW_POLYMORPH.get(npc.getId()), npc);
// register the player in the feedinfo for the mob that just spawned
_feedInfo.put(nextNpc.getObjectId(), player.getObjectId());
nextNpc.setRunning();
nextNpc.addDamageHate(player, 0, 99999);
nextNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player);
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSkillSee(Npc npc, PlayerInstance caster, Skill skill, WorldObject[] targets, boolean isSummon)
{
// this behavior is only run when the target of skill is the passed npc (chest)
// i.e. when the player is attempting to open the chest using a skill
if (!CommonUtil.contains(targets, npc))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// gather some values on local variables
final int npcId = npc.getId();
final int skillId = skill.getId();
// check if the npc and skills used are valid for this script. Exit if invalid.
if ((skillId != SKILL_GOLDEN_SPICE) && (skillId != SKILL_CRYSTAL_SPICE))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// first gather some values on local variables
final int objectId = npc.getObjectId();
int growthLevel = 3; // if a mob is in FEEDABLE_BEASTS but not in _GrowthCapableMobs, then it's at max growth (3)
if (GROWTH_CAPABLE_MOBS.containsKey(npcId))
{
growthLevel = GROWTH_CAPABLE_MOBS.get(npcId).getGrowthLevel();
}
// prevent exploit which allows 2 players to simultaneously raise the same 0-growth beast
// If the mob is at 0th level (when it still listens to all feeders) lock it to the first feeder!
if ((growthLevel == 0) && _feedInfo.containsKey(objectId))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
_feedInfo.put(objectId, caster.getObjectId());
int food = 0;
if (skillId == SKILL_GOLDEN_SPICE)
{
food = GOLDEN_SPICE;
}
else if (skillId == SKILL_CRYSTAL_SPICE)
{
food = CRYSTAL_SPICE;
}
// display the social action of the beast eating the food.
npc.broadcastSocialAction(2);
// if this pet can't grow, it's all done.
if (GROWTH_CAPABLE_MOBS.containsKey(npcId))
{
// do nothing if this mob doesn't eat the specified food (food gets consumed but has no effect).
if (GROWTH_CAPABLE_MOBS.get(npcId).getMob(food, 0, 0) == null)
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// rare random talk...
if (getRandom(20) == 0)
{
final NpcStringId message = TEXT[growthLevel][getRandom(TEXT[growthLevel].length)];
npc.broadcastSay(ChatType.NPC_GENERAL, message, message.getParamCount() > 0 ? caster.getName() : null);
}
if ((growthLevel > 0) && (_feedInfo.get(objectId) != caster.getObjectId()))
{
// check if this is the same player as the one who raised it from growth 0.
// if no, then do not allow a chance to raise the pet (food gets consumed but has no effect).
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// Polymorph the mob, with a certain chance, given its current growth level
if (getRandom(100) < GROWTH_CAPABLE_MOBS.get(npcId).getChance())
{
spawnNext(npc, growthLevel, caster, food);
}
}
else if (CommonUtil.contains(TAMED_BEASTS, npcId) && (npc instanceof TamedBeastInstance))
{
final TamedBeastInstance beast = ((TamedBeastInstance) npc);
if (skillId == beast.getFoodType())
{
beast.onReceiveFood();
final NpcStringId message = TAMED_TEXT[getRandom(TAMED_TEXT.length)];
npc.broadcastSay(ChatType.NPC_GENERAL, message, message.getParamCount() > 0 ? caster.getName() : null);
}
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onKill(Npc npc, PlayerInstance killer, boolean isSummon)
{
// remove the feedinfo of the mob that got killed, if any
if (_feedInfo.containsKey(npc.getObjectId()))
{
_feedInfo.remove(npc.getObjectId());
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new FeedableBeasts();
}
}

View File

@@ -0,0 +1,211 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.BeastFarm;
import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.model.StatsSet;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.ListenerRegisterType;
import org.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import org.l2jmobius.gameserver.model.events.annotations.RegisterType;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLogout;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.skills.SkillCaster;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import ai.AbstractNpcAI;
/**
* Improved Baby Pets AI.
* @author St3eT
*/
public class ImprovedBabyPets extends AbstractNpcAI
{
// NPCs
private static final int[] BABY_PETS =
{
16034, // Improved Baby Buffalo
16035, // Improved Baby Kookaburra
16036, // Improved Baby Cougar
};
// Skills
private static final int PET_CONTROL = 5771;
private ImprovedBabyPets()
{
addSummonSpawnId(BABY_PETS);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (player != null)
{
final Summon summon = player.getPet();
if (summon == null)
{
cancelQuestTimer("HEAL", null, player);
cancelQuestTimer("BUFF", null, player);
}
else if (event.equals("HEAL") && player.isInCombat() && !summon.isHungry())
{
final double hpPer = (player.getCurrentHp() / player.getMaxHp()) * 100;
final double mpPer = (player.getCurrentMp() / player.getMaxMp()) * 100;
final int healType = summon.getTemplate().getParameters().getInt("heal_type", 0);
final int skillLv = (int) Math.floor((summon.getLevel() / 5) - 11);
if (healType == 1)
{
final int stepLv = CommonUtil.constrain(skillLv, 0, 3);
if ((hpPer >= 30) && (hpPer < 70))
{
castHeal(summon, stepLv, 1);
}
else if (hpPer < 30)
{
castHeal(summon, stepLv, 2);
}
}
else if (healType == 0)
{
if (hpPer < 30)
{
castHeal(summon, CommonUtil.constrain(skillLv, 0, 3), 2);
}
else if (mpPer < 60)
{
castHeal(summon, CommonUtil.constrain(skillLv, 0, 5), 1);
}
}
}
else if (event.equals("BUFF") && !summon.isAffectedBySkill(PET_CONTROL) && !summon.isHungry())
{
final int buffStep = (int) CommonUtil.constrain(Math.floor((summon.getLevel() / 5) - 11), 0, 3);
for (int i = 1; i <= (2 * (1 + buffStep)); i++)
{
if (castBuff(summon, buffStep, i))
{
break;
}
}
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public void onSummonSpawn(Summon summon)
{
startQuestTimer("HEAL", 5000, null, summon.getOwner(), true);
startQuestTimer("BUFF", 10000, null, summon.getOwner(), true);
}
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
@RegisterType(ListenerRegisterType.GLOBAL)
public void OnPlayerLogout(OnPlayerLogout event)
{
cancelQuestTimer("HEAL", null, event.getPlayer());
cancelQuestTimer("BUFF", null, event.getPlayer());
}
private boolean castBuff(Summon summon, int stepNumber, int buffNumber)
{
final PlayerInstance owner = summon.getOwner();
final StatsSet parameters = summon.getTemplate().getParameters();
final SkillHolder skill = parameters.getObject("step" + stepNumber + "_buff0" + buffNumber, SkillHolder.class);
if ((skill != null) && (owner != null))
{
final boolean previousFollowStatus = summon.getFollowStatus();
final SkillHolder mergedSkill = parameters.getObject("step" + stepNumber + "_merged_buff0" + buffNumber, SkillHolder.class);
final int targetType = parameters.getInt("step" + stepNumber + "_buff_target0" + buffNumber, 0);
if (!owner.hasAbnormalType(skill.getSkill().getAbnormalType()) && SkillCaster.checkUseConditions(summon, skill.getSkill()) && !owner.isDead())
{
if (mergedSkill != null)
{
if (owner.hasAbnormalType(mergedSkill.getSkill().getAbnormalType()))
{
return false;
}
}
if (!previousFollowStatus && !summon.isInsideRadius3D(owner, skill.getSkill().getCastRange()))
{
return false;
}
if ((targetType >= 0) && (targetType <= 2))
{
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill.getSkill(), (targetType == 1) ? summon : owner);
summon.sendPacket(new SystemMessage(SystemMessageId.YOUR_PET_USES_S1).addSkillName(skill.getSkill()));
if (previousFollowStatus != summon.getFollowStatus())
{
summon.setFollowStatus(previousFollowStatus);
}
return true;
}
}
}
return false;
}
private void castHeal(Summon summon, int stepNumber, int healNumber)
{
final boolean previousFollowStatus = summon.getFollowStatus();
final PlayerInstance owner = summon.getOwner();
final StatsSet parameters = summon.getTemplate().getParameters();
final SkillHolder skill = parameters.getObject("step" + stepNumber + "_heal0" + healNumber, SkillHolder.class);
final int targetType = parameters.getInt("step" + stepNumber + "_heal_target0" + healNumber, 0);
if ((skill != null) && (owner != null) && SkillCaster.checkUseConditions(summon, skill.getSkill()) && !owner.isDead())
{
if (!previousFollowStatus && !summon.isInsideRadius3D(owner, skill.getSkill().getCastRange()))
{
return;
}
if (!owner.hasAbnormalType(skill.getSkill().getAbnormalType()))
{
if ((targetType >= 0) && (targetType <= 2))
{
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill.getSkill(), (targetType == 1) ? summon : owner);
summon.sendPacket(new SystemMessage(SystemMessageId.YOUR_PET_USES_S1).addSkillName(skill.getSkill()));
if (previousFollowStatus != summon.getFollowStatus())
{
summon.setFollowStatus(previousFollowStatus);
}
}
}
}
}
public static void main(String[] args)
{
new ImprovedBabyPets();
}
}

View File

@@ -0,0 +1,4 @@
<html><body>Beast Herder Tunatun:<br>
You wanted a Whip? Don't you already have one?<br>
If you don't, I can give you one again. Unfortunately, if you already have one, I can't give you another. Resources are pretty limited out here, I'm sure you can understand.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Beast Herder Tunatun:<br>
You...? You don't look that strong. Raising beasts is not an easy thing.<br>
It could be really dangerious if something goes wrong. It's OK when they are young, but it becomes too dangerous for you to handle when they're are fully grown up.<br>
Maybe it would be better for you to come back again when you become a little more stronger. Then, I will gladly give you this Beast Handler's Whip.
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Beast Herder Tunatun:<br>
Are you interested in Beast Training? I'll give you a Handler's Whip.<br>
You didn't forget about Beast Training techniques, did you? If you want, I can tell you about them again.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Tunatun 31537-04.html">Listen to the explanation on training techniques</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Tunatun 31537-06.html">Decline, as you already know about them</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Beast Herder Tunatun:<br>
In order to give orders to the beasts, you need this Whip.<br>
One beast used to be our limit, but thanks to the Beast Handler's Whip, it isn't a problem controlling more.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Tunatun 31537-05.html">Go on</Button>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Beast Herder Tunatun:<br>
Look for Feed Sellers in this area like the one standing next to me. The feed you buy from them can be given to <font color="LEVEL">Alpine Buffalo, Alpine Grendel, Alpine Kookaburra, and Alpine Buffalo</font>. The more feed you give each beast, the more they'll grow.<br>Remember though, tamed beasts will run away if you run out of feed to give them. So be careful.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Beast Herder Tunatun:<br>
Oh, I see. I hope you will get a good result.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Beast Herder Tunatun:<br>
Hi! Welcome to the Beast Farm. My name is Tunatun and I'm the one in charge here. I got this job because I thought I'd be able to commune with the beasts. After all, my pet kitty back home absolutely loved me. On this farm though, it's not so easy.<br>As a matter of fact, I'm having a lot of trouble with these beasts. They tend to fight back if you try to feed or tame them, so I've hired a Feed Seller and various adventurers to help me manage and protect the farm. At this point, there's not much else I can do.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Tunatun whip">Take the Beast Handler's Whip</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -1,77 +1,88 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package events.TotalRecall;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
import org.l2jmobius.gameserver.model.skills.SkillCaster;
/**
* Total Recall Event
* @URL https://eu.4gameforum.com/threads/578395/
* @author QuangNguyen
*/
public class TotalRecall extends LongTimeEvent
{
// NPC
private static final int FROG = 9013;
// Skill
private static final SkillHolder FROG_KISS = new SkillHolder(55314, 1);
private TotalRecall()
{
addStartNpc(FROG);
addFirstTalkId(FROG);
addTalkId(FROG);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
String htmltext = null;
switch (event)
{
case "9013-1.htm":
case "9013-2.htm":
case "9013-3.htm":
{
htmltext = event;
break;
}
case "frog_buff":
{
SkillCaster.triggerCast(npc, player, FROG_KISS.getSkill());
htmltext = "9013-4.htm";
break;
}
}
return htmltext;
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
{
return "9013-1.htm";
}
public static void main(String[] args)
{
new TotalRecall();
}
}
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.BeastFarm.Tunatun;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import ai.AbstractNpcAI;
/**
* Beast Herder Tunatun AI.
* @author Adry_85
*/
public class Tunatun extends AbstractNpcAI
{
// NPC
private static final int TUNATUN = 31537;
// Item
private static final int BEAST_HANDLERS_WHIP = 15473;
// Misc
private static final int MIN_LEVEL = 82;
private Tunatun()
{
addStartNpc(TUNATUN);
addFirstTalkId(TUNATUN);
addTalkId(TUNATUN);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
String htmltext = getNoQuestMsg(player);
switch (event)
{
case "31537-04.html":
case "31537-05.html":
case "31537-06.html":
{
htmltext = event;
break;
}
case "whip":
{
{
if (!hasQuestItems(player, BEAST_HANDLERS_WHIP))
{
if (player.getLevel() >= MIN_LEVEL)
{
giveItems(player, BEAST_HANDLERS_WHIP, 1);
htmltext = "31537-03.html";
}
else
{
htmltext = "31537-02.html";
}
}
else
{
htmltext = "31537-01.html";
}
}
break;
}
}
return htmltext;
}
public static void main(String[] args)
{
new Tunatun();
}
}

View File

@@ -0,0 +1,234 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DenOfEvil;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.data.xml.impl.SkillData;
import org.l2jmobius.gameserver.instancemanager.ZoneManager;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.zone.type.EffectZone;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.scripting.annotations.Disabled;
import ai.AbstractNpcAI;
/**
* Dummy AI for spawns/respawns only for testing.
* @author Gnacik
*/
@Disabled // Mobius: this needs to be rewritten.
public class DenOfEvil extends AbstractNpcAI
{
// private static final int _buffer_id = 32656;
protected static final int[] EYE_IDS =
{
18812,
18813,
18814
};
private static final int SKILL_ID = 6150; // others +2
private static final Location[] EYE_SPAWNS =
{
new Location(71544, -129400, -3360, 16472),
new Location(70954, -128854, -3360, 16),
new Location(72145, -128847, -3368, 32832),
new Location(76147, -128372, -3144, 16152),
new Location(71573, -128309, -3360, 49152),
new Location(75211, -127441, -3152, 0),
new Location(77005, -127406, -3144, 32784),
new Location(75965, -126486, -3144, 49120),
new Location(70972, -126429, -3016, 19208),
new Location(69916, -125838, -3024, 2840),
new Location(71658, -125459, -3016, 35136),
new Location(70605, -124646, -3040, 52104),
new Location(67283, -123237, -2912, 12376),
new Location(68383, -122754, -2912, 27904),
new Location(74137, -122733, -3024, 13272),
new Location(66736, -122007, -2896, 60576),
new Location(73289, -121769, -3024, 1024),
new Location(67894, -121491, -2912, 43872),
new Location(75530, -121477, -3008, 34424),
new Location(74117, -120459, -3024, 52344),
new Location(69608, -119855, -2534, 17251),
new Location(71014, -119027, -2520, 31904),
new Location(68944, -118964, -2527, 59874),
new Location(62261, -118263, -3072, 12888),
new Location(70300, -117942, -2528, 46208),
new Location(74312, -117583, -2272, 15280),
new Location(63276, -117409, -3064, 24760),
new Location(68104, -117192, -2168, 15888),
new Location(73758, -116945, -2216, 0),
new Location(74944, -116858, -2220, 30892),
new Location(61715, -116623, -3064, 59888),
new Location(69140, -116464, -2168, 28952),
new Location(67311, -116374, -2152, 1280),
new Location(62459, -116370, -3064, 48624),
new Location(74475, -116260, -2216, 47456),
new Location(68333, -115015, -2168, 45136),
new Location(68280, -108129, -1160, 17992),
new Location(62983, -107259, -2384, 12552),
new Location(67062, -107125, -1144, 64008),
new Location(68893, -106954, -1160, 36704),
new Location(63848, -106771, -2384, 32784),
new Location(62372, -106514, -2384, 0),
new Location(67838, -106143, -1160, 51232),
new Location(62905, -106109, -2384, 51288)
};
private DenOfEvil()
{
addKillId(EYE_IDS);
addSpawnId(EYE_IDS);
for (Location loc : EYE_SPAWNS)
{
addSpawn(EYE_IDS[getRandom(EYE_IDS.length)], loc, false, 0);
}
}
private int getSkillIdByNpcId(int npcId)
{
int diff = npcId - EYE_IDS[0];
diff *= 2;
return SKILL_ID + diff;
}
@Override
public String onSpawn(Npc npc)
{
npc.disableCoreAI(true);
npc.setIsImmobilized(true);
final EffectZone zone = ZoneManager.getInstance().getZone(npc, EffectZone.class);
if (zone == null)
{
LOGGER.warning("NPC " + npc + " spawned outside of EffectZone, check your zone coords! X:" + npc.getX() + " Y:" + npc.getY() + " Z:" + npc.getZ());
return null;
}
final int skillId = getSkillIdByNpcId(npc.getId());
final int skillLevel = zone.getSkillLevel(skillId);
zone.addSkill(skillId, skillLevel + 1);
if (skillLevel == 3) // 3+1=4
{
ThreadPool.schedule(new KashaDestruction(zone), 2 * 60 * 1000);
zone.broadcastPacket(new SystemMessage(SystemMessageId.DEFEAT_KASHA_S_EYES_TO_LIFT_THE_GREAT_CURSE));
}
else if (skillLevel == 2)
{
zone.broadcastPacket(new SystemMessage(SystemMessageId.A_GREAT_CURSE_CAN_BE_FELT_FROM_KASHA_S_EYES));
}
return super.onSpawn(npc);
}
@Override
public String onKill(Npc npc, PlayerInstance killer, boolean isSummon)
{
ThreadPool.schedule(new RespawnNewEye(npc.getLocation()), 15000);
final EffectZone zone = ZoneManager.getInstance().getZone(npc, EffectZone.class);
if (zone == null)
{
LOGGER.warning("NPC " + npc + " killed outside of EffectZone, check your zone coords! X:" + npc.getX() + " Y:" + npc.getY() + " Z:" + npc.getZ());
return null;
}
final int skillId = getSkillIdByNpcId(npc.getId());
final int skillLevel = zone.getSkillLevel(skillId);
zone.addSkill(skillId, skillLevel - 1);
return super.onKill(npc, killer, isSummon);
}
private class RespawnNewEye implements Runnable
{
private final Location _loc;
public RespawnNewEye(Location loc)
{
_loc = loc;
}
@Override
public void run()
{
addSpawn(EYE_IDS[getRandom(EYE_IDS.length)], _loc, false, 0);
}
}
private class KashaDestruction implements Runnable
{
EffectZone _zone;
public KashaDestruction(EffectZone zone)
{
_zone = zone;
}
@Override
public void run()
{
for (int i = SKILL_ID; i <= (SKILL_ID + 4); i += 2)
{
// test 3 skills if some is lvl 4
if (_zone.getSkillLevel(i) > 3)
{
destroyZone();
break;
}
}
}
private void destroyZone()
{
for (Creature creature : _zone.getCharactersInside())
{
if (creature == null)
{
continue;
}
if (creature.isPlayable())
{
final Skill skill = SkillData.getInstance().getSkill(6149, 1);
skill.applyEffects(creature, creature);
}
else if (creature.doDie(null)) // mobs die
{
if (creature.isNpc())
{
// respawn eye
final Npc npc = (Npc) creature;
if (CommonUtil.contains(EYE_IDS, npc.getId()))
{
ThreadPool.schedule(new RespawnNewEye(npc.getLocation()), 15000);
}
}
}
}
for (int i = SKILL_ID; i <= (SKILL_ID + 4); i += 2)
{
_zone.removeSkill(i);
}
}
}
public static void main(String[] args)
{
new DenOfEvil();
}
}

View File

@@ -0,0 +1,145 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DenOfEvil;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.itemcontainer.Inventory;
import org.l2jmobius.gameserver.network.NpcStringId;
import ai.AbstractNpcAI;
/**
* Frightened Ragna Orc AI.
* @author Gladicek, malyelfik
*/
public class FrightenedRagnaOrc extends AbstractNpcAI
{
// NPC ID
private static final int MOB_ID = 18807;
// Chances
private static final int ADENA = 10000;
private static final int CHANCE = 1000;
private static final int ADENA2 = 1000000;
private static final int CHANCE2 = 10;
// Skill
private static final SkillHolder SKILL = new SkillHolder(6234, 1);
private FrightenedRagnaOrc()
{
addAttackId(MOB_ID);
addKillId(MOB_ID);
}
@Override
public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("say", (getRandom(5) + 3) * 1000, npc, null, true);
}
else if ((npc.getCurrentHp() < (npc.getMaxHp() * 0.2)) && npc.isScriptValue(1))
{
startQuestTimer("reward", 10000, npc, attacker);
npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.WAIT_WAIT_STOP_SAVE_ME_AND_I_LL_GIVE_YOU_10_000_000_ADENA);
npc.setScriptValue(2);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(Npc npc, PlayerInstance player, boolean isSummon)
{
final NpcStringId msg = getRandomBoolean() ? NpcStringId.A_CURSE_UPON_YOU_2 : NpcStringId.I_REALLY_DIDN_T_WANT_TO_FIGHT;
npc.broadcastSay(ChatType.NPC_GENERAL, msg);
cancelQuestTimer("say", npc, null);
cancelQuestTimer("reward", npc, player);
return super.onKill(npc, player, isSummon);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
switch (event)
{
case "say":
{
if (npc.isDead() || !npc.isScriptValue(1))
{
cancelQuestTimer("say", npc, null);
return null;
}
final NpcStringId msg = getRandomBoolean() ? NpcStringId.I_DON_T_WANT_TO_FIGHT : NpcStringId.IS_THIS_REALLY_NECESSARY;
npc.broadcastSay(ChatType.NPC_GENERAL, msg);
break;
}
case "reward":
{
if (!npc.isDead() && npc.isScriptValue(2))
{
if (getRandom(100000) < CHANCE2)
{
final NpcStringId msg = getRandomBoolean() ? NpcStringId.TH_THANKS_I_COULD_HAVE_BECOME_GOOD_FRIENDS_WITH_YOU : NpcStringId.I_LL_GIVE_YOU_10_000_000_ADENA_LIKE_I_PROMISED_I_MIGHT_BE_AN_ORC_WHO_KEEPS_MY_PROMISES;
npc.broadcastSay(ChatType.NPC_GENERAL, msg);
npc.setScriptValue(3);
npc.doCast(SKILL.getSkill());
for (int i = 0; i < 10; i++)
{
npc.dropItem(player, Inventory.ADENA_ID, ADENA2);
}
}
else if (getRandom(100000) < CHANCE)
{
final NpcStringId msg = getRandomBoolean() ? NpcStringId.TH_THANKS_I_COULD_HAVE_BECOME_GOOD_FRIENDS_WITH_YOU : NpcStringId.SORRY_BUT_THIS_IS_ALL_I_HAVE_GIVE_ME_A_BREAK;
npc.broadcastSay(ChatType.NPC_GENERAL, msg);
npc.setScriptValue(3);
npc.doCast(SKILL.getSkill());
for (int i = 0; i < 10; i++)
{
npc.dropItem(player, Inventory.ADENA_ID, ADENA);
}
}
else
{
final NpcStringId msg = getRandomBoolean() ? NpcStringId.THANKS_BUT_THAT_THING_ABOUT_10_000_000_ADENA_WAS_A_LIE_SEE_YA : NpcStringId.YOU_RE_PRETTY_DUMB_TO_BELIEVE_ME;
npc.broadcastSay(ChatType.NPC_GENERAL, msg);
}
startQuestTimer("despawn", 1000, npc, null);
}
break;
}
case "despawn":
{
npc.setRunning();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location((npc.getX() + getRandom(-800, 800)), (npc.getY() + getRandom(-800, 800)), npc.getZ(), npc.getHeading()));
npc.deleteMe();
break;
}
}
return null;
}
public static void main(String[] args)
{
new FrightenedRagnaOrc();
}
}

View File

@@ -14,37 +14,35 @@
* 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 events.ChefMonkeyEvent;
package ai.areas.DenOfEvil;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
import ai.AbstractNpcAI;
/**
* Chef Monkey Event
* @URL https://eu.4gameforum.com/threads/603119/
* @author Mobius
* Ragna Orc Commander AI.
* @author Zealar
*/
public class ChefMonkeyEvent extends LongTimeEvent
public class RagnaOrcCommander extends AbstractNpcAI
{
// NPC
private static final int CHEF_MONKEY = 34292;
private static final int RAGNA_ORC_COMMANDER = 22694;
private ChefMonkeyEvent()
private RagnaOrcCommander()
{
addStartNpc(CHEF_MONKEY);
addFirstTalkId(CHEF_MONKEY);
addTalkId(CHEF_MONKEY);
addSpawnId(RAGNA_ORC_COMMANDER);
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
public String onSpawn(Npc npc)
{
return "34292-01.htm";
spawnMinions(npc, "Privates1");
spawnMinions(npc, getRandomBoolean() ? "Privates2" : "Privates3");
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new ChefMonkeyEvent();
new RagnaOrcCommander();
}
}

View File

@@ -14,49 +14,34 @@
* 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 ai.areas.TalkingIsland;
package ai.areas.DenOfEvil;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.network.NpcStringId;
import ai.AbstractNpcAI;
/**
* Roxxy AI.
* @author Mobius
* Ragna Orc Hero AI.
* @author Zealar
*/
public class Roxxy extends AbstractNpcAI
public class RagnaOrcHero extends AbstractNpcAI
{
// NPC
private static final int ROXXY = 30006;
private static final int RAGNA_ORC_HERO = 22693;
private Roxxy()
private RagnaOrcHero()
{
addSpawnId(ROXXY);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (event.equals("TEXT_SPAM") && (npc != null))
{
npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.SPEAK_WITH_ME_ABOUT_TRAVELING_AROUND_ADEN, 1000);
startQuestTimer("TEXT_SPAM", getRandom(10000, 30000), npc, null, false);
}
return super.onAdvEvent(event, npc, player);
addSpawnId(RAGNA_ORC_HERO);
}
@Override
public String onSpawn(Npc npc)
{
startQuestTimer("TEXT_SPAM", 10000, npc, null, false);
spawnMinions(npc, getRandom(100) < 70 ? "Privates1" : "Privates2");
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new Roxxy();
new RagnaOrcHero();
}
}
}

View File

@@ -1,36 +1,47 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package quests.not_done;
import org.l2jmobius.Config;
import org.l2jmobius.gameserver.model.quest.Quest;
/**
* @author Mobius
*/
public class Q10506_DianasRequest extends Quest
{
private static final int START_NPC = 9001;
public Q10506_DianasRequest()
{
super(10506);
addStartNpc(START_NPC);
addTalkId(START_NPC);
addCondMinLevel(Config.PLAYER_MAXIMUM_LEVEL, getNoQuestMsg(null));
}
}
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DenOfEvil;
import org.l2jmobius.gameserver.model.actor.Npc;
import ai.AbstractNpcAI;
/**
* Ragna Orc Seer AI.
* @author Zealar
*/
public class RagnaOrcSeer extends AbstractNpcAI
{
private static final int RAGNA_ORC_SEER = 22697;
private RagnaOrcSeer()
{
addSpawnId(RAGNA_ORC_SEER);
}
@Override
public String onSpawn(Npc npc)
{
spawnMinions(npc, "Privates" + getRandom(1, 2));
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RagnaOrcSeer();
}
}

View File

@@ -1,120 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DungeonOfAbyss;
import org.l2jmobius.gameserver.instancemanager.ZoneManager;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.zone.ZoneType;
import ai.AbstractNpcAI;
/**
* @author Mobius
*/
public class DungeonOfAbyssZone extends AbstractNpcAI
{
private static final ZoneType ABYSS_WEST_ZONE_1 = ZoneManager.getInstance().getZoneByName("The West Dungeon of Abyss");
private static final ZoneType ABYSS_WEST_ZONE_2 = ZoneManager.getInstance().getZoneByName("The West Dungeon of Abyss 2nd");
private static final ZoneType ABYSS_EAST_ZONE_3 = ZoneManager.getInstance().getZoneByName("The East Dungeon of Abyss");
private static final ZoneType ABYSS_EAST_ZONE_4 = ZoneManager.getInstance().getZoneByName("The East Dungeon of Abyss 2nd");
private static final ZoneType ABYSS_WEST_ZONE_BOSS_1 = ZoneManager.getInstance().getZoneByName("The West Dungeon of Abyss Boss Room");
private static final ZoneType ABYSS_WEST_ZONE_BOSS_2 = ZoneManager.getInstance().getZoneByName("The West Dungeon of Abyss 2nd Boss Room");
private static final ZoneType ABYSS_EAST_ZONE_BOSS_3 = ZoneManager.getInstance().getZoneByName("The East Dungeon of Abyss Boss Room");
private static final ZoneType ABYSS_EAST_ZONE_BOSS_4 = ZoneManager.getInstance().getZoneByName("The East Dungeon of Abyss 2nd Boss Room");
private static final int EXIT_TIME = 60 * 60 * 1000; // 60 minute
private static final int EXIT_TIME_BOSS_ROOM = 30 * 60 * 1000; // 60 minute
private static final Location EXIT_LOCATION_1 = new Location(-120019, -182575, -6751); // Move to Magrit
private static final Location EXIT_LOCATION_2 = new Location(-119977, -179753, -6751); // Move to Ingrit
private static final Location EXIT_LOCATION_3 = new Location(-109554, -180408, -6753); // Move to Iris
private static final Location EXIT_LOCATION_4 = new Location(-109595, -177560, -6753); // Move to Rosammy
private DungeonOfAbyssZone()
{
addEnterZoneId(ABYSS_WEST_ZONE_1.getId(), ABYSS_WEST_ZONE_2.getId(), ABYSS_EAST_ZONE_3.getId(), ABYSS_EAST_ZONE_4.getId(), ABYSS_WEST_ZONE_BOSS_1.getId(), ABYSS_WEST_ZONE_BOSS_2.getId(), ABYSS_EAST_ZONE_BOSS_3.getId(), ABYSS_EAST_ZONE_BOSS_4.getId());
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (event.startsWith("EXIT_PLAYER") && (player != null))
{
if (event.contains(ABYSS_WEST_ZONE_1.getName()) && ABYSS_WEST_ZONE_1.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_1);
}
else if (event.contains(ABYSS_WEST_ZONE_2.getName()) && ABYSS_WEST_ZONE_2.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_2);
}
else if (event.contains(ABYSS_EAST_ZONE_3.getName()) && ABYSS_EAST_ZONE_3.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_3);
}
else if (event.contains(ABYSS_EAST_ZONE_4.getName()) && ABYSS_EAST_ZONE_4.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_4);
}
else if (event.contains(ABYSS_WEST_ZONE_BOSS_1.getName()) && ABYSS_WEST_ZONE_BOSS_1.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_1);
}
else if (event.contains(ABYSS_WEST_ZONE_BOSS_2.getName()) && ABYSS_WEST_ZONE_BOSS_2.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_2);
}
else if (event.contains(ABYSS_EAST_ZONE_BOSS_3.getName()) && ABYSS_EAST_ZONE_BOSS_3.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_3);
}
else if (event.contains(ABYSS_EAST_ZONE_BOSS_4.getName()) && ABYSS_EAST_ZONE_BOSS_4.getPlayersInside().contains(player))
{
player.teleToLocation(EXIT_LOCATION_4);
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onEnterZone(Creature creature, ZoneType zone)
{
if (creature.isPlayer())
{
final PlayerInstance player = creature.getActingPlayer();
cancelQuestTimer("EXIT_PLAYER" + ABYSS_WEST_ZONE_1.getName() + player.getObjectId(), null, player);
cancelQuestTimer("EXIT_PLAYER" + ABYSS_WEST_ZONE_2.getName() + player.getObjectId(), null, player);
cancelQuestTimer("EXIT_PLAYER" + ABYSS_EAST_ZONE_3.getName() + player.getObjectId(), null, player);
cancelQuestTimer("EXIT_PLAYER" + ABYSS_EAST_ZONE_4.getName() + player.getObjectId(), null, player);
cancelQuestTimer("EXIT_PLAYER" + ABYSS_WEST_ZONE_BOSS_1.getName() + player.getObjectId(), null, player);
cancelQuestTimer("EXIT_PLAYER" + ABYSS_WEST_ZONE_BOSS_2.getName() + player.getObjectId(), null, player);
cancelQuestTimer("EXIT_PLAYER" + ABYSS_EAST_ZONE_BOSS_3.getName() + player.getObjectId(), null, player);
cancelQuestTimer("EXIT_PLAYER" + ABYSS_EAST_ZONE_BOSS_4.getName() + player.getObjectId(), null, player);
startQuestTimer("EXIT_PLAYER" + zone.getName() + player.getObjectId(), zone.getName().contains("boss") ? EXIT_TIME_BOSS_ROOM : EXIT_TIME, null, player);
}
return super.onEnterZone(creature, zone);
}
public static void main(String[] args)
{
new DungeonOfAbyssZone();
}
}

View File

@@ -1,8 +0,0 @@
<html>body>Magrit:<br>
The Death Eater is the most powerful and dangerous creature in this prison.<br1>
If you have the <font color="LEVEL">Key from the Central Part of the Western Wing of the Dungeon of Abyss</font>, You can get to the Death Eater.<br1>
However, remember: you will be alone with him. No one will come to your rescue. In addition, you will only have <font color="LEVEL">30 minutes</font> to destroy it.<br>
If you decide to retreat or fail and want to try your luck some other time, you will need a new key.<br>
And more: if <font color="LEVEL">the quantity and weight of items in your inventory will exceed 80%</font>, You can not get a reward, so take care of an empty seat before the battle begins.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Magrit 3">Go to the Condemned of Abyss Prison</Button>
</body></html>

View File

@@ -1,8 +0,0 @@
<html><body>Magrit:<br>
An incident occurred in this terrifying prison and put the whole Kingdom of Aden at risk..<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Magrit 1">Go to the West Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Magrit 2">Go to the 2nd entrance to the West Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Chat 1">Go to the Condemned of Abyss Prison</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Magrit 4">Return to Aden</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -1,8 +0,0 @@
<html><body>Ingrit:<br>
The Death Eater is the most powerful and dangerous creature in this prison.<br1>
If you have the <font color="LEVEL">Key from the Central Part of the Western Wing of the Dungeon of Abyss</font>, You can get to the Death Eater.<br1>
However, remember: you will be alone with him. No one will come to your rescue. In addition, you will only have <font color="LEVEL">30 minutes</font> to destroy it.<br>
If you decide to retreat or fail and want to try your luck some other time, you will need a new key.<br>
And more: if <font color="LEVEL">the quantity and weight of items in your inventory will exceed 80%</font>, You can not get a reward, so take care of an empty seat before the battle begins.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Ingrit 3">Go to the Condemned of Abyss Prison</Button>
</body></html>

View File

@@ -1,8 +0,0 @@
<html><body>Ingrit:<br>
An incident occurred in this terrifying prison and put the whole Kingdom of Aden at risk..<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Ingrit 1">Go to the West Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Ingrit 2">Go to the 1nd entrance to the West Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Chat 1">Go to the Condemned of Abyss Prison</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Ingrit 4">Return to Aden</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -1,8 +0,0 @@
<html><body>Iris:<br>
The Death Eater is the most powerful and dangerous creature in this prison.<br1>
If you have the <font color="LEVEL">Key from the Central Part of the Western Wing of the Dungeon of Abyss</font>, You can get to the Death Eater.<br1>
However, remember: you will be alone with him. No one will come to your rescue. In addition, you will only have <font color="LEVEL">30 minutes</font> to destroy it.<br>
If you decide to retreat or fail and want to try your luck some other time, you will need a new key.<br>
And more: if <font color="LEVEL">the quantity and weight of items in your inventory will exceed 80%</font>, You can not get a reward, so take care of an empty seat before the battle begins.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Iris 3">Go to the Condemned of Abyss Prison</Button>
</body></html>

View File

@@ -1,8 +0,0 @@
<html><body>Iris:<br>
An incident occurred in this terrifying prison and put the whole Kingdom of Aden at risk..<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Iris 1">Go to the East Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Iris 2">Go to the 2nd entrance to the East Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Chat 1">Go to the Condemned of Abyss Prison</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Iris 4">Return to Aden</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -1,8 +0,0 @@
<html><body>Rosammy:<br>
The Death Eater is the most powerful and dangerous creature in this prison.<br1>
If you have the <font color="LEVEL">Key from the Central Part of the Western Wing of the Dungeon of Abyss</font>, You can get to the Death Eater.<br1>
However, remember: you will be alone with him. No one will come to your rescue. In addition, you will only have <font color="LEVEL">30 minutes</font> to destroy it.<br>
If you decide to retreat or fail and want to try your luck some other time, you will need a new key.<br>
And more: if <font color="LEVEL">the quantity and weight of items in your inventory will exceed 80%</font>, You can not get a reward, so take care of an empty seat before the battle begins.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Rosammy 3">Go to the Condemned of Abyss Prison</Button>
</body></html>

View File

@@ -1,8 +0,0 @@
<html><body>Rosammy:<br>
An incident occurred in this terrifying prison and put the whole Kingdom of Aden at risk..<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Rosammy 1">Go to the East Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Rosammy 2">Go to the 1nd entrance to the East Wing of the Dungeon of Abyss</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Chat 1">Go to the Condemned of Abyss Prison</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Rosammy 4">Return to Aden</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -1,109 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DungeonOfAbyss.SoulTracker;
import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.quest.QuestState;
import ai.AbstractNpcAI;
/**
* @author QuangNguyen
*/
public class Ingrit extends AbstractNpcAI
{
// NPC
private static final int SOUL_TRACKER_INRGIT = 31775;
// Item
private static final int KEY_OF_WEST_WING = 90010;
// Locations
private static final Map<String, Location> LOCATIONS = new HashMap<>();
static
{
LOCATIONS.put("1", new Location(-119533, -179641, -6751)); // Join Room from Ingrit
LOCATIONS.put("2", new Location(-120325, -182444, -6752)); // Move to West Wing 1nd
LOCATIONS.put("3", new Location(-116975, -178699, -6751)); // Go to the Condemned of Abyss Prison
LOCATIONS.put("4", new Location(146945, 26764, -2200)); // Return to Aden
}
private Ingrit()
{
addStartNpc(SOUL_TRACKER_INRGIT);
addTalkId(SOUL_TRACKER_INRGIT);
addFirstTalkId(SOUL_TRACKER_INRGIT);
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
{
return npc.getId() + ".htm";
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (npc.getId() == SOUL_TRACKER_INRGIT)
{
QuestState qs = player.getQuestState("Q00933_ExploringTheWestWingOfTheDungeonOfAbyss");
switch (event)
{
case "1":
{
if ((qs != null) && qs.isStarted())
{
player.teleToLocation(LOCATIONS.get(event), false); // Join Room from Ingrit
}
else
{
return "no_enter.htm";
}
break;
}
case "2":
{
player.teleToLocation(LOCATIONS.get(event), false); // Move to West Wing 1nd
break;
}
case "3":
{
if (!hasQuestItems(player, KEY_OF_WEST_WING))
{
return "no_key.htm";
}
player.teleToLocation(LOCATIONS.get(event), false); // Go to the Condemned of Abyss Prison
break;
}
case "4":
{
player.teleToLocation(LOCATIONS.get(event), false); // Return to Aden
break;
}
}
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new Ingrit();
}
}

View File

@@ -1,109 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DungeonOfAbyss.SoulTracker;
import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.quest.QuestState;
import ai.AbstractNpcAI;
/**
* @author QuangNguyen
*/
public class Iris extends AbstractNpcAI
{
// NPC
private static final int SOUL_TRACKER_IRIS = 31776;
// Item
private static final int KEY_OF_EAST_WING = 90011;
// Locations
private static final Map<String, Location> LOCATIONS = new HashMap<>();
static
{
LOCATIONS.put("1", new Location(-110038, -180560, -6754)); // Join Room from Iris
LOCATIONS.put("2", new Location(-109234, -177737, -6751)); // Move to East Wing 2nd
LOCATIONS.put("3", new Location(-112648, -181517, -6751)); // Go to the Condemned of Abyss Prison
LOCATIONS.put("4", new Location(146945, 26764, -2200)); // Return to Aden
}
private Iris()
{
addStartNpc(SOUL_TRACKER_IRIS);
addTalkId(SOUL_TRACKER_IRIS);
addFirstTalkId(SOUL_TRACKER_IRIS);
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
{
return npc.getId() + ".htm";
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (npc.getId() == SOUL_TRACKER_IRIS)
{
QuestState qs = player.getQuestState("Q00935_ExploringTheEastWingOfTheDungeonOfAbyss");
switch (event)
{
case "1":
{
if ((qs != null) && qs.isStarted())
{
player.teleToLocation(LOCATIONS.get(event), false); // Join Room form Iris
}
else
{
return "no_enter.htm";
}
break;
}
case "2":
{
player.teleToLocation(LOCATIONS.get(event), false); // Move to East Wing 2nd
break;
}
case "3":
{
if (!hasQuestItems(player, KEY_OF_EAST_WING))
{
return "no_key.htm";
}
player.teleToLocation(LOCATIONS.get(event), false); // Go to the Condemned of Abyss Prison
break;
}
case "4":
{
player.teleToLocation(LOCATIONS.get(event), false); // Return to Aden
break;
}
}
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new Iris();
}
}

View File

@@ -1,109 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DungeonOfAbyss.SoulTracker;
import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.quest.QuestState;
import ai.AbstractNpcAI;
/**
* @author QuangNguyen
*/
public class Magrit extends AbstractNpcAI
{
// NPC
private static final int SOUL_TRACKER_MARGIT = 31774;
// Item
private static final int KEY_OF_WEST_WING = 90010;
// Locations
private static final Map<String, Location> LOCATIONS = new HashMap<>();
static
{
LOCATIONS.put("1", new Location(-119440, -182464, -6752)); // Join Room from Magrit
LOCATIONS.put("2", new Location(-120394, -179651, -6751)); // Move to West Wing 2nd
LOCATIONS.put("3", new Location(-116963, -181492, -6575)); // Go to the Condemned of Abyss Prison
LOCATIONS.put("4", new Location(146945, 26764, -2200)); // Return to Aden
}
private Magrit()
{
addStartNpc(SOUL_TRACKER_MARGIT);
addTalkId(SOUL_TRACKER_MARGIT);
addFirstTalkId(SOUL_TRACKER_MARGIT);
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
{
return npc.getId() + ".htm";
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (npc.getId() == SOUL_TRACKER_MARGIT)
{
QuestState qs = player.getQuestState("Q00933_ExploringTheWestWingOfTheDungeonOfAbyss");
switch (event)
{
case "1":
{
if ((qs != null) && qs.isStarted())
{
player.teleToLocation(LOCATIONS.get(event), false); // Join Room from Magrit
}
else
{
return "no_enter.htm";
}
break;
}
case "2":
{
player.teleToLocation(LOCATIONS.get(event), false); // Move to West Wing 2nd
break;
}
case "3":
{
if (!hasQuestItems(player, KEY_OF_WEST_WING))
{
return "no_key.htm";
}
player.teleToLocation(LOCATIONS.get(event), false); // Go to the Condemned of Abyss Prison
break;
}
case "4":
{
player.teleToLocation(LOCATIONS.get(event), false); // Return to Aden
break;
}
}
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new Magrit();
}
}

View File

@@ -1,109 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DungeonOfAbyss.SoulTracker;
import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.quest.QuestState;
import ai.AbstractNpcAI;
/**
* @author QuangNguyen
*/
public class Rosammy extends AbstractNpcAI
{
// NPC
private static final int SOUL_TRACKER_ROSAMMY = 31777;
// Item
private static final int KEY_OF_EAST_WING = 90011;
// Locations
private static final Map<String, Location> LOCATIONS = new HashMap<>();
static
{
LOCATIONS.put("1", new Location(-110067, -177733, -6751)); // Join Room from Rosammy
LOCATIONS.put("2", new Location(-120318, -179626, -6752)); // Move to East Wing 1nd
LOCATIONS.put("3", new Location(-112632, -178671, -6751)); // Go to the Condemned of Abyss Prison
LOCATIONS.put("4", new Location(146945, 26764, -2200)); // Return to Aden
}
private Rosammy()
{
addStartNpc(SOUL_TRACKER_ROSAMMY);
addTalkId(SOUL_TRACKER_ROSAMMY);
addFirstTalkId(SOUL_TRACKER_ROSAMMY);
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
{
return npc.getId() + ".htm";
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
if (npc.getId() == SOUL_TRACKER_ROSAMMY)
{
QuestState qs = player.getQuestState("Q00935_ExploringTheEastWingOfTheDungeonOfAbyss");
switch (event)
{
case "1":
{
if ((qs != null) && qs.isStarted())
{
player.teleToLocation(LOCATIONS.get(event), false); // Join Room Rosammy
}
else
{
return "no_enter.htm";
}
break;
}
case "2":
{
player.teleToLocation(LOCATIONS.get(event), false); // Move to East Wing 1nd
break;
}
case "3":
{
if (!hasQuestItems(player, KEY_OF_EAST_WING))
{
return "no_key.htm";
}
player.teleToLocation(LOCATIONS.get(event), false); // Go to the Condemned of Abyss Prison
break;
}
case "4":
{
player.teleToLocation(LOCATIONS.get(event), false); // Return to Aden
break;
}
}
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new Rosammy();
}
}

View File

@@ -1,3 +0,0 @@
<html><body>Magrit:<br>
You apparently forgot to take the quest, please take the quest.<br>
</body></html>

View File

@@ -1,3 +0,0 @@
<html><body>Magrit:<br>
If you do not have the Key, you can not move to the Condemned of Abyss Prison.
</body></html>

View File

@@ -1,4 +0,0 @@
<html><body>Tores:<br>
It seems to me that you are not strong enough to go on a mission to the Dungeon of Abyss.<br>
(Western Wing of the Dungeon of Abyss for characters 40-44 level.)
</body></html>

View File

@@ -1,4 +0,0 @@
<html><body>Tores:<br>
It seems to me that you are not strong enough to go on a mission to the Dungeon of Abyss.<br>
(Eastern Wing side of the Dungeon of Abyss for characters 45-49 level.)
</body></html>

View File

@@ -1,6 +0,0 @@
<html><body>Tores:<br>
Have you heard of the Dungeon of Abyss? Especially evil and dangerous monsters are imprisoned there.<br>
But someone has recently removed the seal from its gates. If we do nothing… No, only a thought of it scares me. I need your help.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Tores 1">Go to the West Wing of the Dungeon of Abyss (Level 40-44)</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Tores 2">Go to the East Wing of the Dungeon of Abyss (Level 45-49)</Button>
</body></html>

View File

@@ -1,98 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.DungeonOfAbyss.Tores;
import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import ai.AbstractNpcAI;
/**
* @author QuangNguyen
*/
public class Tores extends AbstractNpcAI
{
// NPC
private static final int TORES = 31778;
// Locations
private static final Map<String, Location> LOCATIONS = new HashMap<>();
static
{
// move from Tores
LOCATIONS.put("1", new Location(-120325, -182444, -6752)); // Move to Magrit
LOCATIONS.put("2", new Location(-109202, -180546, -6751)); // Move to Iris
}
private Tores()
{
addStartNpc(TORES);
addTalkId(TORES);
addFirstTalkId(TORES);
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
{
return "31778.htm";
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
switch (event)
{
case "1":
{
final Location loc = LOCATIONS.get(event);
if ((player.getLevel() > 39) && (player.getLevel() < 45))
{
player.teleToLocation(loc, true);
}
else
{
return "31778-no_level.htm";
}
break;
}
case "2":
{
final Location loc = LOCATIONS.get(event);
if ((player.getLevel() > 44) && (player.getLevel() < 50))
{
player.teleToLocation(loc, true);
}
else
{
return "31778-no_level01.htm";
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new Tores();
}
}

View File

@@ -0,0 +1,205 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.ForgeOfTheGods;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import ai.AbstractNpcAI;
/**
* Forge of the Gods AI
* @author nonom, malyelfik
*/
public class ForgeOfTheGods extends AbstractNpcAI
{
// NPCs
private static final int[] FOG_MOBS =
{
22634, // Scarlet Stakato Worker
22635, // Scarlet Stakato Soldier
22636, // Scarlet Stakato Noble
22637, // Tepra Scorpion
22638, // Tepra Scarab
22639, // Assassin Beetle
22640, // Mercenary of Destruction
22641, // Knight of Destruction
22642, // Lavastone Golem
22643, // Magma Golem
22644, // Arimanes of Destruction
22645, // Balor of Destruction
22646, // Ashuras of Destruction
22647, // Lavasillisk
22648, // Blazing Ifrit
22649, // Magma Drake
};
private static final int[] LAVASAURUSES =
{
18799, // Newborn Lavasaurus
18800, // Fledgling Lavasaurus
18801, // Adult Lavasaurus
18802, // Elderly Lavasaurus
18803, // Ancient Lavasaurus
};
private static final int REFRESH = 15;
private static final int MOBCOUNT_BONUS_MIN = 3;
private static final int BONUS_UPPER_LV01 = 5;
private static final int BONUS_UPPER_LV02 = 10;
private static final int BONUS_UPPER_LV03 = 15;
private static final int BONUS_UPPER_LV04 = 20;
private static final int BONUS_UPPER_LV05 = 35;
private static final int BONUS_LOWER_LV01 = 5;
private static final int BONUS_LOWER_LV02 = 10;
private static final int BONUS_LOWER_LV03 = 15;
private static final int FORGE_BONUS01 = 20;
private static final int FORGE_BONUS02 = 40;
private static int _npcCount = 0;
// private static int _npcsAlive = 0; TODO: Require zone spawn support
private ForgeOfTheGods()
{
addKillId(FOG_MOBS);
addSpawnId(LAVASAURUSES);
startQuestTimer("refresh", REFRESH * 1000, null, null, true);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
switch (event)
{
case "suicide":
{
if (npc != null)
{
npc.doDie(null);
}
break;
}
case "refresh":
{
_npcCount = 0;
break;
}
}
return null;
}
@Override
public String onKill(Npc npc, PlayerInstance killer, boolean isSummon)
{
final int rand = getRandom(100);
Npc mob = null;
_npcCount++;
// For monsters at Forge of the Gods - Lower level
if (npc.getSpawn().getZ() < -5000) // && (_npcsAlive < 48))
{
if ((_npcCount > BONUS_LOWER_LV03) && (rand <= FORGE_BONUS02))
{
mob = addSpawn(LAVASAURUSES[4], npc, true);
}
else if (_npcCount > BONUS_LOWER_LV02)
{
mob = spawnLavasaurus(npc, rand, LAVASAURUSES[4], LAVASAURUSES[3]);
}
else if (_npcCount > BONUS_LOWER_LV01)
{
mob = spawnLavasaurus(npc, rand, LAVASAURUSES[3], LAVASAURUSES[2]);
}
else if (_npcCount >= MOBCOUNT_BONUS_MIN)
{
mob = spawnLavasaurus(npc, rand, LAVASAURUSES[2], LAVASAURUSES[1]);
}
}
else
// if (_npcsAlive < 32)
{
if ((_npcCount > BONUS_UPPER_LV05) && (rand <= FORGE_BONUS02))
{
mob = addSpawn(LAVASAURUSES[1], npc, true);
}
else if (_npcCount > BONUS_UPPER_LV04)
{
mob = spawnLavasaurus(npc, rand, LAVASAURUSES[4], LAVASAURUSES[3]);
}
else if (_npcCount > BONUS_UPPER_LV03)
{
mob = spawnLavasaurus(npc, rand, LAVASAURUSES[3], LAVASAURUSES[2]);
}
else if (_npcCount > BONUS_UPPER_LV02)
{
mob = spawnLavasaurus(npc, rand, LAVASAURUSES[2], LAVASAURUSES[1]);
}
else if (_npcCount > BONUS_UPPER_LV01)
{
mob = spawnLavasaurus(npc, rand, LAVASAURUSES[1], LAVASAURUSES[0]);
}
else if ((_npcCount >= MOBCOUNT_BONUS_MIN) && (rand <= FORGE_BONUS01))
{
mob = addSpawn(LAVASAURUSES[0], npc, true);
}
}
if (mob != null)
{
((Attackable) mob).addDamageHate(killer, 0, 9999);
mob.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK);
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(Npc npc)
{
startQuestTimer("suicide", 60000, npc, null);
return super.onSpawn(npc);
}
private Npc spawnLavasaurus(Npc npc, int rand, int... mobs)
{
if (mobs.length < 2)
{
return null;
}
Npc mob = null;
if (rand <= FORGE_BONUS01)
{
mob = addSpawn(mobs[0], npc, true);
}
else if (rand <= FORGE_BONUS02)
{
mob = addSpawn(mobs[1], npc, true);
}
return mob;
}
public static void main(String[] args)
{
new ForgeOfTheGods();
}
}

View File

@@ -0,0 +1,68 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.FrozenLabyrinth;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.skills.Skill;
import ai.AbstractNpcAI;
/**
* Frozen Labyrinth AI.
* @author malyelfik
*/
public class FrozenLabyrinth extends AbstractNpcAI
{
// Monsters
private static final int PRONGHORN_SPIRIT = 22087;
private static final int PRONGHORN = 22088;
private static final int LOST_BUFFALO = 22093;
private static final int FROST_BUFFALO = 22094;
private FrozenLabyrinth()
{
addAttackId(PRONGHORN, FROST_BUFFALO);
}
@Override
public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill)
{
if (npc.isScriptValue(0) && (skill != null) && !skill.isMagic())
{
final int spawnId = (npc.getId() == PRONGHORN) ? PRONGHORN_SPIRIT : LOST_BUFFALO;
int diff = 0;
for (int i = 0; i < 6; i++)
{
final int x = diff < 60 ? npc.getX() + diff : npc.getX();
final int y = diff >= 60 ? npc.getY() + (diff - 40) : npc.getY();
final Npc monster = addSpawn(spawnId, x, y, npc.getZ(), npc.getHeading(), false, 0);
addAttackPlayerDesire(monster, attacker);
diff += 20;
}
npc.setScriptValue(1);
npc.deleteMe();
}
return super.onAttack(npc, attacker, damage, isSummon, skill);
}
public static void main(String[] args)
{
new FrozenLabyrinth();
}
}

View File

@@ -0,0 +1,107 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.HotSprings;
import org.l2jmobius.gameserver.data.xml.impl.SkillData;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.skills.BuffInfo;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.skills.SkillCaster;
import ai.AbstractNpcAI;
/**
* Hot Springs AI.
* @author Pandragon
*/
public class HotSprings extends AbstractNpcAI
{
// NPCs
private static final int BANDERSNATCHLING = 21314;
private static final int FLAVA = 21316;
private static final int ATROXSPAWN = 21317;
private static final int NEPENTHES = 21319;
private static final int ATROX = 21321;
private static final int BANDERSNATCH = 21322;
// Skills
private static final int RHEUMATISM = 4551;
private static final int CHOLERA = 4552;
private static final int FLU = 4553;
private static final int MALARIA = 4554;
// Misc
private static final int DISEASE_CHANCE = 10;
private HotSprings()
{
addAttackId(BANDERSNATCHLING, FLAVA, ATROXSPAWN, NEPENTHES, ATROX, BANDERSNATCH);
}
@Override
public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon)
{
if (getRandom(100) < DISEASE_CHANCE)
{
tryToInfect(npc, attacker, MALARIA);
}
if (getRandom(100) < DISEASE_CHANCE)
{
switch (npc.getId())
{
case BANDERSNATCHLING:
case ATROX:
{
tryToInfect(npc, attacker, RHEUMATISM);
break;
}
case FLAVA:
case NEPENTHES:
{
tryToInfect(npc, attacker, CHOLERA);
break;
}
case ATROXSPAWN:
case BANDERSNATCH:
{
tryToInfect(npc, attacker, FLU);
break;
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
private void tryToInfect(Npc npc, Creature creature, int diseaseId)
{
final BuffInfo info = creature.getEffectList().getBuffInfoBySkillId(diseaseId);
final int skillLevel = (info == null) ? 1 : (info.getSkill().getLevel() < 10) ? info.getSkill().getLevel() + 1 : 10;
final Skill skill = SkillData.getInstance().getSkill(diseaseId, skillLevel);
if ((skill != null) && SkillCaster.checkUseConditions(npc, skill))
{
npc.setTarget(creature);
npc.doCast(skill);
}
}
public static void main(String[] args)
{
new HotSprings();
}
}

View File

@@ -0,0 +1,4 @@
<html><body>Ghost of Wigoth:<br>
You've destroyed Halisha's Shadow! Good job!<br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Nameless Spirit:<br>
This is the final resting place of the ancient emperors of the Elmoreden Empire! There are four major sepulchers. They are the Sepulcher of Conquerors, the Sepulcher of Rulers, the Sepulcher of Great Sages and the Sepulcher of Judges, respectively. Together they are known as the Four Sepulchers.<br>
But this sacred place is ultimately...<br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Ghost of Wigoth:<br>
Phew! You escaped safely!<br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>Ghost Chamberlain of Elmoreden:<br>
Greetings! I am a chamberlain of the ancient Elmoreden empire! When I was a mortal being I worked at the cemetery of the Elmoreden empire. Now I'm here, serving those who are traveling to the cemetery.<br>
My assistant also assists such travelers. He can be found near the entrance of Argos' Wall.<br>
Do you plan to visit the Elmoreden Cemetery?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest 620_FourGoblets 15">"I want to visit the 4th sepulcher."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest 620_FourGoblets 16">"I want to visit the entrance to the Elmoreden Cemetery."</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>Ghost Chamberlain of Elmoreden:<br>
Woooo! I'm a ghost page of the ancient Elmoreden Empire! I worked in the cemetery when I was a mortal being. Now I'm here to help travelers going to the Elmoreden Cemetery.<br>
My boss is in the Pilgrim's Necropolis. He also helps people visit the cemetery.<br>
Would you like to visit the cemetery of the Elmoreden empire?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest 620_FourGoblets 15">"I want to visit the 4th sepulcher."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest 620_FourGoblets 16">"I want to visit the entrance to the Elmoreden Cemetery."</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Conquerors' Sepulcher Manager:<br>
There is another party already in the sepulcher. Try again later.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Conquerors' Sepulcher Manager:<br>
Visiting hours are over!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Conquerors' Sepulcher Manager:<br>
The statue will only respond to the leader of the party.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Conquerors' Sepulcher Manager:<br>
One among your party hasn't fulfilled the request of the nameless soul. Ask %member% to go and meet with the nameless soul and do as he asks.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Conquerors' Sepulcher Manager:<br>
Enter.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Conquerors' Sepulcher Manager:<br>
One of your party members doesn't have a pass. Either give %member% a pass to enter the sepulcher, or ask him to go get one and come back.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Conquerors' Sepulcher Manager:<br>
Your party must consist of at least four members. Come back when you have more friends.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Conquerors' Sepulcher Manager:<br>
A strange-looking stone statue.<br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Emperors' Sepulcher Manager:<br>
Another party has already entered the sepulcher. Try again later.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Emperors' Sepulcher Manager:<br>
Entry forbidden at this time. Try again later.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Emperors' Sepulcher Manager:<br>
The stone statue will only respond to the hand of the party leader.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Emperors' Sepulcher Manager:<br>
%member% needs to speak with the nameless soul to gain entry.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Emperors' Sepulcher Manager:<br>
Enter.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Emperors' Sepulcher Manager:<br>
%member% doesn't have a pass.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Emperors' Sepulcher Manager:<br>
To gain entry, a party must consist of at least four members.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Emperors' Sepulcher Manager:<br>
A weird-looking statue.<br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Great Sages' Sepulcher Manager:<br>
Sepulcher is full. Try again later.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Great Sages' Sepulcher Manager:<br>
No entry. Try again later.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Great Sages' Sepulcher Manager:<br>
The party leader must place hands on the statue.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Great Sages' Sepulcher Manager:<br>
%member% must talk with the Nameless Soul to get permission.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Great Sages' Sepulcher Manager:<br>
Enter!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Great Sages' Sepulcher Manager:<br>
%member% does not have a pass to enter.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Great Sages' Sepulcher Manager:<br>
A party must consist of at least four members. Come back later.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Great Sages' Sepulcher Manager:<br>
A weird-looking stone statue.<br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Judges' Sepulcher Manager:<br>
Another party has already entered the sepulcher. Come back later!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Judge's Sepulcher Manager:<br>
Come back later!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Judges' Sepulcher Manager:<br>
Only a party leader may lay hands on the stone statue and enter!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Judges' Sepulcher Manager:<br>
%member% must get permission from the nameless soul.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Judges' Sepulcher Manager:<br>
You may enter!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Judges' Sepulcher Manager:<br>
%member% doesn't have a pass!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Judges' Sepulcher Manager:<br>
The combined strength of at least four is needed to gain entry!
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Judge's Sepulcher Manager:<br>
A weird-looking statue.<br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Baron's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Baron.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Viscount's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Viscount.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Count's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Count.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Marquis' Hall Gatekeeper:<br>
I guard the gate connected to the Marquis' Hall.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Duke's Hall Gatekeeper:<br>
I guard the gate connected to the tomb of the Emperor.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Baron's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Baron.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Viscount's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Viscount.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Count's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Count.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Marquis' Hall Gatekeeper:<br>
I guard the gate connected to the Marquis' Hall.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Duke's Hall Gatekeeper:<br>
I guard the gate connected to the tomb of the Emperor.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Baron's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Baron.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Viscount's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Viscount.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Count's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Count.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Marquis' Hall Gatekeeper:<br>
I guard the gate connected to the Marquis' Hall.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Duke's Hall Gatekeeper:<br>
I guard the gate connected to the tomb of the Emperor.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Baron's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Baron.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Viscount's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Viscount.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Count's Hall Gatekeeper:<br>
I guard the gate connected to the hall of a Count.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Marquis' Hall Gatekeeper:<br>
I guard the gate connected to the Marquis' Hall.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Duke's Hall Gatekeeper:<br>
I guard the gate connected to the tomb of the Emperor.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest FourSepulchers OpenGate">Open the gate.</Button>
</body></html>

View File

@@ -0,0 +1,721 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.ImperialTomb.FourSepulchers;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.geoengine.GeoEngine;
import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import org.l2jmobius.gameserver.instancemanager.ZoneManager;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.quest.QuestState;
import org.l2jmobius.gameserver.model.zone.ZoneType;
import org.l2jmobius.gameserver.model.zone.type.EffectZone;
import org.l2jmobius.gameserver.network.NpcStringId;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import org.l2jmobius.gameserver.util.Util;
import ai.AbstractNpcAI;
import quests.Q00620_FourGoblets.Q00620_FourGoblets;
/**
* Four Selpuchers AI
* @author Mobius
*/
public class FourSepulchers extends AbstractNpcAI implements IXmlReader
{
Logger LOGGER = Logger.getLogger(FourSepulchers.class.getName());
// NPCs
private static final int CONQUEROR_MANAGER = 31921;
private static final int EMPEROR_MANAGER = 31922;
private static final int GREAT_SAGES_MANAGER = 31923;
private static final int JUDGE_MANAGER = 31924;
private static final int MYSTERIOUS_CHEST = 31468;
private static final int KEY_CHEST = 31467;
private static final int ROOM_3_VICTIM = 18150;
private static final int ROOM_3_CHEST_REWARDER = 18158;
private static final int ROOM_4_CHARM_1 = 18196;
private static final int ROOM_4_CHARM_2 = 18197;
private static final int ROOM_4_CHARM_3 = 18198;
private static final int ROOM_4_CHARM_4 = 18199;
private static final int ROOM_5_STATUE_GUARD = 18232;
private static final int ROOM_6_REWARD_CHEST = 18256;
private static final int CONQUEROR_BOSS = 25346;
private static final int EMPEROR_BOSS = 25342;
private static final int GREAT_SAGES_BOSS = 25339;
private static final int JUDGE_BOSS = 25349;
private static final int TELEPORTER = 31452;
// @formatter:off
private static final int[] FIRST_TALK_NPCS =
{
TELEPORTER,
31453, 31454, 31919, 31920, 31925, 31926, 31927, 31928,
31929, 31930, 31931, 31932, 31933, 31934, 31935, 31936,
31937, 31938, 31939, 31940, 31941, 31942, 31943, 31944
};
// @formatter:on
private static final int[] CHEST_REWARD_MONSTERS =
{
18120, // room 1
ROOM_3_CHEST_REWARDER,
18177, // room 4
18212, // room 5 - wave 2
};
// Items
private static final int ENTRANCE_PASS = 7075;
private static final int USED_PASS = 7261;
private static final int CHAPEL_KEY = 7260;
private static final int ANTIQUE_BROOCH = 7262;
// Locations
private static final Map<Integer, Location> START_HALL_SPAWNS = new HashMap<>();
static
{
START_HALL_SPAWNS.put(CONQUEROR_MANAGER, new Location(181632, -85587, -7218));
START_HALL_SPAWNS.put(EMPEROR_MANAGER, new Location(179963, -88978, -7218));
START_HALL_SPAWNS.put(GREAT_SAGES_MANAGER, new Location(173217, -86132, -7218));
START_HALL_SPAWNS.put(JUDGE_MANAGER, new Location(175608, -82296, -7218));
}
// Zones
private static final int CONQUEROR_ZONE = 200221;
private static final int EMPEROR_ZONE = 200222;
private static final int GREAT_SAGES_ZONE = 200224;
private static final int JUDGE_ZONE = 200223;
private static final Map<Integer, Integer> MANAGER_ZONES = new HashMap<>();
static
{
MANAGER_ZONES.put(CONQUEROR_MANAGER, CONQUEROR_ZONE);
MANAGER_ZONES.put(EMPEROR_MANAGER, EMPEROR_ZONE);
MANAGER_ZONES.put(GREAT_SAGES_MANAGER, GREAT_SAGES_ZONE);
MANAGER_ZONES.put(JUDGE_MANAGER, JUDGE_ZONE);
}
// Spawns
private static List<int[]> ROOM_SPAWN_DATA = new ArrayList<>();
private static final Map<Integer, List<Npc>> STORED_MONSTER_SPAWNS = new HashMap<>();
static
{
STORED_MONSTER_SPAWNS.put(1, new CopyOnWriteArrayList<>());
STORED_MONSTER_SPAWNS.put(2, new CopyOnWriteArrayList<>());
STORED_MONSTER_SPAWNS.put(3, new CopyOnWriteArrayList<>());
STORED_MONSTER_SPAWNS.put(4, new CopyOnWriteArrayList<>());
}
// @formatter:off
private static final int[][] CHEST_SPAWN_LOCATIONS =
{
// sepulcherId, roomNumber, npcLocX, npcLocY, npcLocZ, npcLocHeading
{1, 1, 182074, -85579, -7216, 32768},
{1, 2, 183868, -85577, -7216, 32768},
{1, 3, 185681, -85573, -7216, 32768},
{1, 4, 187498, -85566, -7216, 32768},
{1, 5, 189306, -85571, -7216, 32768},
{2, 1, 180375, -88968, -7216, 32768},
{2, 2, 182151, -88962, -7216, 32768},
{2, 3, 183960, -88964, -7216, 32768},
{2, 4, 185792, -88966, -7216, 32768},
{2, 5, 187625, -88953, -7216, 32768},
{3, 1, 173218, -85703, -7216, 49152},
{3, 2, 173206, -83929, -7216, 49152},
{3, 3, 173208, -82085, -7216, 49152},
{3, 4, 173191, -80290, -7216, 49152},
{3, 5, 173198, -78465, -7216, 49152},
{4, 1, 175601, -81905, -7216, 49152},
{4, 2, 175619, -80094, -7216, 49152},
{4, 3, 175608, -78268, -7216, 49152},
{4, 4, 175588, -76472, -7216, 49152},
{4, 5, 175594, -74655, -7216, 49152},
};
// Doors
private static final int[][] DOORS =
{
// sepulcherId, waveNumber, doorId
{1, 2, 25150012}, {1, 3, 25150013}, {1, 4, 25150014}, {1, 5, 25150015}, {1, 7, 25150016},
{2, 2, 25150002}, {2, 3, 25150003}, {2, 4, 25150004}, {2, 5, 25150005}, {2, 7, 25150006},
{3, 2, 25150032}, {3, 3, 25150033}, {3, 4, 25150034}, {3, 5, 25150035}, {3, 7, 25150036},
{4, 2, 25150022}, {4, 3, 25150023}, {4, 4, 25150024}, {4, 5, 25150025}, {4, 7, 25150026},
};
// @formatter:on
// Skill
private static final SkillHolder PETRIFY = new SkillHolder(4616, 1);
private static final Map<Integer, Integer> CHARM_SKILLS = new HashMap<>();
static
{
CHARM_SKILLS.put(ROOM_4_CHARM_1, 4146);
CHARM_SKILLS.put(ROOM_4_CHARM_2, 4145);
CHARM_SKILLS.put(ROOM_4_CHARM_3, 4148);
CHARM_SKILLS.put(ROOM_4_CHARM_4, 4624);
}
// Misc
private static final Map<Integer, NpcStringId> CHARM_MSG = new HashMap<>();
static
{
CHARM_MSG.put(ROOM_4_CHARM_1, NpcStringId.THE_P_ATK_REDUCTION_DEVICE_HAS_NOW_BEEN_DESTROYED);
CHARM_MSG.put(ROOM_4_CHARM_2, NpcStringId.THE_P_ATK_REDUCTION_DEVICE_HAS_NOW_BEEN_DESTROYED); // TODO: THE_DEFENSE_REDUCTION_DEVICE_HAS_BEEN_DESTROYED
CHARM_MSG.put(ROOM_4_CHARM_3, NpcStringId.THE_POISON_DEVICE_HAS_NOW_BEEN_DESTROYED);
CHARM_MSG.put(ROOM_4_CHARM_4, NpcStringId.THE_POISON_DEVICE_HAS_NOW_BEEN_DESTROYED); // TODO: THE_HP_REGENERATION_REDUCTION_DEVICE_WILL_BE_ACTIVATED_IN_3_MINUTES2
}
private static final NpcStringId[] VICTIM_MSG =
{
NpcStringId.HELP_ME,
NpcStringId.DON_T_MISS,
NpcStringId.KEEP_PUSHING,
};
private static final Map<Integer, Integer> STORED_PROGRESS = new HashMap<>();
static
{
STORED_PROGRESS.put(1, 1);
STORED_PROGRESS.put(2, 1);
STORED_PROGRESS.put(3, 1);
STORED_PROGRESS.put(4, 1);
}
private static final int PARTY_MEMBER_COUNT = 4;
private static final int ENTRY_DELAY = 3; // minutes
private static final int TIME_ATTACK = 60; // minutes
private FourSepulchers()
{
load();
addFirstTalkId(CONQUEROR_MANAGER, EMPEROR_MANAGER, GREAT_SAGES_MANAGER, JUDGE_MANAGER, MYSTERIOUS_CHEST, KEY_CHEST);
addTalkId(CONQUEROR_MANAGER, EMPEROR_MANAGER, GREAT_SAGES_MANAGER, JUDGE_MANAGER, MYSTERIOUS_CHEST, KEY_CHEST);
addFirstTalkId(FIRST_TALK_NPCS);
addTalkId(FIRST_TALK_NPCS);
addKillId(CHEST_REWARD_MONSTERS);
addKillId(ROOM_3_VICTIM, ROOM_4_CHARM_1, ROOM_4_CHARM_2, ROOM_4_CHARM_3, ROOM_4_CHARM_4, ROOM_6_REWARD_CHEST, CONQUEROR_BOSS, EMPEROR_BOSS, GREAT_SAGES_BOSS, JUDGE_BOSS);
addSpawnId(ROOM_3_VICTIM, ROOM_4_CHARM_1, ROOM_4_CHARM_2, ROOM_4_CHARM_3, ROOM_4_CHARM_4, ROOM_5_STATUE_GUARD, ROOM_6_REWARD_CHEST, CONQUEROR_BOSS, EMPEROR_BOSS, GREAT_SAGES_BOSS, JUDGE_BOSS);
}
@Override
public String onAdvEvent(String event, Npc npc, PlayerInstance player)
{
String htmltext = event;
switch (event)
{
case "Enter":
{
final QuestState qs = player.getQuestState(Q00620_FourGoblets.class.getSimpleName());
if (qs == null)
{
return getNoQuestMsg(player);
}
if (qs.isStarted())
{
tryEnter(npc, player);
return null;
}
break;
}
case "OpenGate":
{
final QuestState qs = player.getQuestState(Q00620_FourGoblets.class.getSimpleName());
if (qs == null)
{
return getNoQuestMsg(player);
}
if (qs.isStarted() && (npc.getScriptValue() == 0))
{
if (hasQuestItems(player, CHAPEL_KEY))
{
npc.setScriptValue(1);
takeItems(player, CHAPEL_KEY, -1);
final int sepulcherId = getSepulcherId(player);
final int currentWave = STORED_PROGRESS.get(sepulcherId) + 1;
STORED_PROGRESS.put(sepulcherId, currentWave); // update progress
for (int[] doorInfo : DOORS)
{
if ((doorInfo[0] == sepulcherId) && (doorInfo[1] == currentWave))
{
openDoor(doorInfo[2], 0);
ThreadPool.schedule(() ->
{
closeDoor(doorInfo[2], 0);
}, 15000);
break;
}
}
if (currentWave < 7)
{
spawnMysteriousChest(player);
}
else
{
spawnNextWave(player);
}
npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.THE_MONSTERS_HAVE_SPAWNED);
}
else
{
final NpcHtmlMessage html = new NpcHtmlMessage(npc.getObjectId());
html.setFile(player, "data/scripts/ai/areas/ImperialTomb/FourSepulchers/Gatekeeper-no.html");
html.replace("%npcname%", npc.getName());
player.sendPacket(html);
}
return null;
}
htmltext = getNoQuestMsg(player); // TODO: Replace with proper html?
break;
}
case "SPAWN_MYSTERIOUS_CHEST":
{
spawnMysteriousChest(player);
return null;
}
case "VICTIM_FLEE":
{
if ((npc != null) && !npc.isDead())
{
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), npc.getSpawn().getLocation().getX() + getRandom(-400, 400), npc.getSpawn().getLocation().getY() + getRandom(-400, 400), npc.getZ(), npc.getInstanceWorld());
if (Util.calculateDistance(npc, npc.getSpawn().getLocation(), false, false) < 600)
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
}
npc.broadcastSay(ChatType.NPC_GENERAL, VICTIM_MSG[getRandom(VICTIM_MSG.length)]);
startQuestTimer("VICTIM_FLEE", 3000, npc, null, false);
}
return null;
}
case "REMOVE_PETRIFY":
{
npc.stopSkillEffects(PETRIFY.getSkill());
npc.setTargetable(true);
npc.setIsInvul(false);
return null;
}
case "WAVE_DEFEATED_CHECK":
{
final int sepulcherId = getSepulcherId(player);
final int currentWave = STORED_PROGRESS.get(sepulcherId);
Location lastLocation = null;
for (Npc spawn : STORED_MONSTER_SPAWNS.get(sepulcherId))
{
lastLocation = spawn.getLocation();
if (spawn.isDead())
{
STORED_MONSTER_SPAWNS.get(sepulcherId).remove(spawn);
}
}
if (STORED_MONSTER_SPAWNS.get(sepulcherId).isEmpty())
{
if (currentWave == 2)
{
if (getRandomBoolean())
{
spawnNextWave(player);
}
else
{
spawnKeyChest(player, lastLocation);
}
}
else if (currentWave == 5)
{
STORED_PROGRESS.put(sepulcherId, currentWave + 1);
spawnNextWave(player);
}
}
else if (sepulcherId > 0)
{
startQuestTimer("WAVE_DEFEATED_CHECK", 5000, null, player, false);
}
return null;
}
}
return htmltext;
}
@Override
public String onFirstTalk(Npc npc, PlayerInstance player)
{
if (npc == null)
{
return null;
}
if (npc.getId() == MYSTERIOUS_CHEST)
{
if (npc.getScriptValue() == 0)
{
npc.setScriptValue(1);
npc.deleteMe();
spawnNextWave(player);
}
return null;
}
if (npc.getId() == KEY_CHEST)
{
if (npc.getScriptValue() == 0)
{
npc.setScriptValue(1);
npc.deleteMe();
giveItems(player, CHAPEL_KEY, 1);
}
return null;
}
return npc.getId() + ".html";
}
@Override
public String onSpawn(Npc npc)
{
npc.setRandomWalking(false);
if (npc.getId() == ROOM_3_VICTIM)
{
npc.disableCoreAI(true);
npc.setRunning();
startQuestTimer("VICTIM_FLEE", 1000, npc, null, false);
}
if (npc.getId() == ROOM_5_STATUE_GUARD)
{
npc.setTarget(npc);
npc.doCast(PETRIFY.getSkill());
((Attackable) npc).setCanReturnToSpawnPoint(false);
npc.setTargetable(false);
npc.setIsInvul(true);
cancelQuestTimer("REMOVE_PETRIFY", npc, null);
startQuestTimer("REMOVE_PETRIFY", 5 * 60 * 1000, npc, null, false); // 5 minutes
}
return super.onSpawn(npc);
}
@Override
public String onKill(Npc npc, PlayerInstance killer, boolean isSummon)
{
switch (npc.getId())
{
case ROOM_3_VICTIM:
{
addSpawn(ROOM_3_CHEST_REWARDER, npc);
break;
}
case ROOM_4_CHARM_1:
case ROOM_4_CHARM_2:
case ROOM_4_CHARM_3:
case ROOM_4_CHARM_4:
{
for (ZoneType zone : ZoneManager.getInstance().getZones(killer))
{
if ((zone instanceof EffectZone) && (((EffectZone) zone).getSkillLevel(CHARM_SKILLS.get(npc.getId())) > 0))
{
zone.setEnabled(false);
break;
}
}
npc.broadcastSay(ChatType.NPC_GENERAL, CHARM_MSG.get(npc.getId()));
break;
}
case CONQUEROR_BOSS:
case EMPEROR_BOSS:
case GREAT_SAGES_BOSS:
case JUDGE_BOSS:
{
final int sepulcherId = getSepulcherId(killer);
final int currentWave = STORED_PROGRESS.get(sepulcherId);
STORED_PROGRESS.put(sepulcherId, currentWave + 1);
if ((killer.getParty() != null) && (sepulcherId > 0))
{
for (PlayerInstance mem : killer.getParty().getMembers())
{
if (Util.checkIfInRange(1500, killer, mem, true))
{
final QuestState qs = killer.getQuestState(Q00620_FourGoblets.class.getSimpleName());
if ((qs != null) && qs.isStarted())
{
giveItems(mem, 7255 + sepulcherId, 1);
}
}
}
}
spawnNextWave(killer);
addSpawn(TELEPORTER, npc, true, 0, false);
break;
}
case ROOM_6_REWARD_CHEST:
{
npc.dropItem(killer, 57, getRandom(300, 1300));
break;
}
default:
{
spawnKeyChest(killer, npc.getLocation());
break;
}
}
return super.onKill(npc, killer, isSummon);
}
private void tryEnter(Npc npc, PlayerInstance player)
{
final int npcId = npc.getId();
if (!ZoneManager.getInstance().getZoneById(MANAGER_ZONES.get(npcId)).getPlayersInside().isEmpty())
{
showHtmlFile(player, npcId + "-FULL.htm", npc, null);
return;
}
if (!player.isInParty() || (player.getParty().getMemberCount() < PARTY_MEMBER_COUNT))
{
showHtmlFile(player, npcId + "-SP.html", npc, null);
return;
}
if (!player.getParty().isLeader(player))
{
showHtmlFile(player, npcId + "-NL.html", npc, null);
return;
}
for (PlayerInstance mem : player.getParty().getMembers())
{
final QuestState qs = mem.getQuestState(Q00620_FourGoblets.class.getSimpleName());
if ((qs == null) || (!qs.isStarted() && !qs.isCompleted()))
{
showHtmlFile(player, npcId + "-NS.html", npc, mem);
return;
}
if (!hasQuestItems(mem, ENTRANCE_PASS))
{
showHtmlFile(player, npcId + "-SE.html", npc, mem);
return;
}
if (player.getWeightPenalty() >= 3)
{
mem.sendPacket(SystemMessageId.UNABLE_TO_PROCESS_THIS_REQUEST_UNTIL_YOUR_INVENTORY_S_WEIGHT_AND_SLOT_COUNT_ARE_LESS_THAN_80_PERCENT_OF_CAPACITY);
return;
}
}
final GlobalVariablesManager vars = GlobalVariablesManager.getInstance();
final long var = vars.getLong("FourSepulchers" + npcId, 0) + (TIME_ATTACK * 60 * 1000);
if (var > System.currentTimeMillis())
{
showHtmlFile(player, npcId + "-NE.html", npc, null);
return;
}
final int sepulcherId = getSepulcherId(player);
// Delete any existing spawns
for (Creature creature : ZoneManager.getInstance().getZoneById(MANAGER_ZONES.get(npcId)).getCharactersInside())
{
if (creature.isMonster() || creature.isRaid() || (creature.isNpc() && ((((Npc) creature).getId() == MYSTERIOUS_CHEST) || (((Npc) creature).getId() == KEY_CHEST) || (((Npc) creature).getId() == TELEPORTER))))
{
creature.deleteMe();
}
}
// Disable EffectZones
for (int[] spawnInfo : CHEST_SPAWN_LOCATIONS)
{
if ((spawnInfo[0] == sepulcherId) && (spawnInfo[1] == 4))
{
for (ZoneType zone : ZoneManager.getInstance().getZones(spawnInfo[2], spawnInfo[3], spawnInfo[4]))
{
if (zone instanceof EffectZone)
{
zone.setEnabled(false);
}
}
break;
}
}
// Close all doors
for (int[] doorInfo : DOORS)
{
if (doorInfo[0] == sepulcherId)
{
closeDoor(doorInfo[2], 0);
}
}
// Teleport players inside
final List<PlayerInstance> members = new ArrayList<>();
for (PlayerInstance mem : player.getParty().getMembers())
{
if (Util.checkIfInRange(700, player, mem, true))
{
members.add(mem);
}
}
for (PlayerInstance mem : members)
{
mem.teleToLocation(START_HALL_SPAWNS.get(npcId), 80);
takeItems(mem, ENTRANCE_PASS, 1);
takeItems(mem, CHAPEL_KEY, -1);
if (!hasQuestItems(mem, ANTIQUE_BROOCH))
{
giveItems(mem, USED_PASS, 1);
}
}
showHtmlFile(player, npcId + "-OK.html", npc, null);
// Kick all players when/if time is over
ThreadPool.schedule(() ->
{
ZoneManager.getInstance().getZoneById(MANAGER_ZONES.get(npcId)).oustAllPlayers();
}, TIME_ATTACK * 60 * 1000);
// Save attack time
vars.set("FourSepulchers" + npcId, System.currentTimeMillis());
// Init progress
STORED_PROGRESS.put(sepulcherId, 1); // start from 1
// Start
startQuestTimer("SPAWN_MYSTERIOUS_CHEST", ENTRY_DELAY * 60 * 1000, npc, player, false);
}
private void spawnNextWave(PlayerInstance player)
{
final int sepulcherId = getSepulcherId(player);
final int currentWave = STORED_PROGRESS.get(sepulcherId);
for (int[] spawnInfo : ROOM_SPAWN_DATA)
{
if ((spawnInfo[0] == sepulcherId) && (spawnInfo[1] == currentWave))
{
STORED_MONSTER_SPAWNS.get(sepulcherId).add(addSpawn(spawnInfo[2], spawnInfo[3], spawnInfo[4], spawnInfo[5], spawnInfo[6], false, 0));
}
}
if (currentWave == 4)
{
for (ZoneType zone : ZoneManager.getInstance().getZones(player))
{
if (zone instanceof EffectZone)
{
zone.setEnabled(true);
}
}
}
if ((currentWave == 2) || (currentWave == 5))
{
startQuestTimer("WAVE_DEFEATED_CHECK", 5000, null, player, false);
}
else
{
STORED_MONSTER_SPAWNS.get(sepulcherId).clear(); // no need check for these waves
}
}
private void spawnMysteriousChest(PlayerInstance player)
{
final int sepulcherId = getSepulcherId(player);
final int currentWave = STORED_PROGRESS.get(sepulcherId);
for (int[] spawnInfo : CHEST_SPAWN_LOCATIONS)
{
if ((spawnInfo[0] == sepulcherId) && (spawnInfo[1] == currentWave))
{
addSpawn(MYSTERIOUS_CHEST, spawnInfo[2], spawnInfo[3], spawnInfo[4], spawnInfo[5], false, 0);
break;
}
}
}
private void spawnKeyChest(PlayerInstance player, Location loc)
{
addSpawn(KEY_CHEST, loc != null ? loc : player);
}
private int getSepulcherId(PlayerInstance player)
{
if (ZoneManager.getInstance().getZoneById(CONQUEROR_ZONE).getPlayersInside().contains(player))
{
return 1;
}
if (ZoneManager.getInstance().getZoneById(EMPEROR_ZONE).getPlayersInside().contains(player))
{
return 2;
}
if (ZoneManager.getInstance().getZoneById(GREAT_SAGES_ZONE).getPlayersInside().contains(player))
{
return 3;
}
if (ZoneManager.getInstance().getZoneById(JUDGE_ZONE).getPlayersInside().contains(player))
{
return 4;
}
return 0;
}
private void showHtmlFile(PlayerInstance player, String file, Npc npc, PlayerInstance member)
{
final NpcHtmlMessage html = new NpcHtmlMessage(npc.getObjectId());
html.setFile(player, "data/scripts/ai/areas/ImperialTomb/FourSepulchers/" + file);
if (member != null)
{
html.replace("%member%", member.getName());
}
player.sendPacket(html);
}
@Override
public void load()
{
ROOM_SPAWN_DATA.clear();
parseDatapackFile("data/scripts/ai/areas/ImperialTomb/FourSepulchers/FourSepulchers.xml");
LOGGER.info("[Four Sepulchers] Loaded " + ROOM_SPAWN_DATA.size() + " spawn zones data.");
}
@Override
public void parseDocument(Document doc, File f)
{
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node b = n.getFirstChild(); b != null; b = b.getNextSibling())
{
if ("spawn".equalsIgnoreCase(b.getNodeName()))
{
final NamedNodeMap attrs = b.getAttributes();
final int[] info =
{
parseInteger(attrs, "sepulcherId"),
parseInteger(attrs, "wave"),
parseInteger(attrs, "npcId"),
parseInteger(attrs, "x"),
parseInteger(attrs, "y"),
parseInteger(attrs, "z"),
parseInteger(attrs, "heading")
};
ROOM_SPAWN_DATA.add(info);
}
}
}
}
}
public static void main(String[] args)
{
new FourSepulchers();
}
}

View File

@@ -0,0 +1,797 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FourSepulchers.xsd">
<!-- SEPULCHER 1 - ROOM 1 -->
<spawn sepulcherId="1" wave="1" npcId="18120" x="182214" y="-85572" z="-7219" heading="53601" /> <!-- key rewarder -->
<spawn sepulcherId="1" wave="1" npcId="18132" x="181626" y="-85799" z="-7218" heading="48022" />
<spawn sepulcherId="1" wave="1" npcId="18132" x="182223" y="-85833" z="-7220" heading="50241" />
<spawn sepulcherId="1" wave="1" npcId="18132" x="181850" y="-85294" z="-7220" heading="20973" />
<spawn sepulcherId="1" wave="1" npcId="18132" x="182260" y="-85353" z="-7218" heading="15208" />
<spawn sepulcherId="1" wave="1" npcId="18133" x="181953" y="-85506" z="-7219" heading="38327" />
<spawn sepulcherId="1" wave="1" npcId="18133" x="181639" y="-85397" z="-7218" heading="20774" />
<spawn sepulcherId="1" wave="1" npcId="18133" x="182364" y="-86036" z="-7220" heading="664" />
<spawn sepulcherId="1" wave="1" npcId="18133" x="182292" y="-85306" z="-7220" heading="11807" />
<spawn sepulcherId="1" wave="1" npcId="18137" x="182499" y="-85379" z="-7218" heading="11039" />
<spawn sepulcherId="1" wave="1" npcId="18137" x="181872" y="-85232" z="-7220" heading="12920" />
<spawn sepulcherId="1" wave="1" npcId="18137" x="181933" y="-85500" z="-7216" heading="41059" />
<spawn sepulcherId="1" wave="1" npcId="18137" x="181668" y="-85847" z="-7220" heading="41059" />
<spawn sepulcherId="1" wave="1" npcId="18137" x="181921" y="-85909" z="-7216" heading="34037" />
<spawn sepulcherId="1" wave="1" npcId="18137" x="182257" y="-85886" z="-7220" heading="39472" />
<!-- SEPULCHER 1 - ROOM 2 -->
<spawn sepulcherId="1" wave="2" npcId="18141" x="183799" y="-85246" z="-7217" heading="3307" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="184179" y="-85391" z="-7218" heading="51226" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="184153" y="-85262" z="-7220" heading="65064" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="184192" y="-85541" z="-7219" heading="50053" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="183812" y="-85901" z="-7220" heading="55728" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="184236" y="-85883" z="-7216" heading="442" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="183629" y="-85903" z="-7220" heading="26470" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="183631" y="-85653" z="-7219" heading="31350" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="183543" y="-85330" z="-7220" heading="9672" />
<spawn sepulcherId="1" wave="2" npcId="18141" x="184213" y="-85694" z="-7219" heading="60977" />
<!-- SEPULCHER 1 - ROOM 3 -->
<spawn sepulcherId="1" wave="3" npcId="18150" x="185710" y="-85584" z="-7218" heading="833" /> <!-- victim -->
<spawn sepulcherId="1" wave="3" npcId="18166" x="185513" y="-85415" z="-7218" heading="29444" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185336" y="-85408" z="-7218" heading="22923" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185548" y="-85174" z="-7220" heading="4022" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185376" y="-85823" z="-7220" heading="18091" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185413" y="-86047" z="-7220" heading="33824" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185442" y="-85589" z="-7219" heading="13516" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185807" y="-85664" z="-7219" heading="64429" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185777" y="-86010" z="-7220" heading="42735" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185895" y="-85843" z="-7220" heading="53917" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185282" y="-85282" z="-7220" heading="27319" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="186031" y="-85572" z="-7219" heading="47324" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="186170" y="-85879" z="-7220" heading="53586" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="186220" y="-85157" z="-7220" heading="40777" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185858" y="-85220" z="-7220" heading="63999" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="186071" y="-85346" z="-7220" heading="59964" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="186050" y="-85970" z="-7220" heading="59476" />
<spawn sepulcherId="1" wave="3" npcId="18166" x="185489" y="-85616" z="-7219" heading="44597" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="186220" y="-86036" z="-7220" heading="61673" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="185884" y="-85339" z="-7220" heading="3121" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="185696" y="-85397" z="-7218" heading="58467" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="185774" y="-85843" z="-7220" heading="26341" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="185524" y="-85895" z="-7219" heading="34907" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="185524" y="-85895" z="-7216" heading="22369" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="185450" y="-85199" z="-7219" heading="3565" />
<spawn sepulcherId="1" wave="3" npcId="18171" x="185233" y="-85336" z="-7220" heading="20883" />
<!-- SEPULCHER 1 - ROOM 4 -->
<spawn sepulcherId="1" wave="4" npcId="18177" x="187536" y="-85561" z="-7219" heading="30267" /> <!-- key rewarder -->
<spawn sepulcherId="1" wave="4" npcId="18196" x="186903" y="-85044" z="-7216" heading="55684" /> <!-- charm -->
<spawn sepulcherId="1" wave="4" npcId="18197" x="188101" y="-85059" z="-7220" heading="38092" /> <!-- charm -->
<spawn sepulcherId="1" wave="4" npcId="18198" x="188115" y="-86084" z="-7220" heading="24830" /> <!-- charm -->
<spawn sepulcherId="1" wave="4" npcId="18199" x="186895" y="-86092" z="-7220" heading="9770" /> <!-- charm -->
<spawn sepulcherId="1" wave="4" npcId="18185" x="187904" y="-85328" z="-7220" heading="8357" />
<spawn sepulcherId="1" wave="4" npcId="18185" x="187696" y="-85307" z="-7220" heading="31718" />
<spawn sepulcherId="1" wave="4" npcId="18185" x="187690" y="-85705" z="-7219" heading="14402" />
<spawn sepulcherId="1" wave="4" npcId="18185" x="187428" y="-85743" z="-7219" heading="48912" />
<spawn sepulcherId="1" wave="4" npcId="18185" x="187135" y="-85904" z="-7220" heading="38008" />
<spawn sepulcherId="1" wave="4" npcId="18185" x="187235" y="-85292" z="-7220" heading="32428" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187955" y="-85906" z="-7220" heading="57628" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187907" y="-85704" z="-7219" heading="19115" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187645" y="-85421" z="-7219" heading="41743" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187774" y="-85271" z="-7216" heading="19492" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187419" y="-85213" z="-7220" heading="25008" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187144" y="-85228" z="-7220" heading="33336" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187066" y="-85410" z="-7218" heading="44928" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187575" y="-85835" z="-7220" heading="469" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187052" y="-85592" z="-7219" heading="48351" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187102" y="-85839" z="-7220" heading="51235" />
<spawn sepulcherId="1" wave="4" npcId="18187" x="187245" y="-85956" z="-7220" heading="58383" />
<!-- SEPULCHER 1 - ROOM 5 (First Wave) -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189912" y="-86051" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189910" y="-85977" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189917" y="-85844" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189924" y="-85911" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189932" y="-85337" z="-7216" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189912" y="-85183" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189927" y="-85265" z="-7216" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18232" x="189910" y="-85102" z="-7216" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="5" npcId="18220" x="189602" y="-85381" z="-7218" heading="16239" />
<spawn sepulcherId="1" wave="5" npcId="18220" x="189433" y="-85782" z="-7218" heading="44991" />
<spawn sepulcherId="1" wave="5" npcId="18220" x="189065" y="-85279" z="-7220" heading="14628" />
<spawn sepulcherId="1" wave="5" npcId="18220" x="188986" y="-85744" z="-7218" heading="31883" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189573" y="-85560" z="-7219" heading="53861" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189444" y="-85294" z="-7220" heading="9381" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189328" y="-85440" z="-7219" heading="59806" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189065" y="-85279" z="-7220" heading="14628" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189214" y="-85161" z="-7220" heading="3036" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189002" y="-85428" z="-7219" heading="10979" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="188937" y="-85244" z="-7220" heading="19925" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="188880" y="-85642" z="-7219" heading="13008" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="188827" y="-85800" z="-7220" heading="18494" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="188859" y="-85956" z="-7220" heading="37418" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189018" y="-85880" z="-7220" heading="43207" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189134" y="-85699" z="-7219" heading="25695" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189319" y="-85848" z="-7220" heading="25290" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189467" y="-85977" z="-7219" heading="40733" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189632" y="-85819" z="-7220" heading="45368" />
<spawn sepulcherId="1" wave="5" npcId="18222" x="189736" y="-85545" z="-7219" heading="957" />
<spawn sepulcherId="1" wave="5" npcId="18226" x="189498" y="-85844" z="-7220" heading="58569" />
<spawn sepulcherId="1" wave="5" npcId="18226" x="189760" y="-85847" z="-7220" heading="65416" />
<spawn sepulcherId="1" wave="5" npcId="18226" x="189247" y="-85646" z="-7219" heading="39071" />
<spawn sepulcherId="1" wave="5" npcId="18226" x="189185" y="-85236" z="-7220" heading="31522" />
<spawn sepulcherId="1" wave="5" npcId="18226" x="188835" y="-85216" z="-7220" heading="32172" />
<spawn sepulcherId="1" wave="5" npcId="18226" x="189585" y="-85284" z="-7220" heading="17265" />
<spawn sepulcherId="1" wave="5" npcId="18226" x="189615" y="-85638" z="-7219" heading="11763" />
<!-- SEPULCHER 1 - ROOM 5 (Second Wave) -->
<spawn sepulcherId="1" wave="6" npcId="18212" x="189403" y="-85583" z="-7219" heading="29699" /> <!-- key rewarder -->
<spawn sepulcherId="1" wave="6" npcId="18232" x="190030" y="-85669" z="-7219" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="6" npcId="18232" x="190038" y="-85583" z="-7219" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="6" npcId="18232" x="190037" y="-85497" z="-7219" heading="32768" /> <!-- statue -->
<spawn sepulcherId="1" wave="6" npcId="18195" x="189357" y="-85356" z="-7218" heading="7328" />
<spawn sepulcherId="1" wave="6" npcId="18195" x="189136" y="-85943" z="-7220" heading="31470" />
<spawn sepulcherId="1" wave="6" npcId="18195" x="189504" y="-85989" z="-7218" heading="51090" />
<spawn sepulcherId="1" wave="6" npcId="18195" x="189070" y="-85599" z="-7219" heading="18361" />
<spawn sepulcherId="1" wave="6" npcId="18221" x="189594" y="-85322" z="-7220" heading="20071" />
<spawn sepulcherId="1" wave="6" npcId="18221" x="188987" y="-85288" z="-7220" heading="19394" />
<spawn sepulcherId="1" wave="6" npcId="18221" x="189232" y="-85782" z="-7218" heading="53954" />
<spawn sepulcherId="1" wave="6" npcId="18221" x="189706" y="-85857" z="-7216" heading="63899" />
<spawn sepulcherId="1" wave="6" npcId="18223" x="189533" y="-85989" z="-7217" heading="60516" />
<spawn sepulcherId="1" wave="6" npcId="18223" x="189813" y="-85246" z="-7220" heading="3484" />
<spawn sepulcherId="1" wave="6" npcId="18223" x="189630" y="-85603" z="-7219" heading="6643" />
<spawn sepulcherId="1" wave="6" npcId="18223" x="189335" y="-85187" z="-7220" heading="32827" />
<spawn sepulcherId="1" wave="6" npcId="18223" x="189223" y="-85456" z="-7219" heading="19322" />
<spawn sepulcherId="1" wave="6" npcId="18223" x="188986" y="-85810" z="-7218" heading="42998" />
<spawn sepulcherId="1" wave="6" npcId="18227" x="189029" y="-85851" z="-7220" heading="50392" />
<spawn sepulcherId="1" wave="6" npcId="18227" x="189165" y="-85302" z="-7220" heading="8388" />
<spawn sepulcherId="1" wave="6" npcId="18227" x="188905" y="-85572" z="-7219" heading="32328" />
<spawn sepulcherId="1" wave="6" npcId="18227" x="189535" y="-85820" z="-7220" heading="4267" />
<spawn sepulcherId="1" wave="6" npcId="18227" x="189688" y="-85478" z="-7219" heading="11996" />
<!-- SEPULCHER 1 - ROOM 6 (Boss) -->
<spawn sepulcherId="1" wave="7" npcId="25346" x="191225" y="-85574" z="-7219" heading="32768" />
<!-- SEPULCHER 1 - ROOM 6 (After Fight) -->
<spawn sepulcherId="1" wave="8" npcId="18256" x="191196" y="-85211" z="-7217" heading="54880" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190811" y="-85324" z="-7220" heading="47417" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190958" y="-85368" z="-7217" heading="62502" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190813" y="-85413" z="-7220" heading="9736" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190948" y="-85157" z="-7220" heading="35471" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191124" y="-85089" z="-7220" heading="18426" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190963" y="-85239" z="-7217" heading="8963" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191048" y="-85380" z="-7217" heading="64153" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191179" y="-85564" z="-7217" heading="55373" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190956" y="-85553" z="-7217" heading="33403" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191169" y="-85540" z="-7217" heading="30012" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190716" y="-85544" z="-7217" heading="32377" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190880" y="-85819" z="-7217" heading="32609" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191064" y="-85913" z="-7217" heading="64993" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190869" y="-85906" z="-7217" heading="47840" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190968" y="-85908" z="-7217" heading="65325" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191012" y="-85821" z="-7217" heading="32639" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191514" y="-86163" z="-7220" heading="3829" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191262" y="-86099" z="-7220" heading="53048" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191449" y="-86188" z="-7220" heading="62329" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191804" y="-85880" z="-7220" heading="17061" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191712" y="-86036" z="-7220" heading="11944" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191588" y="-85839" z="-7217" heading="31438" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191762" y="-86140" z="-7220" heading="59561" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191812" y="-86003" z="-7220" heading="12733" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191678" y="-86111" z="-7220" heading="3202" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191660" y="-85672" z="-7220" heading="32660" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191757" y="-85673" z="-7220" heading="18712" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191406" y="-85942" z="-7217" heading="63246" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191593" y="-86031" z="-7220" heading="60902" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191291" y="-85573" z="-7217" heading="29939" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191666" y="-85849" z="-7220" heading="50363" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191419" y="-85892" z="-7217" heading="37740" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191285" y="-85915" z="-7217" heading="65441" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191116" y="-85398" z="-7217" heading="62836" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191474" y="-85831" z="-7217" heading="32037" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191298" y="-85355" z="-7217" heading="55580" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191160" y="-85543" z="-7217" heading="21543" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191081" y="-85567" z="-7217" heading="33087" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191478" y="-85625" z="-7217" heading="30132" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191317" y="-85830" z="-7217" heading="32701" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191204" y="-85856" z="-7217" heading="58175" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191174" y="-85823" z="-7217" heading="32257" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191213" y="-85974" z="-7216" heading="49946" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191062" y="-85735" z="-7217" heading="53557" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191124" y="-85483" z="-7217" heading="50130" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="190991" y="-85577" z="-7217" heading="33922" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191125" y="-85095" z="-7220" heading="7579" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191474" y="-85153" z="-7220" heading="18365" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191423" y="-85094" z="-7220" heading="33696" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191586" y="-85103" z="-7220" heading="64960" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191404" y="-85197" z="-7216" heading="16187" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191482" y="-85263" z="-7217" heading="55555" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191403" y="-85250" z="-7217" heading="8191" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191479" y="-85089" z="-7220" heading="15570" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191615" y="-85204" z="-7217" heading="52068" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191484" y="-85205" z="-7217" heading="13400" />
<spawn sepulcherId="1" wave="8" npcId="18256" x="191323" y="-86148" z="-7220" heading="58477" />
<!-- SEPULCHER 2 - ROOM 1 -->
<spawn sepulcherId="2" wave="1" npcId="18120" x="180696" y="-88974" z="-7218" heading="213" /> <!-- key rewarder -->
<spawn sepulcherId="2" wave="1" npcId="18132" x="180855" y="-88602" z="-7219" heading="43355" />
<spawn sepulcherId="2" wave="1" npcId="18132" x="179966" y="-88624" z="-7215" heading="59734" />
<spawn sepulcherId="2" wave="1" npcId="18132" x="180376" y="-88623" z="-7219" heading="49152" />
<spawn sepulcherId="2" wave="1" npcId="18132" x="179955" y="-89309" z="-7219" heading="5304" />
<spawn sepulcherId="2" wave="1" npcId="18133" x="180685" y="-89250" z="-7219" heading="24773" />
<spawn sepulcherId="2" wave="1" npcId="18133" x="180167" y="-88737" z="-7220" heading="55285" />
<spawn sepulcherId="2" wave="1" npcId="18133" x="180153" y="-89322" z="-7219" heading="10102" />
<spawn sepulcherId="2" wave="1" npcId="18133" x="180744" y="-88787" z="-7217" heading="33539" />
<spawn sepulcherId="2" wave="1" npcId="18137" x="179979" y="-88951" z="-7218" heading="56294" />
<spawn sepulcherId="2" wave="1" npcId="18137" x="180187" y="-88971" z="-7218" heading="32131" />
<spawn sepulcherId="2" wave="1" npcId="18137" x="179962" y="-88790" z="-7217" heading="17482" />
<spawn sepulcherId="2" wave="1" npcId="18137" x="180367" y="-89168" z="-7217" heading="29297" />
<spawn sepulcherId="2" wave="1" npcId="18137" x="180559" y="-88787" z="-7217" heading="374" />
<spawn sepulcherId="2" wave="1" npcId="18137" x="180589" y="-88974" z="-7218" heading="33297" />
<!-- SEPULCHER 2 - ROOM 2 -->
<spawn sepulcherId="2" wave="2" npcId="18141" x="182096" y="-88646" z="-7217" heading="3307" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="182476" y="-88791" z="-7218" heading="51226" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="182450" y="-88662" z="-7220" heading="65064" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="182489" y="-88941" z="-7219" heading="50053" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="182109" y="-89301" z="-7220" heading="55728" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="182533" y="-89283" z="-7216" heading="442" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="181926" y="-89303" z="-7220" heading="26470" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="181928" y="-89053" z="-7219" heading="31350" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="181840" y="-88730" z="-7220" heading="9672" />
<spawn sepulcherId="2" wave="2" npcId="18141" x="182510" y="-89094" z="-7219" heading="60977" />
<!-- SEPULCHER 2 - ROOM 3 -->
<spawn sepulcherId="2" wave="3" npcId="18150" x="184007" y="-88984" z="-7218" heading="833" /> <!-- victim -->
<spawn sepulcherId="2" wave="3" npcId="18166" x="183810" y="-88815" z="-7218" heading="29444" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="183633" y="-88808" z="-7218" heading="22923" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="183845" y="-88574" z="-7220" heading="4022" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="183673" y="-89223" z="-7220" heading="18091" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="183710" y="-89447" z="-7220" heading="33824" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="183739" y="-88989" z="-7219" heading="13516" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184104" y="-89064" z="-7219" heading="64429" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184074" y="-89410" z="-7220" heading="42735" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184192" y="-89243" z="-7220" heading="53917" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="183579" y="-88682" z="-7220" heading="27319" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184328" y="-88972" z="-7219" heading="47324" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184467" y="-89279" z="-7220" heading="53586" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184517" y="-88557" z="-7220" heading="40777" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184155" y="-88620" z="-7220" heading="63999" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184368" y="-88746" z="-7220" heading="59964" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="184347" y="-89370" z="-7220" heading="59476" />
<spawn sepulcherId="2" wave="3" npcId="18166" x="183786" y="-89016" z="-7219" heading="44597" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="184517" y="-89436" z="-7220" heading="61673" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="184181" y="-88739" z="-7220" heading="3121" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="183993" y="-88797" z="-7218" heading="58467" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="184071" y="-89243" z="-7220" heading="26341" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="183821" y="-89295" z="-7219" heading="34907" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="183821" y="-89295" z="-7216" heading="22369" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="183747" y="-88599" z="-7219" heading="3565" />
<spawn sepulcherId="2" wave="3" npcId="18171" x="183530" y="-88736" z="-7220" heading="20883" />
<!-- SEPULCHER 2 - ROOM 4 -->
<spawn sepulcherId="2" wave="4" npcId="18177" x="185833" y="-88961" z="-7219" heading="30267" /> <!-- key rewarder -->
<spawn sepulcherId="2" wave="4" npcId="18196" x="185200" y="-88444" z="-7216" heading="55684" /> <!-- charm -->
<spawn sepulcherId="2" wave="4" npcId="18197" x="186398" y="-88459" z="-7220" heading="38092" /> <!-- charm -->
<spawn sepulcherId="2" wave="4" npcId="18198" x="186412" y="-89484" z="-7220" heading="24830" /> <!-- charm -->
<spawn sepulcherId="2" wave="4" npcId="18199" x="185192" y="-89492" z="-7220" heading="9770" /> <!-- charm -->
<spawn sepulcherId="2" wave="4" npcId="18185" x="186201" y="-88728" z="-7220" heading="8357" />
<spawn sepulcherId="2" wave="4" npcId="18185" x="185993" y="-88707" z="-7220" heading="31718" />
<spawn sepulcherId="2" wave="4" npcId="18185" x="185987" y="-89105" z="-7219" heading="14402" />
<spawn sepulcherId="2" wave="4" npcId="18185" x="185725" y="-89143" z="-7219" heading="48912" />
<spawn sepulcherId="2" wave="4" npcId="18185" x="185432" y="-89304" z="-7220" heading="38008" />
<spawn sepulcherId="2" wave="4" npcId="18185" x="185532" y="-88692" z="-7220" heading="32428" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="186252" y="-89306" z="-7220" heading="57628" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="186204" y="-89104" z="-7219" heading="19115" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185942" y="-88821" z="-7219" heading="41743" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="186071" y="-88671" z="-7216" heading="19492" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185716" y="-88613" z="-7220" heading="25008" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185441" y="-88628" z="-7220" heading="33336" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185363" y="-88810" z="-7218" heading="44928" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185872" y="-89235" z="-7220" heading="469" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185349" y="-88992" z="-7219" heading="48351" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185399" y="-89239" z="-7220" heading="51235" />
<spawn sepulcherId="2" wave="4" npcId="18187" x="185542" y="-89356" z="-7220" heading="58383" />
<!-- SEPULCHER 2 - ROOM 5 (First Wave) -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188209" y="-89451" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188207" y="-89377" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188214" y="-89244" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188221" y="-89311" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188229" y="-88737" z="-7216" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188209" y="-88583" z="-7220" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188224" y="-88665" z="-7216" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18232" x="188207" y="-88502" z="-7216" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="5" npcId="18220" x="187899" y="-88781" z="-7218" heading="16239" />
<spawn sepulcherId="2" wave="5" npcId="18220" x="187730" y="-89182" z="-7218" heading="44991" />
<spawn sepulcherId="2" wave="5" npcId="18220" x="187362" y="-88679" z="-7220" heading="14628" />
<spawn sepulcherId="2" wave="5" npcId="18220" x="187283" y="-89144" z="-7218" heading="31883" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187870" y="-88960" z="-7219" heading="53861" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187741" y="-88694" z="-7220" heading="9381" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187625" y="-88840" z="-7219" heading="59806" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187362" y="-88679" z="-7220" heading="14628" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187511" y="-88561" z="-7220" heading="3036" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187299" y="-88828" z="-7219" heading="10979" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187234" y="-88644" z="-7220" heading="19925" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187177" y="-89042" z="-7219" heading="13008" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187124" y="-89200" z="-7220" heading="18494" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187156" y="-89356" z="-7220" heading="37418" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187315" y="-89280" z="-7220" heading="43207" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187431" y="-89099" z="-7219" heading="25695" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187616" y="-89248" z="-7220" heading="25290" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187764" y="-89377" z="-7219" heading="40733" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="187929" y="-89219" z="-7220" heading="45368" />
<spawn sepulcherId="2" wave="5" npcId="18222" x="188033" y="-88945" z="-7219" heading="957" />
<spawn sepulcherId="2" wave="5" npcId="18226" x="187795" y="-89244" z="-7220" heading="58569" />
<spawn sepulcherId="2" wave="5" npcId="18226" x="188057" y="-89247" z="-7220" heading="65416" />
<spawn sepulcherId="2" wave="5" npcId="18226" x="187544" y="-89046" z="-7219" heading="39071" />
<spawn sepulcherId="2" wave="5" npcId="18226" x="187482" y="-88636" z="-7220" heading="31522" />
<spawn sepulcherId="2" wave="5" npcId="18226" x="187132" y="-88616" z="-7220" heading="32172" />
<spawn sepulcherId="2" wave="5" npcId="18226" x="187882" y="-88684" z="-7220" heading="17265" />
<spawn sepulcherId="2" wave="5" npcId="18226" x="187912" y="-89038" z="-7219" heading="11763" />
<!-- SEPULCHER 2 - ROOM 5 (Second Wave) -->
<spawn sepulcherId="2" wave="6" npcId="18212" x="187700" y="-88983" z="-7219" heading="29699" /> <!-- key rewarder -->
<spawn sepulcherId="2" wave="6" npcId="18232" x="188327" y="-89069" z="-7219" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="6" npcId="18232" x="188335" y="-88983" z="-7219" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="6" npcId="18232" x="188334" y="-88897" z="-7219" heading="32768" /> <!-- statue -->
<spawn sepulcherId="2" wave="6" npcId="18195" x="187654" y="-88756" z="-7218" heading="7328" />
<spawn sepulcherId="2" wave="6" npcId="18195" x="187433" y="-89343" z="-7220" heading="31470" />
<spawn sepulcherId="2" wave="6" npcId="18195" x="187801" y="-89389" z="-7218" heading="51090" />
<spawn sepulcherId="2" wave="6" npcId="18195" x="187367" y="-88999" z="-7219" heading="18361" />
<spawn sepulcherId="2" wave="6" npcId="18221" x="187891" y="-88722" z="-7220" heading="20071" />
<spawn sepulcherId="2" wave="6" npcId="18221" x="187284" y="-88688" z="-7220" heading="19394" />
<spawn sepulcherId="2" wave="6" npcId="18221" x="187529" y="-89182" z="-7218" heading="53954" />
<spawn sepulcherId="2" wave="6" npcId="18221" x="188003" y="-89257" z="-7216" heading="63899" />
<spawn sepulcherId="2" wave="6" npcId="18223" x="187830" y="-89389" z="-7217" heading="60516" />
<spawn sepulcherId="2" wave="6" npcId="18223" x="188110" y="-88646" z="-7220" heading="3484" />
<spawn sepulcherId="2" wave="6" npcId="18223" x="187927" y="-89003" z="-7219" heading="6643" />
<spawn sepulcherId="2" wave="6" npcId="18223" x="187632" y="-88587" z="-7220" heading="32827" />
<spawn sepulcherId="2" wave="6" npcId="18223" x="187520" y="-88856" z="-7219" heading="19322" />
<spawn sepulcherId="2" wave="6" npcId="18223" x="187283" y="-89210" z="-7218" heading="42998" />
<spawn sepulcherId="2" wave="6" npcId="18227" x="187326" y="-89251" z="-7220" heading="50392" />
<spawn sepulcherId="2" wave="6" npcId="18227" x="187462" y="-88702" z="-7220" heading="8388" />
<spawn sepulcherId="2" wave="6" npcId="18227" x="187202" y="-88972" z="-7219" heading="32328" />
<spawn sepulcherId="2" wave="6" npcId="18227" x="187832" y="-89220" z="-7220" heading="4267" />
<spawn sepulcherId="2" wave="6" npcId="18227" x="187985" y="-88878" z="-7219" heading="11996" />
<!-- SEPULCHER 2 - ROOM 6 (Boss) -->
<spawn sepulcherId="2" wave="7" npcId="25342" x="189528" y="-88968" z="-7217" heading="32768" />
<!-- SEPULCHER 2 - ROOM 6 (After Fight) -->
<spawn sepulcherId="2" wave="8" npcId="18256" x="189493" y="-88611" z="-7217" heading="54880" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189108" y="-88724" z="-7220" heading="47417" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189255" y="-88768" z="-7217" heading="62502" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189110" y="-88813" z="-7220" heading="9736" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189245" y="-88557" z="-7220" heading="35471" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189421" y="-88489" z="-7220" heading="18426" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189260" y="-88639" z="-7217" heading="8963" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189345" y="-88780" z="-7217" heading="64153" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189476" y="-88964" z="-7217" heading="55373" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189253" y="-88953" z="-7217" heading="33403" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189466" y="-88940" z="-7217" heading="30012" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189013" y="-88944" z="-7217" heading="32377" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189177" y="-89219" z="-7217" heading="32609" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189361" y="-89313" z="-7217" heading="64993" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189166" y="-89306" z="-7217" heading="47840" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189265" y="-89308" z="-7217" heading="65325" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189309" y="-89221" z="-7217" heading="32639" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189811" y="-89563" z="-7220" heading="3829" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189559" y="-89499" z="-7220" heading="53048" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189746" y="-89588" z="-7220" heading="62329" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="190101" y="-89280" z="-7220" heading="17061" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="190009" y="-89436" z="-7220" heading="11944" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189885" y="-89239" z="-7217" heading="31438" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="190059" y="-89540" z="-7220" heading="59561" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="190109" y="-89403" z="-7220" heading="12733" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189975" y="-89511" z="-7220" heading="3202" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189957" y="-89072" z="-7220" heading="32660" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="190054" y="-89073" z="-7220" heading="18712" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189703" y="-89342" z="-7217" heading="63246" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189890" y="-89431" z="-7220" heading="60902" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189588" y="-88973" z="-7217" heading="29939" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189963" y="-89249" z="-7220" heading="50363" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189716" y="-89292" z="-7217" heading="37740" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189582" y="-89315" z="-7217" heading="65441" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189413" y="-88798" z="-7217" heading="62836" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189771" y="-89231" z="-7217" heading="32037" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189595" y="-88755" z="-7217" heading="55580" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189457" y="-88943" z="-7217" heading="21543" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189378" y="-88967" z="-7217" heading="33087" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189775" y="-89025" z="-7217" heading="30132" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189614" y="-89230" z="-7217" heading="32701" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189501" y="-89256" z="-7217" heading="58175" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189471" y="-89223" z="-7217" heading="32257" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189510" y="-89374" z="-7216" heading="49946" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189359" y="-89135" z="-7217" heading="53557" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189421" y="-88883" z="-7217" heading="50130" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189288" y="-88977" z="-7217" heading="33922" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189422" y="-88495" z="-7220" heading="7579" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189771" y="-88553" z="-7220" heading="18365" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189720" y="-88494" z="-7220" heading="33696" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189883" y="-88503" z="-7220" heading="64960" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189701" y="-88597" z="-7216" heading="16187" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189779" y="-88663" z="-7217" heading="55555" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189700" y="-88650" z="-7217" heading="8191" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189776" y="-88489" z="-7220" heading="15570" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189912" y="-88604" z="-7217" heading="52068" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189781" y="-88605" z="-7217" heading="13400" />
<spawn sepulcherId="2" wave="8" npcId="18256" x="189620" y="-89548" z="-7220" heading="58477" />
<!-- SEPULCHER 3 - ROOM 1 -->
<spawn sepulcherId="3" wave="1" npcId="18120" x="173134" y="-85740" z="-7219" heading="13290" /> <!-- key rewarder -->
<spawn sepulcherId="3" wave="1" npcId="18132" x="173398" y="-85872" z="-7216" heading="1856" />
<spawn sepulcherId="3" wave="1" npcId="18132" x="172956" y="-85939" z="-7220" heading="43362" />
<spawn sepulcherId="3" wave="1" npcId="18132" x="172956" y="-85441" z="-7220" heading="33547" />
<spawn sepulcherId="3" wave="1" npcId="18132" x="172998" y="-85779" z="-7216" heading="15905" />
<spawn sepulcherId="3" wave="1" npcId="18133" x="173242" y="-86112" z="-7219" heading="54294" />
<spawn sepulcherId="3" wave="1" npcId="18133" x="172915" y="-85667" z="-7220" heading="47280" />
<spawn sepulcherId="3" wave="1" npcId="18133" x="173479" y="-85626" z="-7220" heading="8615" />
<spawn sepulcherId="3" wave="1" npcId="18133" x="173199" y="-85349" z="-7219" heading="24632" />
<spawn sepulcherId="3" wave="1" npcId="18137" x="172964" y="-86198" z="-7220" heading="54316" />
<spawn sepulcherId="3" wave="1" npcId="18137" x="173302" y="-86088" z="-7219" heading="3281" />
<spawn sepulcherId="3" wave="1" npcId="18137" x="173386" y="-85817" z="-7216" heading="36523" />
<spawn sepulcherId="3" wave="1" npcId="18137" x="172993" y="-85470" z="-7216" heading="38307" />
<spawn sepulcherId="3" wave="1" npcId="18137" x="172747" y="-85636" z="-7220" heading="38959" />
<spawn sepulcherId="3" wave="1" npcId="18137" x="173199" y="-85349" z="-7219" heading="24632" />
<!-- SEPULCHER 3 - ROOM 2 -->
<spawn sepulcherId="3" wave="2" npcId="18141" x="172915" y="-83831" z="-7220" heading="44291" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173063" y="-83938" z="-7219" heading="59006" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173000" y="-83662" z="-7216" heading="36263" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="172929" y="-84235" z="-7220" heading="42048" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173512" y="-83749" z="-7220" heading="10405" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173423" y="-84206" z="-7216" heading="14435" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173313" y="-83553" z="-7219" heading="24655" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173390" y="-83938" z="-7216" heading="25116" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173542" y="-84075" z="-7220" heading="4488" />
<spawn sepulcherId="3" wave="2" npcId="18141" x="173176" y="-84243" z="-7219" heading="65198" />
<!-- SEPULCHER 3 - ROOM 3 -->
<spawn sepulcherId="3" wave="3" npcId="18150" x="173307" y="-82096" z="-7219" heading="65275" /> <!-- victim -->
<spawn sepulcherId="3" wave="3" npcId="18166" x="173148" y="-82349" z="-7219" heading="49789" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173488" y="-82501" z="-7220" heading="62942" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173295" y="-82452" z="-7219" heading="59161" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173608" y="-82297" z="-7220" heading="10837" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="172777" y="-82538" z="-7220" heading="42868" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="172940" y="-82301" z="-7220" heading="40896" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="172720" y="-81912" z="-7220" heading="42440" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173048" y="-82059" z="-7218" heading="61025" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="172879" y="-81981" z="-7220" heading="61265" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="172882" y="-81696" z="-7220" heading="34676" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173109" y="-81654" z="-7219" heading="35186" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173380" y="-81590" z="-7218" heading="32420" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173650" y="-81599" z="-7220" heading="9301" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173512" y="-81770" z="-7220" heading="25690" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173641" y="-81874" z="-7220" heading="10595" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173494" y="-82257" z="-7220" heading="29248" />
<spawn sepulcherId="3" wave="3" npcId="18166" x="173517" y="-82074" z="-7219" heading="15079" />
<spawn sepulcherId="3" wave="3" npcId="18171" x="173110" y="-81891" z="-7219" heading="61362" />
<spawn sepulcherId="3" wave="3" npcId="18171" x="173199" y="-82535" z="-7219" heading="64023" />
<spawn sepulcherId="3" wave="3" npcId="18171" x="173632" y="-82529" z="-7220" heading="49712" />
<spawn sepulcherId="3" wave="3" npcId="18171" x="173612" y="-82157" z="-7216" heading="6965" />
<spawn sepulcherId="3" wave="3" npcId="18171" x="172849" y="-82289" z="-7220" heading="32529" />
<spawn sepulcherId="3" wave="3" npcId="18171" x="172831" y="-81773" z="-7216" heading="16747" />
<spawn sepulcherId="3" wave="3" npcId="18171" x="173485" y="-81590" z="-7220" heading="11489" />
<!-- SEPULCHER 3 - ROOM 4 -->
<spawn sepulcherId="3" wave="4" npcId="18177" x="173244" y="-80369" z="-7219" heading="16383" /> <!-- key rewarder -->
<spawn sepulcherId="3" wave="4" npcId="18196" x="172672" y="-80891" z="-7220" heading="2929" /> <!-- charm -->
<spawn sepulcherId="3" wave="4" npcId="18197" x="172612" y="-79655" z="-7219" heading="58713" /> <!-- charm -->
<spawn sepulcherId="3" wave="4" npcId="18198" x="173708" y="-80883" z="-7220" heading="25521" /> <!-- charm -->
<spawn sepulcherId="3" wave="4" npcId="18199" x="173698" y="-79676" z="-7220" heading="36736" /> <!-- charm -->
<spawn sepulcherId="3" wave="4" npcId="18185" x="173153" y="-80062" z="-7219" heading="49218" />
<spawn sepulcherId="3" wave="4" npcId="18185" x="173459" y="-80379" z="-7220" heading="7536" />
<spawn sepulcherId="3" wave="4" npcId="18185" x="173006" y="-80382" z="-7218" heading="43465" />
<spawn sepulcherId="3" wave="4" npcId="18185" x="173155" y="-80647" z="-7219" heading="55372" />
<spawn sepulcherId="3" wave="4" npcId="18185" x="172895" y="-80264" z="-7220" heading="39696" />
<spawn sepulcherId="3" wave="4" npcId="18185" x="173367" y="-79838" z="-7218" heading="16324" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="173479" y="-80694" z="-7220" heading="58422" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="172913" y="-80417" z="-7220" heading="48290" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="172793" y="-79913" z="-7220" heading="21248" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="173436" y="-79863" z="-7220" heading="18223" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="173229" y="-79905" z="-7219" heading="34855" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="173382" y="-80245" z="-7218" heading="19800" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="173485" y="-80138" z="-7220" heading="8390" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="172940" y="-80091" z="-7220" heading="38732" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="172961" y="-80575" z="-7220" heading="46953" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="173470" y="-80504" z="-7220" heading="7605" />
<spawn sepulcherId="3" wave="4" npcId="18187" x="173213" y="-80478" z="-7216" heading="40826" />
<!-- SEPULCHER 3 - ROOM 5 (First Wave) -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="172905" y="-77864" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="172840" y="-77881" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="172763" y="-77884" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="173618" y="-77895" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="173534" y="-77893" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="173452" y="-77901" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="173374" y="-77903" z="-7217" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18232" x="172965" y="-77878" z="-7217" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="5" npcId="18220" x="172824" y="-78791" z="-7219" heading="25363" />
<spawn sepulcherId="3" wave="5" npcId="18220" x="172829" y="-78233" z="-7219" heading="16290" />
<spawn sepulcherId="3" wave="5" npcId="18220" x="173495" y="-78146" z="-7217" heading="1129" />
<spawn sepulcherId="3" wave="5" npcId="18220" x="173523" y="-78661" z="-7219" heading="53052" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="172764" y="-78854" z="-7219" heading="39831" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173124" y="-78487" z="-7218" heading="24278" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="172948" y="-78723" z="-7219" heading="49508" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173121" y="-78899" z="-7218" heading="49076" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173290" y="-78816" z="-7218" heading="62766" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173482" y="-78593" z="-7219" heading="8969" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173519" y="-78873" z="-7219" heading="680" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173422" y="-78216" z="-7219" heading="18030" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173450" y="-78409" z="-7219" heading="12764" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173205" y="-78072" z="-7218" heading="34656" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173560" y="-78007" z="-7219" heading="10297" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173303" y="-78078" z="-7218" heading="11004" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="172852" y="-78058" z="-7219" heading="32354" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="172895" y="-78297" z="-7219" heading="51008" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="173106" y="-78267" z="-7218" heading="23392" />
<spawn sepulcherId="3" wave="5" npcId="18222" x="172939" y="-78460" z="-7219" heading="41711" />
<spawn sepulcherId="3" wave="5" npcId="18226" x="173545" y="-78958" z="-7219" heading="61434" />
<spawn sepulcherId="3" wave="5" npcId="18226" x="173332" y="-78651" z="-7218" heading="63860" />
<spawn sepulcherId="3" wave="5" npcId="18226" x="172854" y="-78747" z="-7219" heading="45974" />
<spawn sepulcherId="3" wave="5" npcId="18226" x="172974" y="-78593" z="-7217" heading="41114" />
<spawn sepulcherId="3" wave="5" npcId="18226" x="172987" y="-78324" z="-7217" heading="43194" />
<spawn sepulcherId="3" wave="5" npcId="18226" x="173183" y="-78019" z="-7218" heading="22569" />
<spawn sepulcherId="3" wave="5" npcId="18226" x="173367" y="-78292" z="-7217" heading="15370" />
<!-- SEPULCHER 3 - ROOM 5 (Second Wave) -->
<spawn sepulcherId="3" wave="6" npcId="18212" x="173195" y="-78387" z="-7218" heading="45514" /> <!-- key rewarder -->
<spawn sepulcherId="3" wave="6" npcId="18232" x="173186" y="-77756" z="-7218" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="6" npcId="18232" x="173256" y="-77755" z="-7218" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="6" npcId="18232" x="173120" y="-77753" z="-7218" heading="49152" /> <!-- statue -->
<spawn sepulcherId="3" wave="6" npcId="18227" x="172727" y="-78149" z="-7219" heading="23490" />
<spawn sepulcherId="3" wave="6" npcId="18195" x="172964" y="-78369" z="-7217" heading="33814" />
<spawn sepulcherId="3" wave="6" npcId="18195" x="173207" y="-78656" z="-7218" heading="56199" />
<spawn sepulcherId="3" wave="6" npcId="18195" x="173262" y="-78339" z="-7218" heading="25711" />
<spawn sepulcherId="3" wave="6" npcId="18195" x="173531" y="-78555" z="-7219" heading="7818" />
<spawn sepulcherId="3" wave="6" npcId="18221" x="173557" y="-78336" z="-7219" heading="11317" />
<spawn sepulcherId="3" wave="6" npcId="18221" x="173473" y="-78710" z="-7219" heading="63315" />
<spawn sepulcherId="3" wave="6" npcId="18221" x="173015" y="-78611" z="-7217" heading="43365" />
<spawn sepulcherId="3" wave="6" npcId="18221" x="173248" y="-78235" z="-7218" heading="29472" />
<spawn sepulcherId="3" wave="6" npcId="18223" x="173404" y="-78358" z="-7217" heading="6698" />
<spawn sepulcherId="3" wave="6" npcId="18223" x="172910" y="-78466" z="-7219" heading="23672" />
<spawn sepulcherId="3" wave="6" npcId="18223" x="173183" y="-78059" z="-7218" heading="7013" />
<spawn sepulcherId="3" wave="6" npcId="18223" x="173152" y="-78754" z="-7218" heading="43240" />
<spawn sepulcherId="3" wave="6" npcId="18223" x="172923" y="-78266" z="-7219" heading="15706" />
<spawn sepulcherId="3" wave="6" npcId="18223" x="173406" y="-78622" z="-7217" heading="54169" />
<spawn sepulcherId="3" wave="6" npcId="18227" x="173456" y="-78263" z="-7219" heading="59104" />
<spawn sepulcherId="3" wave="6" npcId="18227" x="173423" y="-78875" z="-7219" heading="44845" />
<spawn sepulcherId="3" wave="6" npcId="18227" x="172939" y="-78779" z="-7219" heading="25011" />
<spawn sepulcherId="3" wave="6" npcId="18227" x="172997" y="-78482" z="-7217" heading="14372" />
<!-- SEPULCHER 3 - ROOM 6 (Boss) -->
<spawn sepulcherId="3" wave="7" npcId="25339" x="173195" y="-76565" z="-7216" heading="49152" />
<!-- SEPULCHER 3 - ROOM 6 (After Fight) -->
<spawn sepulcherId="3" wave="8" npcId="18256" x="173018" y="-76165" z="-7215" heading="24982" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172973" y="-76550" z="-7216" heading="5423" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172878" y="-76378" z="-7216" heading="18354" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172925" y="-76440" z="-7216" heading="20675" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172864" y="-76718" z="-7216" heading="59534" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172739" y="-76887" z="-7219" heading="35906" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172849" y="-76621" z="-7216" heading="64290" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173402" y="-76970" z="-7219" heading="59429" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173272" y="-77050" z="-7219" heading="40755" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173350" y="-76975" z="-7219" heading="39294" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173434" y="-76844" z="-7216" heading="53275" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173724" y="-76897" z="-7219" heading="2325" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173487" y="-76876" z="-7216" heading="47024" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173687" y="-76665" z="-7219" heading="18033" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173520" y="-76690" z="-7216" heading="50915" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173677" y="-76681" z="-7219" heading="6162" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173356" y="-76574" z="-7216" heading="59624" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173506" y="-76608" z="-7216" heading="51276" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173337" y="-76477" z="-7216" heading="19869" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173376" y="-76705" z="-7216" heading="50732" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173387" y="-76621" z="-7216" heading="31249" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173511" y="-76760" z="-7216" heading="47818" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173113" y="-76577" z="-7216" heading="37147" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173158" y="-76448" z="-7216" heading="51736" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173271" y="-76399" z="-7216" heading="33089" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173396" y="-76249" z="-7216" heading="49151" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173399" y="-76388" z="-7216" heading="47818" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173487" y="-76516" z="-7216" heading="61221" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173405" y="-76480" z="-7216" heading="49831" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173408" y="-76318" z="-7216" heading="50948" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173689" y="-76178" z="-7219" heading="48206" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173694" y="-76123" z="-7219" heading="50292" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173688" y="-76235" z="-7219" heading="48969" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173685" y="-76041" z="-7219" heading="7246" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173498" y="-76392" z="-7216" heading="29118" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173543" y="-76111" z="-7219" heading="25388" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173575" y="-76041" z="-7219" heading="11911" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173646" y="-76446" z="-7219" heading="17752" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173396" y="-76112" z="-7219" heading="36706" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173080" y="-76068" z="-7219" heading="47701" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172984" y="-76095" z="-7219" heading="10228" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173074" y="-76116" z="-7219" heading="47854" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173087" y="-76018" z="-7219" heading="6695" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172911" y="-76204" z="-7216" heading="12608" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172637" y="-76477" z="-7219" heading="39951" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172625" y="-76563" z="-7219" heading="47705" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172801" y="-76342" z="-7215" heading="39904" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172891" y="-76446" z="-7216" heading="34589" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172872" y="-76307" z="-7216" heading="17263" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172667" y="-76633" z="-7219" heading="14412" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172712" y="-76624" z="-7219" heading="49328" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172774" y="-76612" z="-7219" heading="1994" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172619" y="-76889" z="-7219" heading="32941" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172884" y="-76842" z="-7216" heading="26023" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172645" y="-76748" z="-7219" heading="14482" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173049" y="-76936" z="-7216" heading="30541" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173192" y="-76967" z="-7219" heading="24384" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="172986" y="-76919" z="-7216" heading="30018" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173142" y="-76732" z="-7216" heading="65011" />
<spawn sepulcherId="3" wave="8" npcId="18256" x="173221" y="-76850" z="-7216" heading="55305" />
<!-- SEPULCHER 4 - ROOM 1 -->
<spawn sepulcherId="4" wave="1" npcId="18120" x="175524" y="-81903" z="-7219" heading="13290" /> <!-- key rewarder -->
<spawn sepulcherId="4" wave="1" npcId="18132" x="175788" y="-82035" z="-7216" heading="1856" />
<spawn sepulcherId="4" wave="1" npcId="18132" x="175346" y="-82102" z="-7220" heading="43362" />
<spawn sepulcherId="4" wave="1" npcId="18132" x="175346" y="-81604" z="-7220" heading="33547" />
<spawn sepulcherId="4" wave="1" npcId="18132" x="175388" y="-81942" z="-7216" heading="15905" />
<spawn sepulcherId="4" wave="1" npcId="18133" x="175632" y="-82275" z="-7219" heading="54294" />
<spawn sepulcherId="4" wave="1" npcId="18133" x="175305" y="-81830" z="-7220" heading="47280" />
<spawn sepulcherId="4" wave="1" npcId="18133" x="175869" y="-81789" z="-7220" heading="8615" />
<spawn sepulcherId="4" wave="1" npcId="18133" x="175589" y="-81512" z="-7219" heading="24632" />
<spawn sepulcherId="4" wave="1" npcId="18137" x="175354" y="-82361" z="-7220" heading="54316" />
<spawn sepulcherId="4" wave="1" npcId="18137" x="175692" y="-82251" z="-7219" heading="3281" />
<spawn sepulcherId="4" wave="1" npcId="18137" x="175776" y="-81980" z="-7216" heading="36523" />
<spawn sepulcherId="4" wave="1" npcId="18137" x="175383" y="-81633" z="-7216" heading="38307" />
<spawn sepulcherId="4" wave="1" npcId="18137" x="175137" y="-81799" z="-7220" heading="38959" />
<spawn sepulcherId="4" wave="1" npcId="18137" x="175589" y="-81512" z="-7219" heading="24632" />
<!-- SEPULCHER 4 - ROOM 2 -->
<spawn sepulcherId="4" wave="2" npcId="18141" x="175305" y="-79994" z="-7220" heading="44291" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175453" y="-80101" z="-7219" heading="59006" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175390" y="-79825" z="-7216" heading="36263" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175319" y="-80398" z="-7220" heading="42048" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175902" y="-79912" z="-7220" heading="10405" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175813" y="-80369" z="-7216" heading="14435" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175703" y="-79716" z="-7219" heading="24655" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175780" y="-80101" z="-7216" heading="25116" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175932" y="-80238" z="-7220" heading="4488" />
<spawn sepulcherId="4" wave="2" npcId="18141" x="175566" y="-80406" z="-7219" heading="65198" />
<!-- SEPULCHER 4 - ROOM 3 -->
<spawn sepulcherId="4" wave="3" npcId="18150" x="175697" y="-78259" z="-7219" heading="65275" /> <!-- victim -->
<spawn sepulcherId="4" wave="3" npcId="18166" x="175538" y="-78512" z="-7219" heading="49789" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175878" y="-78664" z="-7220" heading="62942" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175685" y="-78615" z="-7219" heading="59161" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175998" y="-78460" z="-7220" heading="10837" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175167" y="-78701" z="-7220" heading="42868" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175330" y="-78464" z="-7220" heading="40896" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175110" y="-78075" z="-7220" heading="42440" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175438" y="-78222" z="-7218" heading="61025" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175269" y="-78144" z="-7220" heading="61265" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175272" y="-77859" z="-7220" heading="34676" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175499" y="-77817" z="-7219" heading="35186" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175770" y="-77753" z="-7218" heading="32420" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="176040" y="-77762" z="-7220" heading="9301" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175902" y="-77933" z="-7220" heading="25690" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="176031" y="-78037" z="-7220" heading="10595" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175884" y="-78420" z="-7220" heading="29248" />
<spawn sepulcherId="4" wave="3" npcId="18166" x="175907" y="-78237" z="-7219" heading="15079" />
<spawn sepulcherId="4" wave="3" npcId="18171" x="175500" y="-78054" z="-7219" heading="61362" />
<spawn sepulcherId="4" wave="3" npcId="18171" x="175589" y="-78698" z="-7219" heading="64023" />
<spawn sepulcherId="4" wave="3" npcId="18171" x="176022" y="-78692" z="-7220" heading="49712" />
<spawn sepulcherId="4" wave="3" npcId="18171" x="176002" y="-78320" z="-7216" heading="6965" />
<spawn sepulcherId="4" wave="3" npcId="18171" x="175239" y="-78452" z="-7220" heading="32529" />
<spawn sepulcherId="4" wave="3" npcId="18171" x="175221" y="-77936" z="-7216" heading="16747" />
<spawn sepulcherId="4" wave="3" npcId="18171" x="175875" y="-77753" z="-7220" heading="11489" />
<!-- SEPULCHER 4 - ROOM 4 -->
<spawn sepulcherId="4" wave="4" npcId="18177" x="175634" y="-76532" z="-7219" heading="16383" /> <!-- key rewarder -->
<spawn sepulcherId="4" wave="4" npcId="18196" x="175029" y="-77073" z="-7219" heading="4074" /> <!-- charm -->
<spawn sepulcherId="4" wave="4" npcId="18197" x="175015" y="-75843" z="-7221" heading="60216" /> <!-- charm -->
<spawn sepulcherId="4" wave="4" npcId="18198" x="176154" y="-77075" z="-7219" heading="27131" /> <!-- charm -->
<spawn sepulcherId="4" wave="4" npcId="18199" x="176181" y="-75837" z="-7221" heading="37604" /> <!-- charm -->
<spawn sepulcherId="4" wave="4" npcId="18185" x="175543" y="-76225" z="-7219" heading="49218" />
<spawn sepulcherId="4" wave="4" npcId="18185" x="175849" y="-76542" z="-7220" heading="7536" />
<spawn sepulcherId="4" wave="4" npcId="18185" x="175396" y="-76545" z="-7218" heading="43465" />
<spawn sepulcherId="4" wave="4" npcId="18185" x="175545" y="-76810" z="-7219" heading="55372" />
<spawn sepulcherId="4" wave="4" npcId="18185" x="175285" y="-76427" z="-7220" heading="39696" />
<spawn sepulcherId="4" wave="4" npcId="18185" x="175757" y="-76001" z="-7218" heading="16324" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175869" y="-76857" z="-7220" heading="58422" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175303" y="-76580" z="-7220" heading="48290" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175183" y="-76076" z="-7220" heading="21248" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175826" y="-76026" z="-7220" heading="18223" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175619" y="-76068" z="-7219" heading="34855" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175772" y="-76408" z="-7218" heading="19800" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175875" y="-76301" z="-7220" heading="8390" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175330" y="-76254" z="-7220" heading="38732" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175351" y="-76738" z="-7220" heading="46953" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175860" y="-76667" z="-7220" heading="7605" />
<spawn sepulcherId="4" wave="4" npcId="18187" x="175603" y="-76641" z="-7216" heading="40826" />
<!-- SEPULCHER 4 - ROOM 5 (First Wave) -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="175295" y="-74027" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="175230" y="-74044" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="175153" y="-74047" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="176008" y="-74058" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="175924" y="-74056" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="175842" y="-74064" z="-7219" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="175764" y="-74066" z="-7217" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18232" x="175355" y="-74041" z="-7217" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="5" npcId="18220" x="175214" y="-74954" z="-7219" heading="25363" />
<spawn sepulcherId="4" wave="5" npcId="18220" x="175219" y="-74396" z="-7219" heading="16290" />
<spawn sepulcherId="4" wave="5" npcId="18220" x="175885" y="-74309" z="-7217" heading="1129" />
<spawn sepulcherId="4" wave="5" npcId="18220" x="175913" y="-74824" z="-7219" heading="53052" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175154" y="-75017" z="-7219" heading="39831" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175514" y="-74650" z="-7218" heading="24278" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175338" y="-74886" z="-7219" heading="49508" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175511" y="-75062" z="-7218" heading="49076" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175680" y="-74979" z="-7218" heading="62766" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175872" y="-74756" z="-7219" heading="8969" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175909" y="-75036" z="-7219" heading="680" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175812" y="-74379" z="-7219" heading="18030" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175840" y="-74572" z="-7219" heading="12764" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175595" y="-74235" z="-7218" heading="34656" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175950" y="-74170" z="-7219" heading="10297" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175693" y="-74241" z="-7218" heading="11004" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175242" y="-74221" z="-7219" heading="32354" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175285" y="-74460" z="-7219" heading="51008" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175496" y="-74430" z="-7218" heading="23392" />
<spawn sepulcherId="4" wave="5" npcId="18222" x="175329" y="-74623" z="-7219" heading="41711" />
<spawn sepulcherId="4" wave="5" npcId="18226" x="175935" y="-75121" z="-7219" heading="61434" />
<spawn sepulcherId="4" wave="5" npcId="18226" x="175722" y="-74814" z="-7218" heading="63860" />
<spawn sepulcherId="4" wave="5" npcId="18226" x="175244" y="-74910" z="-7219" heading="45974" />
<spawn sepulcherId="4" wave="5" npcId="18226" x="175364" y="-74756" z="-7217" heading="41114" />
<spawn sepulcherId="4" wave="5" npcId="18226" x="175377" y="-74487" z="-7217" heading="43194" />
<spawn sepulcherId="4" wave="5" npcId="18226" x="175573" y="-74182" z="-7218" heading="22569" />
<spawn sepulcherId="4" wave="5" npcId="18226" x="175757" y="-74455" z="-7217" heading="15370" />
<!-- SEPULCHER 4 - ROOM 5 (Second Wave) -->
<spawn sepulcherId="4" wave="6" npcId="18212" x="175585" y="-74550" z="-7218" heading="45514" /> <!-- key rewarder -->
<spawn sepulcherId="4" wave="6" npcId="18232" x="175576" y="-73919" z="-7218" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="6" npcId="18232" x="175646" y="-73918" z="-7218" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="6" npcId="18232" x="175510" y="-73916" z="-7218" heading="49152" /> <!-- statue -->
<spawn sepulcherId="4" wave="6" npcId="18227" x="175117" y="-74312" z="-7219" heading="23490" />
<spawn sepulcherId="4" wave="6" npcId="18195" x="175354" y="-74532" z="-7217" heading="33814" />
<spawn sepulcherId="4" wave="6" npcId="18195" x="175597" y="-74819" z="-7218" heading="56199" />
<spawn sepulcherId="4" wave="6" npcId="18195" x="175652" y="-74502" z="-7218" heading="25711" />
<spawn sepulcherId="4" wave="6" npcId="18195" x="175921" y="-74718" z="-7219" heading="7818" />
<spawn sepulcherId="4" wave="6" npcId="18221" x="175947" y="-74499" z="-7219" heading="11317" />
<spawn sepulcherId="4" wave="6" npcId="18221" x="175863" y="-74873" z="-7219" heading="63315" />
<spawn sepulcherId="4" wave="6" npcId="18221" x="175405" y="-74774" z="-7217" heading="43365" />
<spawn sepulcherId="4" wave="6" npcId="18221" x="175638" y="-74398" z="-7218" heading="29472" />
<spawn sepulcherId="4" wave="6" npcId="18223" x="175794" y="-74521" z="-7217" heading="6698" />
<spawn sepulcherId="4" wave="6" npcId="18223" x="175300" y="-74629" z="-7219" heading="23672" />
<spawn sepulcherId="4" wave="6" npcId="18223" x="175573" y="-74222" z="-7218" heading="7013" />
<spawn sepulcherId="4" wave="6" npcId="18223" x="175542" y="-74917" z="-7218" heading="43240" />
<spawn sepulcherId="4" wave="6" npcId="18223" x="175313" y="-74429" z="-7219" heading="15706" />
<spawn sepulcherId="4" wave="6" npcId="18223" x="175796" y="-74785" z="-7217" heading="54169" />
<spawn sepulcherId="4" wave="6" npcId="18227" x="175846" y="-74426" z="-7219" heading="59104" />
<spawn sepulcherId="4" wave="6" npcId="18227" x="175813" y="-75038" z="-7219" heading="44845" />
<spawn sepulcherId="4" wave="6" npcId="18227" x="175329" y="-74942" z="-7219" heading="25011" />
<spawn sepulcherId="4" wave="6" npcId="18227" x="175387" y="-74645" z="-7217" heading="14372" />
<!-- SEPULCHER 4 - ROOM 6 (Boss) -->
<spawn sepulcherId="4" wave="7" npcId="25349" x="175590" y="-72749" z="-7218" heading="31944" />
<!-- SEPULCHER 4 - ROOM 6 (After Fight) -->
<spawn sepulcherId="4" wave="8" npcId="18256" x="175408" y="-72328" z="-7215" heading="24982" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175363" y="-72713" z="-7216" heading="5423" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175268" y="-72541" z="-7216" heading="18354" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175315" y="-72603" z="-7216" heading="20675" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175254" y="-72881" z="-7216" heading="59534" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175129" y="-73050" z="-7219" heading="35906" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175239" y="-72784" z="-7216" heading="64290" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175792" y="-73133" z="-7219" heading="59429" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175662" y="-73213" z="-7219" heading="40755" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175740" y="-73138" z="-7219" heading="39294" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175824" y="-73007" z="-7216" heading="53275" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176114" y="-73060" z="-7219" heading="2325" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175877" y="-73039" z="-7216" heading="47024" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176077" y="-72828" z="-7219" heading="18033" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175910" y="-72853" z="-7216" heading="50915" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176067" y="-72844" z="-7219" heading="6162" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175746" y="-72737" z="-7216" heading="59624" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175896" y="-72771" z="-7216" heading="51276" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175727" y="-72640" z="-7216" heading="19869" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175766" y="-72868" z="-7216" heading="50732" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175777" y="-72784" z="-7216" heading="31249" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175901" y="-72923" z="-7216" heading="47818" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175503" y="-72740" z="-7216" heading="37147" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175548" y="-72611" z="-7216" heading="51736" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175661" y="-72562" z="-7216" heading="33089" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175786" y="-72412" z="-7216" heading="49151" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175789" y="-72551" z="-7216" heading="47818" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175877" y="-72679" z="-7216" heading="61221" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175795" y="-72643" z="-7216" heading="49831" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175798" y="-72481" z="-7216" heading="50948" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176079" y="-72341" z="-7219" heading="48206" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176084" y="-72286" z="-7219" heading="50292" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176078" y="-72398" z="-7219" heading="48969" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176075" y="-72204" z="-7219" heading="7246" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175888" y="-72555" z="-7216" heading="29118" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175933" y="-72274" z="-7219" heading="25388" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175965" y="-72204" z="-7219" heading="11911" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="176036" y="-72609" z="-7219" heading="17752" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175786" y="-72275" z="-7219" heading="36706" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175470" y="-72231" z="-7219" heading="47701" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175374" y="-72258" z="-7219" heading="10228" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175464" y="-72279" z="-7219" heading="47854" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175477" y="-72181" z="-7219" heading="6695" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175301" y="-72367" z="-7216" heading="12608" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175027" y="-72640" z="-7219" heading="39951" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175015" y="-72726" z="-7219" heading="47705" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175191" y="-72505" z="-7215" heading="39904" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175281" y="-72609" z="-7216" heading="34589" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175262" y="-72470" z="-7216" heading="17263" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175057" y="-72796" z="-7219" heading="14412" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175102" y="-72787" z="-7219" heading="49328" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175164" y="-72775" z="-7219" heading="1994" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175009" y="-73052" z="-7219" heading="32941" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175274" y="-73005" z="-7216" heading="26023" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175035" y="-72911" z="-7219" heading="14482" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175439" y="-73099" z="-7216" heading="30541" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175582" y="-73130" z="-7219" heading="24384" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175376" y="-73082" z="-7216" heading="30018" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175532" y="-72895" z="-7216" heading="65011" />
<spawn sepulcherId="4" wave="8" npcId="18256" x="175611" y="-73013" z="-7216" heading="55305" />
</list>

View File

@@ -0,0 +1,23 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="spawn" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="sepulcherId" use="optional"/>
<xs:attribute type="xs:int" name="wave" use="optional"/>
<xs:attribute type="xs:int" name="npcId" use="optional"/>
<xs:attribute type="xs:int" name="x" use="optional"/>
<xs:attribute type="xs:int" name="y" use="optional"/>
<xs:attribute type="xs:int" name="z" use="optional"/>
<xs:attribute type="xs:int" name="heading" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,3 @@
<html><body>%npcname%:<br>
There is no key.
</body></html>

Some files were not shown because too many files have changed in this diff Show More