Re-organisation of some AI scripts from group folder.

This commit is contained in:
MobiusDev
2016-06-18 12:06:43 +00:00
parent 4898ba65a2
commit f768338b37
13 changed files with 72 additions and 278 deletions

View File

@@ -0,0 +1,418 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.Wastelands;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.CommonSkill;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import ai.AbstractNpcAI;
/**
* 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 L2ZoneType _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 Set<L2MonsterInstance> _nurses = ConcurrentHashMap.newKeySet();
ScheduledFuture<?> _task = null;
private QueenAnt()
{
addSpawnId(MOBS);
addKillId(MOBS);
addAggroRangeEnterId(MOBS);
addFactionCallId(NURSE);
_zone = ZoneManager.getInstance().getZoneById(12012);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
final int status = GrandBossManager.getInstance().getBossStatus(QUEEN);
if (status == DEAD)
{
// load the unlock date and time for queen ant from DB
final 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.
final 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 = info.getInt("loc_x");
int loc_y = info.getInt("loc_y");
int loc_z = info.getInt("loc_z");
final int heading = info.getInt("heading");
final double hp = info.getDouble("currentHP");
final double mp = info.getDouble("currentMP");
if (!_zone.isInsideZone(loc_x, loc_y, loc_z))
{
loc_x = QUEEN_X;
loc_y = QUEEN_Y;
loc_z = QUEEN_Z;
}
final 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(SkillCaster::isAnyNormalType))
{
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"))
{
final 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.setUndying(true);
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(SkillCaster::isAnyNormalType) && (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.hasAbnormalType(CommonSkill.RAID_CURSE.getSkill().getAbnormalType()) && (getRandom(4) == 0))
{
curse = CommonSkill.RAID_CURSE.getSkill();
}
}
else
{
if (!character.hasAbnormalType(CommonSkill.RAID_CURSE2.getSkill().getAbnormalType()) && (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)
{
final 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.
final long respawnTime = (Config.QUEEN_ANT_SPAWN_INTERVAL + getRandom(-Config.QUEEN_ANT_SPAWN_RANDOM, Config.QUEEN_ANT_SPAWN_RANDOM)) * 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
final 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)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
if (mob.getLeader() != null)
{
mob.getLeader().getMinionList().onMinionDie(mob, (280 + getRandom(40)) * 1000);
}
}
else if (npcId == NURSE)
{
final 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,337 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.areas.Wastelands;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2QuestGuardInstance;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.ListenerRegisterType;
import com.l2jmobius.gameserver.model.events.annotations.Id;
import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import com.l2jmobius.gameserver.model.events.annotations.RegisterType;
import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureDeath;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.AbstractNpcAI;
/**
* Wastelands AI.
* @author St3eT
*/
public final class Wastelands extends AbstractNpcAI
{
// NPCs
private static final int JOEL = 33516;
private static final int SCHUAZEN = 33517;
private static final int COMMANDER = 33434;
private static final int GUARD = 33437;
private static final int DECO_GUARD = 19140; // Antharas Decoration 5
private static final int DECO_GUARD2 = 19163; // Wastelands Decoration 1
private static final int REGENERATED_KANILOV = 27459;
private static final int REGENERATED_POSLOF = 27460;
private static final int SAKUM = 27453;
private static final int COMMANDO = 19126;
private static final int COMMANDO_CAPTAIN = 19127;
// Locations
private static final Location GUARD_POSLOF_LOC = new Location(-29474, 187083, -3912);
private static final Location[] COMMANDO_SAKUM_LOC =
{
new Location(-36525, 192032, -3640),
new Location(-36160, 191912, -3640),
new Location(-36371, 191370, -3632),
new Location(-36765, 191759, -3632),
};
private static final Location[] COMMANDO_CAPTAIN_SAKUM_LOC =
{
new Location(-36683, 191475, -3632),
new Location(-36131, 191574, -3632),
};
private Wastelands()
{
addSpawnId(COMMANDER, GUARD, DECO_GUARD, REGENERATED_KANILOV, REGENERATED_POSLOF, SAKUM);
addSeeCreatureId(JOEL, SCHUAZEN, COMMANDO, COMMANDO_CAPTAIN);
addKillId(REGENERATED_POSLOF, SAKUM);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "SOCIAL_SHOW":
{
npc.broadcastSocialAction(4);
L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 500).stream().filter(n -> n.getId() == GUARD).forEach(guard ->
{
startQuestTimer("SOCIAL_ACTION", getRandom(2500, 3500), guard, null);
});
break;
}
case "SOCIAL_ACTION":
{
npc.broadcastSocialAction(4);
break;
}
case "START_ATTACK":
{
final L2Attackable guard = (L2Attackable) npc;
final int attackId;
switch (guard.getId())
{
case JOEL:
{
attackId = REGENERATED_KANILOV;
break;
}
case SCHUAZEN:
{
attackId = REGENERATED_POSLOF;
break;
}
case COMMANDO:
case COMMANDO_CAPTAIN:
{
attackId = SAKUM;
break;
}
default:
{
attackId = 0;
break;
}
}
if (attackId > 0)
{
//@formatter:off
final L2Npc monster = L2World.getInstance().getVisibleObjects(guard, L2Npc.class, 1000)
.stream()
.filter(obj -> (obj.getId() == attackId))
.findFirst()
.orElse(null);
//@formatter:on
if (monster != null)
{
guard.reduceCurrentHp(1, monster, null); // TODO: Find better way for attack
monster.reduceCurrentHp(1, guard, null);
guard.setCanStopAttackByTime(false);
if ((guard.getId() != COMMANDO) && (guard.getId() != COMMANDO_CAPTAIN))
{
guard.setIsInvul(true);
}
if (guard.getId() == SCHUAZEN)
{
//@formatter:off
final L2QuestGuardInstance decoGuard = (L2QuestGuardInstance) L2World.getInstance().getVisibleObjects(guard, L2Npc.class, 500)
.stream()
.filter(obj -> (obj.getId() == DECO_GUARD2))
.findFirst()
.orElse(null);
//@formatter:on
if (decoGuard != null)
{
decoGuard.reduceCurrentHp(0, monster, null); // TODO: Find better way for attack
monster.reduceCurrentHp(1, decoGuard, null);
decoGuard.setCanStopAttackByTime(false);
decoGuard.setIsInvul(true);
}
}
}
else
{
startQuestTimer("START_ATTACK", 250, guard, null);
}
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
{
if (creature.isPlayer() && (npc.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK))
{
startQuestTimer("START_ATTACK", 250, npc, null);
}
return super.onSeeCreature(npc, creature, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
switch (npc.getId())
{
case COMMANDER:
{
startQuestTimer("SOCIAL_SHOW", 13000, npc, null, true);
npc.setRandomAnimation(false);
break;
}
case REGENERATED_KANILOV:
case REGENERATED_POSLOF:
{
final int guardId = npc.getId() == REGENERATED_KANILOV ? JOEL : SCHUAZEN;
//@formatter:off
final L2QuestGuardInstance guard = (L2QuestGuardInstance) L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 500)
.stream()
.filter(obj -> (obj.getId() == guardId))
.findFirst()
.orElse(null);
//@formatter:on
if (guard != null)
{
if (guard.getId() == SCHUAZEN)
{
addSpawn(DECO_GUARD2, GUARD_POSLOF_LOC);
}
guard.broadcastSay(ChatType.NPC_GENERAL, guard.getId() == JOEL ? NpcStringId.AH_REGENERATOR_POSLOF_APPEARED_AGAIN : NpcStringId.AH_REGENERATOR_KANILOV_APPEARED_AGAIN);
notifyEvent("START_ATTACK", guard, null);
}
break;
}
case SAKUM:
{
manageCommando((L2Attackable) npc);
break;
}
case GUARD:
case DECO_GUARD:
{
npc.setRandomAnimation(false);
break;
}
}
return super.onSpawn(npc);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.getId() == REGENERATED_POSLOF)
{
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Attackable.class, 1000, guard ->
{
if ((guard.getId() == DECO_GUARD2))
{
guard.deleteMe();
}
});
}
else if (npc.getId() == SAKUM)
{
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Attackable.class, 1000, guard ->
{
if ((guard.getId() == COMMANDO) || (guard.getId() == COMMANDO_CAPTAIN))
{
guard.deleteMe();
}
});
}
return super.onKill(npc, killer, isSummon);
}
@RegisterEvent(EventType.ON_CREATURE_DEATH)
@RegisterType(ListenerRegisterType.NPC)
@Id(COMMANDO)
@Id(COMMANDO_CAPTAIN)
public void onCreatureKill(OnCreatureDeath event)
{
final L2Attackable guard = (L2Attackable) event.getTarget();
//@formatter:off
final L2Attackable sakum = L2World.getInstance().getVisibleObjects(guard, L2Attackable.class, 1000)
.stream()
.filter(obj -> (obj.getId() == SAKUM))
.findFirst()
.orElse(null);
//@formatter:on
if (sakum != null)
{
manageCommando(sakum);
}
}
private void manageCommando(L2Attackable sakum)
{
int guardCount = sakum.getVariables().getInt("GUARD_COUNT", 0);
guardCount--;
if (guardCount <= 0)
{
if (sakum.getVariables().getBoolean("GUARD_CAPTAIN", false))
{
sakum.getVariables().set("GUARD_COUNT", COMMANDO_CAPTAIN_SAKUM_LOC.length);
sakum.getVariables().set("GUARD_CAPTAIN", false);
for (Location loc : COMMANDO_CAPTAIN_SAKUM_LOC)
{
final L2Attackable commander = (L2Attackable) addSpawn(COMMANDO_CAPTAIN, loc);
commander.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.HOW_DARE_YOU_ATTACK);
commander.reduceCurrentHp(1, sakum, null); // TODO: Find better way for attack
sakum.reduceCurrentHp(1, commander, null);
commander.setCanStopAttackByTime(false);
notifyEvent("START_ATTACK", commander, null);
}
}
else
{
sakum.getVariables().set("GUARD_COUNT", COMMANDO_SAKUM_LOC.length);
sakum.getVariables().set("GUARD_CAPTAIN", true);
for (Location loc : COMMANDO_SAKUM_LOC)
{
final L2Attackable commander = (L2Attackable) addSpawn(COMMANDO, loc);
commander.reduceCurrentHp(1, sakum, null); // TODO: Find better way for attack
sakum.reduceCurrentHp(1, commander, null);
commander.setCanStopAttackByTime(false);
notifyEvent("START_ATTACK", commander, null);
}
}
}
else
{
sakum.getVariables().set("GUARD_COUNT", guardCount);
}
}
public static void main(String[] args)
{
new Wastelands();
}
}