Separated the Classic Datapack to it's own folder.

This commit is contained in:
MobiusDev
2015-05-02 03:45:56 +00:00
parent 08e28fe058
commit 484bff80bb
11501 changed files with 2200482 additions and 627 deletions

View File

@@ -0,0 +1,483 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SkillData;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2TamedBeastInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.serverpackets.NpcInfo;
import com.l2jserver.gameserver.util.Util;
/**
* Growth-capable mobs: Polymorphing upon successful feeding.<br>
* Updated to Freya.
* @author Fulminus, Gigiikun
*/
public final 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 final Map<Integer, Integer> FEED_INFO = new ConcurrentHashMap<>();
private static final Map<Integer, GrowthCapableMob> GROWTH_CAPABLE_MONSTERS = new HashMap<>();
private static List<TamedBeast> TAMED_BEAST_DATA = new ArrayList<>();
private BeastFarm()
{
super(BeastFarm.class.getSimpleName(), "ai/group_template");
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_MONSTERS.put(18873, temp);
temp = new GrowthCapableMob(40, 1, 18869);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18876);
GROWTH_CAPABLE_MONSTERS.put(18874, temp);
temp = new GrowthCapableMob(40, 1, 18869);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18877);
GROWTH_CAPABLE_MONSTERS.put(18875, temp);
temp = new GrowthCapableMob(25, 2, 18869);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18878);
GROWTH_CAPABLE_MONSTERS.put(18876, temp);
temp = new GrowthCapableMob(25, 2, 18869);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18879);
GROWTH_CAPABLE_MONSTERS.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_MONSTERS.put(18880, temp);
temp = new GrowthCapableMob(40, 1, 18870);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18883);
GROWTH_CAPABLE_MONSTERS.put(18881, temp);
temp = new GrowthCapableMob(40, 1, 18870);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18884);
GROWTH_CAPABLE_MONSTERS.put(18882, temp);
temp = new GrowthCapableMob(25, 2, 18870);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18885);
GROWTH_CAPABLE_MONSTERS.put(18883, temp);
temp = new GrowthCapableMob(25, 2, 18870);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18886);
GROWTH_CAPABLE_MONSTERS.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_MONSTERS.put(18887, temp);
temp = new GrowthCapableMob(40, 1, 18871);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18890);
GROWTH_CAPABLE_MONSTERS.put(18888, temp);
temp = new GrowthCapableMob(40, 1, 18871);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18891);
GROWTH_CAPABLE_MONSTERS.put(18889, temp);
temp = new GrowthCapableMob(25, 2, 18871);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18892);
GROWTH_CAPABLE_MONSTERS.put(18890, temp);
temp = new GrowthCapableMob(25, 2, 18871);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18893);
GROWTH_CAPABLE_MONSTERS.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_MONSTERS.put(18894, temp);
temp = new GrowthCapableMob(40, 1, 18872);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18897);
GROWTH_CAPABLE_MONSTERS.put(18895, temp);
temp = new GrowthCapableMob(40, 1, 18872);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18898);
GROWTH_CAPABLE_MONSTERS.put(18896, temp);
temp = new GrowthCapableMob(25, 2, 18872);
temp.addNpcIdForSkillId(SKILL_GOLDEN_SPICE, 18899);
GROWTH_CAPABLE_MONSTERS.put(18897, temp);
temp = new GrowthCapableMob(25, 2, 18872);
temp.addNpcIdForSkillId(SKILL_CRYSTAL_SPICE, 18900);
GROWTH_CAPABLE_MONSTERS.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(L2Npc npc, L2PcInstance player, int nextNpcId, int food)
{
// remove the feedinfo of the mob that got despawned, if any
if (FEED_INFO.containsKey(npc.getObjectId()))
{
if (FEED_INFO.get(npc.getObjectId()) == player.getObjectId())
{
FEED_INFO.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 (Util.contains(TAMED_BEASTS, nextNpcId))
{
final L2TamedBeastInstance nextNpc = new L2TamedBeastInstance(nextNpcId, player, food, npc.getX(), npc.getY(), npc.getZ(), true);
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();
SkillData st = SkillData.getInstance();
for (SkillHolder sh : beast.getSkills())
{
nextNpc.addBeastSkill(st.getSkill(sh.getSkillId(), sh.getSkillLvl()));
}
// 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?!)
L2Attackable nextNpc = (L2Attackable) addSpawn(nextNpcId, npc);
// register the player in the feedinfo for the mob that just spawned
FEED_INFO.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(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] 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 (!Util.contains(targets, npc))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// gather some values on local variables
int npcId = npc.getId();
int skillId = skill.getId();
// check if the npc and skills used are valid for this script. Exit if invalid.
if (!Util.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
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_MONSTERS.containsKey(npcId))
{
growthLevel = GROWTH_CAPABLE_MONSTERS.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) && FEED_INFO.containsKey(objectId))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
FEED_INFO.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_MONSTERS.containsKey(npcId))
{
// do nothing if this mob doesn't eat the specified food (food gets consumed but has no effect).
int newNpcId = GROWTH_CAPABLE_MONSTERS.get(npcId).getLeveledNpcId(skillId);
if (newNpcId == -1)
{
if (growthLevel == 0)
{
FEED_INFO.remove(objectId);
npc.setRunning();
((L2Attackable) 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) && (FEED_INFO.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(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
// remove the feedinfo of the mob that got killed, if any
if (FEED_INFO.containsKey(npc.getObjectId()))
{
FEED_INFO.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 HashMap<>();
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,246 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.datatables.SkillData;
import com.l2jserver.gameserver.instancemanager.ZoneManager;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.model.zone.type.L2EffectZone;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.util.Util;
/**
* Dummy AI for spawns/respawns only for testing.
* @author Gnacik
*/
public final 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 final static boolean DEBUG = false;
private DenOfEvil()
{
super(DenOfEvil.class.getSimpleName(), "ai/group_template");
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(L2Npc npc)
{
npc.disableCoreAI(true);
npc.setIsImmobilized(true);
L2EffectZone zone = ZoneManager.getInstance().getZone(npc, L2EffectZone.class);
if (zone == null)
{
if (DEBUG)
{
_log.warning("NPC " + npc + " spawned outside of L2EffectZone, check your zone coords! X:" + npc.getX() + " Y:" + npc.getY() + " Z:" + npc.getZ());
}
return null;
}
int skillId = getSkillIdByNpcId(npc.getId());
int skillLevel = zone.getSkillLevel(skillId);
zone.addSkill(skillId, skillLevel + 1);
if (skillLevel == 3) // 3+1=4
{
ThreadPoolManager.getInstance().scheduleAi(new KashaDestruction(zone), 2 * 60 * 1000l);
zone.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.DEFEAT_KASHA_S_EYES_TO_LIFT_THE_GREAT_CURSE));
}
else if (skillLevel == 2)
{
zone.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.A_GREAT_CURSE_CAN_BE_FELT_FROM_KASHA_S_EYES));
}
return super.onSpawn(npc);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
ThreadPoolManager.getInstance().scheduleAi(new RespawnNewEye(npc.getLocation()), 15000);
L2EffectZone zone = ZoneManager.getInstance().getZone(npc, L2EffectZone.class);
if (zone == null)
{
if (DEBUG)
{
_log.warning("NPC " + npc + " killed outside of L2EffectZone, check your zone coords! X:" + npc.getX() + " Y:" + npc.getY() + " Z:" + npc.getZ());
}
return null;
}
int skillId = getSkillIdByNpcId(npc.getId());
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
{
L2EffectZone _zone;
public KashaDestruction(L2EffectZone zone)
{
_zone = zone;
}
@Override
public void run()
{
for (int i = SKILL_ID; i <= (SKILL_ID + 4); i = i + 2)
{
// test 3 skills if some is lvl 4
if (_zone.getSkillLevel(i) > 3)
{
destroyZone();
break;
}
}
}
private void destroyZone()
{
for (L2Character character : _zone.getCharactersInside())
{
if (character == null)
{
continue;
}
if (character.isPlayable())
{
Skill skill = SkillData.getInstance().getSkill(6149, 1);
skill.applyEffects(character, character);
}
else
{
if (character.doDie(null)) // mobs die
{
if (character.isNpc())
{
// respawn eye
L2Npc npc = (L2Npc) character;
if (Util.contains(EYE_IDS, npc.getId()))
{
ThreadPoolManager.getInstance().scheduleAi(new RespawnNewEye(npc.getLocation()), 15000);
}
}
}
}
}
for (int i = SKILL_ID; i <= (SKILL_ID + 4); i = i + 2)
{
_zone.removeSkill(i);
}
}
}
public static void main(String[] args)
{
new DenOfEvil();
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
/**
* Fairy Trees AI.
* @author Charus
*/
public class FairyTrees extends AbstractNpcAI
{
// NPC
private static final int SOUL_GUARDIAN = 27189; // Soul of Tree Guardian
private static final int[] MOBS =
{
27185, // Fairy Tree of Wind
27186, // Fairy Tree of Star
27187, // Fairy Tree of Twilight
27188, // Fairy Tree of Abyss
};
// Skill
private static SkillHolder VENOMOUS_POISON = new SkillHolder(4243, 1); // Venomous Poison
// Misc
private static final int MIN_DISTANCE = 1500;
private FairyTrees()
{
super(FairyTrees.class.getSimpleName(), "ai/group_template");
addKillId(MOBS);
addSpawnId(MOBS);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.calculateDistance(killer, true, false) <= MIN_DISTANCE)
{
for (int i = 0; i < 20; i++)
{
final L2Npc guardian = addSpawn(SOUL_GUARDIAN, npc, false, 30000);
final L2Playable attacker = isSummon ? killer.getServitors().values().stream().findFirst().orElse(killer.getPet()) : killer;
addAttackPlayerDesire(guardian, attacker);
if (getRandomBoolean())
{
guardian.setTarget(attacker);
guardian.doCast(VENOMOUS_POISON.getSkill());
}
}
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setIsNoRndWalk(true);
npc.setIsImmobilized(true);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new FairyTrees();
}
}

View File

@@ -0,0 +1,627 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2TamedBeastInstance;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.util.Util;
/**
* Growth-capable mobs: Polymorphing upon successful feeding.
* @author Fulminus
*/
public final 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 =
{
21451, 21452, 21453, 21454, 21455, 21456, 21457, 21458, 21459, 21460,
21461, 21462, 21463, 21464, 21465, 21466, 21467, 21468, 21469, 21470,
21471, 21472, 21473, 21474, 21475, 21476, 21477, 21478, 21479, 21480,
21481, 21482, 21483, 21484, 21485, 21486, 21487, 21488, 21489, 21490,
21491, 21492, 21493, 21494, 21495, 21496, 21497, 21498, 21499, 21500,
21501, 21502, 21503, 21504, 21505, 21506, 21507, 21824, 21825, 21826,
21827, 21828, 21829, 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<>();
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 static final Map<Integer, Integer> FEED_INFO = new ConcurrentHashMap<>();
private static final Map<Integer, GrowthCapableMob> GROWTH_CAPABLE_MONSTERS = 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 HashMap<>();
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);
int rand = getRandom(temp[0].length);
return temp[0][rand];
}
public Integer getChance()
{
return _chance;
}
public Integer getGrowthLevel()
{
return _growthLevel;
}
}
private FeedableBeasts()
{
super(FeedableBeasts.class.getSimpleName(), "ai/group_template");
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_MONSTERS.put(21451, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Kookabura_1_Gold_1);
GROWTH_CAPABLE_MONSTERS.put(21452, temp);
GROWTH_CAPABLE_MONSTERS.put(21454, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Kookabura_1_Gold_2);
GROWTH_CAPABLE_MONSTERS.put(21453, temp);
GROWTH_CAPABLE_MONSTERS.put(21455, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Kookabura_1_Crystal_1);
GROWTH_CAPABLE_MONSTERS.put(21456, temp);
GROWTH_CAPABLE_MONSTERS.put(21458, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Kookabura_1_Crystal_2);
GROWTH_CAPABLE_MONSTERS.put(21457, temp);
GROWTH_CAPABLE_MONSTERS.put(21459, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Kookabura_2_1);
GROWTH_CAPABLE_MONSTERS.put(21460, temp);
GROWTH_CAPABLE_MONSTERS.put(21462, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Kookabura_2_2);
GROWTH_CAPABLE_MONSTERS.put(21461, temp);
GROWTH_CAPABLE_MONSTERS.put(21463, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Kookabura_2_1);
GROWTH_CAPABLE_MONSTERS.put(21464, temp);
GROWTH_CAPABLE_MONSTERS.put(21466, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Kookabura_2_2);
GROWTH_CAPABLE_MONSTERS.put(21465, temp);
GROWTH_CAPABLE_MONSTERS.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_MONSTERS.put(21470, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Buffalo_1_Gold_1);
GROWTH_CAPABLE_MONSTERS.put(21471, temp);
GROWTH_CAPABLE_MONSTERS.put(21473, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Buffalo_1_Gold_2);
GROWTH_CAPABLE_MONSTERS.put(21472, temp);
GROWTH_CAPABLE_MONSTERS.put(21474, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Buffalo_1_Crystal_1);
GROWTH_CAPABLE_MONSTERS.put(21475, temp);
GROWTH_CAPABLE_MONSTERS.put(21477, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Buffalo_1_Crystal_2);
GROWTH_CAPABLE_MONSTERS.put(21476, temp);
GROWTH_CAPABLE_MONSTERS.put(21478, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Buffalo_2_1);
GROWTH_CAPABLE_MONSTERS.put(21479, temp);
GROWTH_CAPABLE_MONSTERS.put(21481, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Buffalo_2_2);
GROWTH_CAPABLE_MONSTERS.put(21480, temp);
GROWTH_CAPABLE_MONSTERS.put(21482, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Buffalo_2_1);
GROWTH_CAPABLE_MONSTERS.put(21483, temp);
GROWTH_CAPABLE_MONSTERS.put(21485, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Buffalo_2_2);
GROWTH_CAPABLE_MONSTERS.put(21484, temp);
GROWTH_CAPABLE_MONSTERS.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_MONSTERS.put(21489, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Cougar_1_Gold_1);
GROWTH_CAPABLE_MONSTERS.put(21490, temp);
GROWTH_CAPABLE_MONSTERS.put(21492, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(GOLDEN_SPICE, Cougar_1_Gold_2);
GROWTH_CAPABLE_MONSTERS.put(21491, temp);
GROWTH_CAPABLE_MONSTERS.put(21493, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Cougar_1_Crystal_1);
GROWTH_CAPABLE_MONSTERS.put(21494, temp);
GROWTH_CAPABLE_MONSTERS.put(21496, temp);
temp = new GrowthCapableMob(1, 40);
temp.addMobs(CRYSTAL_SPICE, Cougar_1_Crystal_2);
GROWTH_CAPABLE_MONSTERS.put(21495, temp);
GROWTH_CAPABLE_MONSTERS.put(21497, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Cougar_2_1);
GROWTH_CAPABLE_MONSTERS.put(21498, temp);
GROWTH_CAPABLE_MONSTERS.put(21500, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(GOLDEN_SPICE, Cougar_2_2);
GROWTH_CAPABLE_MONSTERS.put(21499, temp);
GROWTH_CAPABLE_MONSTERS.put(21501, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Cougar_2_1);
GROWTH_CAPABLE_MONSTERS.put(21502, temp);
GROWTH_CAPABLE_MONSTERS.put(21504, temp);
temp = new GrowthCapableMob(2, 25);
temp.addMobs(CRYSTAL_SPICE, Cougar_2_2);
GROWTH_CAPABLE_MONSTERS.put(21503, temp);
GROWTH_CAPABLE_MONSTERS.put(21505, temp);
}
private void spawnNext(L2Npc npc, int growthLevel, L2PcInstance player, int food)
{
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_MONSTERS.get(npcId).getMob(food, 1, 1);
}
else
{
nextNpcId = GROWTH_CAPABLE_MONSTERS.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_MONSTERS.get(npcId).getMob(food, 0, 1);
}
else
{
nextNpcId = GROWTH_CAPABLE_MONSTERS.get(npcId).getMob(food, 0, 0);
}
}
}
else
{
// all other levels of growth are straight-forward
nextNpcId = GROWTH_CAPABLE_MONSTERS.get(npcId).getRandomMob(food);
}
// remove the feedinfo of the mob that got despawned, if any
if (FEED_INFO.containsKey(npc.getObjectId()))
{
if (FEED_INFO.get(npc.getObjectId()) == player.getObjectId())
{
FEED_INFO.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 (Util.contains(TAMED_BEASTS, nextNpcId))
{
if ((player.getTrainedBeasts() != null) && !player.getTrainedBeasts().isEmpty())
{
for (L2TamedBeastInstance oldTrained : player.getTrainedBeasts())
{
oldTrained.deleteMe();
}
}
final L2TamedBeastInstance nextNpc = new L2TamedBeastInstance(nextNpcId, player, food - FOODSKILLDIFF, npc.getX(), npc.getY(), npc.getZ());
nextNpc.setRunning();
// Q00020_BringUpWithLove.checkJewelOfInnocence(player);
// Support for A Grand Plan for Taming Wild Beasts (655) quest.
// Q00655_AGrandPlanForTamingWildBeasts.reward(player, nextNpc);
// also, perform a rare random chat
if (getRandom(20) == 0)
{
NpcStringId message = NpcStringId.getNpcStringId(getRandom(2024, 2029));
NpcSay packet = new NpcSay(nextNpc, ChatType.NPC_GENERAL, message);
if (message.getParamCount() > 0) // player name, $s1
{
packet.addStringParameter(player.getName());
}
npc.broadcastPacket(packet);
}
// @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?!)
L2Attackable nextNpc = (L2Attackable) addSpawn(nextNpcId, npc);
if (MAD_COW_POLYMORPH.containsKey(nextNpcId))
{
this.startQuestTimer("polymorph Mad Cow", 10000, nextNpc, player);
}
// register the player in the feedinfo for the mob that just spawned
FEED_INFO.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, L2Npc npc, L2PcInstance 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 (FEED_INFO.get(npc.getObjectId()) == player.getObjectId())
{
FEED_INFO.remove(npc.getObjectId());
}
// despawn the mad cow
npc.deleteMe();
// spawn the new mob
L2Attackable nextNpc = (L2Attackable) addSpawn(MAD_COW_POLYMORPH.get(npc.getId()), npc);
// register the player in the feedinfo for the mob that just spawned
FEED_INFO.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(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] 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 (!Util.contains(targets, npc))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// gather some values on local variables
int npcId = npc.getId();
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
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_MONSTERS.containsKey(npcId))
{
growthLevel = GROWTH_CAPABLE_MONSTERS.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) && FEED_INFO.containsKey(objectId))
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
FEED_INFO.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_MONSTERS.containsKey(npcId))
{
// do nothing if this mob doesn't eat the specified food (food gets consumed but has no effect).
if (GROWTH_CAPABLE_MONSTERS.get(npcId).getMob(food, 0, 0) == null)
{
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
// rare random talk...
if (getRandom(20) == 0)
{
NpcStringId message = TEXT[growthLevel][getRandom(TEXT[growthLevel].length)];
NpcSay packet = new NpcSay(npc, ChatType.NPC_GENERAL, message);
if (message.getParamCount() > 0) // player name, $s1
{
packet.addStringParameter(caster.getName());
}
npc.broadcastPacket(packet);
}
if ((growthLevel > 0) && (FEED_INFO.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_MONSTERS.get(npcId).getChance())
{
spawnNext(npc, growthLevel, caster, food);
}
}
else if (Util.contains(TAMED_BEASTS, npcId) && (npc instanceof L2TamedBeastInstance))
{
L2TamedBeastInstance beast = ((L2TamedBeastInstance) npc);
if (skillId == beast.getFoodType())
{
beast.onReceiveFood();
NpcStringId message = TAMED_TEXT[getRandom(TAMED_TEXT.length)];
NpcSay packet = new NpcSay(npc, ChatType.NPC_GENERAL, message);
if (message.getParamCount() > 0)
{
packet.addStringParameter(caster.getName());
}
beast.broadcastPacket(packet);
}
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
// remove the feedinfo of the mob that got killed, if any
if (FEED_INFO.containsKey(npc.getObjectId()))
{
FEED_INFO.remove(npc.getObjectId());
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new FeedableBeasts();
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.interfaces.ILocational;
import com.l2jserver.gameserver.util.Util;
/**
* Flee Monsters AI.
* @author Pandragon, NosBit
*/
public final class FleeMonsters extends AbstractNpcAI
{
// NPCs
private static final int[] MOBS =
{
18150, // Victim
18151, // Victim
18152, // Victim
18153, // Victim
18154, // Victim
18155, // Victim
18156, // Victim
18157, // Victim
20002, // Rabbit
20432, // Elpy
22228, // Grey Elpy
25604, // Mutated Elpy
};
// Misc
private static final int FLEE_DISTANCE = 500;
private FleeMonsters()
{
super(FleeMonsters.class.getSimpleName(), "ai/group_template");
addAttackId(MOBS);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
npc.disableCoreAI(true);
npc.setRunning();
final L2Summon summon = isSummon ? attacker.getServitors().values().stream().findFirst().orElse(attacker.getPet()) : null;
final ILocational attackerLoc = summon == null ? attacker : summon;
final double radians = Math.toRadians(Util.calculateAngleFrom(attackerLoc, npc));
final int posX = (int) (npc.getX() + (FLEE_DISTANCE * Math.cos(radians)));
final int posY = (int) (npc.getY() + (FLEE_DISTANCE * Math.sin(radians)));
final int posZ = npc.getZ();
final Location destination = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, attacker.getInstanceId());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
return super.onAttack(npc, attacker, damage, isSummon);
}
public static void main(String[] args)
{
new FleeMonsters();
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.skills.Skill;
/**
* Frozen Labyrinth AI.
* @author malyelfik
*/
public final 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()
{
super(FrozenLabyrinth.class.getSimpleName(), "ai/group_template");
addAttackId(PRONGHORN, FROST_BUFFALO);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance 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 L2Npc 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,114 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Giant's Cave AI.
* @author Gnacik, St3eT
*/
public final class GiantsCave extends AbstractNpcAI
{
// NPC
private static final int[] SCOUTS =
{
22668, // Gamlin (Scout)
22669, // Leogul (Scout)
};
private GiantsCave()
{
super(GiantsCave.class.getSimpleName(), "ai/group_template");
addAttackId(SCOUTS);
addAggroRangeEnterId(SCOUTS);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("ATTACK") && (player != null) && (npc != null) && !npc.isDead())
{
if (npc.getId() == SCOUTS[0]) // Gamlin
{
broadcastNpcSay(npc, ChatType.NPC_SHOUT, NpcStringId.INTRUDER_DETECTED);
}
else
{
broadcastNpcSay(npc, ChatType.NPC_SHOUT, NpcStringId.OH_GIANTS_AN_INTRUDER_HAS_BEEN_DISCOVERED);
}
for (L2Character characters : npc.getKnownList().getKnownCharactersInRadius(450))
{
if ((characters != null) && (characters.isAttackable()) && (getRandomBoolean()))
{
addAttackPlayerDesire((L2Npc) characters, player);
}
}
}
else if (event.equals("CLEAR") && (npc != null) && !npc.isDead())
{
npc.setScriptValue(0);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("ATTACK", 6000, npc, attacker);
startQuestTimer("CLEAR", 120000, npc, null);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
if (getRandomBoolean())
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.YOU_GUYS_ARE_DETECTED);
}
else
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.WHAT_KIND_OF_CREATURES_ARE_YOU);
}
startQuestTimer("ATTACK", 6000, npc, player);
startQuestTimer("CLEAR", 120000, npc, null);
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
public static void main(String[] args)
{
new GiantsCave();
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.datatables.SkillData;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.skills.BuffInfo;
import com.l2jserver.gameserver.model.skills.Skill;
/**
* Hot Springs AI.
* @author Pandragon
*/
public final 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()
{
super(HotSprings.class.getSimpleName(), "ai/group_template");
addAttackId(BANDERSNATCHLING, FLAVA, ATROXSPAWN, NEPENTHES, ATROX, BANDERSNATCH);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance 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(L2Npc npc, L2Character player, int diseaseId)
{
final BuffInfo info = player.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) && !npc.isCastingNow() && npc.checkDoCastConditions(skill))
{
npc.setTarget(player);
npc.doCast(skill);
}
}
public static void main(String[] args)
{
new HotSprings();
}
}

View File

@@ -0,0 +1,455 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import java.util.HashSet;
import java.util.Set;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.MinionHolder;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Minion Spawn Manager.
* @author Zealar
*/
public final class MinionSpawnManager extends AbstractNpcAI
{
private static final Set<Integer> NPC = new HashSet<>(354);
static
{
NPC.add(18344); // Ancient Egg
NPC.add(18352); // Kamael Guard
NPC.add(18353); // Guardian of Records
NPC.add(18354); // Guardian of Observation
NPC.add(18355); // Spicula's Guard
NPC.add(18356); // Harkilgamed's Gatekeeper
NPC.add(18357); // Rodenpicula's Gatekeeper
NPC.add(18359); // Arviterre's Guardian
NPC.add(18360); // Katenar's Gatekeeper
NPC.add(18361); // Guardian of Prediction
NPC.add(18484); // Naia Failan
NPC.add(18491); // Lock
NPC.add(18547); // Ancient Experiment
NPC.add(18551); // Cruma Phantom
NPC.add(35375); // Bloody Lord Nurka
NPC.add(20376); // Varikan Brigand Leader
NPC.add(20398); // Vrykolakas
NPC.add(20520); // Pirate Captain Uthanka
NPC.add(20522); // White Fang
NPC.add(20738); // Kobold Looter Bepook
NPC.add(20745); // Gigantiops
NPC.add(20747); // Roxide
NPC.add(20749); // Death Fire
NPC.add(20751); // Snipe
NPC.add(20753); // Dark Lord
NPC.add(20755); // Talakin
NPC.add(20758); // Dragon Bearer Chief
NPC.add(20761); // Pytan
NPC.add(20767); // Timak Orc Troop Leader
NPC.add(20773); // Conjurer Bat Lord
NPC.add(20939); // Tanor Silenos Warrior
NPC.add(20941); // Tanor Silenos Chieftain
NPC.add(20944); // Nightmare Lord
NPC.add(20956); // Past Knight
NPC.add(20959); // Dark Guard
NPC.add(20963); // Bloody Lord
NPC.add(20974); // Spiteful Soul Leader
NPC.add(20977); // Elmoradan's Lady
NPC.add(20980); // Hallate's Follower Mul
NPC.add(20983); // Binder
NPC.add(20986); // Sairon
NPC.add(20991); // Swamp Tribe
NPC.add(20994); // Garden Guard Leader
NPC.add(21075); // Slaughter Bathin
NPC.add(21078); // Magus Valac
NPC.add(21081); // Power Angel Amon
NPC.add(21090); // Bloody Guardian
NPC.add(21312); // Eye of Ruler
NPC.add(21343); // Ketra Commander
NPC.add(21345); // Ketra's Head Shaman
NPC.add(21347); // Ketra Prophet
NPC.add(21369); // Varka's Commander
NPC.add(21371); // Varka's Head Magus
NPC.add(21373); // Varka's Prophet
NPC.add(21432); // Chakram Beetle
NPC.add(21434); // Seer of Blood
NPC.add(21512); // Splinter Stakato Drone
NPC.add(21517); // Needle Stakato Drone
NPC.add(21541); // Pilgrim of Splendor
NPC.add(21544); // Judge of Splendor
NPC.add(21596); // Requiem Lord
NPC.add(21599); // Requiem Priest
NPC.add(21652); // Scarlet Stakato Noble
NPC.add(21653); // Assassin Beetle
NPC.add(21654); // Necromancer of Destruction
NPC.add(21655); // Arimanes of Destruction
NPC.add(21656); // Ashuras of Destruction
NPC.add(21657); // Magma Drake
NPC.add(22028); // Vagabond of the Ruins
NPC.add(22080); // Massive Lost Bandersnatch
NPC.add(22084); // Panthera
NPC.add(22092); // Frost Iron Golem
NPC.add(22096); // Ursus
NPC.add(22100); // Freya's Gardener
NPC.add(22102); // Freya's Servant
NPC.add(22104); // Freya's Dog
NPC.add(22155); // Triol's High Priest
NPC.add(22159); // Triol's High Priest
NPC.add(22163); // Triol's High Priest
NPC.add(22167); // Triol's High Priest
NPC.add(22171); // Triol's High Priest
NPC.add(22188); // Andreas' Captain of the Royal Guard
NPC.add(22196); // Velociraptor
NPC.add(22198); // Velociraptor
NPC.add(22202); // Ornithomimus
NPC.add(22205); // Deinonychus
NPC.add(22210); // Pachycephalosaurus
NPC.add(22213); // Wild Strider
NPC.add(22223); // Velociraptor
NPC.add(22224); // Ornithomimus
NPC.add(22225); // Deinonychus
NPC.add(22275); // Gatekeeper Lohan
NPC.add(22277); // Gatekeeper Provo
NPC.add(22305); // Kechi's Captain
NPC.add(22306); // Kechi's Captain
NPC.add(22307); // Kechi's Captain
NPC.add(22320); // Junior Watchman
NPC.add(22321); // Junior Summoner
NPC.add(22346); // Quarry Foreman
NPC.add(22363); // Body Destroyer
NPC.add(22370); // Passageway Captain
NPC.add(22377); // Master Zelos
NPC.add(22390); // Foundry Foreman
NPC.add(22416); // Kechi's Captain
NPC.add(22423); // Original Sin Warden
NPC.add(22431); // Original Sin Warden
NPC.add(22448); // Leodas
NPC.add(22449); // Amaskari
NPC.add(22621); // Male Spiked Stakato
NPC.add(22625); // Cannibalistic Stakato Leader
NPC.add(22630); // Spiked Stakato Nurse
NPC.add(22666); // Barif
NPC.add(22670); // Cursed Lord
NPC.add(22742); // Ornithomimus
NPC.add(22743); // Deinonychus
NPC.add(25001); // Greyclaw Kutus
NPC.add(25004); // Turek Mercenary Captain
NPC.add(25007); // Retreat Spider Cletu
NPC.add(25010); // Furious Thieles
NPC.add(25013); // Ghost of Peasant Leader
NPC.add(25016); // The 3rd Underwater Guardian
NPC.add(25020); // Breka Warlock Pastu
NPC.add(25023); // Stakato Queen Zyrnna
NPC.add(25026); // Ketra Commander Atis
NPC.add(25029); // Atraiban
NPC.add(25032); // Eva's Guardian Millenu
NPC.add(25035); // Shilen's Messenger Cabrio
NPC.add(25038); // Tirak
NPC.add(25041); // Remmel
NPC.add(25044); // Barion
NPC.add(25047); // Karte
NPC.add(25051); // Rahha
NPC.add(25054); // Kernon
NPC.add(25057); // Beacon of Blue Sky
NPC.add(25060); // Unrequited Kael
NPC.add(25064); // Wizard of Storm Teruk
NPC.add(25067); // Captain of Red Flag Shaka
NPC.add(25070); // Enchanted Forest Watcher Ruell
NPC.add(25073); // Bloody Priest Rudelto
NPC.add(25076); // Princess Molrang
NPC.add(25079); // Cat's Eye Bandit
NPC.add(25082); // Leader of Cat Gang
NPC.add(25085); // Timak Orc Chief Ranger
NPC.add(25089); // Soulless Wild Boar
NPC.add(25092); // Korim
NPC.add(25095); // Elf Renoa
NPC.add(25099); // Rotting Tree Repiro
NPC.add(25103); // Sorcerer Isirr
NPC.add(25106); // Ghost of the Well Lidia
NPC.add(25109); // Antharas Priest Cloe
NPC.add(25112); // Beleth's Agent, Meana
NPC.add(25115); // Icarus Sample 1
NPC.add(25119); // Messenger of Fairy Queen Berun
NPC.add(25122); // Refugee Applicant Leo
NPC.add(25128); // Vuku Grand Seer Gharmash
NPC.add(25131); // Carnage Lord Gato
NPC.add(25134); // Leto Chief Talkin
NPC.add(25137); // Beleth's Seer, Sephia
NPC.add(25140); // Hekaton Prime
NPC.add(25143); // Fire of Wrath Shuriel
NPC.add(25146); // Serpent Demon Bifrons
NPC.add(25149); // Zombie Lord Crowl
NPC.add(25152); // Flame Lord Shadar
NPC.add(25155); // Shaman King Selu
NPC.add(25159); // Paniel the Unicorn
NPC.add(25166); // Ikuntai
NPC.add(25170); // Lizardmen Leader Hellion
NPC.add(25173); // Tiger King Karuta
NPC.add(25176); // Black Lily
NPC.add(25179); // Guardian of the Statue of Giant Karum
NPC.add(25182); // Demon Kuri
NPC.add(25185); // Tasaba Patriarch Hellena
NPC.add(25189); // Cronos's Servitor Mumu
NPC.add(25192); // Earth Protector Panathen
NPC.add(25199); // Water Dragon Seer Sheshark
NPC.add(25202); // Krokian Padisha Sobekk
NPC.add(25205); // Ocean Flame Ashakiel
NPC.add(25208); // Water Couatle Ateka
NPC.add(25211); // Sebek
NPC.add(25214); // Fafurion's Page Sika
NPC.add(25217); // Cursed Clara
NPC.add(25220); // Death Lord Hallate
NPC.add(25223); // Soul Collector Acheron
NPC.add(25226); // Roaring Lord Kastor
NPC.add(25230); // Timak Seer Ragoth
NPC.add(25235); // Vanor Chief Kandra
NPC.add(25238); // Abyss Brukunt
NPC.add(25241); // Harit Hero Tamash
NPC.add(25245); // Last Lesser Giant Glaki
NPC.add(25249); // Menacing Palatanos
NPC.add(25252); // Palibati Queen Themis
NPC.add(25256); // Taik High Prefect Arak
NPC.add(25260); // Iron Giant Totem
NPC.add(25263); // Kernon's Faithful Servant Kelone
NPC.add(25266); // Bloody Empress Decarbia
NPC.add(25269); // Beast Lord Behemoth
NPC.add(25273); // Carnamakos
NPC.add(25277); // Lilith's Witch Marilion
NPC.add(25283); // Lilith
NPC.add(25286); // Anakim
NPC.add(25290); // Daimon the White-Eyed
NPC.add(25293); // Hesti Guardian Deity of the Hot Springs
NPC.add(25296); // Icicle Emperor Bumbalump
NPC.add(25299); // Ketra's Hero Hekaton
NPC.add(25302); // Ketra's Commander Tayr
NPC.add(25306); // Soul of Fire Nastron
NPC.add(25309); // Varka's Hero Shadith
NPC.add(25312); // Varka's Commander Mos
NPC.add(25316); // Soul of Water Ashutar
NPC.add(25319); // Ember
NPC.add(25322); // Demon's Agent Falston
NPC.add(25325); // Flame of Splendor Barakiel
NPC.add(25328); // Eilhalder von Hellmann
NPC.add(25352); // Giant Wasteland Basilisk
NPC.add(25354); // Gargoyle Lord Sirocco
NPC.add(25357); // Sukar Wererat Chief
NPC.add(25360); // Tiger Hornet
NPC.add(25362); // Tracker Leader Sharuk
NPC.add(25366); // Kuroboros' Priest
NPC.add(25369); // Soul Scavenger
NPC.add(25373); // Malex Herald of Dagoniel
NPC.add(25375); // Zombie Lord Ferkel
NPC.add(25378); // Madness Beast
NPC.add(25380); // Kaysha Herald of Icarus
NPC.add(25383); // Revenant of Sir Calibus
NPC.add(25385); // Evil Spirit Tempest
NPC.add(25388); // Red Eye Captain Trakia
NPC.add(25392); // Captain of Queen's Royal Guards
NPC.add(25395); // Archon Suscepter
NPC.add(25398); // Beleth's Eye
NPC.add(25401); // Skyla
NPC.add(25404); // Corsair Captain Kylon
NPC.add(25407); // Lord Ishka
NPC.add(25410); // Road Scavenger Leader
NPC.add(25412); // Necrosentinel Royal Guard
NPC.add(25415); // Nakondas
NPC.add(25418); // Dread Avenger Kraven
NPC.add(25420); // Orfen's Handmaiden
NPC.add(25423); // Fairy Queen Timiniel
NPC.add(25426); // Betrayer of Urutu Freki
NPC.add(25429); // Mammon Collector Talos
NPC.add(25431); // Flamestone Golem
NPC.add(25434); // Bandit Leader Barda
NPC.add(25438); // Thief Kelbar
NPC.add(25441); // Evil Spirit Cyrion
NPC.add(25444); // Enmity Ghost Ramdal
NPC.add(25447); // Immortal Savior Mardil
NPC.add(25450); // Cherub Galaxia
NPC.add(25453); // Meanas Anor
NPC.add(25456); // Mirror of Oblivion
NPC.add(25460); // Deadman Ereve
NPC.add(25463); // Harit Guardian Garangky
NPC.add(25467); // Gorgolos
NPC.add(25470); // Last Titan Utenus
NPC.add(25473); // Grave Robber Kim
NPC.add(25475); // Ghost Knight Kabed
NPC.add(25478); // Shilen's Priest Hisilrome
NPC.add(25481); // Magus Kenishee
NPC.add(25484); // Zaken's Chief Mate Tillion
NPC.add(25487); // Water Spirit Lian
NPC.add(25490); // Gwindorr
NPC.add(25493); // Eva's Spirit Niniel
NPC.add(25496); // Fafurion's Envoy Pingolpin
NPC.add(25498); // Fafurion's Henchman Istary
NPC.add(25501); // Boss Akata
NPC.add(25504); // Nellis' Vengeful Spirit
NPC.add(25506); // Rayito the Looter
NPC.add(25509); // Dark Shaman Varangka
NPC.add(25514); // Queen Shyeed
NPC.add(25524); // Flamestone Giant
NPC.add(25528); // Tiberias
NPC.add(25536); // Hannibal
NPC.add(25546); // Rhianna the Traitor
NPC.add(25549); // Tesla the Deceiver
NPC.add(25554); // Brutus the Obstinate
NPC.add(25557); // Ranger Karankawa
NPC.add(25560); // Sargon the Mad
NPC.add(25563); // Beautiful Atrielle
NPC.add(25566); // Nagen the Tomboy
NPC.add(25569); // Jax the Destroyer
NPC.add(25572); // Hager the Outlaw
NPC.add(25575); // All-Seeing Rango
NPC.add(25579); // Helsing
NPC.add(25582); // Gillien
NPC.add(25585); // Medici
NPC.add(25589); // Brand the Exile
NPC.add(25593); // Gerg the Hunter
NPC.add(25600); // Temenir
NPC.add(25601); // Draksius
NPC.add(25602); // Kiretcenah
NPC.add(25671); // Queen Shyeed
NPC.add(25674); // Gwindorr
NPC.add(25677); // Water Spirit Lian
NPC.add(25681); // Gorgolos
NPC.add(25684); // Last Titan Utenus
NPC.add(25687); // Hekaton Prime
NPC.add(25703); // Gigantic Golem
NPC.add(25710); // Lost Captain
NPC.add(25735); // Greyclaw Kutus
NPC.add(25738); // Lead Tracker Sharuk
NPC.add(25741); // Sukar Wererat Chief
NPC.add(25744); // Ikuntai
NPC.add(25747); // Zombie Lord Crowl
NPC.add(25750); // Zombie Lord Ferkel
NPC.add(25754); // Fire Lord Shadar
NPC.add(25757); // Soul Collector Acheron
NPC.add(25760); // Lord Ishka
NPC.add(25763); // Demon Kuri
NPC.add(25767); // Carnage Lord Gato
NPC.add(25770); // Ketra Commander Atis
NPC.add(25773); // Beacon of Blue Sky
NPC.add(25776); // Earth Protector Panathen
NPC.add(25779); // Betrayer of Urutu Freki
NPC.add(25782); // Nellis' Vengeful Spirit
NPC.add(25784); // Rayito the Looter
NPC.add(25787); // Ketra's Hero Hekaton
NPC.add(25790); // Varka's Hero Shadith
NPC.add(25794); // Kernon
NPC.add(25797); // Meanas Anor
NPC.add(25800); // Mammon Collector Talos
NPC.add(27036); // Calpico
NPC.add(27041); // Varangka's Messenger
NPC.add(27062); // Tanukia
NPC.add(27065); // Roko
NPC.add(27068); // Murtika
NPC.add(27093); // Delu Chief Kalkis
NPC.add(27108); // Stenoa Gorgon Queen
NPC.add(27110); // Shyslassys
NPC.add(27112); // Gorr
NPC.add(27113); // Baraham
NPC.add(27114); // Succubus Queen
NPC.add(27185); // Fairy Tree of Wind
NPC.add(27186); // Fairy Tree of Star
NPC.add(27187); // Fairy Tree of Twilight
NPC.add(27188); // Fairy Tree of Abyss
NPC.add(27259); // Archangel Iconoclasis
NPC.add(27260); // Archangel Iconoclasis
NPC.add(27266); // Fallen Angel Haures
NPC.add(27267); // Fallen Angel Haures
NPC.add(27290); // White Wing Commander
NPC.add(29030); // Fenril Hound Kerinne
NPC.add(29033); // Fenril Hound Freki
NPC.add(29037); // Fenril Hound Kinaz
NPC.add(29040); // Wings of Flame, Ixion
NPC.add(29056); // Ice Fairy Sirra
NPC.add(29062); // Andreas Van Halter
NPC.add(29096); // Anais
NPC.add(29129); // Lost Captain
NPC.add(29132); // Lost Captain
NPC.add(29135); // Lost Captain
NPC.add(29138); // Lost Captain
NPC.add(29141); // Lost Captain
NPC.add(29144); // Lost Captain
NPC.add(29147); // Lost Captain
}
private static final NpcStringId[] ON_ATTACK_MSG =
{
NpcStringId.COME_OUT_YOU_CHILDREN_OF_DARKNESS,
NpcStringId.SHOW_YOURSELVES,
NpcStringId.DESTROY_THE_ENEMY_MY_BROTHERS,
NpcStringId.FORCES_OF_DARKNESS_FOLLOW_ME
};
private static final int[] ON_ATTACK_NPC =
{
20767, // Timak Orc Troop Leader
};
private MinionSpawnManager()
{
super(MinionSpawnManager.class.getSimpleName(), "ai/group_template");
addSpawnId(NPC);
addAttackId(ON_ATTACK_NPC);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.getTemplate().getParameters().getSet().get("SummonPrivateRate") == null)
{
((L2MonsterInstance) npc).getMinionList().spawnMinions(npc.getTemplate().getParameters().getMinionList("Privates"));
}
return super.onSpawn(npc);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.isMonster())
{
final L2MonsterInstance monster = (L2MonsterInstance) npc;
if (!monster.isTeleporting())
{
if (getRandom(1, 100) <= npc.getTemplate().getParameters().getInt("SummonPrivateRate", 0))
{
for (MinionHolder is : npc.getTemplate().getParameters().getMinionList("Privates"))
{
addMinion((L2MonsterInstance) npc, is.getId());
}
broadcastNpcSay(npc, ChatType.NPC_GENERAL, ON_ATTACK_MSG[getRandom(ON_ATTACK_MSG.length)]);
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
public static void main(String[] args)
{
new MinionSpawnManager();
}
}

View File

@@ -0,0 +1,296 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.effects.L2EffectType;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Monastery of Silence AI.
* @author Kerberos, nonom
*/
public final class MonasteryOfSilence extends AbstractNpcAI
{
// NPCs
private static final int CAPTAIN = 18910; // Solina Knight Captain
private static final int KNIGHT = 18909; // Solina Knights
private static final int SCARECROW = 18912; // Scarecrow
private static final int GUIDE = 22789; // Guide Solina
private static final int SEEKER = 22790; // Seeker Solina
private static final int SAVIOR = 22791; // Savior Solina
private static final int ASCETIC = 22793; // Ascetic Solina
private static final int[] DIVINITY_CLAN =
{
22794, // Divinity Judge
22795, // Divinity Manager
};
// Skills
private static final SkillHolder ORDEAL_STRIKE = new SkillHolder(6303, 1); // Trial of the Coup
private static final SkillHolder LEADER_STRIKE = new SkillHolder(6304, 1); // Shock
private static final SkillHolder SAVER_STRIKE = new SkillHolder(6305, 1); // Sacred Gnosis
private static final SkillHolder SAVER_BLEED = new SkillHolder(6306, 1); // Solina Strike
private static final SkillHolder LEARNING_MAGIC = new SkillHolder(6308, 1); // Opus of the Wave
private static final SkillHolder STUDENT_CANCEL = new SkillHolder(6310, 1); // Loss of Quest
private static final SkillHolder WARRIOR_THRUSTING = new SkillHolder(6311, 1); // Solina Thrust
private static final SkillHolder KNIGHT_BLESS = new SkillHolder(6313, 1); // Solina Bless
// Misc
private static final NpcStringId[] DIVINITY_MSG =
{
NpcStringId.S1_WHY_WOULD_YOU_CHOOSE_THE_PATH_OF_DARKNESS,
NpcStringId.S1_HOW_DARE_YOU_DEFY_THE_WILL_OF_EINHASAD
};
private static final NpcStringId[] SOLINA_KNIGHTS_MSG =
{
NpcStringId.PUNISH_ALL_THOSE_WHO_TREAD_FOOTSTEPS_IN_THIS_PLACE,
NpcStringId.WE_ARE_THE_SWORD_OF_TRUTH_THE_SWORD_OF_SOLINA,
NpcStringId.WE_RAISE_OUR_BLADES_FOR_THE_GLORY_OF_SOLINA
};
private MonasteryOfSilence()
{
super(MonasteryOfSilence.class.getSimpleName(), "ai/group_template");
addSkillSeeId(DIVINITY_CLAN);
addAttackId(KNIGHT, CAPTAIN, GUIDE, SEEKER, ASCETIC);
addNpcHateId(GUIDE, SEEKER, SAVIOR, ASCETIC);
addAggroRangeEnterId(GUIDE, SEEKER, SAVIOR, ASCETIC);
addSpawnId(SCARECROW);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "TRAINING":
{
for (L2Character character : npc.getKnownList().getKnownCharactersInRadius(400))
{
if ((getRandom(100) < 30) && character.isNpc() && !character.isDead() && !character.isInCombat())
{
if ((character.getId() == CAPTAIN) && (getRandom(100) < 10) && npc.isScriptValue(0))
{
final L2Npc captain = (L2Npc) character;
broadcastNpcSay(captain, ChatType.NPC_GENERAL, SOLINA_KNIGHTS_MSG[getRandom(SOLINA_KNIGHTS_MSG.length)]);
captain.setScriptValue(1);
startQuestTimer("TIMER", 10000, captain, null);
}
else if (character.getId() == KNIGHT)
{
character.setRunning();
((L2Attackable) character).addDamageHate(npc, 0, 100);
character.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, npc, null);
}
}
}
break;
}
case "DO_CAST":
{
if ((npc != null) && (player != null) && (getRandom(100) < 3))
{
if (npc.checkDoCastConditions(STUDENT_CANCEL.getSkill()))
{
npc.setTarget(player);
npc.doCast(STUDENT_CANCEL.getSkill());
}
npc.setScriptValue(0);
}
break;
}
case "TIMER":
{
if (npc != null)
{
npc.setScriptValue(0);
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
final L2Attackable mob = (L2Attackable) npc;
switch (npc.getId())
{
case KNIGHT:
{
if ((getRandom(100) < 10) && (mob.getMostHated() == player) && mob.checkDoCastConditions(WARRIOR_THRUSTING.getSkill()))
{
npc.setTarget(player);
npc.doCast(WARRIOR_THRUSTING.getSkill());
}
break;
}
case CAPTAIN:
{
if ((getRandom(100) < 20) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) && npc.isScriptValue(0))
{
if (npc.checkDoCastConditions(KNIGHT_BLESS.getSkill()))
{
npc.setTarget(npc);
npc.doCast(KNIGHT_BLESS.getSkill());
}
npc.setScriptValue(1);
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.FOR_THE_GLORY_OF_SOLINA);
addAttackPlayerDesire(addSpawn(KNIGHT, npc), player);
}
break;
}
case GUIDE:
{
if ((getRandom(100) < 3) && (mob.getMostHated() == player) && npc.checkDoCastConditions(ORDEAL_STRIKE.getSkill()))
{
npc.setTarget(player);
npc.doCast(ORDEAL_STRIKE.getSkill());
}
break;
}
case SEEKER:
{
if ((getRandom(100) < 33) && (mob.getMostHated() == player) && npc.checkDoCastConditions(SAVER_STRIKE.getSkill()))
{
npc.setTarget(npc);
npc.doCast(SAVER_STRIKE.getSkill());
}
break;
}
case ASCETIC:
{
if ((mob.getMostHated() == player) && npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("DO_CAST", 20000, npc, player);
}
break;
}
}
return super.onAttack(npc, player, damage, isSummon);
}
@Override
public boolean onNpcHate(L2Attackable mob, L2PcInstance player, boolean isSummon)
{
return player.getActiveWeaponInstance() != null;
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (player.getActiveWeaponInstance() != null)
{
SkillHolder skill = null;
switch (npc.getId())
{
case GUIDE:
{
if (getRandom(100) < 3)
{
skill = LEADER_STRIKE;
}
break;
}
case SEEKER:
{
skill = SAVER_BLEED;
break;
}
case SAVIOR:
{
skill = LEARNING_MAGIC;
break;
}
case ASCETIC:
{
if (getRandom(100) < 3)
{
skill = STUDENT_CANCEL;
}
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("DO_CAST", 20000, npc, player);
}
break;
}
}
if ((skill != null) && npc.checkDoCastConditions(skill.getSkill()))
{
npc.setTarget(player);
npc.doCast(skill.getSkill());
}
if (!npc.isInCombat())
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.YOU_CANNOT_CARRY_A_WEAPON_WITHOUT_AUTHORIZATION);
}
addAttackPlayerDesire(npc, player);
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (skill.hasEffectType(L2EffectType.AGGRESSION) && (targets.length != 0))
{
for (L2Object obj : targets)
{
if (obj.equals(npc))
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, DIVINITY_MSG[getRandom(DIVINITY_MSG.length)], caster.getName());
addAttackPlayerDesire(npc, caster);
break;
}
}
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setIsInvul(true);
npc.disableCoreAI(true);
startQuestTimer("TRAINING", 30000, npc, null, true);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new MonasteryOfSilence();
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* @author UnAfraid
*/
public final class NonLethalableNpcs extends AbstractNpcAI
{
private static final int[] NPCS =
{
35062, // Headquarters
};
public NonLethalableNpcs()
{
super(NonLethalableNpcs.class.getSimpleName(), "ai/group_template");
addSpawnId(NPCS);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setLethalable(false);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new NonLethalableNpcs();
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* Pagan Temple AI.
* @author Mobius
*/
public class PaganTemple extends AbstractNpcAI
{
// Npc
private static final int CHAPEL_GATEKEEPER = 22138;
public PaganTemple()
{
super(PaganTemple.class.getSimpleName(), "ai/group_template");
addSpawnId(CHAPEL_GATEKEEPER);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setIsNoRndWalk(true);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new PaganTemple();
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* Pavel Archaic AI.
* @author Gnacik, St3eT
*/
public final class PavelArchaic extends AbstractNpcAI
{
private static final int SAFETY_DEVICE = 18917; // Pavel Safety Device
private static final int PINCER_GOLEM = 22801; // Cruel Pincer Golem
private static final int PINCER_GOLEM2 = 22802; // Cruel Pincer Golem
private static final int PINCER_GOLEM3 = 22803; // Cruel Pincer Golem
private static final int JACKHAMMER_GOLEM = 22804; // Horrifying Jackhammer Golem
private PavelArchaic()
{
super(PavelArchaic.class.getSimpleName(), "ai/group_template");
addKillId(SAFETY_DEVICE, PINCER_GOLEM, JACKHAMMER_GOLEM);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (getRandom(100) < 70)
{
final L2Npc golem1 = addSpawn(PINCER_GOLEM2, npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), false, 0, false);
addAttackPlayerDesire(golem1, killer);
final L2Npc golem2 = addSpawn(PINCER_GOLEM3, npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), false, 0, false);
addAttackPlayerDesire(golem2, killer);
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new PavelArchaic();
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.util.Util;
/**
* AI for mobs in Plains of Dion (near Floran Village).
* @author Gladicek
*/
public final class PlainsOfDion extends AbstractNpcAI
{
private static final int DELU_LIZARDMEN[] =
{
21104, // Delu Lizardman Supplier
21105, // Delu Lizardman Special Agent
21107, // Delu Lizardman Commander
};
private static final NpcStringId[] MONSTERS_MSG =
{
NpcStringId.S1_HOW_DARE_YOU_INTERRUPT_OUR_FIGHT_HEY_GUYS_HELP,
NpcStringId.S1_HEY_WE_RE_HAVING_A_DUEL_HERE,
NpcStringId.THE_DUEL_IS_OVER_ATTACK,
NpcStringId.FOUL_KILL_THE_COWARD,
NpcStringId.HOW_DARE_YOU_INTERRUPT_A_SACRED_DUEL_YOU_MUST_BE_TAUGHT_A_LESSON
};
private static final NpcStringId[] MONSTERS_ASSIST_MSG =
{
NpcStringId.DIE_YOU_COWARD,
NpcStringId.KILL_THE_COWARD,
NpcStringId.WHAT_ARE_YOU_LOOKING_AT
};
private PlainsOfDion()
{
super(PlainsOfDion.class.getSimpleName(), "ai/group_template");
addAttackId(DELU_LIZARDMEN);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
if (npc.isScriptValue(0))
{
final int i = getRandom(5);
if (i < 2)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, MONSTERS_MSG[i], player.getName());
}
else
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, MONSTERS_MSG[i]);
}
for (L2Character obj : npc.getKnownList().getKnownCharactersInRadius(npc.getTemplate().getClanHelpRange()))
{
if (obj.isMonster() && Util.contains(DELU_LIZARDMEN, obj.getId()) && !obj.isAttackingNow() && !obj.isDead() && GeoData.getInstance().canSeeTarget(npc, obj))
{
final L2Npc monster = (L2Npc) obj;
addAttackPlayerDesire(monster, player);
broadcastNpcSay(monster, ChatType.NPC_GENERAL, MONSTERS_ASSIST_MSG[getRandom(3)]);
}
}
npc.setScriptValue(1);
}
return super.onAttack(npc, player, damage, isSummon);
}
public static void main(String[] args)
{
new PlainsOfDion();
}
}

View File

@@ -0,0 +1,244 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
/**
* Plains of Lizardmen AI.
* @author Gnacik, malyelfik
*/
public final class PlainsOfLizardman extends AbstractNpcAI
{
// NPCs
private static final int INVISIBLE_NPC = 18919;
private static final int TANTA_GUARD = 18862;
private static final int FANTASY_MUSHROOM = 18864;
private static final int STICKY_MUSHROOM = 18865;
private static final int RAINBOW_FROG = 18866;
private static final int ENERGY_PLANT = 18868;
private static final int TANTA_SCOUT = 22768;
private static final int TANTA_MAGICIAN = 22773;
private static final int TANTA_SUMMONER = 22774;
private static final int[] TANTA_LIZARDMEN =
{
22768, // Tanta Lizardman Scout
22769, // Tanta Lizardman Warrior
22770, // Tanta Lizardman Soldier
22771, // Tanta Lizardman Berserker
22772, // Tanta Lizardman Archer
22773, // Tanta Lizardman Magician
22774, // Tanta Lizardman Summoner
};
// Skills
private static final SkillHolder STUN_EFFECT = new SkillHolder(6622, 1);
private static final SkillHolder DEMOTIVATION_HEX = new SkillHolder(6425, 1);
private static final SkillHolder FANTASY_MUSHROOM_SKILL = new SkillHolder(6427, 1);
private static final SkillHolder RAINBOW_FROG_SKILL = new SkillHolder(6429, 1);
private static final SkillHolder STICKY_MUSHROOM_SKILL = new SkillHolder(6428, 1);
private static final SkillHolder ENERGY_PLANT_SKILL = new SkillHolder(6430, 1);
// Buffs
private static final SkillHolder[] BUFFS =
{
new SkillHolder(6625, 1), // Energy of Life
new SkillHolder(6626, 2), // Energy of Life's Power
new SkillHolder(6627, 3), // Energy of Life's Highest Power
new SkillHolder(6628, 1), // Energy of Mana
new SkillHolder(6629, 2), // Energy of Mana's Power
new SkillHolder(6630, 3), // Energy of Mana's Highest Power
new SkillHolder(6631, 1), // Energy of Power
new SkillHolder(6633, 1), // Energy of Attack Speed
new SkillHolder(6635, 1), // Energy of Crt Rate
new SkillHolder(6636, 1), // Energy of Moving Speed
new SkillHolder(6638, 1), // Aura of Mystery
new SkillHolder(6639, 1), // Bane of Auras - Damage
new SkillHolder(6640, 1), // Energizing Aura
new SkillHolder(6674, 1), // Energy of Range Increment
};
// Misc
// @formatter:off
private static final int[] BUFF_LIST =
{
6, 7, 8, 11, 13
};
// @formatter:on
private PlainsOfLizardman()
{
super(PlainsOfLizardman.class.getSimpleName(), "ai/group_template");
addAttackId(FANTASY_MUSHROOM, RAINBOW_FROG, STICKY_MUSHROOM, ENERGY_PLANT, TANTA_SUMMONER);
addKillId(TANTA_LIZARDMEN);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("fantasy_mushroom") && (npc != null) && (player != null))
{
npc.doCast(FANTASY_MUSHROOM_SKILL.getSkill());
for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(200))
{
if ((target != null) && target.isAttackable())
{
final L2Npc monster = (L2Npc) target;
npc.setTarget(monster);
npc.doCast(STUN_EFFECT.getSkill());
addAttackPlayerDesire(monster, player);
}
}
npc.doDie(player);
}
return null;
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
switch (npc.getId())
{
case TANTA_SUMMONER:
if (!npc.isAffectedBySkill(DEMOTIVATION_HEX.getSkillId()))
{
npc.doCast(DEMOTIVATION_HEX.getSkill());
}
break;
case RAINBOW_FROG:
castSkill(npc, attacker, RAINBOW_FROG_SKILL);
break;
case ENERGY_PLANT:
castSkill(npc, attacker, ENERGY_PLANT_SKILL);
break;
case STICKY_MUSHROOM:
castSkill(npc, attacker, STICKY_MUSHROOM_SKILL);
break;
case FANTASY_MUSHROOM:
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
npc.setIsInvul(true);
for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(1000))
{
if ((target != null) && target.isAttackable())
{
final L2Attackable monster = (L2Attackable) target;
if ((monster.getId() == TANTA_MAGICIAN) || (monster.getId() == TANTA_SCOUT))
{
target.setIsRunning(true);
target.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(npc.getX(), npc.getY(), npc.getZ(), 0));
}
}
}
startQuestTimer("fantasy_mushroom", 4000, npc, attacker);
}
break;
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
// Tanta Guard
if (getRandom(1000) == 0)
{
addAttackPlayerDesire(addSpawn(TANTA_GUARD, npc), killer);
}
// Invisible buff npc
final int random = getRandom(100);
final L2Npc buffer = addSpawn(INVISIBLE_NPC, npc.getLocation(), false, 6000);
buffer.setTarget(killer);
if (random <= 42)
{
castRandomBuff(buffer, 7, 45, BUFFS[0], BUFFS[1], BUFFS[2]);
}
if (random <= 11)
{
castRandomBuff(buffer, 8, 60, BUFFS[3], BUFFS[4], BUFFS[5]);
castRandomBuff(buffer, 3, 6, BUFFS[9], BUFFS[10], BUFFS[12]);
}
if (random <= 25)
{
buffer.doCast(BUFFS[BUFF_LIST[getRandom(BUFF_LIST.length)]].getSkill());
}
if (random <= 10)
{
buffer.doCast(BUFFS[13].getSkill());
}
if (random <= 1)
{
final int i = getRandom(100);
if (i <= 34)
{
buffer.doCast(BUFFS[6].getSkill());
buffer.doCast(BUFFS[7].getSkill());
buffer.doCast(BUFFS[8].getSkill());
}
else if (i < 67)
{
buffer.doCast(BUFFS[13].getSkill());
}
else
{
buffer.doCast(BUFFS[2].getSkill());
buffer.doCast(BUFFS[5].getSkill());
}
}
return super.onKill(npc, killer, isSummon);
}
private void castRandomBuff(L2Npc npc, int chance1, int chance2, SkillHolder... buffs)
{
final int rand = getRandom(100);
if (rand <= chance1)
{
npc.doCast(buffs[2].getSkill());
}
else if (rand <= chance2)
{
npc.doCast(buffs[1].getSkill());
}
else
{
npc.doCast(buffs[0].getSkill());
}
}
@Override
protected void castSkill(L2Npc npc, L2Playable target, SkillHolder skill)
{
npc.doDie(target);
super.castSkill(addSpawn(INVISIBLE_NPC, npc, false, 6000), target, skill);
}
public static void main(String[] args)
{
new PlainsOfLizardman();
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import java.util.HashMap;
import java.util.Map;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* Angel spawns...when one of the angels in the keys dies, the other angel will spawn.
*/
public final class PolymorphingAngel extends AbstractNpcAI
{
private static final Map<Integer, Integer> ANGELSPAWNS = new HashMap<>();
static
{
ANGELSPAWNS.put(20830, 20859);
ANGELSPAWNS.put(21067, 21068);
ANGELSPAWNS.put(21062, 21063);
ANGELSPAWNS.put(20831, 20860);
ANGELSPAWNS.put(21070, 21071);
}
private PolymorphingAngel()
{
super(PolymorphingAngel.class.getSimpleName(), "ai/group_template");
addKillId(ANGELSPAWNS.keySet());
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
final L2Attackable newNpc = (L2Attackable) addSpawn(ANGELSPAWNS.get(npc.getId()), npc);
newNpc.setRunning();
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new PolymorphingAngel();
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.serverpackets.CreatureSay;
/**
* Polymorphing on attack monsters AI.
* @author Slyce
*/
public final class PolymorphingOnAttack extends AbstractNpcAI
{
private static final Map<Integer, List<Integer>> MOBSPAWNS = new HashMap<>();
static
{
MOBSPAWNS.put(21258, Arrays.asList(21259, 100, 100, -1)); // Fallen Orc Shaman -> Sharp Talon Tiger (always polymorphs)
MOBSPAWNS.put(21261, Arrays.asList(21262, 100, 20, 0)); // Ol Mahum Transcender 1st stage
MOBSPAWNS.put(21262, Arrays.asList(21263, 100, 10, 1)); // Ol Mahum Transcender 2nd stage
MOBSPAWNS.put(21263, Arrays.asList(21264, 100, 5, 2)); // Ol Mahum Transcender 3rd stage
MOBSPAWNS.put(21265, Arrays.asList(21271, 100, 33, 0)); // Cave Ant Larva -> Cave Ant
MOBSPAWNS.put(21266, Arrays.asList(21269, 100, 100, -1)); // Cave Ant Larva -> Cave Ant (always polymorphs)
MOBSPAWNS.put(21267, Arrays.asList(21270, 100, 100, -1)); // Cave Ant Larva -> Cave Ant Soldier (always polymorphs)
MOBSPAWNS.put(21271, Arrays.asList(21272, 66, 10, 1)); // Cave Ant -> Cave Ant Soldier
MOBSPAWNS.put(21272, Arrays.asList(21273, 33, 5, 2)); // Cave Ant Soldier -> Cave Noble Ant
MOBSPAWNS.put(21521, Arrays.asList(21522, 100, 30, -1)); // Claws of Splendor
MOBSPAWNS.put(21527, Arrays.asList(21528, 100, 30, -1)); // Anger of Splendor
MOBSPAWNS.put(21533, Arrays.asList(21534, 100, 30, -1)); // Alliance of Splendor
MOBSPAWNS.put(21537, Arrays.asList(21538, 100, 30, -1)); // Fang of Splendor
}
protected static final NpcStringId[][] MOBTEXTS =
{
new NpcStringId[]
{
NpcStringId.ENOUGH_FOOLING_AROUND_GET_READY_TO_DIE,
NpcStringId.YOU_IDIOT_I_VE_JUST_BEEN_TOYING_WITH_YOU,
NpcStringId.NOW_THE_FUN_STARTS
},
new NpcStringId[]
{
NpcStringId.I_MUST_ADMIT_NO_ONE_MAKES_MY_BLOOD_BOIL_QUITE_LIKE_YOU_DO,
NpcStringId.NOW_THE_BATTLE_BEGINS,
NpcStringId.WITNESS_MY_TRUE_POWER
},
new NpcStringId[]
{
NpcStringId.PREPARE_TO_DIE,
NpcStringId.I_LL_DOUBLE_MY_STRENGTH,
NpcStringId.YOU_HAVE_MORE_SKILL_THAN_I_THOUGHT
}
};
private PolymorphingOnAttack()
{
super(PolymorphingOnAttack.class.getSimpleName(), "ai/group_template");
addAttackId(MOBSPAWNS.keySet());
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.isVisible() && !npc.isDead())
{
final List<Integer> tmp = MOBSPAWNS.get(npc.getId());
if (tmp != null)
{
if ((npc.getCurrentHp() <= ((npc.getMaxHp() * tmp.get(1)) / 100.0)) && (getRandom(100) < tmp.get(2)))
{
if (tmp.get(3) >= 0)
{
NpcStringId npcString = MOBTEXTS[tmp.get(3)][getRandom(MOBTEXTS[tmp.get(3)].length)];
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), ChatType.NPC_GENERAL, npc.getName(), npcString));
}
npc.deleteMe();
final L2Attackable newNpc = (L2Attackable) addSpawn(tmp.get(0), npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), false, 0, true);
final L2Character originalAttacker = isSummon ? attacker.getServitors().values().stream().findFirst().orElse(attacker.getPet()) : attacker;
newNpc.setRunning();
newNpc.addDamageHate(originalAttacker, 0, 500);
newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, originalAttacker);
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
public static void main(String[] args)
{
new PolymorphingOnAttack();
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Prison Guards AI.
* @author St3eT
*/
public final class PrisonGuards extends AbstractNpcAI
{
// NPCs
private static final int GUARD_HEAD = 18367; // Prison Guard
private static final int GUARD = 18368; // Prison Guard
// Item
private static final int STAMP = 10013; // Race Stamp
// Skills
private static final int TIMER = 5239; // Event Timer
private static final SkillHolder STONE = new SkillHolder(4578, 1); // Petrification
private static final SkillHolder SILENCE = new SkillHolder(4098, 9); // Silence
private PrisonGuards()
{
super(PrisonGuards.class.getSimpleName(), "ai/group_template");
addAttackId(GUARD_HEAD, GUARD);
addSpawnId(GUARD_HEAD, GUARD);
addNpcHateId(GUARD);
addSkillSeeId(GUARD);
addSpellFinishedId(GUARD_HEAD, GUARD);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("CLEAR_STATUS"))
{
npc.setScriptValue(0);
}
else if (event.equals("CHECK_HOME"))
{
if ((npc.calculateDistance(npc.getSpawn().getLocation(), false, false) > 10) && !npc.isInCombat() && !npc.isDead())
{
npc.teleToLocation(npc.getSpawn().getLocation());
}
startQuestTimer("CHECK_HOME", 30000, npc, null);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
if (npc.getId() == GUARD_HEAD)
{
if (player.isAffectedBySkill(TIMER))
{
if ((getRandom(100) < 10) && (npc.calculateDistance(player, true, false) < 100))
{
if ((getQuestItemsCount(player, STAMP) <= 3) && npc.isScriptValue(0))
{
giveItems(player, STAMP, 1);
npc.setScriptValue(1);
startQuestTimer("CLEAR_STATUS", 600000, npc, null);
}
}
}
else
{
npc.setTarget(player);
npc.doCast(STONE.getSkill());
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.IT_S_NOT_EASY_TO_OBTAIN);
}
}
else
{
if (!player.isAffectedBySkill(TIMER) && (npc.calculateDistance(npc.getSpawn().getLocation(), false, false) < 2000))
{
npc.setTarget(player);
npc.doCast(STONE.getSkill());
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.YOU_RE_OUT_OF_YOUR_MIND_COMING_HERE);
}
}
return super.onAttack(npc, player, damage, isSummon);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (!caster.isAffectedBySkill(TIMER))
{
npc.setTarget(caster);
npc.doCast(SILENCE.getSkill());
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if ((skill == SILENCE.getSkill()) || (skill == STONE.getSkill()))
{
((L2Attackable) npc).clearAggroList();
npc.setTarget(npc);
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public boolean onNpcHate(L2Attackable mob, L2PcInstance player, boolean isSummon)
{
return player.isAffectedBySkill(TIMER);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.getId() == GUARD_HEAD)
{
npc.setIsImmobilized(true);
npc.setIsInvul(true);
}
else
{
npc.setIsNoRndWalk(true);
cancelQuestTimer("CHECK_HOME", npc, null);
startQuestTimer("CHECK_HOME", 30000, npc, null);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new PrisonGuards();
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import java.util.HashMap;
import java.util.Map;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* Manages spawn of NPCs having several random spawn points.
* @author GKR
*/
public final class RandomSpawn extends AbstractNpcAI
{
private static final Map<Integer, Location[]> SPAWN_POINTS = new HashMap<>();
static
{
// Keltas
SPAWN_POINTS.put(22341, new Location[]
{
new Location(-27136, 250938, -3523),
new Location(-29658, 252897, -3523),
new Location(-27237, 251943, -3527),
new Location(-28868, 250113, -3479)
});
// Keymaster
SPAWN_POINTS.put(22361, new Location[]
{
new Location(14091, 250533, -1940),
new Location(15762, 252440, -2015),
new Location(19836, 256212, -2090),
new Location(21940, 254107, -2010),
new Location(17299, 252943, -2015),
});
// Typhoon
SPAWN_POINTS.put(25539, new Location[]
{
new Location(-20641, 255370, -3235),
new Location(-16157, 250993, -3058),
new Location(-18269, 250721, -3151),
new Location(-16532, 254864, -3223),
new Location(-19055, 253489, -3440),
new Location(-9684, 254256, -3148),
new Location(-6209, 251924, -3189),
new Location(-10547, 251359, -2929),
new Location(-7254, 254997, -3261),
new Location(-4883, 253171, -3322)
});
// Mutated Elpy
SPAWN_POINTS.put(25604, new Location[]
{
new Location(-46080, 246368, -14183),
new Location(-44816, 246368, -14183),
new Location(-44224, 247440, -14184),
new Location(-44896, 248464, -14183),
new Location(-46064, 248544, -14183),
new Location(-46720, 247424, -14183)
});
}
public RandomSpawn()
{
super(RandomSpawn.class.getSimpleName(), "ai/group_template");
addSpawnId(SPAWN_POINTS.keySet());
}
@Override
public final String onSpawn(L2Npc npc)
{
final Location[] spawnlist = SPAWN_POINTS.get(npc.getId());
final Location loc = spawnlist[getRandom(spawnlist.length)];
if (!npc.isInsideRadius(loc, 200, false, false))
{
npc.getSpawn().setLocation(loc);
ThreadPoolManager.getInstance().scheduleGeneral(new Teleport(npc, loc), 100);
}
return super.onSpawn(npc);
}
private static class Teleport implements Runnable
{
private final L2Npc _npc;
private final Location _loc;
public Teleport(L2Npc npc, Location loc)
{
_npc = npc;
_loc = loc;
}
@Override
public void run()
{
_npc.teleToLocation(_loc, false);
}
}
public static void main(String[] args)
{
new RandomSpawn();
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* See Through Silent Move AI.
* @author Gigiikun
*/
public class SeeThroughSilentMove extends AbstractNpcAI
{
//@formatter:off
private static final int[] MONSTERS =
{
18001, 18002, 22199, 22215, 22216, 22217, 22327, 22746, 22747, 22748,
22749, 22750, 22751, 22752, 22753, 22754, 22755, 22756, 22757, 22758,
22759, 22760, 22761, 22762, 22763, 22764, 22765, 22794, 22795, 22796,
22797, 22798, 22799, 22800, 22843, 22857, 25725, 25726, 25727, 29009,
29010, 29011, 29012, 29013
};
//@formatter:on
private SeeThroughSilentMove()
{
super(SeeThroughSilentMove.class.getSimpleName(), "ai/group_template");
addSpawnId(MONSTERS);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.isAttackable())
{
((L2Attackable) npc).setSeeThroughSilentMove(true);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new SeeThroughSilentMove();
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Silent Valley AI
* @author malyelfik
*/
public final class SilentValley extends AbstractNpcAI
{
// Skills
private static final SkillHolder BETRAYAL = new SkillHolder(6033, 1); // Treasure Seeker's Betrayal
private static final SkillHolder BLAZE = new SkillHolder(4157, 10); // NPC Blaze - Magic
// Item
private static final int SACK = 13799; // Treasure Sack of the Ancient Giants
// Chance
private static final int SPAWN_CHANCE = 2;
private static final int CHEST_DIE_CHANCE = 5;
// Monsters
private static final int CHEST = 18693; // Treasure Chest of the Ancient Giants
private static final int GUARD1 = 18694; // Treasure Chest Guard
private static final int GUARD2 = 18695; // Treasure Chest Guard
private static final int[] MOBS =
{
20965, // Chimera Piece
20966, // Changed Creation
20967, // Past Creature
20968, // Nonexistent Man
20969, // Giant's Shadow
20970, // Soldier of Ancient Times
20971, // Warrior of Ancient Times
20972, // Shaman of Ancient Times
20973, // Forgotten Ancient People
};
private SilentValley()
{
super(SilentValley.class.getSimpleName(), "ai/group_template");
addAttackId(MOBS);
addAttackId(CHEST, GUARD1, GUARD2);
addEventReceivedId(GUARD1, GUARD2);
addKillId(MOBS);
addSeeCreatureId(MOBS);
addSeeCreatureId(GUARD1, GUARD2);
addSpawnId(CHEST, GUARD2);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if ((npc != null) && !npc.isDead())
{
switch (event)
{
case "CLEAR":
npc.doDie(null);
break;
case "CLEAR_EVENT":
npc.broadcastEvent("CLEAR_ALL_INSTANT", 2000, null);
npc.doDie(null);
break;
case "SPAWN_CHEST":
addSpawn(CHEST, npc.getX() - 100, npc.getY(), npc.getZ() - 100, 0, false, 0);
break;
}
}
return null;
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
switch (npc.getId())
{
case CHEST:
{
if (!isSummon && npc.isScriptValue(0))
{
npc.setScriptValue(1);
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.YOU_WILL_BE_CURSED_FOR_SEEKING_THE_TREASURE);
npc.setTarget(player);
npc.doCast(BETRAYAL.getSkill());
}
else if (isSummon || (getRandom(100) < CHEST_DIE_CHANCE))
{
npc.dropItem(player, SACK, 1);
npc.broadcastEvent("CLEAR_ALL", 2000, null);
npc.doDie(null);
cancelQuestTimer("CLEAR_EVENT", npc, null);
}
break;
}
case GUARD1:
case GUARD2:
{
npc.setTarget(player);
npc.doCast(BLAZE.getSkill());
addAttackPlayerDesire(npc, player);
break;
}
default:
{
if (isSummon)
{
addAttackPlayerDesire(npc, player);
}
}
}
return super.onAttack(npc, player, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (getRandom(1000) < SPAWN_CHANCE)
{
final int newZ = npc.getZ() + 100;
addSpawn(GUARD2, npc.getX() + 100, npc.getY(), newZ, 0, false, 0);
addSpawn(GUARD1, npc.getX() - 100, npc.getY(), newZ, 0, false, 0);
addSpawn(GUARD1, npc.getX(), npc.getY() + 100, newZ, 0, false, 0);
addSpawn(GUARD1, npc.getX(), npc.getY() - 100, newZ, 0, false, 0);
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
{
if (creature.isPlayable())
{
final L2PcInstance player = (isSummon) ? ((L2Summon) creature).getOwner() : creature.getActingPlayer();
if ((npc.getId() == GUARD1) || (npc.getId() == GUARD2))
{
npc.setTarget(player);
npc.doCast(BLAZE.getSkill());
addAttackPlayerDesire(npc, player);
}
else if (creature.isAffectedBySkill(BETRAYAL.getSkillId()))
{
addAttackPlayerDesire(npc, player);
}
}
return super.onSeeCreature(npc, creature, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.getId() == CHEST)
{
npc.setIsInvul(true);
startQuestTimer("CLEAR_EVENT", 300000, npc, null);
}
else
{
startQuestTimer("SPAWN_CHEST", 10000, npc, null);
}
return super.onSpawn(npc);
}
@Override
public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
{
if ((receiver != null) && !receiver.isDead())
{
switch (eventName)
{
case "CLEAR_ALL":
startQuestTimer("CLEAR", 60000, receiver, null);
break;
case "CLEAR_ALL_INSTANT":
receiver.doDie(null);
break;
}
}
return super.onEventReceived(eventName, sender, receiver, reference);
}
public static void main(String[] args)
{
new SilentValley();
}
}

View File

@@ -0,0 +1,244 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import java.util.List;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.datatables.SkillData;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.util.Broadcast;
import com.l2jserver.gameserver.util.Util;
/**
* Stakato Nest AI.
* @author Gnacik
*/
public final class StakatoNest extends AbstractNpcAI
{
// @formatter:off
// List of all mobs just for register
private static final int[] STAKATO_MOBS =
{
18793, 18794, 18795, 18796, 18797, 18798, 22617, 22618, 22619, 22620,
22621, 22622, 22623, 22624, 22625, 22626, 22627, 22628, 22629, 22630,
22631, 22632, 22633, 25667
};
// Coocons
private static final int[] COCOONS =
{
18793, 18794, 18795, 18796, 18797, 18798
};
// @formatter:on
// Cannibalistic Stakato Leader
private static final int STAKATO_LEADER = 22625;
// Spike Stakato Nurse
private static final int STAKATO_NURSE = 22630;
// Spike Stakato Nurse (Changed)
private static final int STAKATO_NURSE_2 = 22631;
// Spiked Stakato Baby
private static final int STAKATO_BABY = 22632;
// Spiked Stakato Captain
private static final int STAKATO_CAPTAIN = 22629;
// Female Spiked Stakato
private static final int STAKATO_FEMALE = 22620;
// Male Spiked Stakato
private static final int STAKATO_MALE = 22621;
// Male Spiked Stakato (Changed)
private static final int STAKATO_MALE_2 = 22622;
// Spiked Stakato Guard
private static final int STAKATO_GUARD = 22619;
// Cannibalistic Stakato Chief
private static final int STAKATO_CHIEF = 25667;
// Growth Accelerator
private static final int GROWTH_ACCELERATOR = 2905;
// Small Stakato Cocoon
private static final int SMALL_COCOON = 14833;
// Large Stakato Cocoon
private static final int LARGE_COCOON = 14834;
private StakatoNest()
{
super(StakatoNest.class.getSimpleName(), "ai/group_template");
registerMobs(STAKATO_MOBS);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
if ((mob.getId() == STAKATO_LEADER) && (getRandom(1000) < 100) && (mob.getCurrentHp() < (mob.getMaxHp() * 0.3)))
{
final L2MonsterInstance _follower = checkMinion(npc);
if (_follower != null)
{
double _hp = _follower.getCurrentHp();
if (_hp > (_follower.getMaxHp() * 0.3))
{
mob.abortAttack();
mob.abortCast();
mob.setHeading(Util.calculateHeadingFrom(mob, _follower));
mob.doCast(SkillData.getInstance().getSkill(4484, 1));
mob.setCurrentHp(mob.getCurrentHp() + _hp);
_follower.doDie(_follower);
_follower.deleteMe();
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
final L2MonsterInstance monster;
switch (npc.getId())
{
case STAKATO_NURSE:
monster = checkMinion(npc);
if (monster != null)
{
Broadcast.toSelfAndKnownPlayers(npc, new MagicSkillUse(npc, 2046, 1, 1000, 0));
for (int i = 0; i < 3; i++)
{
L2Npc spawned = addSpawn(STAKATO_CAPTAIN, monster, true);
addAttackPlayerDesire(spawned, killer);
}
}
break;
case STAKATO_BABY:
monster = ((L2MonsterInstance) npc).getLeader();
if ((monster != null) && !monster.isDead())
{
startQuestTimer("nurse_change", 5000, monster, killer);
}
break;
case STAKATO_MALE:
monster = checkMinion(npc);
if (monster != null)
{
Broadcast.toSelfAndKnownPlayers(npc, new MagicSkillUse(npc, 2046, 1, 1000, 0));
for (int i = 0; i < 3; i++)
{
L2Npc spawned = addSpawn(STAKATO_GUARD, monster, true);
addAttackPlayerDesire(spawned, killer);
}
}
break;
case STAKATO_FEMALE:
monster = ((L2MonsterInstance) npc).getLeader();
if ((monster != null) && !monster.isDead())
{
startQuestTimer("male_change", 5000, monster, killer);
}
break;
case STAKATO_CHIEF:
if (killer.isInParty())
{
List<L2PcInstance> party = killer.getParty().getMembers();
for (L2PcInstance member : party)
{
giveCocoon(member, npc);
}
}
else
{
giveCocoon(killer, npc);
}
break;
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (Util.contains(COCOONS, npc.getId()) && Util.contains(targets, npc) && (skill.getId() == GROWTH_ACCELERATOR))
{
npc.doDie(caster);
final L2Npc spawned = addSpawn(STAKATO_CHIEF, npc.getX(), npc.getY(), npc.getZ(), Util.calculateHeadingFrom(npc, caster), false, 0, true);
addAttackPlayerDesire(spawned, caster);
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public final String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if ((npc == null) || (player == null) || npc.isDead())
{
return null;
}
int npcId = 0;
switch (event)
{
case "nurse_change":
npcId = STAKATO_NURSE_2;
break;
case "male_change":
npcId = STAKATO_MALE_2;
break;
}
if (npcId > 0)
{
npc.getSpawn().decreaseCount(npc);
npc.deleteMe();
final L2Npc spawned = addSpawn(npcId, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), false, 0, true);
addAttackPlayerDesire(spawned, player);
}
return super.onAdvEvent(event, npc, player);
}
private static L2MonsterInstance checkMinion(L2Npc npc)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
if (mob.hasMinions())
{
final List<L2MonsterInstance> minion = mob.getMinionList().getSpawnedMinions();
if ((minion != null) && !minion.isEmpty() && (minion.get(0) != null) && !minion.get(0).isDead())
{
return minion.get(0);
}
}
return null;
}
private static void giveCocoon(L2PcInstance player, L2Npc npc)
{
player.addItem("StakatoCocoon", ((getRandom(100) > 80) ? LARGE_COCOON : SMALL_COCOON), 1, npc, true);
}
public static void main(String[] args)
{
new StakatoNest();
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.skills.Skill;
/**
* Summon Pc AI.<br>
* Summon the player to the NPC on attack.
* @author Zoey76
*/
public final class SummonPc extends AbstractNpcAI
{
// NPCs
private static final int PORTA = 20213;
private static final int PERUM = 20221;
// Skill
private static final SkillHolder SUMMON_PC = new SkillHolder(4161, 1);
private SummonPc()
{
super(SummonPc.class.getSimpleName(), "ai/group_template");
addAttackId(PORTA, PERUM);
addSpellFinishedId(PORTA, PERUM);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
final int chance = getRandom(100);
final boolean attacked = npc.getVariables().getBoolean("attacked", false);
if ((npc.calculateDistance(attacker, true, false) > 300) && !attacked)
{
if (chance < 50)
{
if ((SUMMON_PC.getSkill().getMpConsume() < npc.getCurrentMp()) && (SUMMON_PC.getSkill().getHpConsume() < npc.getCurrentHp()) && !npc.isSkillDisabled(SUMMON_PC.getSkill()))
{
npc.setTarget(attacker);
npc.doCast(SUMMON_PC.getSkill());
}
if ((SUMMON_PC.getSkill().getMpConsume() < npc.getCurrentMp()) && (SUMMON_PC.getSkill().getHpConsume() < npc.getCurrentHp()) && !npc.isSkillDisabled(SUMMON_PC.getSkill()))
{
npc.setTarget(attacker);
npc.doCast(SUMMON_PC.getSkill());
npc.getVariables().set("attacked", true);
}
}
}
else if ((npc.calculateDistance(attacker, true, false) > 100) && !attacked)
{
final L2Attackable monster = (L2Attackable) npc;
if (monster.getMostHated() != null)
{
if (((monster.getMostHated() == attacker) && (chance < 50)) || (chance < 10))
{
if ((SUMMON_PC.getSkill().getMpConsume() < npc.getCurrentMp()) && (SUMMON_PC.getSkill().getHpConsume() < npc.getCurrentHp()) && !npc.isSkillDisabled(SUMMON_PC.getSkill()))
{
npc.setTarget(attacker);
npc.doCast(SUMMON_PC.getSkill());
npc.getVariables().set("attacked", true);
}
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if ((skill.getId() == SUMMON_PC.getSkillId()) && !npc.isDead() && npc.getVariables().getBoolean("attacked", false))
{
player.teleToLocation(npc);
npc.getVariables().set("attacked", false);
}
return super.onSpellFinished(npc, player, skill);
}
public static void main(String[] args)
{
new SummonPc();
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Turek Orcs AI - flee and return with assistance
* @author GKR
*/
public final class TurekOrcs extends AbstractNpcAI
{
// NPC's
private static final int[] MOBS =
{
20494, // Turek War Hound
20495, // Turek Orc Warlord
20497, // Turek Orc Skirmisher
20498, // Turek Orc Supplier
20499, // Turek Orc Footman
20500, // Turek Orc Sentinel
};
private TurekOrcs()
{
super(TurekOrcs.class.getSimpleName(), "ai/group_template");
addAttackId(MOBS);
addEventReceivedId(MOBS);
addMoveFinishedId(MOBS);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("checkState") && !npc.isDead() && (npc.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK))
{
if ((npc.getCurrentHp() > (npc.getMaxHp() * 0.7)) && (npc.getVariables().getInt("state") == 2))
{
npc.getVariables().set("state", 3);
((L2Attackable) npc).returnHome();
}
else
{
npc.getVariables().remove("state");
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (!npc.getVariables().hasVariable("isHit"))
{
npc.getVariables().set("isHit", 1);
}
else if ((npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) && (npc.getCurrentHp() > (npc.getMaxHp() * 0.3)) && (attacker.getCurrentHp() > (attacker.getMaxHp() * 0.25)) && npc.hasAIValue("fleeX") && npc.hasAIValue("fleeY") && npc.hasAIValue("fleeZ") && (npc.getVariables().getInt("state") == 0) && (getRandom(100) < 10))
{
// Say and flee
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.getNpcStringId(getRandom(1000007, 1000027)));
npc.disableCoreAI(true); // to avoid attacking behaviour, while flee
npc.setIsRunning(true);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(npc.getAIValue("fleeX"), npc.getAIValue("fleeY"), npc.getAIValue("fleeZ")));
npc.getVariables().set("state", 1);
npc.getVariables().set("attacker", attacker.getObjectId());
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
{
if (eventName.equals("WARNING") && !receiver.isDead() && (receiver.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) && (reference != null) && (reference.getActingPlayer() != null) && !reference.getActingPlayer().isDead())
{
receiver.getVariables().set("state", 3);
receiver.setIsRunning(true);
((L2Attackable) receiver).addDamageHate(reference.getActingPlayer(), 0, 99999);
receiver.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, reference.getActingPlayer());
}
return super.onEventReceived(eventName, sender, receiver, reference);
}
@Override
public void onMoveFinished(L2Npc npc)
{
// NPC reaches flee point
if (npc.getVariables().getInt("state") == 1)
{
if ((npc.getX() == npc.getAIValue("fleeX")) && (npc.getY() == npc.getAIValue("fleeY")))
{
npc.disableCoreAI(false);
startQuestTimer("checkState", 15000, npc, null);
npc.getVariables().set("state", 2);
npc.broadcastEvent("WARNING", 400, L2World.getInstance().getPlayer(npc.getVariables().getInt("attacker")));
}
else
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(npc.getAIValue("fleeX"), npc.getAIValue("fleeY"), npc.getAIValue("fleeZ")));
}
}
else if ((npc.getVariables().getInt("state") == 3) && npc.staysInSpawnLoc())
{
npc.disableCoreAI(false);
npc.getVariables().remove("state");
}
}
public static void main(String[] args)
{
new TurekOrcs();
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.group_template;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlEvent;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Warrior Fishing Block AI.
* @author Zoey76
*/
public final class WarriorFishingBlock extends AbstractNpcAI
{
// Monsters
private static final int[] MONSTERS =
{
18319, // Caught Frog
18320, // Caught Undine
18321, // Caught Rakul
18322, // Caught Sea Giant
18323, // Caught Sea Horse Soldier
18324, // Caught Homunculus
18325, // Caught Flava
18326, // Caught Gigantic Eye
};
// NPC Strings
private static final NpcStringId[] NPC_STRINGS_ON_SPAWN =
{
NpcStringId.CROAK_CROAK_FOOD_LIKE_S1_IN_THIS_PLACE,
NpcStringId.S1_HOW_LUCKY_I_AM,
NpcStringId.PRAY_THAT_YOU_CAUGHT_A_WRONG_FISH_S1
};
private static final NpcStringId[] NPC_STRINGS_ON_ATTACK =
{
NpcStringId.DO_YOU_KNOW_WHAT_A_FROG_TASTES_LIKE,
NpcStringId.I_WILL_SHOW_YOU_THE_POWER_OF_A_FROG,
NpcStringId.I_WILL_SWALLOW_AT_A_MOUTHFUL
};
private static final NpcStringId[] NPC_STRINGS_ON_KILL =
{
NpcStringId.UGH_NO_CHANCE_HOW_COULD_THIS_ELDER_PASS_AWAY_LIKE_THIS,
NpcStringId.CROAK_CROAK_A_FROG_IS_DYING,
NpcStringId.A_FROG_TASTES_BAD_YUCK
};
// Misc
private static final int CHANCE_TO_SHOUT_ON_ATTACK = 33;
private static final int DESPAWN_TIME = 50; // 50 seconds to despawn
public WarriorFishingBlock()
{
super(WarriorFishingBlock.class.getSimpleName(), "ai/group_template");
addAttackId(MONSTERS);
addKillId(MONSTERS);
addSpawnId(MONSTERS);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "SPAWN":
{
final L2Object obj = npc.getTarget();
if ((obj == null) || !obj.isPlayer())
{
npc.decayMe();
}
else
{
final L2PcInstance target = obj.getActingPlayer();
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NPC_STRINGS_ON_SPAWN[getRandom(NPC_STRINGS_ON_SPAWN.length)], target.getName());
((L2Attackable) npc).addDamageHate(target, 0, 2000);
npc.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, target);
npc.addAttackerToAttackByList(target);
startQuestTimer("DESPAWN", DESPAWN_TIME * 1000, npc, target);
}
break;
}
case "DESPAWN":
{
npc.decayMe();
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (getRandom(100) < CHANCE_TO_SHOUT_ON_ATTACK)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NPC_STRINGS_ON_ATTACK[getRandom(NPC_STRINGS_ON_ATTACK.length)]);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NPC_STRINGS_ON_KILL[getRandom(NPC_STRINGS_ON_KILL.length)]);
cancelQuestTimer("DESPAWN", npc, killer);
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
startQuestTimer("SPAWN", 2000, npc, null);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new WarriorFishingBlock();
}
}

View File

@@ -0,0 +1,12 @@
Group Template AI:
This folder contains AI scripts for group templates. That is, if many different mobs share the same behaviour,
a group AI script can be created for all of them. Such group templates ought to be here.
Group templates can be subclassed. In other words, a group may inherit from another group. For example,
one group template might define mobs that cast spells. Another template may then define the AI for mobs
that cast spells AND use shots. In that case, instead of rewriting all the attack and spell-use AI, we can
inherit from the first group template, then add the new behaviours, and split up the NPC registrations appropriately.
"NPC registrations" refers to the addition of NPCs in the various events of the scripts, such as onAttack, onKill, etc
Those are done by using keywords such as "addKillId" etc. For more details on registrations, see
"scripts/quests/documentation.txt"

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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/>.
*/
/**
* Group Template AI:<br>
* This folder contains AI scripts for group templates.<br>
* That is, if many different mobs share the same behavior, a group AI script can be created for all of them.<br>
* Such group templates ought to be here.<br>
* <br>
* Group templates can be sub-classed.<br>
* In other words, a group may inherit from another group.<br>
* For example, one group template might define mobs that cast spells.<br>
* Another template may then define the AI for mobs that cast spells AND use shots.<br>
* In that case, instead of rewriting all the attack and spell-use AI, we can inherit from the first group template, then add the new behaviors, and split up the NPC registrations appropriately.<br>
* <br>
* "NPC registrations" refers to the addition of NPCs in the various events of the scripts, such as onAttack, onKill, etc.<br>
* Those are done by using methods such as addKillId(..) etc.<br>
* @see quests
* @author Fulminus, Zoey76
*/
package ai.group_template;

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* AI for Kamaloka (33) - Crimson Hatu Otis
* @author Gladicek
*/
public final class CrimsonHatuOtis extends AbstractNpcAI
{
// Npc
private static final int CRIMSON_HATU_OTIS = 18558;
// Skills
private static SkillHolder BOSS_SPINING_SLASH = new SkillHolder(4737, 1);
private static SkillHolder BOSS_HASTE = new SkillHolder(4175, 1);
private CrimsonHatuOtis()
{
super(CrimsonHatuOtis.class.getSimpleName(), "ai/individual");
addAttackId(CRIMSON_HATU_OTIS);
addKillId(CRIMSON_HATU_OTIS);
}
@Override
public final String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "SKILL":
{
if (npc.isDead())
{
cancelQuestTimer("SKILL", npc, null);
return null;
}
npc.setTarget(player);
npc.doCast(BOSS_SPINING_SLASH.getSkill());
startQuestTimer("SKILL", 60000, npc, null);
break;
}
case "BUFF":
{
if (npc.isScriptValue(2))
{
npc.setTarget(npc);
npc.doCast(BOSS_HASTE.getSkill());
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("SKILL", 5000, npc, null);
}
else if (npc.isScriptValue(1) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)))
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.I_VE_HAD_IT_UP_TO_HERE_WITH_YOU_I_LL_TAKE_CARE_OF_YOU);
npc.setScriptValue(2);
startQuestTimer("BUFF", 1000, npc, null);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance player, boolean isSummon)
{
cancelQuestTimer("SKILL", npc, null);
cancelQuestTimer("BUFF", npc, null);
return super.onKill(npc, player, isSummon);
}
public static void main(String[] args)
{
new CrimsonHatuOtis();
}
}

View File

@@ -0,0 +1,247 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.data.xml.impl.NpcData;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* Dark Water Dragon's AI.
*/
public final class DarkWaterDragon extends AbstractNpcAI
{
private static final int DRAGON = 22267;
private static final int SHADE1 = 22268;
private static final int SHADE2 = 22269;
private static final int FAFURION = 18482;
private static final int DETRACTOR1 = 22270;
private static final int DETRACTOR2 = 22271;
private static final Set<Integer> SECOND_SPAWN = ConcurrentHashMap.newKeySet(); // Used to track if second Shades were already spawned
private static Set<Integer> MY_TRACKING_SET = ConcurrentHashMap.newKeySet(); // Used to track instances of npcs
private static Map<Integer, L2PcInstance> ID_MAP = new ConcurrentHashMap<>(); // Used to track instances of npcs
private DarkWaterDragon()
{
super(DarkWaterDragon.class.getSimpleName(), "ai/individual");
int[] mobs =
{
DRAGON,
SHADE1,
SHADE2,
FAFURION,
DETRACTOR1,
DETRACTOR2
};
addKillId(mobs);
addAttackId(mobs);
addSpawnId(mobs);
MY_TRACKING_SET.clear();
SECOND_SPAWN.clear();
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (npc != null)
{
if (event.equalsIgnoreCase("first_spawn")) // timer to start timer "1"
{
startQuestTimer("1", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("second_spawn")) // timer to start timer "2"
{
startQuestTimer("2", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("third_spawn")) // timer to start timer "3"
{
startQuestTimer("3", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("fourth_spawn")) // timer to start timer "4"
{
startQuestTimer("4", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("1")) // spawns a detractor
{
addSpawn(DETRACTOR1, (npc.getX() + 100), (npc.getY() + 100), npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("2")) // spawns a detractor
{
addSpawn(DETRACTOR2, (npc.getX() + 100), (npc.getY() - 100), npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("3")) // spawns a detractor
{
addSpawn(DETRACTOR1, (npc.getX() - 100), (npc.getY() + 100), npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("4")) // spawns a detractor
{
addSpawn(DETRACTOR2, (npc.getX() - 100), (npc.getY() - 100), npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("fafurion_despawn")) // Fafurion Kindred disappears and drops reward
{
cancelQuestTimer("fafurion_poison", npc, null);
cancelQuestTimer("1", npc, null);
cancelQuestTimer("2", npc, null);
cancelQuestTimer("3", npc, null);
cancelQuestTimer("4", npc, null);
MY_TRACKING_SET.remove(npc.getObjectId());
player = ID_MAP.remove(npc.getObjectId());
if (player != null)
{
((L2Attackable) npc).doItemDrop(NpcData.getInstance().getTemplate(18485), player);
}
npc.deleteMe();
}
else if (event.equalsIgnoreCase("fafurion_poison")) // Reduces Fafurions hp like it is poisoned
{
if (npc.getCurrentHp() <= 500)
{
cancelQuestTimer("fafurion_despawn", npc, null);
cancelQuestTimer("first_spawn", npc, null);
cancelQuestTimer("second_spawn", npc, null);
cancelQuestTimer("third_spawn", npc, null);
cancelQuestTimer("fourth_spawn", npc, null);
cancelQuestTimer("1", npc, null);
cancelQuestTimer("2", npc, null);
cancelQuestTimer("3", npc, null);
cancelQuestTimer("4", npc, null);
MY_TRACKING_SET.remove(npc.getObjectId());
ID_MAP.remove(npc.getObjectId());
}
npc.reduceCurrentHp(500, npc, null); // poison kills Fafurion if he is not healed
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
int npcId = npc.getId();
int npcObjId = npc.getObjectId();
if (npcId == DRAGON)
{
if (!MY_TRACKING_SET.contains(npcObjId)) // this allows to handle multiple instances of npc
{
MY_TRACKING_SET.add(npcObjId);
// Spawn first 5 shades on first attack on Dark Water Dragon
L2Character originalAttacker = isSummon ? attacker.getServitors().values().stream().findFirst().orElse(attacker.getPet()) : attacker;
spawnShade(originalAttacker, SHADE1, npc.getX() + 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() + 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() - 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() - 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() - 150, npc.getY() + 150, npc.getZ());
}
else if ((npc.getCurrentHp() < (npc.getMaxHp() / 2.0)) && !(SECOND_SPAWN.contains(npcObjId)))
{
SECOND_SPAWN.add(npcObjId);
// Spawn second 5 shades on half hp of on Dark Water Dragon
L2Character originalAttacker = isSummon ? attacker.getServitors().values().stream().findFirst().orElse(attacker.getPet()) : attacker;
spawnShade(originalAttacker, SHADE2, npc.getX() + 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() + 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() - 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() - 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() - 150, npc.getY() + 150, npc.getZ());
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
int npcId = npc.getId();
int npcObjId = npc.getObjectId();
if (npcId == DRAGON)
{
MY_TRACKING_SET.remove(npcObjId);
SECOND_SPAWN.remove(npcObjId);
L2Attackable faf = (L2Attackable) addSpawn(FAFURION, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0); // spawns Fafurion Kindred when Dard Water Dragon is dead
ID_MAP.put(faf.getObjectId(), killer);
}
else if (npcId == FAFURION)
{
cancelQuestTimer("fafurion_poison", npc, null);
cancelQuestTimer("fafurion_despawn", npc, null);
cancelQuestTimer("first_spawn", npc, null);
cancelQuestTimer("second_spawn", npc, null);
cancelQuestTimer("third_spawn", npc, null);
cancelQuestTimer("fourth_spawn", npc, null);
cancelQuestTimer("1", npc, null);
cancelQuestTimer("2", npc, null);
cancelQuestTimer("3", npc, null);
cancelQuestTimer("4", npc, null);
MY_TRACKING_SET.remove(npcObjId);
ID_MAP.remove(npcObjId);
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
int npcId = npc.getId();
int npcObjId = npc.getObjectId();
if (npcId == FAFURION)
{
if (!MY_TRACKING_SET.contains(npcObjId))
{
MY_TRACKING_SET.add(npcObjId);
// Spawn 4 Detractors on spawn of Fafurion
int x = npc.getX();
int y = npc.getY();
addSpawn(DETRACTOR2, x + 100, y + 100, npc.getZ(), 0, false, 40000);
addSpawn(DETRACTOR1, x + 100, y - 100, npc.getZ(), 0, false, 40000);
addSpawn(DETRACTOR2, x - 100, y + 100, npc.getZ(), 0, false, 40000);
addSpawn(DETRACTOR1, x - 100, y - 100, npc.getZ(), 0, false, 40000);
startQuestTimer("first_spawn", 2000, npc, null); // timer to delay timer "1"
startQuestTimer("second_spawn", 4000, npc, null); // timer to delay timer "2"
startQuestTimer("third_spawn", 8000, npc, null); // timer to delay timer "3"
startQuestTimer("fourth_spawn", 10000, npc, null); // timer to delay timer "4"
startQuestTimer("fafurion_poison", 3000, npc, null, true); // Every three seconds reduces Fafurions hp like it is poisoned
startQuestTimer("fafurion_despawn", 120000, npc, null); // Fafurion Kindred disappears after two minutes
}
}
return super.onSpawn(npc);
}
public void spawnShade(L2Character attacker, int npcId, int x, int y, int z)
{
final L2Npc shade = addSpawn(npcId, x, y, z, 0, false, 0);
shade.setRunning();
((L2Attackable) shade).addDamageHate(attacker, 0, 999);
shade.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
}
public static void main(String[] args)
{
new DarkWaterDragon();
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* Simple AI that manages special conditions for Divine Beast summon.
* @author UnAfraid
*/
public final class DivineBeast extends AbstractNpcAI
{
private static final int DIVINE_BEAST = 14870;
private static final int TRANSFORMATION_ID = 258;
private static final int CHECK_TIME = 2 * 1000;
private DivineBeast()
{
super(DivineBeast.class.getSimpleName(), "ai");
addSummonSpawnId(DIVINE_BEAST);
}
@Override
public void onSummonSpawn(L2Summon summon)
{
startQuestTimer("VALIDATE_TRANSFORMATION", CHECK_TIME, null, summon.getActingPlayer(), true);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if ((player == null) || !player.hasServitors())
{
cancelQuestTimer(event, npc, player);
}
else if (player.getTransformationId() != TRANSFORMATION_ID)
{
cancelQuestTimer(event, npc, player);
player.getServitors().values().forEach(summon -> summon.unSummon(player));
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new DivineBeast();
}
}

View File

@@ -0,0 +1,329 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.StatsSet;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.network.serverpackets.SpecialCamera;
import com.l2jserver.util.Rnd;
/**
* Dr. Chaos is a boss @ Pavel's Ruins. Some things to know :
* <ul>
* <li>As a mad scientist, he thinks all are spies, and for so if you stand too much longer near him you're considered as an "assassin from Black Anvil Guild".</li>
* <li>You can chat with him, but if you try too much he will become angry.</li>
* <li>That adaptation sends a decent cinematic made with the different social actions too.</li>
* <li>The status of the RB is saved under GBs table, in order to retrieve the state if server restarts.</li>
* <li>The spawn of the different NPCs (Dr. Chaos / War golem) is handled by that script aswell.</li>
* </ul>
* @author Kerberos, Tryskell.
*/
public class DrChaos extends AbstractNpcAI
{
private static final int DOCTOR_CHAOS = 32033;
private static final int CHAOS_GOLEM = 25512;
private static final byte NORMAL = 0; // Dr. Chaos is in NPC form.
private static final byte CRAZY = 1; // Dr. Chaos entered on golem form.
private static final byte DEAD = 2; // Dr. Chaos has been killed and has not yet spawned.
private long _lastAttackVsGolem = 0;
private int _pissedOffTimer;
public DrChaos()
{
super(DrChaos.class.getSimpleName(), "ai");
addFirstTalkId(DOCTOR_CHAOS); // Different HTMs following actual humor.
addSpawnId(DOCTOR_CHAOS); // Timer activation at 30sec + paranoia activity.
addKillId(CHAOS_GOLEM); // Message + despawn.
addAttackId(CHAOS_GOLEM); // Random messages when he attacks.
StatsSet info = GrandBossManager.getInstance().getStatsSet(CHAOS_GOLEM);
int status = GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM);
// Load the reset date and time for Dr. Chaos from DB.
if (status == DEAD)
{
long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
if (temp > 0)
{
startQuestTimer("reset_drchaos", temp, null, null, false);
}
else
{
// The time has already expired while the server was offline. Delete the saved time and
// immediately spawn Dr. Chaos. Also the state need to be changed for NORMAL
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0, false);
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, NORMAL);
}
}
// Spawn the war golem.
else if (status == CRAZY)
{
int loc_x = info.getInt("loc_x");
int loc_y = info.getInt("loc_y");
int loc_z = info.getInt("loc_z");
int heading = info.getInt("heading");
final int hp = info.getInt("currentHP");
final int mp = info.getInt("currentMP");
L2GrandBossInstance golem = (L2GrandBossInstance) addSpawn(CHAOS_GOLEM, loc_x, loc_y, loc_z, heading, false, 0, false);
GrandBossManager.getInstance().addBoss(golem);
final L2Npc _golem = golem;
_golem.setCurrentHpMp(hp, mp);
_golem.setRunning();
// start monitoring Dr. Chaos's inactivity
_lastAttackVsGolem = System.currentTimeMillis();
startQuestTimer("golem_despawn", 60000, _golem, null, true);
}
// Spawn the regular NPC.
else
{
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0, false);
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("reset_drchaos"))
{
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, NORMAL);
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0, false);
}
// despawn the live Dr. Chaos after 30 minutes of inactivity
else if (event.equalsIgnoreCase("golem_despawn") && (npc != null))
{
if (npc.getId() == CHAOS_GOLEM)
{
if ((_lastAttackVsGolem + 1800000) < System.currentTimeMillis())
{
// Despawn the war golem.
npc.deleteMe();
addSpawn(DOCTOR_CHAOS, 96320, -110912, -3328, 8191, false, 0, false); // spawn Dr. Chaos
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, NORMAL); // mark Dr. Chaos is not crazy any more
cancelQuestTimer("golem_despawn", npc, null);
}
}
}
else if (event.equalsIgnoreCase("1"))
{
npc.broadcastPacket(new SocialAction(npc.getObjectId(), 2));
npc.broadcastPacket(new SpecialCamera(npc, 1, -200, 15, 5500, 1000, 13500, 0, 0, 0, 0, 0));
}
else if (event.equalsIgnoreCase("2"))
{
npc.broadcastPacket(new SocialAction(npc.getObjectId(), 3));
}
else if (event.equalsIgnoreCase("3"))
{
npc.broadcastPacket(new SocialAction(npc.getObjectId(), 1));
}
else if (event.equalsIgnoreCase("4"))
{
npc.broadcastPacket(new SpecialCamera(npc, 1, -150, 10, 3500, 1000, 5000, 0, 0, 0, 0, 0));
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(95928, -110671, -3340, 0));
}
else if (event.equalsIgnoreCase("5"))
{
// Delete Dr. Chaos && spawn the war golem.
npc.deleteMe();
L2GrandBossInstance golem = (L2GrandBossInstance) addSpawn(CHAOS_GOLEM, 96080, -110822, -3343, 0, false, 0, false);
GrandBossManager.getInstance().addBoss(golem);
// The "npc" variable attribution is now for the golem.
npc = golem;
npc.broadcastPacket(new SpecialCamera(npc, 30, 200, 20, 6000, 700, 8000, 0, 0, 0, 0, 0));
npc.broadcastPacket(new SocialAction(npc.getObjectId(), 1));
npc.broadcastPacket(new PlaySound(1, "Rm03_A", 0, 0, 0, 0, 0));
// start monitoring Dr. Chaos's inactivity
_lastAttackVsGolem = System.currentTimeMillis();
startQuestTimer("golem_despawn", 60000, npc, null, true);
}
// Check every sec if someone is in range, if found, launch one task to decrease the timer.
else if (event.equalsIgnoreCase("paranoia_activity"))
{
if (GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM) == NORMAL)
{
for (L2PcInstance obj : npc.getKnownList().getKnownPlayersInRadius(500))
{
if (obj.isDead())
{
continue;
}
_pissedOffTimer -= 1;
// Make him speak.
if (_pissedOffTimer == 15)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, "How dare you trespass into my territory! Have you no fear?");
}
// That was "too much" for that time.
if (_pissedOffTimer <= 0)
{
crazyMidgetBecomesAngry(npc);
}
}
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
String htmltext = "";
if (GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM) == NORMAL)
{
_pissedOffTimer -= 1 + Rnd.get(5); // remove 1-5 secs.
if ((_pissedOffTimer > 20) && (_pissedOffTimer <= 30))
{
htmltext = "<html><body>Doctor Chaos:<br>What?! Who are you? How did you come here?<br>You really look suspicious... Aren't those filthy members of Black Anvil guild send you? No? Mhhhhh... I don't trust you!</body></html>";
}
else if ((_pissedOffTimer > 10) && (_pissedOffTimer <= 20))
{
htmltext = "<html><body>Doctor Chaos:<br>Why are you standing here? Don't you see it's a private propertie? Don't look at him with those eyes... Did you smile?! Don't make fun of me! He will ... destroy ... you ... if you continue!</body></html>";
}
else if ((_pissedOffTimer > 0) && (_pissedOffTimer <= 10))
{
htmltext = "<html><body>Doctor Chaos:<br>I know why you are here, traitor! He discovered your plans! You are assassin ... sent by the Black Anvil guild! But you won't kill the Emperor of Evil!</body></html>";
}
else if (_pissedOffTimer <= 0)
{
crazyMidgetBecomesAngry(npc);
}
}
return htmltext;
}
@Override
public String onSpawn(L2Npc npc)
{
// 30 seconds timer at initialization.
_pissedOffTimer = 30;
// Initialization of the paranoia.
startQuestTimer("paranoia_activity", 1000, npc, null, true);
return null;
}
@Override
public String onKill(L2Npc npc, L2PcInstance player, boolean isPet)
{
cancelQuestTimer("golem_despawn", npc, null);
broadcastNpcSay(npc, ChatType.NPC_GENERAL, "Urggh! You will pay dearly for this insult.");
// "lock" Dr. Chaos for regular RB time (36H fixed +- 24H random)
long respawnTime = (36 + Rnd.get(-24, 24)) * 3600000;
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, DEAD);
startQuestTimer("reset_drchaos", respawnTime, null, null, false);
// also save the respawn time so that the info is maintained past reboots
StatsSet info = GrandBossManager.getInstance().getStatsSet(CHAOS_GOLEM);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(CHAOS_GOLEM, info);
return null;
}
@Override
public String onAttack(L2Npc npc, L2PcInstance victim, int damage, boolean isPet)
{
int chance = Rnd.get(300);
// Choose a message from 3 choices (1/100)
if (chance < 3)
{
String message = "";
switch (chance)
{
case 0:
message = "Bwah-ha-ha! Your doom is at hand! Behold the Ultra Secret Super Weapon!";
break;
case 1:
message = "Foolish, insignificant creatures! How dare you challenge me!";
break;
default:
message = "I see that none will challenge me now!";
break;
}
// Make him speak.
broadcastNpcSay(npc, ChatType.NPC_GENERAL, message);
}
return null;
}
/**
* Launches the complete animation.
* @param npc the midget.
*/
private void crazyMidgetBecomesAngry(L2Npc npc)
{
if (GrandBossManager.getInstance().getBossStatus(CHAOS_GOLEM) == NORMAL)
{
// Set the status to "crazy".
GrandBossManager.getInstance().setBossStatus(CHAOS_GOLEM, CRAZY);
// Cancels the paranoia timer.
cancelQuestTimer("paranoia_activity", npc, null);
// Makes the NPC moves near the Strange Box speaking.
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(96323, -110914, -3328, 0));
broadcastNpcSay(npc, ChatType.NPC_GENERAL, "Fools! Why haven't you fled yet? Prepare to learn a lesson!");
// Delayed animation timers.
startQuestTimer("1", 2000, npc, null, false); // 2 secs, time to launch dr.C anim 2. Cam 1 on.
startQuestTimer("2", 4000, npc, null, false); // 2,5 secs, time to launch dr.C anim 3.
startQuestTimer("3", 6500, npc, null, false); // 6 secs, time to launch dr.C anim 1.
startQuestTimer("4", 12500, npc, null, false); // 4,5 secs to make the NPC moves to the grotto. Cam 2 on.
startQuestTimer("5", 17000, npc, null, false); // 4 secs for golem spawn, and golem anim. Cam 3 on.
}
}
public static void main(String[] args)
{
new DrChaos();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.ItemHolder;
/**
* Eva's Gift Box AI.
* @author St3eT
*/
public final class EvasGiftBox extends AbstractNpcAI
{
// NPC
private static final int BOX = 32342; // Eva's Gift Box
// Skill
private static final int BUFF = 1073; // Kiss of Eva
// Items
private static final ItemHolder CORAL = new ItemHolder(9692, 1); // Red Coral
private static final ItemHolder CRYSTAL = new ItemHolder(9693, 1); // Crystal Fragment
private EvasGiftBox()
{
super(EvasGiftBox.class.getSimpleName(), "ai/individual");
addKillId(BOX);
addSpawnId(BOX);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (killer.isAffectedBySkill(BUFF))
{
if (getRandomBoolean())
{
npc.dropItem(killer, CRYSTAL);
}
if (getRandom(100) < 33)
{
npc.dropItem(killer, CORAL);
}
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setIsNoRndWalk(true);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new EvasGiftBox();
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.itemcontainer.Inventory;
import com.l2jserver.gameserver.network.NpcStringId;
/**
* Frightened Ragna Orc AI.
* @author Gladicek, malyelfik
*/
public final 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()
{
super(FrightenedRagnaOrc.class.getSimpleName(), "ai/individual");
addAttackId(MOB_ID);
addKillId(MOB_ID);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance 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);
broadcastNpcSay(npc, 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(L2Npc npc, L2PcInstance player, boolean isSummon)
{
final NpcStringId msg = getRandomBoolean() ? NpcStringId.UGH_A_CURSE_UPON_YOU : NpcStringId.I_REALLY_DIDN_T_WANT_TO_FIGHT;
broadcastNpcSay(npc, ChatType.NPC_GENERAL, msg);
cancelQuestTimer("say", npc, null);
cancelQuestTimer("reward", npc, player);
return super.onKill(npc, player, isSummon);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance 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;
broadcastNpcSay(npc, 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;
broadcastNpcSay(npc, 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;
broadcastNpcSay(npc, ChatType.NPC_GENERAL, msg);
npc.setScriptValue(3);
npc.doCast(SKILL.getSkill());
for (int i = 0; i < 10; i++)
{
((L2Attackable) 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;
broadcastNpcSay(npc, 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

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* Grove Robber's AI.<br>
* <ul>
* <li>Grove Robber Summoner</li>
* <li>Grove Robber Megician</li>
* </ul>
* @author Zealar
*/
public final class GraveRobbers extends AbstractNpcAI
{
private static final int GRAVE_ROBBER_SUMMONER = 22678;
private static final int GRAVE_ROBBER_MEGICIAN = 22679;
private GraveRobbers()
{
super(GraveRobbers.class.getSimpleName(), "ai/individual");
addSpawnId(GRAVE_ROBBER_SUMMONER, GRAVE_ROBBER_MEGICIAN);
}
@Override
public String onSpawn(L2Npc npc)
{
spawnMinions(npc, "Privates" + getRandom(1, 2));
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new GraveRobbers();
}
}

View File

@@ -0,0 +1,357 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import ai.npc.AbstractNpcAI;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SkillData;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.StatsSet;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
/**
* Orfen's AI
* @author Emperorc
*/
public final class Orfen extends AbstractNpcAI
{
private static final Location[] POS =
{
new Location(43728, 17220, -4342),
new Location(55024, 17368, -5412),
new Location(53504, 21248, -5486),
new Location(53248, 24576, -5262)
};
private static final NpcStringId[] TEXT =
{
NpcStringId.S1_STOP_KIDDING_YOURSELF_ABOUT_YOUR_OWN_POWERLESSNESS,
NpcStringId.S1_I_LL_MAKE_YOU_FEEL_WHAT_TRUE_FEAR_IS,
NpcStringId.YOU_RE_REALLY_STUPID_TO_HAVE_CHALLENGED_ME_S1_GET_READY,
NpcStringId.S1_DO_YOU_THINK_THAT_S_GOING_TO_WORK
};
private static final int ORFEN = 29014;
// private static final int RAIKEL = 29015;
private static final int RAIKEL_LEOS = 29016;
// private static final int RIBA = 29017;
private static final int RIBA_IREN = 29018;
private static boolean _IsTeleported;
private static final List<L2Attackable> MINIONS = new CopyOnWriteArrayList<>();
private static L2BossZone ZONE;
private static final byte ALIVE = 0;
private static final byte DEAD = 1;
private Orfen()
{
super(Orfen.class.getSimpleName(), "ai/individual");
int[] mobs =
{
ORFEN,
RAIKEL_LEOS,
RIBA_IREN
};
registerMobs(mobs);
_IsTeleported = false;
ZONE = GrandBossManager.getInstance().getZone(POS[0]);
StatsSet info = GrandBossManager.getInstance().getStatsSet(ORFEN);
int status = GrandBossManager.getInstance().getBossStatus(ORFEN);
if (status == DEAD)
{
// load the unlock date and time for Orfen from DB
long temp = info.getLong("respawn_time") - System.currentTimeMillis();
// if Orfen is locked until a certain time, mark it so and start the unlock timer
// the unlock time has not yet expired.
if (temp > 0)
{
startQuestTimer("orfen_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Immediately spawn Orfen.
int i = getRandom(10);
Location loc;
if (i < 4)
{
loc = POS[1];
}
else if (i < 7)
{
loc = POS[2];
}
else
{
loc = POS[3];
}
L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, loc, false, 0);
GrandBossManager.getInstance().setBossStatus(ORFEN, ALIVE);
spawnBoss(orfen);
}
}
else
{
int loc_x = info.getInt("loc_x");
int loc_y = info.getInt("loc_y");
int loc_z = info.getInt("loc_z");
int heading = info.getInt("heading");
int hp = info.getInt("currentHP");
int mp = info.getInt("currentMP");
L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, loc_x, loc_y, loc_z, heading, false, 0);
orfen.setCurrentHpMp(hp, mp);
spawnBoss(orfen);
}
}
public void setSpawnPoint(L2Npc npc, int index)
{
((L2Attackable) npc).clearAggroList();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
L2Spawn spawn = npc.getSpawn();
spawn.setLocation(POS[index]);
npc.teleToLocation(POS[index], false);
}
public void spawnBoss(L2GrandBossInstance npc)
{
GrandBossManager.getInstance().addBoss(npc);
npc.broadcastPacket(new PlaySound(1, "BS01_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
startQuestTimer("check_orfen_pos", 10000, npc, null, true);
// Spawn minions
int x = npc.getX();
int y = npc.getY();
L2Attackable mob;
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x + 100, y + 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x + 100, y - 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x - 100, y + 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x - 100, y - 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
startQuestTimer("check_minion_loc", 10000, npc, null, true);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("orfen_unlock"))
{
int i = getRandom(10);
Location loc;
if (i < 4)
{
loc = POS[1];
}
else if (i < 7)
{
loc = POS[2];
}
else
{
loc = POS[3];
}
L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, loc, false, 0);
GrandBossManager.getInstance().setBossStatus(ORFEN, ALIVE);
spawnBoss(orfen);
}
else if (event.equalsIgnoreCase("check_orfen_pos"))
{
if ((_IsTeleported && (npc.getCurrentHp() > (npc.getMaxHp() * 0.95))) || (!ZONE.isInsideZone(npc) && !_IsTeleported))
{
setSpawnPoint(npc, getRandom(3) + 1);
_IsTeleported = false;
}
else if (_IsTeleported && !ZONE.isInsideZone(npc))
{
setSpawnPoint(npc, 0);
}
}
else if (event.equalsIgnoreCase("check_minion_loc"))
{
for (int i = 0; i < MINIONS.size(); i++)
{
L2Attackable mob = MINIONS.get(i);
if (!npc.isInsideRadius(mob, 3000, false, false))
{
mob.teleToLocation(npc.getLocation());
((L2Attackable) npc).clearAggroList();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
}
}
}
else if (event.equalsIgnoreCase("despawn_minions"))
{
for (int i = 0; i < MINIONS.size(); i++)
{
L2Attackable mob = MINIONS.get(i);
if (mob != null)
{
mob.decayMe();
}
}
MINIONS.clear();
}
else if (event.equalsIgnoreCase("spawn_minion"))
{
L2Attackable mob = (L2Attackable) addSpawn(RAIKEL_LEOS, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (npc.getId() == ORFEN)
{
L2Character originalCaster = isSummon ? caster.getServitors().values().stream().findFirst().orElse(caster.getPet()) : caster;
if ((skill.getEffectPoint() > 0) && (getRandom(5) == 0) && npc.isInsideRadius(originalCaster, 1000, false, false))
{
NpcSay packet = new NpcSay(npc.getObjectId(), ChatType.NPC_GENERAL, npc.getId(), TEXT[getRandom(4)]);
packet.addStringParameter(caster.getName().toString());
npc.broadcastPacket(packet);
originalCaster.teleToLocation(npc.getLocation());
npc.setTarget(originalCaster);
npc.doCast(SkillData.getInstance().getSkill(4064, 1));
}
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
{
if ((caller == null) || (npc == null) || npc.isCastingNow())
{
return super.onFactionCall(npc, caller, attacker, isSummon);
}
int npcId = npc.getId();
int callerId = caller.getId();
if ((npcId == RAIKEL_LEOS) && (getRandom(20) == 0))
{
npc.setTarget(attacker);
npc.doCast(SkillData.getInstance().getSkill(4067, 4));
}
else if (npcId == RIBA_IREN)
{
int chance = 1;
if (callerId == ORFEN)
{
chance = 9;
}
if ((callerId != RIBA_IREN) && (caller.getCurrentHp() < (caller.getMaxHp() / 2.0)) && (getRandom(10) < chance))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
npc.setTarget(caller);
npc.doCast(SkillData.getInstance().getSkill(4516, 1));
}
}
return super.onFactionCall(npc, caller, attacker, isSummon);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
int npcId = npc.getId();
if (npcId == ORFEN)
{
if (!_IsTeleported && ((npc.getCurrentHp() - damage) < (npc.getMaxHp() / 2)))
{
_IsTeleported = true;
setSpawnPoint(npc, 0);
}
else if (npc.isInsideRadius(attacker, 1000, false, false) && !npc.isInsideRadius(attacker, 300, false, false) && (getRandom(10) == 0))
{
NpcSay packet = new NpcSay(npc.getObjectId(), ChatType.NPC_GENERAL, npcId, TEXT[getRandom(3)]);
packet.addStringParameter(attacker.getName().toString());
npc.broadcastPacket(packet);
attacker.teleToLocation(npc.getLocation());
npc.setTarget(attacker);
npc.doCast(SkillData.getInstance().getSkill(4064, 1));
}
}
else if (npcId == RIBA_IREN)
{
if (!npc.isCastingNow() && ((npc.getCurrentHp() - damage) < (npc.getMaxHp() / 2.0)))
{
npc.setTarget(attacker);
npc.doCast(SkillData.getInstance().getSkill(4516, 1));
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.getId() == ORFEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(ORFEN, DEAD);
// Calculate Min and Max respawn times randomly.
long respawnTime = Config.ORFEN_SPAWN_INTERVAL + getRandom(-Config.ORFEN_SPAWN_RANDOM, Config.ORFEN_SPAWN_RANDOM);
respawnTime *= 3600000;
startQuestTimer("orfen_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
StatsSet info = GrandBossManager.getInstance().getStatsSet(ORFEN);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(ORFEN, info);
cancelQuestTimer("check_minion_loc", npc, null);
cancelQuestTimer("check_orfen_pos", npc, null);
startQuestTimer("despawn_minions", 20000, null, null);
cancelQuestTimers("spawn_minion");
}
else if ((GrandBossManager.getInstance().getBossStatus(ORFEN) == ALIVE) && (npc.getId() == RAIKEL_LEOS))
{
MINIONS.remove(npc);
startQuestTimer("spawn_minion", 360000, npc, null);
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new Orfen();
}
}

View File

@@ -0,0 +1,410 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import ai.npc.AbstractNpcAI;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.StatsSet;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.skills.CommonSkill;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
/**
* Queen Ant's AI
* @author Emperorc
*/
public final class QueenAnt extends AbstractNpcAI
{
private static final int QUEEN = 29001;
private static final int LARVA = 29002;
private static final int NURSE = 29003;
private static final int GUARD = 29004;
private static final int ROYAL = 29005;
private static final int[] MOBS =
{
QUEEN,
LARVA,
NURSE,
GUARD,
ROYAL
};
private static final Location OUST_LOC_1 = new Location(-19480, 187344, -5600);
private static final Location OUST_LOC_2 = new Location(-17928, 180912, -5520);
private static final Location OUST_LOC_3 = new Location(-23808, 182368, -5600);
private static final int QUEEN_X = -21610;
private static final int QUEEN_Y = 181594;
private static final int QUEEN_Z = -5734;
// QUEEN Status Tracking :
private static final byte ALIVE = 0; // Queen Ant is spawned.
private static final byte DEAD = 1; // Queen Ant has been killed.
private static L2BossZone _zone;
private static SkillHolder HEAL1 = new SkillHolder(4020, 1);
private static SkillHolder HEAL2 = new SkillHolder(4024, 1);
L2MonsterInstance _queen = null;
private L2MonsterInstance _larva = null;
private final List<L2MonsterInstance> _nurses = new CopyOnWriteArrayList<>();
ScheduledFuture<?> _task = null;
private QueenAnt()
{
super(QueenAnt.class.getSimpleName(), "ai/individual");
addSpawnId(MOBS);
addKillId(MOBS);
addAggroRangeEnterId(MOBS);
addFactionCallId(NURSE);
_zone = GrandBossManager.getInstance().getZone(QUEEN_X, QUEEN_Y, QUEEN_Z);
StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
int status = GrandBossManager.getInstance().getBossStatus(QUEEN);
if (status == DEAD)
{
// load the unlock date and time for queen ant from DB
long temp = info.getLong("respawn_time") - System.currentTimeMillis();
// if queen ant is locked until a certain time, mark it so and start the unlock timer
// the unlock time has not yet expired.
if (temp > 0)
{
startQuestTimer("queen_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Immediately spawn queen ant.
L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, QUEEN_X, QUEEN_Y, QUEEN_Z, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE);
spawnBoss(queen);
}
}
else
{
int loc_x = QUEEN_X;
int loc_y = QUEEN_Y;
int loc_z = QUEEN_Z;
int heading = info.getInt("heading");
int hp = info.getInt("currentHP");
int mp = info.getInt("currentMP");
L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, loc_x, loc_y, loc_z, heading, false, 0);
queen.setCurrentHpMp(hp, mp);
spawnBoss(queen);
}
}
private void spawnBoss(L2GrandBossInstance npc)
{
GrandBossManager.getInstance().addBoss(npc);
if (getRandom(100) < 33)
{
_zone.movePlayersTo(OUST_LOC_1);
}
else if (getRandom(100) < 50)
{
_zone.movePlayersTo(OUST_LOC_2);
}
else
{
_zone.movePlayersTo(OUST_LOC_3);
}
GrandBossManager.getInstance().addBoss(npc);
startQuestTimer("action", 10000, npc, null, true);
startQuestTimer("heal", 1000, null, null, true);
npc.broadcastPacket(new PlaySound(1, "BS01_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
_queen = npc;
_larva = (L2MonsterInstance) addSpawn(LARVA, -21600, 179482, -5846, getRandom(360), false, 0);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("heal"))
{
boolean notCasting;
final boolean larvaNeedHeal = (_larva != null) && (_larva.getCurrentHp() < _larva.getMaxHp());
final boolean queenNeedHeal = (_queen != null) && (_queen.getCurrentHp() < _queen.getMaxHp());
for (L2MonsterInstance nurse : _nurses)
{
if ((nurse == null) || nurse.isDead() || nurse.isCastingNow())
{
continue;
}
notCasting = nurse.getAI().getIntention() != CtrlIntention.AI_INTENTION_CAST;
if (larvaNeedHeal)
{
if ((nurse.getTarget() != _larva) || notCasting)
{
nurse.setTarget(_larva);
nurse.useMagic(getRandomBoolean() ? HEAL1.getSkill() : HEAL2.getSkill());
}
continue;
}
if (queenNeedHeal)
{
if (nurse.getLeader() == _larva)
{
continue;
}
if ((nurse.getTarget() != _queen) || notCasting)
{
nurse.setTarget(_queen);
nurse.useMagic(HEAL1.getSkill());
}
continue;
}
// if nurse not casting - remove target
if (notCasting && (nurse.getTarget() != null))
{
nurse.setTarget(null);
}
}
}
else if (event.equalsIgnoreCase("action") && (npc != null))
{
if (getRandom(3) == 0)
{
if (getRandom(2) == 0)
{
npc.broadcastSocialAction(3);
}
else
{
npc.broadcastSocialAction(4);
}
}
}
else if (event.equalsIgnoreCase("queen_unlock"))
{
L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, QUEEN_X, QUEEN_Y, QUEEN_Z, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE);
spawnBoss(queen);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSpawn(L2Npc npc)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
switch (npc.getId())
{
case LARVA:
mob.setIsImmobilized(true);
mob.setIsMortal(false);
mob.setIsRaidMinion(true);
break;
case NURSE:
mob.disableCoreAI(true);
mob.setIsRaidMinion(true);
_nurses.add(mob);
break;
case ROYAL:
case GUARD:
mob.setIsRaidMinion(true);
break;
case QUEEN:
_task = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new QueenAntTask(), 5 * 1000, 5 * 1000);
break;
}
return super.onSpawn(npc);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
{
if ((caller == null) || (npc == null))
{
return super.onFactionCall(npc, caller, attacker, isSummon);
}
if (!npc.isCastingNow() && (npc.getAI().getIntention() != CtrlIntention.AI_INTENTION_CAST))
{
if (caller.getCurrentHp() < caller.getMaxHp())
{
npc.setTarget(caller);
((L2Attackable) npc).useMagic(HEAL1.getSkill());
}
}
return null;
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if ((npc == null) || (player.isGM() && player.isInvisible()))
{
return null;
}
final boolean isMage;
final L2Playable character;
if (isSummon)
{
isMage = false;
character = player.getServitors().values().stream().findFirst().orElse(player.getPet());
}
else
{
isMage = player.isMageClass();
character = player;
}
if (character == null)
{
return null;
}
if (!Config.RAID_DISABLE_CURSE && ((character.getLevel() - npc.getLevel()) > 8))
{
Skill curse = null;
if (isMage)
{
if (!character.isMuted() && (getRandom(4) == 0))
{
curse = CommonSkill.RAID_CURSE.getSkill();
}
}
else
{
if (!character.isParalyzed() && (getRandom(4) == 0))
{
curse = CommonSkill.RAID_CURSE2.getSkill();
}
}
if (curse != null)
{
npc.broadcastPacket(new MagicSkillUse(npc, character, curse.getId(), curse.getLevel(), 300, 0));
curse.applyEffects(npc, character);
}
((L2Attackable) npc).stopHating(character); // for calling again
return null;
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
int npcId = npc.getId();
if (npcId == QUEEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(QUEEN, DEAD);
// Calculate Min and Max respawn times randomly.
long respawnTime = Config.QUEEN_ANT_SPAWN_INTERVAL + getRandom(-Config.QUEEN_ANT_SPAWN_RANDOM, Config.QUEEN_ANT_SPAWN_RANDOM);
respawnTime *= 3600000;
startQuestTimer("queen_unlock", respawnTime, null, null);
cancelQuestTimer("action", npc, null);
cancelQuestTimer("heal", null, null);
// also save the respawn time so that the info is maintained past reboots
StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(QUEEN, info);
_nurses.clear();
_larva.deleteMe();
_larva = null;
_queen = null;
if (_task != null)
{
_task.cancel(false);
_task = null;
}
}
else if ((_queen != null) && !_queen.isAlikeDead())
{
if (npcId == ROYAL)
{
L2MonsterInstance mob = (L2MonsterInstance) npc;
if (mob.getLeader() != null)
{
mob.getLeader().getMinionList().onMinionDie(mob, (280 + getRandom(40)) * 1000);
}
}
else if (npcId == NURSE)
{
L2MonsterInstance mob = (L2MonsterInstance) npc;
_nurses.remove(mob);
if (mob.getLeader() != null)
{
mob.getLeader().getMinionList().onMinionDie(mob, 10000);
}
}
}
return super.onKill(npc, killer, isSummon);
}
private class QueenAntTask implements Runnable
{
public QueenAntTask()
{
// Constructor stub
}
@Override
public void run()
{
if ((_queen == null) || _queen.isDead())
{
_task.cancel(false);
_task = null;
}
else
{
if (_queen.calculateDistance(QUEEN_X, QUEEN_Y, QUEEN_Z, false, false) > 2000.)
{
_queen.clearAggroList();
_queen.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(QUEEN_X, QUEEN_Y, QUEEN_Z, 0));
}
}
}
}
public static void main(String[] args)
{
new QueenAnt();
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* Ragna Orc Commander AI.
* @author Zealar
*/
public final class RagnaOrcCommander extends AbstractNpcAI
{
private static final int RAGNA_ORC_COMMANDER = 22694;
private RagnaOrcCommander()
{
super(RagnaOrcCommander.class.getSimpleName(), "ai/individual");
addSpawnId(RAGNA_ORC_COMMANDER);
}
@Override
public String onSpawn(L2Npc npc)
{
spawnMinions(npc, "Privates1");
spawnMinions(npc, getRandomBoolean() ? "Privates2" : "Privates3");
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RagnaOrcCommander();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* Ragna Orc Hero AI.
* @author Zealar
*/
public final class RagnaOrcHero extends AbstractNpcAI
{
private static final int RAGNA_ORC_HERO = 22693;
private RagnaOrcHero()
{
super(RagnaOrcHero.class.getSimpleName(), "ai/individual");
addSpawnId(RAGNA_ORC_HERO);
}
@Override
public String onSpawn(L2Npc npc)
{
spawnMinions(npc, getRandom(100) < 70 ? "Privates1" : "Privates2");
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RagnaOrcHero();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
/**
* Ragna Orc Seer AI.
* @author Zealar
*/
public final class RagnaOrcSeer extends AbstractNpcAI
{
private static final int RAGNA_ORC_SEER = 22697;
private RagnaOrcSeer()
{
super(RagnaOrcSeer.class.getSimpleName(), "ai/individual");
addSpawnId(RAGNA_ORC_SEER);
}
@Override
public String onSpawn(L2Npc npc)
{
spawnMinions(npc, "Privates" + getRandom(1, 2));
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RagnaOrcSeer();
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.events.EventType;
import com.l2jserver.gameserver.model.events.ListenerRegisterType;
import com.l2jserver.gameserver.model.events.annotations.Id;
import com.l2jserver.gameserver.model.events.annotations.RegisterEvent;
import com.l2jserver.gameserver.model.events.annotations.RegisterType;
import com.l2jserver.gameserver.model.events.impl.character.OnCreatureAttacked;
import com.l2jserver.gameserver.model.events.impl.character.OnCreatureKill;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
/**
* Sin Eater AI.
* @author St3eT.
*/
public final class SinEater extends AbstractNpcAI
{
// NPCs
private static final int SIN_EATER = 12564;
private SinEater()
{
super(SinEater.class.getSimpleName(), "ai/individual");
addSummonSpawnId(SIN_EATER);
addSummonTalkId(SIN_EATER);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("TALK") && (player != null) && (player.getPet() != null))
{
if (getRandom(100) < 30)
{
final int random = getRandom(100);
final L2Summon summon = player.getPet();
if (random < 20)
{
broadcastSummonSay(summon, NpcStringId.YAWWWWN_IT_S_SO_BORING_HERE_WE_SHOULD_GO_AND_FIND_SOME_ACTION);
}
else if (random < 40)
{
broadcastSummonSay(summon, NpcStringId.HEY_IF_YOU_CONTINUE_TO_WASTE_TIME_YOU_WILL_NEVER_FINISH_YOUR_PENANCE);
}
else if (random < 60)
{
broadcastSummonSay(summon, NpcStringId.I_KNOW_YOU_DON_T_LIKE_ME_THE_FEELING_IS_MUTUAL);
}
else if (random < 80)
{
broadcastSummonSay(summon, NpcStringId.I_NEED_A_DRINK);
}
else
{
broadcastSummonSay(summon, NpcStringId.OH_THIS_IS_DRAGGING_ON_TOO_LONG_AT_THIS_RATE_I_WON_T_MAKE_IT_HOME_BEFORE_THE_SEVEN_SEALS_ARE_BROKEN);
}
}
startQuestTimer("TALK", 60000, null, player);
}
return super.onAdvEvent(event, npc, player);
}
@RegisterEvent(EventType.ON_CREATURE_KILL)
@RegisterType(ListenerRegisterType.NPC)
@Id(SIN_EATER)
public void onCreatureKill(OnCreatureKill event)
{
final int random = getRandom(100);
final L2Summon summon = (L2Summon) event.getTarget();
if (random < 30)
{
broadcastSummonSay(summon, NpcStringId.OH_THIS_IS_JUST_GREAT_WHAT_ARE_YOU_GOING_TO_DO_NOW);
}
else if (random < 70)
{
broadcastSummonSay(summon, NpcStringId.YOU_INCONSIDERATE_MORON_CAN_T_YOU_EVEN_TAKE_CARE_OF_LITTLE_OLD_ME);
}
else
{
broadcastSummonSay(summon, NpcStringId.OH_NO_THE_MAN_WHO_EATS_ONE_S_SINS_HAS_DIED_PENITENCE_IS_FURTHER_AWAY);
}
}
@RegisterEvent(EventType.ON_CREATURE_ATTACKED)
@RegisterType(ListenerRegisterType.NPC)
@Id(SIN_EATER)
public void onCreatureAttacked(OnCreatureAttacked event)
{
if (getRandom(100) < 30)
{
final int random = getRandom(100);
final L2Summon summon = (L2Summon) event.getTarget();
if (random < 35)
{
broadcastSummonSay(summon, NpcStringId.OH_THAT_SMARTS);
}
else if (random < 70)
{
broadcastSummonSay(summon, NpcStringId.HEY_MASTER_PAY_ATTENTION_I_M_DYING_OVER_HERE);
}
else
{
broadcastSummonSay(summon, NpcStringId.WHAT_HAVE_I_DONE_TO_DESERVE_THIS);
}
}
}
@Override
public void onSummonSpawn(L2Summon summon)
{
broadcastSummonSay(summon, getRandomBoolean() ? NpcStringId.HEY_IT_SEEMS_LIKE_YOU_NEED_MY_HELP_DOESN_T_IT : NpcStringId.ALMOST_GOT_IT_OUCH_STOP_DAMN_THESE_BLOODY_MANACLES);
startQuestTimer("TALK", 60000, null, summon.getOwner());
}
@Override
public void onSummonTalk(L2Summon summon)
{
if (getRandom(100) < 10)
{
final int random = getRandom(100);
if (random < 25)
{
broadcastSummonSay(summon, NpcStringId.USING_A_SPECIAL_SKILL_HERE_COULD_TRIGGER_A_BLOODBATH);
}
else if (random < 50)
{
broadcastSummonSay(summon, NpcStringId.HEY_WHAT_DO_YOU_EXPECT_OF_ME);
}
else if (random < 75)
{
broadcastSummonSay(summon, NpcStringId.UGGGGGH_PUSH_IT_S_NOT_COMING_OUT);
}
else
{
broadcastSummonSay(summon, NpcStringId.AH_I_MISSED_THE_MARK);
}
}
}
private void broadcastSummonSay(L2Summon summon, NpcStringId npcstringId)
{
summon.broadcastPacket(new NpcSay(summon.getObjectId(), ChatType.NPC_GENERAL, summon.getId(), npcstringId));
}
public static void main(String[] args)
{
new SinEater();
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.individual;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
/**
* Manages Sin Wardens disappearing and chat.
* @author GKR
*/
public final class SinWardens extends AbstractNpcAI
{
private static final int[] SIN_WARDEN_MINIONS =
{
22424,
22425,
22426,
22427,
22428,
22429,
22430,
22432,
22433,
22434,
22435,
22436,
22437,
22438
};
private final Map<Integer, Integer> killedMinionsCount = new ConcurrentHashMap<>();
private SinWardens()
{
super(SinWardens.class.getSimpleName(), "ai/individual");
addKillId(SIN_WARDEN_MINIONS);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.isMinion())
{
final L2MonsterInstance master = ((L2MonsterInstance) npc).getLeader();
if ((master != null) && !master.isDead())
{
int killedCount = killedMinionsCount.containsKey(master.getObjectId()) ? killedMinionsCount.get(master.getObjectId()) : 0;
killedCount++;
if ((killedCount) == 5)
{
master.broadcastPacket(new NpcSay(master.getObjectId(), ChatType.NPC_GENERAL, master.getId(), NpcStringId.WE_MIGHT_NEED_NEW_SLAVES_I_LL_BE_BACK_SOON_SO_WAIT));
master.doDie(killer);
killedMinionsCount.remove(master.getObjectId());
}
else
{
killedMinionsCount.put(master.getObjectId(), killedCount);
}
}
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new SinWardens();
}
}

View File

@@ -0,0 +1,13 @@
Individual AI:
This folder contains AI scripts for single npc templates (one npc ID, but possibly many instances).
That is, if a particular NPC/mob has a unique AI or something slightly different from all other generic NPCs,
an individual AI script can be created for all occurences of that npc/mob. Such individual scripts ought to be here.
Individual AI scripts can be subclassed. In other words, an individual may inherit from a group or other individual.
For example, one group template might define mobs that cast spells. A particular mob may cast spells but may also
talk whenever it gets attacked. In that case, instead of writing all the AI for attacking and casting spells, it may
inherit from a group template that defines AI for ALL mobs that cast spells, then add behaviours for talking onAttack.
"NPC registrations" refers to the addition of NPCs in the various events of the scripts, such as onAttack, onKill, etc
Those are done by using keywords such as "addKillId" etc. For more details on registrations, see
"scripts/quests/documentation.txt"

View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc;
import com.l2jserver.gameserver.enums.ChatType;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.MinionHolder;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.util.Broadcast;
/**
* Abstract NPC AI class for datapack based AIs.
* @author UnAfraid, Zoey76
*/
public abstract class AbstractNpcAI extends Quest
{
public AbstractNpcAI(String name, String descr)
{
super(-1, name, descr);
}
/**
* Simple on first talk event handler.
*/
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
return npc.getId() + ".html";
}
/**
* Registers the following events to the current script:<br>
* <ul>
* <li>ON_ATTACK</li>
* <li>ON_KILL</li>
* <li>ON_SPAWN</li>
* <li>ON_SPELL_FINISHED</li>
* <li>ON_SKILL_SEE</li>
* <li>ON_FACTION_CALL</li>
* <li>ON_AGGR_RANGE_ENTER</li>
* </ul>
* @param mobs
*/
public void registerMobs(int... mobs)
{
addAttackId(mobs);
addKillId(mobs);
addSpawnId(mobs);
addSpellFinishedId(mobs);
addSkillSeeId(mobs);
addAggroRangeEnterId(mobs);
addFactionCallId(mobs);
}
/**
* Broadcasts NpcSay packet to all known players with custom string.
* @param npc
* @param type
* @param text
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, String text)
{
Broadcast.toKnownPlayers(npc, new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), text));
}
/**
* Broadcasts NpcSay packet to all known players with npc string id.
* @param npc
* @param type
* @param stringId
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, NpcStringId stringId)
{
Broadcast.toKnownPlayers(npc, new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), stringId));
}
/**
* Broadcasts NpcSay packet to all known players with npc string id.
* @param npc
* @param type
* @param stringId
* @param parameters
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, NpcStringId stringId, String... parameters)
{
final NpcSay say = new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), stringId);
if (parameters != null)
{
for (String parameter : parameters)
{
say.addStringParameter(parameter);
}
}
Broadcast.toKnownPlayers(npc, say);
}
/**
* Broadcasts NpcSay packet to all known players with custom string in specific radius.
* @param npc
* @param type
* @param text
* @param radius
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, String text, int radius)
{
Broadcast.toKnownPlayersInRadius(npc, new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), text), radius);
}
/**
* Broadcasts NpcSay packet to all known players with npc string id in specific radius.
* @param npc
* @param type
* @param stringId
* @param radius
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, NpcStringId stringId, int radius)
{
Broadcast.toKnownPlayersInRadius(npc, new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), stringId), radius);
}
/**
* Broadcasts SocialAction packet to self and known players.
* @param character
* @param actionId
*/
protected void broadcastSocialAction(L2Character character, int actionId)
{
Broadcast.toSelfAndKnownPlayers(character, new SocialAction(character.getObjectId(), actionId));
}
/**
* Broadcasts SocialAction packet to self and known players in specific radius.
* @param character
* @param actionId
* @param radius
*/
protected void broadcastSocialAction(L2Character character, int actionId, int radius)
{
Broadcast.toSelfAndKnownPlayersInRadius(character, new SocialAction(character.getObjectId(), actionId), radius);
}
public void spawnMinions(final L2Npc npc, final String spawnName)
{
for (MinionHolder is : npc.getTemplate().getParameters().getMinionList(spawnName))
{
addMinion((L2MonsterInstance) npc, is.getId());
}
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc.AdventurersGuide;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.skills.Skill;
/**
* Adventurers Guide AI.
* @author St3eT
*/
public final class AdventurersGuide extends AbstractNpcAI
{
// NPCs
private static final int[] ADVENTURERS_GUIDE =
{
32327,
33454, // Newbie Helper
};
// Skills
private static final SkillHolder BLESS_PROTECTION = new SkillHolder(5182, 1); // Blessing of Protection
private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer)
private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer)
private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer)
private static final SkillHolder[] GROUP_BUFFS =
{
new SkillHolder(15642, 1), // Horn Melody (Adventurer)
new SkillHolder(15643, 1), // Drum Melody (Adventurer)
new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer)
new SkillHolder(15645, 1), // Guitar Melody (Adventurer)
new SkillHolder(15646, 1), // Harp Melody (Adventurer)
new SkillHolder(15647, 1), // Lute Melody (Adventurer)
new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer)
new SkillHolder(15652, 1), // Daring Sonata (Adventurer)
new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer)
};
private AdventurersGuide()
{
super(AdventurersGuide.class.getSimpleName(), "ai/npc");
addStartNpc(ADVENTURERS_GUIDE);
addTalkId(ADVENTURERS_GUIDE);
addFirstTalkId(ADVENTURERS_GUIDE);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
String htmltext = null;
switch (event)
{
case "guide-01.html":
case "guide-02.html":
case "guide-03.html":
case "guide-04.html":
{
htmltext = event;
break;
}
case "weakenBreath":
{
if (player.getShilensBreathDebuffLevel() < 3)
{
htmltext = "guide-noBreath.html";
break;
}
player.setShilensBreathDebuffLevel(2);
htmltext = ""; // TODO: Any success html?
break;
}
case "knight":
{
htmltext = applyBuffs(npc, player, KNIGHT.getSkill());
break;
}
case "warrior":
{
htmltext = applyBuffs(npc, player, WARRIOR.getSkill());
break;
}
case "wizard":
{
htmltext = applyBuffs(npc, player, WIZARD.getSkill());
break;
}
}
return htmltext;
}
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
return "guide.html";
}
private String applyBuffs(L2Npc npc, L2PcInstance player, Skill skill)
{
if (player.getLevel() > 90)
{
return "guide-noBuffs.html";
}
for (SkillHolder holder : GROUP_BUFFS)
{
holder.getSkill().applyEffects(npc, player);
}
skill.applyEffects(npc, player);
if ((player.getLevel() < 40) && (player.getClassId().level() <= 1))
{
BLESS_PROTECTION.getSkill().applyEffects(npc, player);
}
return null;
}
public static void main(String[] args)
{
new AdventurersGuide();
}
}

View File

@@ -0,0 +1,11 @@
<html><body>
I can offer you the following buffs, if you're below Lv. 91.<br>
Horn Melody / Drum Melody / Pipe Organ Melody<br1>
Guitar Melody / Harp Melody / Lute Melody<br1>
Prevailing Sonata / Daring Sonata / Refreshing Sonata<br1>
You can receive the above buffs as a group.<br>
For Knight's Harmony / Warrior's Harmony / Wizard's Harmony, you will have to choose one.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide knight">"I want the Knight's Harmony."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide warrior">"Warrior's Harmony, please."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide wizard">"Wizard's Harmony, of course!"</Button>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Adventurers' Guide:<br>
The Steel Door Guild tops all Dwarven guilds in power and prestige. As such, it is our duty to aid adventurers who work to restore peace unto this war-torn land. We will be happy to offer special assistance if you have Steel Door Guild Coins.<br>
Well?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide guide-03.html">"How do I use Steel Door Guild Coins?"</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide guide-04.html">"Here, I have some Steel Door Guild Coins..."</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Adventurers' Guide:<br>
You can use Steel Door Guild Coins to purchase <font color="LEVEL">weapons, armor, and accessories of each grade</font>. These items may be restricted in terms of augmentations or attribute options, but they will be more than enough to help you on your journey.<br>
Once you outgrow the equipment, <font color="LEVEL">you can trade them back for Steel Door Guild Coins again</font>! You can also invest in the Aden Reconstruction project if it suits your fancy, or even gamble. Don't forget that Steel Weapon Packs and Steel Armor Packs have a chance of yielding Requiem, Apocalypse, or Specter equipment!<br>
<Button ALIGN=LEFT ICON="RETURN" action="bypass -h npc_%objectId%_Quest AdventurersGuide guide-02.html">Back</Button>
</body></html>

View File

@@ -0,0 +1,14 @@
<html><body>Adventurers' Guide:<br>
You can use Steel Door Guild Coins to receive equipment, and trade them back for coins again. Just remember, <font color="LEVEL">you cannot bring us junk to exchange for coins!</font><br>
So, what would you like to do?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 893">"I'd like a weapon or a shield / Sigil."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 894">"I want to buy a top."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 895">"I am looking for some pants."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 896">"Do you have any good helmets?"</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 897">"Gloves would be nice."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 898">"Give me the best boots you got."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 899">"Can I take a look at your necklaces?"</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 900">"I'm up for a ring..."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 901">"I want some earrings."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_exc_multisell 903">"I want to return my Steel equipment."</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Adventurers' Guide<br>
I can only weaken Shilen's Breath Lv. 3 or above.<br>
There is nothing I can do for you.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>
Characters who are Lv. 91 or above cannot receive Newbie Buffs.
</body></html>

View File

@@ -0,0 +1,9 @@
<html><body>Adventurers' Guide:<br>
Greetings, traveler! How may I be of assistance?<br>
My job is to offer what little assistance I can as you charge into all this endless evil and intense fighting!<br>
Even now, the monster attacks on this village grow stronger each day; it is only due to your tireless efforts that we have remained safe this long.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide guide-01.html"><font color="LEVEL">"Can I see the list of available buffs?"</font></Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide guide-02.html">"Here, I have some Steel Door Guild Coins..."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_Quest AdventurersGuide weakenBreath">"I heard you could weaken Shilen's Breath Lv.3 or above."</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,9 @@
<html><body>Trader Alexandria:<br><br>
Ah, you have excellent taste! This bracelet is truly unique. In fact, it is said that it contains an <font color="LEVEL">Agathion</font>. Quite a find, eh? Wondering if it is for sale? Of course it is -- that's why I'm here!<br>
Both this <font color="LEVEL">Little Angel Agathion Bracelet</font> and this <font color="LEVEL">Little Devil Agathion Bracelet</font> were discovered by another group of adventurers while exploring some ancient ruins. I am positive that they contain Agathions! Of course, no one knows for sure the power an Agathion possesses or how long it lasts. I have been reluctant to experiment on them because it's clear that some of the bracelets possess only limited magic power.<br>
Others have more, however. What you get depends on your luck, I'm afraid.<br>
To get either the angel or devil bracelet, you must bring me <font color="LEVEL">10 Fish Bones</font>, <font color="LEVEL">10 Fish Scales</font>, <font color="LEVEL">10 units of Fish Oil</font>, <font color="LEVEL">10 Fish Fins</font>, <font color="LEVEL">10 Fish Gems</font>, <font color="LEVEL">5 units of Whale Blubber</font>, and <font color="LEVEL">3,000,000 Adena</font>. I wish I could part with them in exchange for crystals as I normally would, but the adventurers who delivered the bracelets here insisted on these other items for payment.<br>
Even so, I still believe this is a reasonable price. After all, an Agathion isn't something you run across every day, eh? So, would you like to buy one?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Alexandria littleAngel">Purchase the Little Angel Agathion Bracelet</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Alexandria littleDevil">Purchase the Little Devil Agathion Bracelet</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Trader Alexandria:<br>
Yes, I've checked the necessary items. Thank you for your hard work.<br>
I'm telling you ahead that I don't know for sure what kind of power each bracelet has. I only can tell you that the angel-engraved bracelet has an angel-type Agathion, and the devil-engraved one has a devil-type Agathion. You can find out the capability and magic power of each Agathion on your own.
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Trader Alexandria:<br>
Yes, I checked the necessary items. It must have been difficult to obtain them all!<br>
I must warn you that I do not know for sure what kind of power posessed by each bracelet. I only can tell you that the Angel's Bracelet contains an angel-type Agathion, while the Devil's Bracelet contains a devil-type Agathion. You must discover the capability and magic power of each on your own.<br>
Here, please take this as an extra token of my appreciation for your business...<br>
(I have a strange feeling about that bracelet -- I hope this adventurer will simply take this and leave here immediately.)
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Trader Alexandria:<br>
Oh, you don't have the items required to buy either the Angel's Bracelet or the Devil's Bracelet. In order to obtain one, you must first bring me <font color="LEVEL">25 Big Red Nimble Fish</font>, <font color="LEVEL">50 Great Codrans</font>, and <font color="LEVEL">4 Memento Moris, 5 Earth Eggs, 5 Nonliving Nuclei, 3 Dragon Hearts</font>, and <font color="LEVEL">7,500,000 Adena</font>.
</body></html>

View File

@@ -0,0 +1,9 @@
<html><body>Trader Alexandria:<br>
Welcome! Thank you so much for visiting our boutique. We sell precious and valuable things that you would never find anywhere else. We've also added some luxury accessories this time. Look around see if you can find anything you like.<br>
Ah! Now, you can use <font color="LEVEL">Adena</font> to pay for your goods.<br>
If you would like to purchase a weapon, please ask my husband.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 300984001">Purchase Armor</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 300984002">Purchase supplies</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest Alexandria 30098-02.html">Purchase an Agathion Bracelet</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc.Alexandria;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.ItemHolder;
import com.l2jserver.gameserver.model.holders.QuestItemHolder;
/**
* Alexandria (Armor Merchant) AI.
* @author xban1x
*/
public final class Alexandria extends AbstractNpcAI
{
// NPC
private static final int ALEXANDRIA = 30098;
// Items
private static final ItemHolder[] REQUIRED_ITEMS = new ItemHolder[]
{
new ItemHolder(57, 3550000),
new ItemHolder(5094, 400),
new ItemHolder(6471, 200),
new ItemHolder(9814, 40),
new ItemHolder(9815, 30),
new ItemHolder(9816, 50),
new ItemHolder(9817, 50),
};
// Agathions
private static final QuestItemHolder[] LITTLE_DEVILS = new QuestItemHolder[]
{
new AdditionalQuestItemHolder(10321, 600, 1, 10408),
new QuestItemHolder(10322, 10),
new QuestItemHolder(10323, 10),
new QuestItemHolder(10324, 5),
new QuestItemHolder(10325, 5),
new QuestItemHolder(10326, 370),
};
private static final QuestItemHolder[] LITTLE_ANGELS = new QuestItemHolder[]
{
new AdditionalQuestItemHolder(10315, 600, 1, 10408),
new QuestItemHolder(10316, 10),
new QuestItemHolder(10317, 10),
new QuestItemHolder(10318, 5),
new QuestItemHolder(10319, 5),
new QuestItemHolder(10320, 370),
};
private static final Map<String, List<QuestItemHolder>> AGATHIONS = new HashMap<>();
static
{
AGATHIONS.put("littleAngel", Arrays.asList(LITTLE_ANGELS));
AGATHIONS.put("littleDevil", Arrays.asList(LITTLE_DEVILS));
}
private Alexandria()
{
super(Alexandria.class.getSimpleName(), "ai/npc");
addStartNpc(ALEXANDRIA);
addTalkId(ALEXANDRIA);
addFirstTalkId(ALEXANDRIA);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
String htmltext = null;
if (event.equals("30098-02.html"))
{
htmltext = event;
}
else if (AGATHIONS.containsKey(event))
{
final int chance = getRandom(1000);
int chance2 = 0;
int chance3 = 0;
for (QuestItemHolder agathion : AGATHIONS.get(event))
{
chance3 += agathion.getChance();
if ((chance >= chance2) && (chance2 < chance3))
{
if (takeAllItems(player, REQUIRED_ITEMS))
{
giveItems(player, agathion);
htmltext = "30098-03.html";
if (agathion instanceof AdditionalQuestItemHolder)
{
giveItems(player, ((AdditionalQuestItemHolder) agathion).getAdditionalId(), 1);
htmltext = "30098-03a.html";
}
}
else
{
htmltext = "30098-04.html";
}
break;
}
chance2 += agathion.getChance();
}
}
return htmltext;
}
public static class AdditionalQuestItemHolder extends QuestItemHolder
{
private final int _additionalId;
public AdditionalQuestItemHolder(int id, int chance, long count, int additionalId)
{
super(id, chance, count);
_additionalId = additionalId;
}
public int getAdditionalId()
{
return _additionalId;
}
}
public static void main(String[] args)
{
new Alexandria();
}
}

View File

@@ -0,0 +1,10 @@
<html><body>Arena Manager:<br>
Way to go! Hooray! Hooray!!!<br>
(Be careful! CP/HP will not get recovered inside the fence.)<br><br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest ArenaManager CPrecovery">CP Recovery : 1,000 Adena</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest ArenaManager HPrecovery">HP Recovery : 1,000 Adena</Button><br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest ArenaManager Buff">Buff for Battle Ground : 2,000 Adena</Button><br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_DepositP">Private Warehouse: Deposit an item.</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_WithdrawP">Private Warehouse: Withdraw an item.</Button><br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,9 @@
<html><body>Arena Director:<br>
Play the game according to the rules! The loser should be silent! What? Unfair? Then, why don't you hold your tongue and give it another try!<br><br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest ArenaManager CPrecovery">CP Recovery : 1,000 Adena</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest ArenaManager HPrecovery">HP Recovery : 1,000 Adena</Button><br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest ArenaManager Buff">Buff for Battle Ground : 2,000 Adena</Button><br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_DepositP">Private Warehouse: Deposit an item.</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_WithdrawP">Private Warehouse: Withdraw an item.</Button><br>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc.ArenaManager;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.holders.SkillHolder;
import com.l2jserver.gameserver.model.itemcontainer.Inventory;
import com.l2jserver.gameserver.model.zone.ZoneId;
import com.l2jserver.gameserver.network.SystemMessageId;
/**
* Arena Manager AI.
* @author St3eT
*/
public final class ArenaManager extends AbstractNpcAI
{
// NPCs
private static final int[] ARENA_MANAGER =
{
31226, // Arena Director (MDT)
31225, // Arena Manager (Coliseum)
};
// Skill
private static final SkillHolder[] BUFFS =
{
new SkillHolder(6805, 1), // Arena Empower
new SkillHolder(6806, 1), // Arena Acumen
new SkillHolder(6807, 1), // Arena Concentration
new SkillHolder(6808, 1), // Arena Might
new SkillHolder(6804, 1), // Arena Wind Walk
new SkillHolder(6812, 1), // Arena Berserker Spirit
};
private static final SkillHolder CP_RECOVERY = new SkillHolder(4380, 1); // Arena: CP Recovery
private static final SkillHolder HP_RECOVERY = new SkillHolder(6817, 1); // Arena HP Recovery
// Misc
private static final int CP_COST = 1000;
private static final int HP_COST = 1000;
private static final int BUFF_COST = 2000;
private ArenaManager()
{
super(ArenaManager.class.getSimpleName(), "ai/npc");
addStartNpc(ARENA_MANAGER);
addTalkId(ARENA_MANAGER);
addFirstTalkId(ARENA_MANAGER);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "CPrecovery":
{
if (player.getAdena() >= CP_COST)
{
takeItems(player, Inventory.ADENA_ID, CP_COST);
startQuestTimer("CPrecovery_delay", 2000, npc, player);
}
else
{
player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
}
break;
}
case "CPrecovery_delay":
{
if ((player != null) && !player.isInsideZone(ZoneId.PVP))
{
npc.setTarget(player);
npc.doCast(CP_RECOVERY.getSkill());
}
break;
}
case "HPrecovery":
{
if (player.getAdena() >= HP_COST)
{
takeItems(player, Inventory.ADENA_ID, HP_COST);
startQuestTimer("HPrecovery_delay", 2000, npc, player);
}
else
{
player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
}
break;
}
case "HPrecovery_delay":
{
if ((player != null) && !player.isInsideZone(ZoneId.PVP))
{
npc.setTarget(player);
npc.doCast(HP_RECOVERY.getSkill());
}
break;
}
case "Buff":
{
if (player.getAdena() >= BUFF_COST)
{
takeItems(player, Inventory.ADENA_ID, BUFF_COST);
npc.setTarget(player);
for (SkillHolder skill : BUFFS)
{
npc.doCast(skill.getSkill());
}
}
else
{
player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new ArenaManager();
}
}

View File

@@ -0,0 +1,9 @@
<html><body>Transformation Wizard Avant-Garde:<br>
I am Avant-Garde, the Transformation Wizard. I have long wandered through the land and only recently settled here.<br>
In fact, my young friend, I am not a wizard of the Ivory Tower. You look surprised! Heh. Think of me as a wanderer who acquired a special power quite by chance... My magic, however, requires some very specialized items.<br>
If you have acquired these unique items from the dark wizard in Hardin's Academy, then perhaps I can help you.<br>
<a action="bypass -h Quest AvantGarde 32323-02.html">Ask about transformation.</a><br>
<a action="bypass -h Quest AvantGarde LearnTransformationSkill">Learn transformation.</a><br>
<a action="bypass -h Quest AvantGarde BuyTransformationItems">Purchase items related to transformation.</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest.</a>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Wizard of Trasformation Avant-Garde:<br>
What do you wish to know about transformation?<br>
<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-02a.html">"What do I need to know about transformation?"</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-02b.html">"What do I need to do to transform into another shape?"</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-02c.html">"What do I need to know before transformation?"</Button>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Transformation Wizard Avant-Garde:<br>
To learn the magic of transformation, you will need to receive special training.<br>
Find the Wizard of Darkness, who lives at Hardin's Academy. He will open the path to transformation.<br>
You must have reached at least <font color="LEVEL">level 50 </font> to embark on this path.<br>
You will also need a special seal. I do not know how you can obtain it, but without it transformation is impossible.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-02.html">Back.</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Transformation Wizard Avant-Garde:<br>
After you have been guided through the process of transformation by a wizard, you may transform yourself into another shape by bringing a transform sealbook to me.<br>
Know that it is no easy task to earn one. I have heard, however, that you may find one through the Marketeer of Mammon or the Adventure Guild.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-02.html">Back.</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Transformation Wizard Avant-Garde:<br>
You must remember that once you have been transformed, you must not go into <font color="LEVEL">deep water</font>. Once you have reverted to your original form, your soul will need time to recover -- you will not be able to transform again for some time. Understand?<br>
Other than that... Each individual soul contains its own <font color="LEVEL">unique character</font>. If you transform into something that matches that character, you may earn some benefits. Think of it as wearing a suit of clothes that fit you perfectly. Every race has its own respective "figure," so I advise you to do a little research about what kind of transformation would fit you best.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-02.html">Back.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Transformation Wizard Avant-Garde:<br>
This is not a path for every one. It is meaningless for me to even teach you Transformation until you have proven your ability.<br>
Meet the great wizard who uses black magic, open the road of Transformation, and then return to me.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Transformation Wizard Avant-Garde:<br>
You must be able to transform in order to buy transformation-related goods.<br>
Find a great wizard who wields black magic and can open the path to transformation for you. Then you may return here.
</body></html>

View File

@@ -0,0 +1,10 @@
<html><body>Transformation Wizard Avant-Garde:<br>
If your subclass skill is above a certain level, you can transfer that power to your main class.<br>
Because this is a very dangerous mission, however, you must be certified in order to carry it out.<br>
If you were certified by your subclass master and have brought the certificate, I will transfer some of your subclass power to your main class.<br>
Be warned: this will inflict a serious shock to your soul. You must strengthen it in preparation for this rite.<br>
In order to learn certified subclass skills, you must first speak to Hardin and obtain the first sealbook. Hardin's Academy is in Dragon Valley.<br>
Do you wish to proceed?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde LearnSubClassSkill">Learn skills.</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-06.html">Return.</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Transformation Wizard Avant-Garde:<br>
What do you wish to know about subclass certification?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-05.html">Learn skills of the certified subclass.</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-05no.html">Certification removal.</Button>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Transformation Wizard Avant-Garde:<br>
It is a tremendous endeavor to obtain subclass certification and learn the appropriate skills. Beyond the purely physical effort, the burden on your soul is beyond your imagination... It is almost a suicidal venture.<br>
However, the process can be undone. There is a special kind of herb that can be used to remove your previously chosen skills. The price of the herb, though, is approximately <font color="LEVEL">10 million Adena</font>... I have the herb here, so I can cancel the certification anytime once you have paid.<br>
If the certification is canceled, <font color="LEVEL">the current certification status and skills will vanish immediately -- poof!</font> Now then, do you really wish to cancel certification?<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde CancelCertification">Cancel certification.</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest AvantGarde 32323-06no.html">Return.</Button>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Transformation Wizard Avant-Garde:<br>
If you want to give up, I cannot help you.<br>
To use the subclass power in the main class requires a great deal of power, after all.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Transformation Wizard Avant-Garde:<br>
An excellent decision, I think. In fact, it is very difficult to even get the herb. Since there's no one except that vicious Dark Wizard who lives in Dragon Valley who knows the technique, I didn't feel like it either...<br>
But isn't it a pity to throw away all of the skills for which you have already been certified?
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Transformation Wizard Avant-garde:<br>
A great deal of soul energy is needed to transfer subclass powers to the main class. Although you vanquished the Bridle of Soul by Mimir's Elixir, it is not so easy to practice it.<br>
To utilize the subclass power, you must be ritually cleansed by both the <font color="LEVEL">Dark Wizard and Mimir's Elixir</font>. Visit the Dark Wizard inside the Dragon Valley to obtain the magic power of transformation.<br>
Once you have learned the magic power of transformation, <font color="LEVEL">visit a subclass master</font> in order to certify your ability. Then come back to me on your main class.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Transformation Wizard Avant-Garde:<br>
To transfer the sub-class power, <font color="LEVEL">make your current class your main class and bring me either a certificate or a Scroll of Transformation</font>.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Transformation Wizard Avant-Garde:<br>
As I just told you, you need 10 million Adena.<br>
I don't see that much money on you...
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Transformation Wizard Avant-Garde:<br>
Then I have no choice...<br>
Your certifications are all canceled in exchange for <font color="LEVEL">10 million Adena</font>. However, that does not change the fact that you are very skilled. Why don't you find another master and obtain the certification you want?
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Transformation Wizard Avant-Garde:<br>
What are you going to cancel? You have neither certification nor the related skills.<br>
This herb is very rare -- unless you really need it, I would rather not use it.
</body></html>

View File

@@ -0,0 +1,158 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc.AvantGarde;
import java.util.List;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.data.xml.impl.MultisellData;
import com.l2jserver.gameserver.data.xml.impl.SkillTreesData;
import com.l2jserver.gameserver.model.L2SkillLearn;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.base.AcquireSkillType;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.clientpackets.RequestAcquireSkill;
import com.l2jserver.gameserver.network.serverpackets.ExAcquirableSkillListByClass;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
/**
* Avant-Garde AI.<br>
* Sub-Class Certification system, skill learning and certification canceling.<br>
* Transformation skill learning and transformation scroll sell.
* @author Zoey76
*/
public final class AvantGarde extends AbstractNpcAI
{
// NPC
private static final int AVANT_GARDE = 32323;
public AvantGarde()
{
super(AvantGarde.class.getSimpleName(), "ai/npc");
addStartNpc(AVANT_GARDE);
addTalkId(AVANT_GARDE);
addFirstTalkId(AVANT_GARDE);
addAcquireSkillId(AVANT_GARDE);
}
@Override
public String onAcquireSkill(L2Npc npc, L2PcInstance player, Skill skill, AcquireSkillType type)
{
if (type.equals(AcquireSkillType.TRANSFORM))
{
showTransformSkillList(player);
}
return null;
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
String htmltext = null;
switch (event)
{
case "32323-02.html":
case "32323-02a.html":
case "32323-02b.html":
case "32323-02c.html":
case "32323-05.html":
case "32323-05no.html":
case "32323-06.html":
case "32323-06no.html":
{
htmltext = event;
break;
}
case "LearnTransformationSkill":
{
if (RequestAcquireSkill.canTransform(player))
{
showTransformSkillList(player);
}
else
{
htmltext = "32323-03.html";
}
break;
}
case "BuyTransformationItems":
{
if (RequestAcquireSkill.canTransform(player))
{
MultisellData.getInstance().separateAndSend(32323001, player, npc, false);
}
else
{
htmltext = "32323-04.html";
}
break;
}
}
return htmltext;
}
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
return "32323-01.html";
}
@Override
public String onTalk(L2Npc npc, L2PcInstance talker)
{
return "32323-01.html";
}
/**
* This displays Transformation Skill List to the player.
* @param player the active character.
*/
public static void showTransformSkillList(L2PcInstance player)
{
final List<L2SkillLearn> skills = SkillTreesData.getInstance().getAvailableTransformSkills(player);
if (skills.isEmpty())
{
final int minlevel = SkillTreesData.getInstance().getMinLevelForNewSkill(player, SkillTreesData.getInstance().getTransformSkillTree());
if (minlevel > 0)
{
// No more skills to learn, come back when you level.
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_DO_NOT_HAVE_ANY_FURTHER_SKILLS_TO_LEARN_COME_BACK_WHEN_YOU_HAVE_REACHED_LEVEL_S1);
sm.addInt(minlevel);
player.sendPacket(sm);
}
else
{
player.sendPacket(SystemMessageId.THERE_ARE_NO_OTHER_SKILLS_TO_LEARN);
}
}
else
{
player.sendPacket(new ExAcquirableSkillListByClass(skills, AcquireSkillType.TRANSFORM));
}
}
public static void main(String[] args)
{
new AvantGarde();
}
}

View File

@@ -0,0 +1,6 @@
<html><body>Black Judge:<br>
Death leaves a scar which all must bear.<br>
Do you wish it to be healed completely?<br>
Ah, I perceive that you have long been apart from this world. I am strangely heartened by your return. I will heal this wound and remove death's scar.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackJudge remove_dp">Remove 1 level of Death Penalty (3600 Adena).</Button>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Black Judge:<br>
Death leaves a scar which all must bear.<br>
Do you wish it to be healed completely?<br>
You have only recently begun your journey in this world, and your youth touches me. I will heal this wound and remove death's scar.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackJudge remove_dp">Remove 1 level of Death Penalty (8640 Adena)</Button>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Black Judge:<br>
Death leaves a scar which all must bear.<br>
Do you wish it to be healed completely?<br>
You have only begun to learn the world, and your innocence touches me. I will heal this wound and remove death's scar.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackJudge remove_dp">Remove 1 level of Death Penalty (25200 Adena).</Button>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Black Judge:<br>
Death leaves a scar which all must bear.<br>
Do you wish it to be healed completely?<br>
As I see you are a true adventurer, I will heal this wound and remove death's scar.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackJudge remove_dp">Remove 1 level of Death Penalty (50400 Adena).</Button>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Black Judge:<br>
Death leaves a scar which all must bear.<br>
Do you wish it to be healed completely?<br>
Great adventurer, I will heal this wound and remove death's scar.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackJudge remove_dp">Remove 1 level of Death Penalty (86400 Adena)</Button>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Black Judge:<br>
Death leaves a scar which all must bear.<br>
Do you wish it to be healed completely?<br>
Because you walk the hero's path, I will heal this wound and remove death's scar.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackJudge remove_dp">Remove 1 level of Death Penalty (144000 Adena).</Button>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Black Judge:<br>
The wound you have received from death's touch is too deep to be healed for the money you have to give me. Find more money if you wish death's mark to be fully removed from you.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Black Judge:<br>
You have no more death wounds that require healing.<br>
Go forth and fight, both for this world and your own glory.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Black Judge:<br>
I came to this land to save those poor souls who are contaminated by sin. We black judges do not divide good and evil by light and darkness. We help instead those with strong wills and noble souls -- whether or not they wish our help. Come, sinners, come to us . . .<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackJudge remove_info">Remove Death Penalties.</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc.BlackJudge;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.datatables.SkillData;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.itemcontainer.Inventory;
import com.l2jserver.gameserver.model.skills.BuffInfo;
import com.l2jserver.gameserver.model.skills.CommonSkill;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
/**
* Black Judge AI.
* @author St3eT
*/
public class BlackJudge extends AbstractNpcAI
{
// NPC
private static final int BLACK_JUDGE = 30981;
// Misc
// @formatter:off
private static final int[] COSTS =
{
3600, 8640, 25200, 50400, 86400, 144000
};
// @formatter:on
private BlackJudge()
{
super(BlackJudge.class.getSimpleName(), "ai/npc");
addStartNpc(BLACK_JUDGE);
addTalkId(BLACK_JUDGE);
addFirstTalkId(BLACK_JUDGE);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
String htmltext = null;
final int level = ((player.getExpertiseLevel() < 5) ? player.getExpertiseLevel() : 5);
switch (event)
{
case "remove_info":
{
htmltext = "30981-0" + (level + 1) + ".html";
break;
}
case "remove_dp":
{
if (player.getShilensBreathDebuffLevel() > 0)
{
int cost = COSTS[level];
if (player.getAdena() >= cost)
{
takeItems(player, Inventory.ADENA_ID, cost);
final int nextLv = player.getShilensBreathDebuffLevel() - 1;
if (nextLv > 0)
{
final Skill skill = SkillData.getInstance().getSkill(CommonSkill.SHILENS_BREATH.getId(), nextLv);
if (skill != null)
{
skill.applyEffects(player, player);
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_BEEN_AFFLICTED_BY_SHILEN_S_BREATH_LEVEL_S1).addInt(nextLv));
}
}
else
{
final BuffInfo buff = player.getEffectList().getBuffInfoBySkillId(CommonSkill.SHILENS_BREATH.getId());
if (buff != null)
{
player.getEffectList().remove(true, buff);
}
player.sendPacket(SystemMessageId.SHILEN_S_BREATH_HAS_BEEN_PURIFIED);
}
}
else
{
htmltext = "30981-07.html";
}
}
else
{
htmltext = "30981-08.html";
}
break;
}
}
return htmltext;
}
public static void main(String[] args)
{
new BlackJudge();
}
}

View File

@@ -0,0 +1,6 @@
<html><body>Black Marketeer of Mammon:<br>
<font color="LEVEL">[Exchange Ancient Adena for Adena]</font><br>
Enter the amount of Ancient Adena you wish to exchange.<br>
<td align=left><edit var="data1" width=100></td>
<button value="Exchange" action="bypass -h Quest BlackMarketeerOfMammon exchange $data1" back="L2UI_CT1.Button_DF_Down" fore="L2UI_CT1.Button_DF" width=80 height=27>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><head><body>Black Marketeer of Mammon:<br>
<font color="FF0000">[Exchange failure]</font><br>
You've entered an invalid value. Please input a correct amount.<br>
<Button ALIGN=LEFT ICON="RETURN" action="bypass -h Quest BlackMarketeerOfMammon 31092-01.html">Back</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><head><body>Black Marketeer of Mammon:<br>
<font color="FF0000">[Exchange failure]</font><br>
You don't have enough of the item that you're trying to exchange.<br>
<Button ALIGN=LEFT ICON="RETURN" action="bypass -h Quest BlackMarketeerOfMammon 31092-01.html">Back</Button>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Black Marketeer of Mammon:<br>
<FONT color="LEVEL">[Exchange success]</FONT><br>
Thank you! There you go! Are you satisfied now? Or do you want to exchange something else?<br>
<Button ALIGN=LEFT ICON="RETURN" action="Quest BlackMarketeerOfMammon 31092-01.html">Back</Button>
</body></html>

View File

@@ -0,0 +1,11 @@
<html><body>Black Marketeer of Mammon:<br>
The Lords of Dawn and the Revolutionary Troops of Dusk use <font color="LEVEL">Ancient Adena</font> as their currency, following in the old empire's tradition.<br>
Tradition and customs are important but they are so old... If you were to go to the market with that money in this day and age, you couldn't buy a thing.<br>
Do you have any ancient adena that you don't know what to do with? If you do, I'll exchange them for adena.<br>
Also, if your weapon has a special ability that you do not want, I can remove that, too. I dont't know why you would want to take off a special ability that's been bestowed on your weapon, but we'll do anything for adena.<br>
I have also obtained some rare goods, so stop by some time - these items aren't easy to obtain!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BlackMarketeerOfMammon 31092-01.html">"I want to exchange Ancient Adena for Adena."</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 310922002">"Can I trade black market goods?"</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_exc_multisell 310922001">"I want to remove special abilities from my weapon."</Button>
<Button ALIGN=LEFT ICON="QUEST" action="bypass -h npc_%objectId%_Quest">Quest</Button>
</body></html>

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc.BlackMarketeerOfMammon;
import java.util.StringTokenizer;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.itemcontainer.Inventory;
import com.l2jserver.gameserver.util.Util;
/**
* Black Marketeer of Mammon AI.
* @author St3eT
*/
public final class BlackMarketeerOfMammon extends AbstractNpcAI
{
// NPC
private static final int BLACK_MARKETEER = 31092;
private BlackMarketeerOfMammon()
{
super(BlackMarketeerOfMammon.class.getSimpleName(), "ai/npc");
addStartNpc(BLACK_MARKETEER);
addTalkId(BLACK_MARKETEER);
addFirstTalkId(BLACK_MARKETEER);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("31092-01.html"))
{
return event;
}
else if (event.startsWith("exchange"))
{
final StringTokenizer st = new StringTokenizer(event, " ");
event = st.nextToken();
if (!st.hasMoreElements())
{
return "31092-02.html";
}
final String value = st.nextToken();
if (!Util.isDigit(value))
{
return "31092-02.html";
}
final long count = Integer.parseInt(value);
final long AAcount = player.getAncientAdena();
if (count < 1)
{
return "31092-02.html";
}
if (count > AAcount)
{
return "31092-03.html";
}
takeItems(player, Inventory.ANCIENT_ADENA_ID, count);
giveAdena(player, count, false);
return "31092-04.html";
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new BlackMarketeerOfMammon();
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright (C) 2004-2015 L2J DataPack
*
* This file is part of L2J DataPack.
*
* L2J DataPack 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.
*
* L2J DataPack 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.npc.CastleAmbassador;
import ai.npc.AbstractNpcAI;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.entity.Castle;
import com.l2jserver.gameserver.model.entity.Fort;
import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
/**
* Castle Ambassador AI.
* @author St3eT
*/
public final class CastleAmbassador extends AbstractNpcAI
{
// NPCs
// @formatter:off
private static final int[] CASTLE_AMBASSADOR =
{
36393, 36394, 36437, 36435, // Gludio
36395, 36436, 36439, 36441, // Dion
36396, 36440, 36444, 36449, 36451, // Giran
36397, 36438, 36442, 36443, 36446, // Oren
36398, 36399, 36445, 36448, // Aden
36400, 36450, // Innadril
36401, 36447, 36453, // Goddard
36433, 36452, 36454, // Rune
36434, 36455, // Schuttgart
};
// @formatter:on
private CastleAmbassador()
{
super(CastleAmbassador.class.getSimpleName(), "ai/npc");
addStartNpc(CASTLE_AMBASSADOR);
addTalkId(CASTLE_AMBASSADOR);
addFirstTalkId(CASTLE_AMBASSADOR);
addEventReceivedId(CASTLE_AMBASSADOR);
addSpawnId(CASTLE_AMBASSADOR);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (npc != null)
{
final Fort fortresss = npc.getFort();
String htmltext = null;
switch (event)
{
case "signed":
{
if (fortresss.getFortState() == 0)
{
fortresss.setFortState(2, fortresss.getCastleIdByAmbassador(npc.getId()));
cancelQuestTimer("DESPAWN", npc, null);
startQuestTimer("DESPAWN", 3000, npc, null);
htmltext = "ambassador-05.html";
}
else if (fortresss.getFortState() == 1)
{
htmltext = "ambassador-04.html";
}
break;
}
case "rejected":
{
if (fortresss.getFortState() == 0)
{
fortresss.setFortState(1, fortresss.getCastleIdByAmbassador(npc.getId()));
cancelQuestTimer("DESPAWN", npc, null);
startQuestTimer("DESPAWN", 3000, npc, null);
htmltext = "ambassador-02.html";
}
else if (fortresss.getFortState() == 2)
{
htmltext = "ambassador-02.html";
}
break;
}
case "DESPAWN":
{
if (fortresss.getFortState() == 0)
{
fortresss.setFortState(1, fortresss.getCastleIdByAmbassador(npc.getId()));
}
cancelQuestTimer("DESPAWN", npc, null);
npc.broadcastEvent("DESPAWN", 1000, null);
npc.deleteMe();
break;
}
}
if (htmltext != null)
{
final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId());
packet.setHtml(getHtm(player.getHtmlPrefix(), htmltext));
packet.replace("%castleName%", String.valueOf(fortresss.getCastleByAmbassador(npc.getId()).getName()));
player.sendPacket(packet);
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
{
if (receiver != null)
{
receiver.deleteMe();
}
return super.onEventReceived(eventName, sender, receiver, reference);
}
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
final Fort fortresss = npc.getFort();
final int fortOwner = fortresss.getOwnerClan() == null ? 0 : fortresss.getOwnerClan().getId();
String htmltext = null;
if (player.isClanLeader() && (player.getClanId() == fortOwner))
{
htmltext = (fortresss.isBorderFortress()) ? "ambassador-01.html" : "ambassador.html";
}
else
{
htmltext = "ambassador-03.html";
}
final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId());
packet.setHtml(getHtm(player.getHtmlPrefix(), htmltext));
packet.replace("%castleName%", String.valueOf(fortresss.getCastleByAmbassador(npc.getId()).getName()));
player.sendPacket(packet);
return null;
}
@Override
public String onSpawn(L2Npc npc)
{
final Castle castle = npc.getFort().getCastleByAmbassador(npc.getId());
if (castle.getOwnerId() == 0)
{
npc.deleteMe();
}
else
{
startQuestTimer("DESPAWN", 3600000, npc, null);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new CastleAmbassador();
}
}

View File

@@ -0,0 +1,8 @@
<html><body>Ambassador of %castleName%:<br>
My master is the great ruler of %castleName% Castle. The message I am commanded to relay to you, the new possessor of this fortress, is: "Protect this territory from our enemies!"<br>
If you do not have the strength to protect this place, my master inquires whether you would care to use our clan's strength to develop your skills.<br>
<br>
<center>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest CastleAmbassador rejected">"We decline. We will walk our own path."</Button>
</center>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Ambassador of %castleName%:<br>
Hmm... I see that negotiations have been broken off. I must cease for now.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Ambassador of %castleName%:<br>
Impudent pup! The letter I hold may only be seen by your leader.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Ambassador of %castleName%:<br>
You have already rejected my lord's offer. Why have you now changed your mind?
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Ambassador of %castleName%:<br>
You have signed the contract. I am sure that my lord will be pleased.
</body></html>

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