actual freya branch

This commit is contained in:
2026-09-12 15:39:57 +00:00
parent 9fa534b20e
commit 8049e0a882
18540 changed files with 1228200 additions and 0 deletions
@@ -0,0 +1,911 @@
/*
* 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.individual;
import gnu.trove.TIntObjectHashMap;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import javolution.util.FastList;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.Config;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.L2World;
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.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.Earthquake;
import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SpecialCamera;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
import com.l2jserver.util.Rnd;
/**
*
* This class ... control for sequence of fight against Antharas.
*
* @version $Revision: $ $Date: $
* @author L2J_JP SANDMAN
*/
public class Antharas extends L2AttackableAIScript
{
// config
private static final int FWA_ACTIVITYTIMEOFANTHARAS = 120;
//private static final int FWA_APPTIMEOFANTHARAS = 1800000;
private static final int FWA_INACTIVITYTIME = 900000;
private static final boolean FWA_OLDANTHARAS = false;
private static final boolean FWA_MOVEATRANDOM = true;
private static final boolean FWA_DOSERVEREARTHQUAKE = true;
private static final int FWA_LIMITOFWEAK = 45;
private static final int FWA_LIMITOFNORMAL = 63;
private static final int FWA_MAXMOBS = 10; // this includes Antharas itself
private static final int FWA_INTERVALOFMOBSWEAK = 180000;
private static final int FWA_INTERVALOFMOBSNORMAL = 150000;
private static final int FWA_INTERVALOFMOBSSTRONG = 120000;
private static final int FWA_PERCENTOFBEHEMOTH = 60;
private static final int FWA_SELFDESTRUCTTIME = 15000;
// Location of teleport cube.
private final int _teleportCubeId = 31859;
private final int _teleportCubeLocation[][] = { { 177615, 114941, -7709, 0 } };
protected List<L2Spawn> _teleportCubeSpawn = new FastList<L2Spawn>();
protected List<L2Npc> _teleportCube = new FastList<L2Npc>();
// Spawn data of monsters.
protected TIntObjectHashMap<L2Spawn> _monsterSpawn = new TIntObjectHashMap<L2Spawn>();
// Instance of monsters.
protected List<L2Npc> _monsters = new FastList<L2Npc>();
protected L2GrandBossInstance _antharas = null;
// monstersId
private static final int ANTHARASOLDID = 29019;
private static final int ANTHARASWEAKID = 29066;
private static final int ANTHARASNORMALID = 29067;
private static final int ANTHARASSTRONGID = 29068;
// Tasks.
protected ScheduledFuture<?> _cubeSpawnTask = null;
protected ScheduledFuture<?> _monsterSpawnTask = null;
protected ScheduledFuture<?> _activityCheckTask = null;
protected ScheduledFuture<?> _socialTask = null;
protected ScheduledFuture<?> _mobiliseTask = null;
protected ScheduledFuture<?> _mobsSpawnTask = null;
protected ScheduledFuture<?> _selfDestructionTask = null;
protected ScheduledFuture<?> _moveAtRandomTask = null;
protected ScheduledFuture<?> _movieTask = null;
//Antharas Status Tracking :
private static final byte DORMANT = 0; //Antharas is spawned and no one has entered yet. Entry is unlocked
private static final byte WAITING = 1; //Antharas is spawend and someone has entered, triggering a 30 minute window for additional people to enter
//before he unleashes his attack. Entry is unlocked
private static final byte FIGHTING = 2; //Antharas is engaged in battle, annihilating his foes. Entry is locked
private static final byte DEAD = 3; //Antharas has been killed. Entry is locked
protected static long _LastAction = 0;
protected static L2BossZone _Zone;
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new Antharas(-1,"antharas","ai");
}
// Boss: Antharas
public Antharas(int id,String name,String descr)
{
super(id,name,descr);
int[] mob = {ANTHARASOLDID,ANTHARASWEAKID,ANTHARASNORMALID,ANTHARASSTRONGID,29069,29070,29071,29072,29073,29074,29075,29076};
this.registerMobs(mob);
init();
}
// Initialize
private void init()
{
// Setting spawn data of monsters.
try
{
_Zone = GrandBossManager.getInstance().getZone(179700,113800,-7709);
L2NpcTemplate template1;
L2Spawn tempSpawn;
// Old Antharas
template1 = NpcTable.getInstance().getTemplate(ANTHARASOLDID);
tempSpawn = new L2Spawn(template1);
tempSpawn.setLocx(181323);
tempSpawn.setLocy(114850);
tempSpawn.setLocz(-7623);
tempSpawn.setHeading(32542);
tempSpawn.setAmount(1);
tempSpawn.setRespawnDelay(FWA_ACTIVITYTIMEOFANTHARAS * 2);
SpawnTable.getInstance().addNewSpawn(tempSpawn, false);
_monsterSpawn.put(29019, tempSpawn);
// Weak Antharas
template1 = NpcTable.getInstance().getTemplate(ANTHARASWEAKID);
tempSpawn = new L2Spawn(template1);
tempSpawn.setLocx(181323);
tempSpawn.setLocy(114850);
tempSpawn.setLocz(-7623);
tempSpawn.setHeading(32542);
tempSpawn.setAmount(1);
tempSpawn.setRespawnDelay(FWA_ACTIVITYTIMEOFANTHARAS * 2);
SpawnTable.getInstance().addNewSpawn(tempSpawn, false);
_monsterSpawn.put(29066, tempSpawn);
// Normal Antharas
template1 = NpcTable.getInstance().getTemplate(ANTHARASNORMALID);
tempSpawn = new L2Spawn(template1);
tempSpawn.setLocx(181323);
tempSpawn.setLocy(114850);
tempSpawn.setLocz(-7623);
tempSpawn.setHeading(32542);
tempSpawn.setAmount(1);
tempSpawn.setRespawnDelay(FWA_ACTIVITYTIMEOFANTHARAS * 2);
SpawnTable.getInstance().addNewSpawn(tempSpawn, false);
_monsterSpawn.put(29067, tempSpawn);
// Strong Antharas
template1 = NpcTable.getInstance().getTemplate(ANTHARASSTRONGID);
tempSpawn = new L2Spawn(template1);
tempSpawn.setLocx(181323);
tempSpawn.setLocy(114850);
tempSpawn.setLocz(-7623);
tempSpawn.setHeading(32542);
tempSpawn.setAmount(1);
tempSpawn.setRespawnDelay(FWA_ACTIVITYTIMEOFANTHARAS * 2);
SpawnTable.getInstance().addNewSpawn(tempSpawn, false);
_monsterSpawn.put(29068, tempSpawn);
}
catch (Exception e)
{
_log.warning(e.getMessage());
}
// Setting spawn data of teleport cube.
try
{
L2NpcTemplate Cube = NpcTable.getInstance().getTemplate(_teleportCubeId);
L2Spawn spawnDat;
for (int[] element : _teleportCubeLocation)
{
spawnDat = new L2Spawn(Cube);
spawnDat.setAmount(1);
spawnDat.setLocx(element[0]);
spawnDat.setLocy(element[1]);
spawnDat.setLocz(element[2]);
spawnDat.setHeading(element[3]);
spawnDat.setRespawnDelay(60);
spawnDat.setLocation(0);
SpawnTable.getInstance().addNewSpawn(spawnDat, false);
_teleportCubeSpawn.add(spawnDat);
}
}
catch (Exception e)
{
_log.warning(e.getMessage());
}
int status = GrandBossManager.getInstance().getBossStatus(ANTHARASOLDID);
if (FWA_OLDANTHARAS || status == WAITING)
{
StatsSet info = GrandBossManager.getInstance().getStatsSet(ANTHARASOLDID);
Long respawnTime = info.getLong("respawn_time");
if (status == DEAD && respawnTime <= System.currentTimeMillis())
{
// the time has already expired while the server was offline. Immediately spawn antharas in his cave.
// also, the status needs to be changed to DORMANT
GrandBossManager.getInstance().setBossStatus(ANTHARASOLDID,DORMANT);
status = DORMANT;
}
else if (status == FIGHTING)
{
int loc_x = info.getInteger("loc_x");
int loc_y = info.getInteger("loc_y");
int loc_z = info.getInteger("loc_z");
int heading = info.getInteger("heading");
int hp = info.getInteger("currentHP");
int mp = info.getInteger("currentMP");
_antharas = (L2GrandBossInstance) addSpawn(ANTHARASOLDID,loc_x,loc_y,loc_z,heading,false,0);
GrandBossManager.getInstance().addBoss(_antharas);
_antharas.setCurrentHpMp(hp,mp);
_LastAction = System.currentTimeMillis();
// Start repeating timer to check for inactivity
_activityCheckTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CheckActivity(), 60000, 60000);
}
else if (status == DEAD)
{
ThreadPoolManager.getInstance().scheduleGeneral(new UnlockAntharas(ANTHARASOLDID), respawnTime - System.currentTimeMillis());
}
else
{
setAntharasSpawnTask();
}
}
else
{
int statusWeak = GrandBossManager.getInstance().getBossStatus(ANTHARASWEAKID);
int statusNormal = GrandBossManager.getInstance().getBossStatus(ANTHARASNORMALID);
int statusStrong = GrandBossManager.getInstance().getBossStatus(ANTHARASSTRONGID);
int antharasId = 0;
if (statusWeak == FIGHTING || statusWeak == DEAD)
{
antharasId = ANTHARASWEAKID;
status = statusWeak;
}
else if (statusNormal == FIGHTING || statusNormal == DEAD)
{
antharasId = ANTHARASNORMALID;
status = statusNormal;
}
else if (statusStrong == FIGHTING || statusStrong == DEAD)
{
antharasId = ANTHARASSTRONGID;
status = statusStrong;
}
if (antharasId != 0 && status == FIGHTING)
{
StatsSet info = GrandBossManager.getInstance().getStatsSet(antharasId);
int loc_x = info.getInteger("loc_x");
int loc_y = info.getInteger("loc_y");
int loc_z = info.getInteger("loc_z");
int heading = info.getInteger("heading");
int hp = info.getInteger("currentHP");
int mp = info.getInteger("currentMP");
_antharas = (L2GrandBossInstance) addSpawn(antharasId,loc_x,loc_y,loc_z,heading,false,0);
GrandBossManager.getInstance().addBoss(_antharas);
_antharas.setCurrentHpMp(hp,mp);
_LastAction = System.currentTimeMillis();
// Start repeating timer to check for inactivity
_activityCheckTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CheckActivity(), 60000, 60000);
}
else if (antharasId != 0 && status == DEAD)
{
StatsSet info = GrandBossManager.getInstance().getStatsSet(antharasId);
Long respawnTime = info.getLong("respawn_time");
if (respawnTime <= System.currentTimeMillis())
{
// the time has already expired while the server was offline. Immediately spawn antharas in his cave.
// also, the status needs to be changed to DORMANT
GrandBossManager.getInstance().setBossStatus(antharasId,DORMANT);
status = DORMANT;
}
else
{
ThreadPoolManager.getInstance().scheduleGeneral(new UnlockAntharas(antharasId), respawnTime - System.currentTimeMillis());
}
}
}
}
// Do spawn teleport cube.
public void spawnCube()
{
if (_mobsSpawnTask != null)
{
_mobsSpawnTask.cancel(true);
_mobsSpawnTask = null;
}
if (_selfDestructionTask != null)
{
_selfDestructionTask.cancel(true);
_selfDestructionTask = null;
}
if (_activityCheckTask != null)
{
_activityCheckTask.cancel(false);
_activityCheckTask = null;
}
for (L2Spawn spawnDat : _teleportCubeSpawn)
{
_teleportCube.add(spawnDat.doSpawn());
}
}
// Setting Antharas spawn task.
public void setAntharasSpawnTask()
{
if (_monsterSpawnTask == null)
{
synchronized(this)
{
if (_monsterSpawnTask == null)
{
GrandBossManager.getInstance().setBossStatus(ANTHARASOLDID,WAITING);
_monsterSpawnTask = ThreadPoolManager.getInstance().scheduleGeneral(new AntharasSpawn(1),Config.Antharas_Wait_Time);
}
}
}
}
private void startMinionSpawns(int antharasId)
{
int intervalOfMobs;
// Interval of minions is decided by the type of Antharas
// that invaded the lair.
switch (antharasId)
{
case ANTHARASWEAKID:
intervalOfMobs = FWA_INTERVALOFMOBSWEAK;
break;
case ANTHARASNORMALID:
intervalOfMobs = FWA_INTERVALOFMOBSNORMAL;
break;
default:
intervalOfMobs = FWA_INTERVALOFMOBSSTRONG;
break;
}
// Spawn mobs.
_mobsSpawnTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new MobsSpawn(), intervalOfMobs, intervalOfMobs);
}
// Do spawn Antharas.
private class AntharasSpawn implements Runnable
{
private int _taskId = 0;
private final Collection<L2Character> _players = _Zone.getCharactersInside().values();
public AntharasSpawn(int taskId)
{
_taskId = taskId;
}
@Override
public void run()
{
int npcId;
L2Spawn antharasSpawn = null;
switch (_taskId)
{
case 1: // Spawn.
// Strength of Antharas is decided by the number of players that
// invaded the lair.
_monsterSpawnTask.cancel(false);
_monsterSpawnTask = null;
if (FWA_OLDANTHARAS)
npcId = 29019; // old
else if (_players.size() <= FWA_LIMITOFWEAK)
npcId = 29066; // weak
else if (_players.size() > FWA_LIMITOFNORMAL)
npcId = 29068; // strong
else
npcId = 29067; // normal
// Do spawn.
antharasSpawn = _monsterSpawn.get(npcId);
_antharas = (L2GrandBossInstance) antharasSpawn.doSpawn();
GrandBossManager.getInstance().addBoss(_antharas);
_monsters.add(_antharas);
_antharas.setIsImmobilized(true);
GrandBossManager.getInstance().setBossStatus(ANTHARASOLDID,DORMANT);
GrandBossManager.getInstance().setBossStatus(npcId,FIGHTING);
_LastAction = System.currentTimeMillis();
// Start repeating timer to check for inactivity
_activityCheckTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CheckActivity(), 60000, 60000);
// Setting 1st time of minions spawn task.
if (!FWA_OLDANTHARAS)
{
startMinionSpawns(npcId);
}
// Set next task.
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new AntharasSpawn(2), 16);
break;
case 2:
// Set camera.
broadcastPacket(new SpecialCamera(_antharas.getObjectId(),700,13,-19,0,20000,0,0,1,0));
// Set next task.
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new AntharasSpawn(3), 3000);
break;
case 3:
// Do social.
broadcastPacket(new SpecialCamera(_antharas.getObjectId(),700,13,0,6000,20000,0,0,1,0));
// Set next task.
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new AntharasSpawn(4), 10000);
break;
case 4:
broadcastPacket(new SpecialCamera(_antharas.getObjectId(),3700,0,-3,0,10000,0,0,1,0));
// Set next task.
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new AntharasSpawn(5), 200);
break;
case 5:
// Do social.
broadcastPacket(new SpecialCamera(_antharas.getObjectId(),1100,0,-3,22000,30000,0,0,1,0));
// Set next task.
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new AntharasSpawn(6), 10800);
break;
case 6:
// Set camera.
broadcastPacket(new SpecialCamera(_antharas.getObjectId(),1100,0,-3,300,7000,0,0,1,0));
// Set next task.
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new AntharasSpawn(7), 1900);
break;
case 7:
_antharas.abortCast();
_mobiliseTask = ThreadPoolManager.getInstance().scheduleGeneral(new SetMobilised(_antharas), 16);
// Move at random.
if (FWA_MOVEATRANDOM)
{
L2CharPosition pos = new L2CharPosition(Rnd.get(175000,178500), Rnd.get(112400, 116000), -7707, 0);
_moveAtRandomTask = ThreadPoolManager.getInstance().scheduleGeneral(new MoveAtRandom(_antharas, pos),500);
}
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
break;
}
}
}
private void broadcastPacket(L2GameServerPacket mov)
{
if (_Zone != null)
{
for (L2Character characters : _Zone.getCharactersInside().values())
{
if (characters instanceof L2PcInstance)
characters.sendPacket(mov);
}
}
}
// Do spawn Behemoth or Bomber.
private class MobsSpawn implements Runnable
{
public MobsSpawn()
{
}
@Override
public void run()
{
L2NpcTemplate template1;
L2Spawn tempSpawn;
boolean isBehemoth = Rnd.get(100) < FWA_PERCENTOFBEHEMOTH;
try
{
int mobNumber = (isBehemoth ? 2 : 3);
// Set spawn.
for(int i = 0; i < mobNumber; i++)
{
if (_monsters.size() >= FWA_MAXMOBS)
break;
int npcId;
if (isBehemoth)
npcId = 29069;
else
npcId = Rnd.get(29070, 29076);
template1 = NpcTable.getInstance().getTemplate(npcId);
tempSpawn = new L2Spawn(template1);
// allocates it at random in the lair of Antharas.
int tried = 0;
boolean notFound = true;
int x = 175000;
int y = 112400;
int dt = (_antharas.getX() - x) * (_antharas.getX() - x) + (_antharas.getY() - y) * (_antharas.getY() - y);
while (tried++ < 25 && notFound)
{
int rx = Rnd.get(175000, 179900);
int ry = Rnd.get(112400, 116000);
int rdt = (_antharas.getX() - rx) * (_antharas.getX() - rx) + (_antharas.getY() - ry) * (_antharas.getY() - ry);
if (GeoData.getInstance().canSeeTarget(_antharas.getX(), _antharas.getY(), -7704, rx, ry, -7704))
if (rdt < dt)
{
x = rx;
y = ry;
dt = rdt;
if (rdt <= 900000)
notFound = false;
}
}
tempSpawn.setLocx(x);
tempSpawn.setLocy(y);
tempSpawn.setLocz(-7704);
tempSpawn.setHeading(0);
tempSpawn.setAmount(1);
tempSpawn.setRespawnDelay(FWA_ACTIVITYTIMEOFANTHARAS * 2);
SpawnTable.getInstance().addNewSpawn(tempSpawn, false);
// Do spawn.
_monsters.add(tempSpawn.doSpawn());
}
}
catch (Exception e)
{
_log.warning(e.getMessage());
}
}
}
@Override
public String onAggroRangeEnter (L2Npc npc, L2PcInstance player, boolean isPet)
{
switch (npc.getNpcId())
{
case 29070:
case 29071:
case 29072:
case 29073:
case 29074:
case 29075:
case 29076:
if (_selfDestructionTask == null && !npc.isDead())
_selfDestructionTask = ThreadPoolManager.getInstance().scheduleGeneral(new SelfDestructionOfBomber(npc), FWA_SELFDESTRUCTTIME);
break;
}
return super.onAggroRangeEnter(npc, player, isPet);
}
// Do self destruction.
private class SelfDestructionOfBomber implements Runnable
{
private final L2Npc _bomber;
public SelfDestructionOfBomber(L2Npc bomber)
{
_bomber = bomber;
}
@Override
public void run()
{
L2Skill skill = null;
switch (_bomber.getNpcId())
{
case 29070:
case 29071:
case 29072:
case 29073:
case 29074:
case 29075:
skill = SkillTable.getInstance().getInfo(5097, 1);
break;
case 29076:
skill = SkillTable.getInstance().getInfo(5094, 1);
break;
}
_bomber.doCast(skill);
if (_selfDestructionTask != null)
{
_selfDestructionTask.cancel(false);
_selfDestructionTask = null;
}
}
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
{
if (npc.isInvul())
{
return null;
}
else if (skill != null && (skill.getId() == 5097 || skill.getId() == 5094))
{
switch (npc.getNpcId())
{
case 29070:
case 29071:
case 29072:
case 29073:
case 29074:
case 29075:
case 29076:
npc.doDie(npc);
break;
}
}
return super.onSpellFinished(npc, player, skill);
}
// At end of activity time.
private class CheckActivity implements Runnable
{
@Override
public void run()
{
Long temp = (System.currentTimeMillis() - _LastAction);
if (temp > FWA_INACTIVITYTIME)
{
GrandBossManager.getInstance().setBossStatus(_antharas.getNpcId(),DORMANT);
setUnspawn();
}
}
}
// Clean Antharas's lair.
public void setUnspawn()
{
// Eliminate players.
_Zone.oustAllPlayers();
// Not executed tasks is canceled.
if (_cubeSpawnTask != null)
{
_cubeSpawnTask.cancel(true);
_cubeSpawnTask = null;
}
if (_monsterSpawnTask != null)
{
_monsterSpawnTask.cancel(true);
_monsterSpawnTask = null;
}
if (_activityCheckTask != null)
{
_activityCheckTask.cancel(false);
_activityCheckTask = null;
}
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
if (_mobiliseTask != null)
{
_mobiliseTask.cancel(true);
_mobiliseTask = null;
}
if (_mobsSpawnTask != null)
{
_mobsSpawnTask.cancel(true);
_mobsSpawnTask = null;
}
if (_selfDestructionTask != null)
{
_selfDestructionTask.cancel(true);
_selfDestructionTask = null;
}
if (_moveAtRandomTask != null)
{
_moveAtRandomTask.cancel(true);
_moveAtRandomTask = null;
}
// Delete monsters.
for (L2Npc mob : _monsters)
{
mob.getSpawn().stopRespawn();
mob.deleteMe();
}
_monsters.clear();
// Delete teleport cube.
for (L2Npc cube : _teleportCube)
{
cube.getSpawn().stopRespawn();
cube.deleteMe();
}
_teleportCube.clear();
}
// Do spawn teleport cube.
private class CubeSpawn implements Runnable
{
private final int _type;
public CubeSpawn(int type)
{
_type = type;
}
@Override
public void run()
{
if (_type == 0)
{
spawnCube();
_cubeSpawnTask = ThreadPoolManager.getInstance().scheduleGeneral(new CubeSpawn(1), 1800000);
}
else
setUnspawn();
}
}
// UnLock Antharas.
private static class UnlockAntharas implements Runnable
{
private final int _bossId;
public UnlockAntharas(int bossId)
{
_bossId = bossId;
}
@Override
public void run()
{
GrandBossManager.getInstance().setBossStatus(_bossId,DORMANT);
if (FWA_DOSERVEREARTHQUAKE)
for(L2PcInstance p : L2World.getInstance().getAllPlayers().values())
p.broadcastPacket(new Earthquake(185708,114298,-8221,20,10));
}
}
// Action is enabled the boss.
private class SetMobilised implements Runnable
{
private final L2GrandBossInstance _boss;
public SetMobilised(L2GrandBossInstance boss)
{
_boss = boss;
}
@Override
public void run()
{
_boss.setIsImmobilized(false);
// When it is possible to act, a social action is canceled.
if (_socialTask != null)
{
_socialTask.cancel(true);
_socialTask = null;
}
}
}
// Move at random on after Antharas appears.
private static class MoveAtRandom implements Runnable
{
private final L2Npc _npc;
private final L2CharPosition _pos;
public MoveAtRandom(L2Npc npc, L2CharPosition pos)
{
_npc = npc;
_pos = pos;
}
@Override
public void run()
{
_npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, _pos);
}
}
@Override
public String onAttack (L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
{
if (npc.getNpcId() == 29019 || npc.getNpcId() == 29066 || npc.getNpcId() == 29067 || npc.getNpcId() == 29068)
{
_LastAction = System.currentTimeMillis();
if (GrandBossManager.getInstance().getBossStatus(_antharas.getNpcId()) != FIGHTING)
{
_Zone.oustAllPlayers();
}
else if (!FWA_OLDANTHARAS && _mobsSpawnTask == null)
{
startMinionSpawns(npc.getNpcId());
}
}
else if (npc.getNpcId() > 29069 && npc.getNpcId() < 29077 && npc.getCurrentHp() <= damage)
{
L2Skill skill = null;
switch (npc.getNpcId())
{
case 29070:
case 29071:
case 29072:
case 29073:
case 29074:
case 29075:
skill = SkillTable.getInstance().getInfo(5097, 1);
break;
case 29076:
skill = SkillTable.getInstance().getInfo(5094, 1);
break;
}
npc.doCast(skill);
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill (L2Npc npc, L2PcInstance killer, boolean isPet)
{
if (npc.getNpcId() == 29019 || npc.getNpcId() == 29066 || npc.getNpcId() == 29067 || npc.getNpcId() == 29068)
{
npc.broadcastPacket(new PlaySound(1, "BS01_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
_cubeSpawnTask = ThreadPoolManager.getInstance().scheduleGeneral(new CubeSpawn(0), 10000);
GrandBossManager.getInstance().setBossStatus(npc.getNpcId(),DEAD);
long respawnTime = (long)Config.Interval_Of_Antharas_Spawn + Rnd.get(Config.Random_Of_Antharas_Spawn);
ThreadPoolManager.getInstance().scheduleGeneral(new UnlockAntharas(npc.getNpcId()), respawnTime);
// also save the respawn time so that the info is maintained past reboots
StatsSet info = GrandBossManager.getInstance().getStatsSet(npc.getNpcId());
info.set("respawn_time",(System.currentTimeMillis() + respawnTime));
GrandBossManager.getInstance().setStatsSet(npc.getNpcId(),info);
}
else if (npc.getNpcId() == 29069)
{
int countHPHerb = Rnd.get(6, 18);
int countMPHerb = Rnd.get(6, 18);
for (int i = 0; i < countHPHerb; i++)
((L2MonsterInstance)npc).dropItem(killer, 8602, 1);
for (int i = 0; i < countMPHerb; i++)
((L2MonsterInstance)npc).dropItem(killer, 8605, 1);
}
if (_monsters.contains(npc))
_monsters.remove(npc);
return super.onKill(npc,killer,isPet);
}
}
@@ -0,0 +1,602 @@
/*
* 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.individual;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import javolution.util.FastList;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.Config;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Effect;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
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.L2DecoyInstance;
import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.quest.QuestTimer;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.Earthquake;
import com.l2jserver.gameserver.network.serverpackets.MoveToPawn;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Rnd;
/**
* Baium AI
*
* Note1: if the server gets rebooted while players are still fighting Baium, there is no lock, but
* players also lose their ability to wake baium up. However, should another person
* enter the room and wake him up, the players who had stayed inside may join the raid.
* This can be helpful for players who became victims of a reboot (they only need 1 new player to
* enter and wake up baium) and is not too exploitable since any player wishing to exploit it
* would have to suffer 5 days of being parked in an empty room.
* Note2: Neither version of Baium should be a permanent spawn. This script is fully capable of
* spawning the statue-version when the lock expires and switching it to the mob version promptly.
*
* Additional notes ( source http://aleenaresron.blogspot.com/2006_08_01_archive.html ):
* * Baium only first respawns five days after his last death. And from those five days he will
* respawn within 1-8 hours of his last death. So, you have to know his last time of death.
* * If by some freak chance you are the only one in Baium's chamber and NO ONE comes in
* [ha, ha] you or someone else will have to wake Baium. There is a good chance that Baium
* will automatically kill whoever wakes him. There are some people that have been able to
* wake him and not die, however if you've already gone through the trouble of getting the
* bloody fabric and camped him out and researched his spawn time, are you willing to take that
* chance that you'll wake him and not be able to finish your quest? Doubtful.
* [ this powerful attack vs the player who wakes him up is NOT yet implemented here]
* * once someone starts attacking Baium no one else can port into the chamber where he is.
* Unlike with the other raid bosses, you can just show up at any time as long as you are there
* when they die. Not true with Baium. Once he gets attacked, the port to Baium closes. byebye,
* see you in 5 days. If nobody attacks baium for 30 minutes, he auto-despawns and unlocks the
* vortex
*
* @author Fulminus version 0.1
*/
public class Baium extends L2AttackableAIScript
{
private L2Character _target;
private L2Skill _skill;
private static final int STONE_BAIUM = 29025;
private static final int ANGELIC_VORTEX = 31862;
private static final int LIVE_BAIUM = 29020;
private static final int ARCHANGEL = 29021;
//Baium status tracking
private static final byte ASLEEP = 0; // baium is in the stone version, waiting to be woken up. Entry is unlocked
private static final byte AWAKE = 1; // baium is awake and fighting. Entry is locked.
private static final byte DEAD = 2; // baium has been killed and has not yet spawned. Entry is locked
// fixed archangel spawnloc
private final static int ANGEL_LOCATION[][] =
{
{ 114239, 17168, 10080, 63544 },
{ 115780, 15564, 10080, 13620 },
{ 114880, 16236, 10080, 5400 },
{ 115168, 17200, 10080, 0 },
{ 115792, 16608, 10080, 0 },
};
private long _LastAttackVsBaiumTime = 0;
private List<L2Npc> _Minions = new ArrayList<L2Npc>(5);
private L2BossZone _Zone;
public Baium (int questId, String name, String descr)
{
super(questId, name, descr);
int[] mob = {LIVE_BAIUM};
this.registerMobs(mob);
// Quest NPC starter initialization
addStartNpc(STONE_BAIUM);
addStartNpc(ANGELIC_VORTEX);
addTalkId(STONE_BAIUM);
addTalkId(ANGELIC_VORTEX);
_Zone = GrandBossManager.getInstance().getZone(113100,14500,10077);
StatsSet info = GrandBossManager.getInstance().getStatsSet(LIVE_BAIUM);
int status = GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM);
if (status == DEAD)
{
// load the unlock date and time for baium from DB
long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
if (temp > 0)
{
// the unlock time has not yet expired. Mark Baium as currently locked (dead). Setup a timer
// to fire at the correct time (calculate the time between now and the unlock time,
// setup a timer to fire after that many msec)
startQuestTimer("baium_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Delete the saved time and
// immediately spawn the stone-baium. Also the state need not be changed from ASLEEP
addSpawn(STONE_BAIUM,116033,17447,10104,40188,false,0);
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM,ASLEEP);
}
}
else if (status == AWAKE)
{
int loc_x = info.getInteger("loc_x");
int loc_y = info.getInteger("loc_y");
int loc_z = info.getInteger("loc_z");
int heading = info.getInteger("heading");
final int hp = info.getInteger("currentHP");
final int mp = info.getInteger("currentMP");
L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM,loc_x,loc_y,loc_z,heading,false,0);
GrandBossManager.getInstance().addBoss(baium);
final L2Npc _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() {
public void run()
{
try
{
_baium.setCurrentHpMp(hp,mp);
_baium.setIsInvul(true);
_baium.setIsImmobilized(true);
_baium.setRunning();
_baium.broadcastPacket(new SocialAction(_baium,2));
startQuestTimer("baium_wakeup",15000, _baium, null);
}
catch (Exception e)
{
e.printStackTrace();
}
}
},100L);
}
else
addSpawn(STONE_BAIUM,116033,17447,10104,40188,false,0);
}
@Override
public String onAdvEvent (String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("baium_unlock"))
{
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM,ASLEEP);
addSpawn(STONE_BAIUM,116033,17447,10104,40188,false,0);
}
else if (event.equalsIgnoreCase("skill_range") && npc != null)
{
callSkillAI(npc);
}
else if (event.equalsIgnoreCase("clean_player"))
{
_target = getRandomTarget(npc);
}
else if (event.equalsIgnoreCase("baium_wakeup") && npc != null)
{
if (npc.getNpcId() == LIVE_BAIUM)
{
npc.broadcastPacket(new SocialAction(npc,1));
npc.broadcastPacket(new Earthquake(npc.getX(), npc.getY(), npc.getZ(),40,5));
// start monitoring baium's inactivity
_LastAttackVsBaiumTime = System.currentTimeMillis();
startQuestTimer("baium_despawn", 60000, npc, null, true);
startQuestTimer("skill_range", 500, npc, null, true);
final L2Npc baium = npc;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() {
public void run()
{
try
{
baium.setIsInvul(false);
baium.setIsImmobilized(false);
for (L2Npc minion : _Minions)
minion.setShowSummonAnimation(false);
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
}
}
},11100L);
// TODO: the person who woke baium up should be knocked across the room, onto a wall, and
// lose massive amounts of HP.
for (int i = 0; i < ANGEL_LOCATION.length; i++)
{
L2Npc angel = addSpawn(ARCHANGEL, ANGEL_LOCATION[i][0], ANGEL_LOCATION[i][1], ANGEL_LOCATION[i][2], ANGEL_LOCATION[i][3], false, 0, true);
angel.setIsInvul(true);
_Minions.add(angel);
}
}
// despawn the live baium after 30 minutes of inactivity
// also check if the players are cheating, having pulled Baium outside his zone...
}
else if (event.equalsIgnoreCase("baium_despawn") && npc != null)
{
if (npc.getNpcId() == LIVE_BAIUM)
{
// just in case the zone reference has been lost (somehow...), restore the reference
if (_Zone == null)
_Zone = GrandBossManager.getInstance().getZone(113100,14500,10077);
if (_LastAttackVsBaiumTime + 1800000 < System.currentTimeMillis())
{
npc.deleteMe(); // despawn the live-baium
for (L2Npc minion : _Minions)
if (minion != null)
{
minion.getSpawn().stopRespawn();
minion.deleteMe();
}
_Minions.clear();
addSpawn(STONE_BAIUM,116033,17447,10104,40188,false,0); // spawn stone-baium
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM,ASLEEP); // mark that Baium is not awake any more
_Zone.oustAllPlayers();
cancelQuestTimer("baium_despawn", npc, null);
}
else if ((_LastAttackVsBaiumTime + 300000 < System.currentTimeMillis()) && npc.getCurrentHp() < ( ( npc.getMaxHp() * 3 ) / 4.0 ))
{
npc.setIsCastingNow(false); //just in case
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4135,1));
npc.setIsCastingNow(true);
}
else if (!_Zone.isInsideZone(npc))
npc.teleToLocation(116033,17447,10104);
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onTalk(L2Npc npc,L2PcInstance player)
{
int npcId = npc.getNpcId();
String htmltext = "";
if (_Zone == null)
_Zone = GrandBossManager.getInstance().getZone(113100,14500,10077);
if (_Zone == null)
return "<html><body>Angelic Vortex:<br>You may not enter while admin disabled this zone</body></html>";
if (npcId == STONE_BAIUM && GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM) == ASLEEP)
{
if (_Zone.isPlayerAllowed(player))
{
// once Baium is awaken, no more people may enter until he dies, the server reboots, or
// 30 minutes pass with no attacks made against Baium.
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM,AWAKE);
npc.deleteMe();
L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, npc, true);
GrandBossManager.getInstance().addBoss(baium);
final L2Npc _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() {
public void run()
{
try
{
_baium.setIsInvul(true);
_baium.setRunning();
_baium.broadcastPacket(new SocialAction(_baium,2));
startQuestTimer("baium_wakeup",15000, _baium, null);
_baium.setShowSummonAnimation(false);
}
catch (Throwable e)
{
_log.log(Level.WARNING, "", e);
}
}
},100L);
}
else
htmltext = "Conditions are not right to wake up Baium";
}
else if (npcId == ANGELIC_VORTEX)
{
if (player.isFlying())
{
//print "Player "+player.getName()+" attempted to enter Baium's lair while flying!";
return "<html><body>Angelic Vortex:<br>You may not enter while flying a wyvern</body></html>";
}
if (GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM) == ASLEEP
&& player.getQuestState("baium").getQuestItemsCount(4295) > 0) // bloody fabric
{
player.getQuestState("baium").takeItems(4295,1);
// allow entry for the player for the next 30 secs (more than enough time for the TP to happen)
// Note: this just means 30secs to get in, no limits on how long it takes before we get out.
_Zone.allowPlayerEntry(player,30);
player.teleToLocation(113100,14500,10077);
}
else
npc.showChatWindow(player, 1);
}
return htmltext;
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
{
if (npc.isInvul())
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
return null;
}
else if (npc.getNpcId() == LIVE_BAIUM && !npc.isInvul())
{
callSkillAI(npc);
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.disableCoreAI(true);
return super.onSpawn(npc);
}
@Override
public String onAttack (L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
{
if (!_Zone.isInsideZone(attacker))
{
attacker.reduceCurrentHp(attacker.getCurrentHp(),attacker,false,false, null);
return super.onAttack(npc, attacker, damage, isPet);
}
if (npc.isInvul())
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
return super.onAttack(npc, attacker, damage, isPet);
}
else if (npc.getNpcId() == LIVE_BAIUM && !npc.isInvul())
{
if (attacker.getMountType() == 1)
{
int sk_4258 = 0;
L2Effect[] effects = attacker.getAllEffects();
if (effects != null && effects.length != 0)
{
for (L2Effect e : effects)
{
if (e.getSkill().getId() == 4258)
sk_4258 = 1;
}
}
if (sk_4258 == 0)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4258,1));
}
}
// update a variable with the last action against baium
_LastAttackVsBaiumTime = System.currentTimeMillis();
callSkillAI(npc);
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill (L2Npc npc, L2PcInstance killer, boolean isPet)
{
cancelQuestTimer("baium_despawn", npc, null);
npc.broadcastPacket(new PlaySound(1, "BS01_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
// spawn the "Teleportation Cubic" for 15 minutes (to allow players to exit the lair)
addSpawn(29055,115203,16620,10078,0,false,900000); ////should we teleport everyone out if the cubic despawns??
// "lock" baium for 5 days and 1 to 8 hours [i.e. 432,000,000 + 1*3,600,000 + random-less-than(8*3,600,000) millisecs]
long respawnTime = (long)Config.Interval_Of_Baium_Spawn + Rnd.get(Config.Random_Of_Baium_Spawn);
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM,DEAD);
startQuestTimer("baium_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
StatsSet info = GrandBossManager.getInstance().getStatsSet(LIVE_BAIUM);
info.set("respawn_time",(System.currentTimeMillis()) + respawnTime);
GrandBossManager.getInstance().setStatsSet(LIVE_BAIUM,info);
for (L2Npc minion : _Minions)
if (minion != null)
{
minion.getSpawn().stopRespawn();
minion.deleteMe();
}
_Minions.clear();
if (getQuestTimer("skill_range", npc, null) != null)
getQuestTimer("skill_range", npc, null).cancel();
return super.onKill(npc,killer,isPet);
}
public L2Character getRandomTarget(L2Npc npc)
{
FastList<L2Character> result = FastList.newInstance();
Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
{
for (L2Object obj : objs)
{
if (obj instanceof L2Playable || obj instanceof L2DecoyInstance)
{
if (obj instanceof L2PcInstance)
{
if (((L2PcInstance) obj).getAppearance().getInvisible())
continue;
}
if (((L2Character) obj).getZ() < ( npc.getZ() - 100 ) && ((L2Character) obj).getZ() > ( npc.getZ() + 100 )
|| !(GeoData.getInstance().canSeeTarget(((L2Character) obj).getX(), ((L2Character) obj).getY(), ((L2Character) obj).getZ(), npc.getX(), npc.getY(), npc.getZ())))
continue;
}
if (obj instanceof L2Playable || obj instanceof L2DecoyInstance)
{
if (Util.checkIfInRange(9000, npc, obj, true) && !((L2Character) obj).isDead())
result.add((L2Character) obj);
}
}
}
if (result.isEmpty())
{
for (L2Npc minion : _Minions)
if (minion != null)
result.add(minion);
}
if (result.isEmpty())
{
FastList.recycle(result);
return null;
}
Object[] characters = result.toArray();
QuestTimer timer = getQuestTimer("clean_player", npc, null);
if (timer != null)
timer.cancel();
startQuestTimer("clean_player", 20000, npc, null);
L2Character target = (L2Character) characters[Rnd.get(characters.length)];
FastList.recycle(result);
return target;
}
public synchronized void callSkillAI(L2Npc npc)
{
if (npc.isInvul() || npc.isCastingNow()) return;
if (_target == null || _target.isDead() || !(_Zone.isInsideZone(_target)))
{
_target = getRandomTarget(npc);
if (_target != null)
_skill = SkillTable.getInstance().getInfo(getRandomSkill(npc),1);
}
L2Character target = _target;
L2Skill skill = _skill;
if (skill == null)
skill = SkillTable.getInstance().getInfo(getRandomSkill(npc),1);
if (target == null || target.isDead() || !(_Zone.isInsideZone(target)))
{
npc.setIsCastingNow(false);
return;
}
if (Util.checkIfInRange(skill.getCastRange(), npc, target, true))
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
npc.setTarget(target);
npc.setIsCastingNow(true);
_target = null;
_skill = null;
if (getDist(skill.getCastRange()) > 0)
npc.broadcastPacket(new MoveToPawn(npc,target,getDist(skill.getCastRange())));
try
{
Thread.sleep(1000);
npc.stopMove(null);
npc.doCast(skill);
}
catch (Exception e)
{e.printStackTrace();}
}
else
{
npc.getAI().setIntention(AI_INTENTION_FOLLOW, target, null);
npc.setIsCastingNow(false);
}
}
public int getRandomSkill(L2Npc npc)
{
int skill;
if( npc.getCurrentHp() > ( ( npc.getMaxHp() * 3 ) / 4.0 ) )
{
if( Rnd.get(100) < 10 )
skill = 4128;
else if( Rnd.get(100) < 10 )
skill = 4129;
else
skill = 4127;
}
else if( npc.getCurrentHp() > ( ( npc.getMaxHp() * 2 ) / 4.0) )
{
if( Rnd.get(100) < 10 )
skill = 4131;
else if( Rnd.get(100) < 10 )
skill = 4128;
else if( Rnd.get(100) < 10 )
skill = 4129;
else
skill = 4127;
}
else if( npc.getCurrentHp() > ( ( npc.getMaxHp() * 1 ) / 4.0 ) )
{
if( Rnd.get(100) < 10 )
skill = 4130;
else if( Rnd.get(100) < 10 )
skill = 4131;
else if( Rnd.get(100) < 10 )
skill = 4128;
else if( Rnd.get(100) < 10 )
skill = 4129;
else
skill = 4127;
}
else if( Rnd.get(100) < 10 )
skill = 4130;
else if( Rnd.get(100) < 10 )
skill = 4131;
else if( Rnd.get(100) < 10 )
skill = 4128;
else if( Rnd.get(100) < 10 )
skill = 4129;
else
skill = 4127;
return skill;
}
@Override
public String onSkillSee (L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isPet)
{
if (npc.isInvul())
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
return null;
}
npc.setTarget(caster);
return super.onSkillSee(npc, caster, skill, targets, isPet);
}
public int getDist(int range)
{
int dist = 0;
switch(range)
{
case -1:
break;
case 100:
dist = 85;
break;
default:
dist = range-85;
break;
}
return dist;
}
public static void main(String[] args)
{
// Quest class and state definition
new Baium(-1, "baium", "ai");
}
}
@@ -0,0 +1,225 @@
/*
* 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.individual;
import java.util.List;
import javolution.util.FastList;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.Config;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.actor.L2Attackable;
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.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.util.Rnd;
/**
* Core AI
*
* @author DrLecter Revised By Emperorc
*/
public class Core extends L2AttackableAIScript
{
private static final int CORE = 29006;
private static final int DEATH_KNIGHT = 29007;
private static final int DOOM_WRAITH = 29008;
//private static final int DICOR = 29009;
//private static final int VALIDUS = 29010;
private static final int SUSCEPTOR = 29011;
//private static final int PERUM = 29012;
//private static final int PREMO = 29013;
//CORE Status Tracking :
private static final byte ALIVE = 0; //Core is spawned.
private static final byte DEAD = 1; //Core has been killed.
private static boolean _FirstAttacked;
List<L2Attackable> Minions = new FastList<L2Attackable>();
public Core(int id, String name, String descr)
{
super(id, name, descr);
int[] mobs =
{
CORE, DEATH_KNIGHT, DOOM_WRAITH, SUSCEPTOR
};
registerMobs(mobs);
_FirstAttacked = false;
StatsSet info = GrandBossManager.getInstance().getStatsSet(CORE);
int status = GrandBossManager.getInstance().getBossStatus(CORE);
if (status == DEAD)
{
// load the unlock date and time for Core from DB
long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
// if Core 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("core_unlock", temp, null, null);
else
{
// the time has already expired while the server was offline. Immediately spawn Core.
L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, 17726, 108915, -6480, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(CORE, ALIVE);
this.spawnBoss(core);
}
}
else
{
String test = loadGlobalQuestVar("Core_Attacked");
if (test.equalsIgnoreCase("true"))
_FirstAttacked = true;
int loc_x = info.getInteger("loc_x");
int loc_y = info.getInteger("loc_y");
int loc_z = info.getInteger("loc_z");
int heading = info.getInteger("heading");
int hp = info.getInteger("currentHP");
int mp = info.getInteger("currentMP");
L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, loc_x, loc_y, loc_z, heading, false, 0);
core.setCurrentHpMp(hp, mp);
this.spawnBoss(core);
}
}
@Override
public void saveGlobalData()
{
String val = "" + _FirstAttacked;
saveGlobalQuestVar("Core_Attacked", val);
}
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()));
//Spawn minions
L2Attackable mob;
for (int i = 0; i < 5; i++)
{
int x = 16800 + i * 360;
mob = (L2Attackable)addSpawn(DEATH_KNIGHT, x, 110000, npc.getZ(), 280 + Rnd.get(40), false, 0);
mob.setIsRaidMinion(true);
Minions.add(mob);
mob = (L2Attackable)addSpawn(DEATH_KNIGHT, x, 109000, npc.getZ(), 280 + Rnd.get(40), false, 0);
mob.setIsRaidMinion(true);
Minions.add(mob);
int x2 = 16800 + i * 600;
mob = (L2Attackable)addSpawn(DOOM_WRAITH, x2, 109300, npc.getZ(), 280 + Rnd.get(40), false, 0);
mob.setIsRaidMinion(true);
Minions.add(mob);
}
for (int i = 0; i < 4; i++)
{
int x = 16800 + i * 450;
mob = (L2Attackable)addSpawn(SUSCEPTOR, x, 110300, npc.getZ(), 280 + Rnd.get(40), false, 0);
mob.setIsRaidMinion(true);
Minions.add(mob);
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("core_unlock"))
{
L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, 17726, 108915, -6480, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(CORE, ALIVE);
spawnBoss(core);
}
else if (event.equalsIgnoreCase("spawn_minion"))
{
L2Attackable mob = (L2Attackable)addSpawn(npc.getNpcId(), npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), false, 0);
mob.setIsRaidMinion(true);
Minions.add(mob);
}
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();
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
{
if (npc.getNpcId() == CORE)
{
if (_FirstAttacked)
{
if (Rnd.get(100) == 0)
npc.broadcastPacket(new NpcSay(npc.getObjectId(), 0, npc.getNpcId(), 1000003)); // Removing intruders.
}
else
{
_FirstAttacked = true;
npc.broadcastPacket(new NpcSay(npc.getObjectId(), 0, npc.getNpcId(), 1000001)); // A non-permitted target has been discovered.
npc.broadcastPacket(new NpcSay(npc.getObjectId(), 0, npc.getNpcId(), 1000002)); // Intruder removal system initiated.
}
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isPet)
{
int npcId = npc.getNpcId();
if (npcId == CORE)
{
int objId = npc.getObjectId();
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, objId, npc.getX(), npc.getY(), npc.getZ()));
npc.broadcastPacket(new NpcSay(objId, 0, npcId, 1000004)); // A fatal error has occurred.
npc.broadcastPacket(new NpcSay(objId, 0, npcId, 1000005)); // System is being shut down...
npc.broadcastPacket(new NpcSay(objId, 0, npcId, 1000006)); // ......
_FirstAttacked = false;
addSpawn(31842, 16502, 110165, -6394, 0, false, 900000);
addSpawn(31842, 18948, 110166, -6397, 0, false, 900000);
GrandBossManager.getInstance().setBossStatus(CORE, DEAD);
//time is 60hour +/- 23hour
long respawnTime = (long) Config.Interval_Of_Core_Spawn + Rnd.get(Config.Random_Of_Core_Spawn);
startQuestTimer("core_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
StatsSet info = GrandBossManager.getInstance().getStatsSet(CORE);
info.set("respawn_time", (System.currentTimeMillis() + respawnTime));
GrandBossManager.getInstance().setStatsSet(CORE, info);
this.startQuestTimer("despawn_minions", 20000, null, null);
this.cancelQuestTimers("spawn_minion");
}
else if (GrandBossManager.getInstance().getBossStatus(CORE) == ALIVE && Minions != null && Minions.contains(npc))
{
Minions.remove(npc);
startQuestTimer("spawn_minion", 60000, npc, null);
}
return super.onKill(npc, killer, isPet);
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new Core(-1, "core", "ai");
}
}
@@ -0,0 +1,227 @@
/*
* 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.individual;
import javolution.util.FastMap;
import javolution.util.FastSet;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.NpcTable;
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;
public class DarkWaterDragon extends L2AttackableAIScript
{
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 FastSet<Integer> secondSpawn = new FastSet<Integer>(); //Used to track if second Shades were already spawned
private static FastSet<Integer> myTrackingSet = new FastSet<Integer>(); //Used to track instances of npcs
private static FastMap<Integer, L2PcInstance> _idmap = new FastMap<Integer, L2PcInstance>().shared(); //Used to track instances of npcs
public DarkWaterDragon(int id, String name, String descr)
{
super(id,name,descr);
int[] mobs = {DRAGON, SHADE1, SHADE2, FAFURION, DETRACTOR1, DETRACTOR2};
this.registerMobs(mobs, QuestEventType.ON_KILL, QuestEventType.ON_SPAWN, QuestEventType.ON_ATTACK);
myTrackingSet.clear();
secondSpawn.clear();
}
@Override
public String onAdvEvent (String event, L2Npc npc, L2PcInstance player)
{
if (npc != null)
{
if (event.equalsIgnoreCase("first_spawn")) //timer to start timer "1"
{
this.startQuestTimer("1",40000, npc, null, true); //spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("second_spawn")) //timer to start timer "2"
{
this.startQuestTimer("2",40000, npc, null, true); //spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("third_spawn")) //timer to start timer "3"
{
this.startQuestTimer("3",40000, npc, null, true); //spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("fourth_spawn")) //timer to start timer "4"
{
this.startQuestTimer("4",40000, npc, null, true); //spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("1")) //spawns a detractor
{
this.addSpawn(DETRACTOR1,(npc.getX()+100),(npc.getY()+100),npc.getZ(),0,false,40000);
}
else if (event.equalsIgnoreCase("2")) //spawns a detractor
{
this.addSpawn(DETRACTOR2,(npc.getX()+100),(npc.getY()-100),npc.getZ(),0,false,40000);
}
else if (event.equalsIgnoreCase("3")) //spawns a detractor
{
this.addSpawn(DETRACTOR1,(npc.getX()-100),(npc.getY()+100),npc.getZ(),0,false,40000);
}
else if (event.equalsIgnoreCase("4")) //spawns a detractor
{
this.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
{
this.cancelQuestTimer("fafurion_poison", npc, null);
this.cancelQuestTimer("1", npc, null);
this.cancelQuestTimer("2", npc, null);
this.cancelQuestTimer("3", npc, null);
this.cancelQuestTimer("4", npc, null);
myTrackingSet.remove(npc.getObjectId());
player = _idmap.remove(npc.getObjectId());
if(player != null) //You never know ...
((L2Attackable)npc).doItemDrop(NpcTable.getInstance().getTemplate(18485), player);
npc.deleteMe();
}
else if (event.equalsIgnoreCase("fafurion_poison")) //Reduces Fafurions hp like it is poisoned
{
if (npc.getCurrentHp() <= 500)
{
this.cancelQuestTimer("fafurion_despawn", npc, null);
this.cancelQuestTimer("first_spawn", npc, null);
this.cancelQuestTimer("second_spawn", npc, null);
this.cancelQuestTimer("third_spawn", npc, null);
this.cancelQuestTimer("fourth_spawn", npc, null);
this.cancelQuestTimer("1", npc, null);
this.cancelQuestTimer("2", npc, null);
this.cancelQuestTimer("3", npc, null);
this.cancelQuestTimer("4", npc, null);
myTrackingSet.remove(npc.getObjectId());
_idmap.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 isPet)
{
int npcId = npc.getNpcId();
int npcObjId = npc.getObjectId();
if (npcId == DRAGON)
{
if (!myTrackingSet.contains(npcObjId)) //this allows to handle multiple instances of npc
{
myTrackingSet.add(npcObjId);
//Spawn first 5 shades on first attack on Dark Water Dragon
L2Character originalAttacker = isPet? 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) && !(secondSpawn.contains(npcObjId)))
{
secondSpawn.add(npcObjId);
//Spawn second 5 shades on half hp of on Dark Water Dragon
L2Character originalAttacker = isPet? 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, isPet);
}
@Override
public String onKill (L2Npc npc, L2PcInstance killer, boolean isPet)
{
int npcId = npc.getNpcId();
int npcObjId = npc.getObjectId();
if (npcId == DRAGON)
{
myTrackingSet.remove(npcObjId);
secondSpawn.remove(npcObjId);
L2Attackable faf = (L2Attackable) this.addSpawn(FAFURION,npc.getX(),npc.getY(),npc.getZ(),0,false,0); //spawns Fafurion Kindred when Dard Water Dragon is dead
_idmap.put(faf.getObjectId(),killer);
}
else if (npcId == FAFURION)
{
this.cancelQuestTimer("fafurion_poison", npc, null);
this.cancelQuestTimer("fafurion_despawn", npc, null);
this.cancelQuestTimer("first_spawn", npc, null);
this.cancelQuestTimer("second_spawn", npc, null);
this.cancelQuestTimer("third_spawn", npc, null);
this.cancelQuestTimer("fourth_spawn", npc, null);
this.cancelQuestTimer("1", npc, null);
this.cancelQuestTimer("2", npc, null);
this.cancelQuestTimer("3", npc, null);
this.cancelQuestTimer("4", npc, null);
myTrackingSet.remove(npcObjId);
_idmap.remove(npcObjId);
}
return super.onKill(npc,killer,isPet);
}
@Override
public String onSpawn (L2Npc npc)
{
int npcId = npc.getNpcId();
int npcObjId = npc.getObjectId();
if (npcId == FAFURION)
{
if (!myTrackingSet.contains(npcObjId))
{
myTrackingSet.add(npcObjId);
//Spawn 4 Detractors on spawn of Fafurion
int x = npc.getX();
int y = npc.getY();
this.addSpawn(DETRACTOR2,x+100,y+100,npc.getZ(),0,false,40000);
this.addSpawn(DETRACTOR1,x+100,y-100,npc.getZ(),0,false,40000);
this.addSpawn(DETRACTOR2,x-100,y+100,npc.getZ(),0,false,40000);
this.addSpawn(DETRACTOR1,x-100,y-100,npc.getZ(),0,false,40000);
this.startQuestTimer("first_spawn",2000, npc, null); //timer to delay timer "1"
this.startQuestTimer("second_spawn",4000, npc, null); //timer to delay timer "2"
this.startQuestTimer("third_spawn",8000, npc, null); //timer to delay timer "3"
this.startQuestTimer("fourth_spawn",10000, npc, null); //timer to delay timer "4"
this.startQuestTimer("fafurion_poison",3000, npc, null, true); //Every three seconds reduces Fafurions hp like it is poisoned
this.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)
{
// Quest class and state definition
new DarkWaterDragon(-1,"DarkWaterDragon","ai");
}
}
@@ -0,0 +1,122 @@
/*
* 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.individual;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.network.serverpackets.SpecialCamera;
/**
* DrChaos AI
* @author Kerberos
*
*/
public class DrChaos extends Quest
{
private static final int DOCTER_CHAOS = 32033;
private static final int STRANGE_MACHINE = 32032;
private static final int CHAOS_GOLEM = 25512;
private static boolean _IsGolemSpawned;
public DrChaos(int questId, String name, String descr)
{
super(questId, name, descr);
addFirstTalkId(32033);
_IsGolemSpawned = false;
}
public L2Npc findTemplate(int npcId)
{
for(L2Spawn spawn : SpawnTable.getInstance().getSpawnTable())
{
if (spawn != null && spawn.getNpcid() == npcId)
{
return spawn.getLastSpawn();
}
}
return null;
}
@Override
public String onAdvEvent (String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("1"))
{
L2Npc machine_instance = findTemplate(STRANGE_MACHINE);
if (machine_instance != null)
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, machine_instance);
machine_instance.broadcastPacket(new SpecialCamera(machine_instance.getObjectId(),1,-200,15,10000,20000,0,0,1,0));
}
else
//print "Dr Chaos AI: problem finding Strange Machine (npcid = "+STRANGE_MACHINE+"). Error: not spawned!"
startQuestTimer("2",2000,npc,player);
startQuestTimer("3",10000,npc,player);
}
else if (event.equalsIgnoreCase("2"))
npc.broadcastPacket(new SocialAction(npc,3));
else if (event.equalsIgnoreCase("3"))
{
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(),1,-150,10,3000,20000,0,0,1,0));
startQuestTimer("4",2500,npc,player);
}
else if (event.equalsIgnoreCase("4"))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(96055,-110759,-3312,0));
startQuestTimer("5",2000,npc,player);
}
else if (event.equalsIgnoreCase("5"))
{
player.teleToLocation(94832,-112624,-3304);
npc.teleToLocation(-113091,-243942,-15536);
if (!_IsGolemSpawned)
{
L2Npc golem = addSpawn(CHAOS_GOLEM,94640,-112496,-3336,0,false,0);
_IsGolemSpawned = true;
startQuestTimer("6",1000,golem,player);
player.sendPacket(new PlaySound(1,"Rm03_A",0,0,0,0,0));
}
}
else if (event.equalsIgnoreCase("6"))
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(),30,-200,20,6000,8000,0,0,1,0));
return super.onAdvEvent(event, npc, player);
}
@Override
public String onFirstTalk (L2Npc npc, L2PcInstance player)
{
if (npc.getNpcId() == DOCTER_CHAOS)
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(96323,-110914,-3328,0));
this.startQuestTimer("1",3000,npc,player);
}
return "";
}
public static void main(String[] args)
{
new DrChaos(-1,"Doctor Chaos","ai");
}
}
@@ -0,0 +1,64 @@
/*
* 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.individual;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.util.Rnd;
public class FleeNpc extends L2AttackableAIScript
{
private int[] _npcId = { 20432, 22228 ,18150,18151,18152,18153,18154,18155,18156,18157};
public FleeNpc(int questId, String name, String descr)
{
super(questId, name, descr);
for( int i = 0; i < _npcId.length; i++ )
{
this.addEventId(_npcId[i], Quest.QuestEventType.ON_ATTACK);
}
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
{
if (npc.getNpcId() >= 18150 && npc.getNpcId() <= 18157)
{
npc.getAI().setIntention( CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition((npc.getX() + Rnd.get(-40, 40)), (npc.getY()+ Rnd.get(-40, 40)), npc.getZ(), npc.getHeading()));
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
return null;
}
else if (npc.getNpcId() == 20432 || npc.getNpcId() == 22228)
{
if (Rnd.get(3) == 2)
npc.getAI().setIntention( CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition((npc.getX() + Rnd.get(-200, 200)), (npc.getY()+ Rnd.get(-200, 200)), npc.getZ(), npc.getHeading()));
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
return null;
}
return super.onAttack(npc, attacker, damage, isPet);
}
// Register the new Script at the Script System
public static void main(String[] args)
{
new FleeNpc(-1, "FleeNpc", "Ai for Flee Npcs");
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,109 @@
/*
* 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.individual;
import java.util.ArrayList;
import java.util.List;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.util.Rnd;
/**
* Dilios AI
* @author JIV, Sephiroth, Apocalipce
*
*/
public class GeneralDilios extends L2AttackableAIScript
{
private static final int generalId = 32549;
private static final int guardId = 32619;
private L2Npc _general;
private List<L2Npc> _guards = new ArrayList<L2Npc>();
private static final int[] diliosText =
{
1800695, // Messenger, inform the patrons of the Keucereus Alliance Base! We're gathering brave adventurers to attack Tiat's Mounted Troop that's rooted in the Seed of Destruction.
//1800696, Messenger, inform the patrons of the Keucereus Alliance Base! The Seed of Destruction is currently secured under the flag of the Keucereus Alliance!
//1800697, Messenger, inform the patrons of the Keucereus Alliance Base! Tiat's Mounted Troop is currently trying to retake Seed of Destruction! Commit all the available reinforcements into Seed of Destruction!
1800698, // Messenger, inform the brothers in Kucereus' clan outpost! Brave adventurers who have challenged the Seed of Infinity are currently infiltrating the Hall of Erosion through the defensively weak Hall of Suffering!
//1800699, Messenger, inform the brothers in Kucereus' clan outpost! Sweeping the Seed of Infinity is currently complete to the Heart of the Seed. Ekimus is being directly attacked, and the Undead remaining in the Hall of Suffering are being eradicated!
1800700 // Messenger, inform the patrons of the Keucereus Alliance Base! The Seed of Infinity is currently secured under the flag of the Keucereus Alliance!
//1800702 Messenger, inform the patrons of the Keucereus Alliance Base! The resurrected Undead in the Seed of Infinity are pouring into the Hall of Suffering and the Hall of Erosion!
//1800703 Messenger, inform the brothers in Kucereus' clan outpost! Ekimus is about to be revived by the resurrected Undead in Seed of Infinity. Send all reinforcements to the Heart and the Hall of Suffering!
};
public GeneralDilios(int questId, String name, String descr)
{
super(questId, name, descr);
findNpcs();
if (_general == null || _guards.isEmpty())
throw new NullPointerException("Cannot find npcs!");
startQuestTimer("command_0", 60000, null, null);
}
public void findNpcs()
{
for (L2Spawn spawn : SpawnTable.getInstance().getSpawnTable())
if (spawn != null)
if (spawn.getNpcid() == generalId)
_general = spawn.getLastSpawn();
else if (spawn.getNpcid() == guardId)
_guards.add(spawn.getLastSpawn());
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.startsWith("command_"))
{
int value = Integer.parseInt(event.substring(8));
if (value < 6)
{
_general.broadcastPacket(new NpcSay(_general.getObjectId(), 0, generalId, 1800704)); // Stabbing three times!
startQuestTimer("guard_animation_0", 3400, null, null);
}
else
{
value = -1;
_general.broadcastPacket(new NpcSay(_general.getObjectId(), 1, generalId, diliosText[Rnd.get(diliosText.length)]));
}
startQuestTimer("command_"+(value+1), 60000, null, null);
}
else if (event.startsWith("guard_animation_"))
{
int value = Integer.parseInt(event.substring(16));
for (L2Npc guard : _guards)
{
guard.broadcastPacket(new SocialAction(guard, 4));
}
if (value < 2)
startQuestTimer("guard_animation_"+(value+1), 1500, null, null);
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new GeneralDilios(-1, "GeneralDilios", "ai");
}
}
@@ -0,0 +1,237 @@
/*
* 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.individual;
import java.util.Collection;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* Gordon AI
* @author TOFIZ
* @version $Revision: 1.1 $ $Date: 2008/08/21 $
*/
public class Gordon extends L2AttackableAIScript
{
private static final int GORDON = 29095;
private static int _npcMoveX = 0;
private static int _npcMoveY = 0;
private static int _isWalkTo = 0;
private static int _npcBlock = 0;
private static int X = 0;
private static int Y = 0;
private static int Z = 0;
private static final int[][] WALKS = {
{141569, -45908, -2387},{142494, -45456, -2397},{142922, -44561, -2395},
{143672, -44130, -2398},{144557, -43378, -2325},{145839, -43267, -2301},
{147044, -43601, -2307},{148140, -43206, -2303},{148815, -43434, -2328},
{149862, -44151, -2558},{151037, -44197, -2708},{152555, -42756, -2836},
{154808, -39546, -3236},{155333, -39962, -3272},{156531, -41240, -3470},
{156863, -43232, -3707},{156783, -44198, -3764},{158169, -45163, -3541},
{158952, -45479, -3473},{160039, -46514, -3634},{160244, -47429, -3656},
{159155, -48109, -3665},{159558, -51027, -3523},{159396, -53362, -3244},
{160872, -56556, -2789},{160857, -59072, -2613},{160410, -59888, -2647},
{158770, -60173, -2673},{156368, -59557, -2638},{155188, -59868, -2642},
{154118, -60591, -2731},{153571, -61567, -2821},{153457, -62819, -2886},
{152939, -63778, -3003},{151816, -64209, -3120},{147655, -64826, -3433},
{145422, -64576, -3369},{144097, -64320, -3404},{140780, -61618, -3096},
{139688, -61450, -3062},{138267, -61743, -3056},{138613, -58491, -3465},
{138139, -57252, -3517},{139555, -56044, -3310},{139107, -54537, -3240},
{139279, -53781, -3091},{139810, -52687, -2866},{139657, -52041, -2793},
{139215, -51355, -2698},{139334, -50514, -2594},{139817, -49715, -2449},
{139824, -48976, -2263},{140130, -47578, -2213},{140483, -46339, -2382},
{141569, -45908, -2387}};
private static boolean _isAttacked = false;
private static boolean _isSpawned = false;
public Gordon (int id, String name, String descr)
{
super(id,name,descr);
int[] mobs = {GORDON};
registerMobs(mobs, QuestEventType.ON_ATTACK, QuestEventType.ON_KILL, QuestEventType.ON_SPAWN);
// wait 2 minutes after Start AI
startQuestTimer("check_ai", 120000, null, null, true);
_isSpawned = false;
_isAttacked = false;
_isWalkTo = 1;
_npcMoveX = 0;
_npcMoveY = 0;
_npcBlock = 0;
}
public L2Npc findTemplate(int npcId)
{
L2Npc npc = null;
for (L2Spawn spawn : SpawnTable.getInstance().getSpawnTable())
{
if (spawn != null && spawn.getNpcid() == npcId)
{
npc = spawn.getLastSpawn();
break;
}
}
return npc;
}
@Override
public String onAdvEvent (String event, L2Npc npc, L2PcInstance player)
{
X = WALKS[_isWalkTo-1][0];
Y = WALKS[_isWalkTo-1][1];
Z = WALKS[_isWalkTo-1][2];
if (event.equalsIgnoreCase("time_isAttacked"))
{
_isAttacked = false;
if (npc.getNpcId() == GORDON)
{
npc.setWalking();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(X, Y, Z, 0));
}
}
else if (event.equalsIgnoreCase("check_ai"))
{
cancelQuestTimer("check_ai", null, null);
if (_isSpawned == false)
{
L2Npc gordon_ai = findTemplate(GORDON);
if (gordon_ai != null)
{
_isSpawned = true;
startQuestTimer("Start", 1000, gordon_ai, null, true);
return super.onAdvEvent(event, npc, player);
}
}
}
else if (event.equalsIgnoreCase("Start"))
{
if (npc != null && _isSpawned == true)
{
// check if player have Cursed Weapon and in radius
if (npc.getNpcId() == GORDON)
{
Collection<L2PcInstance> chars = npc.getKnownList().getKnownPlayers().values();
if (chars != null && chars.size() > 0)
{
for (L2PcInstance pc : chars)
{
if (pc.isCursedWeaponEquipped() && pc.isInsideRadius(npc,5000,false,false))
{
npc.setRunning();
((L2Attackable)npc).addDamageHate(pc,0,9999);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, pc);
_isAttacked = true;
cancelQuestTimer("time_isAttacked",null, null);
startQuestTimer("time_isAttacked",180000, npc, null);
return super.onAdvEvent(event, npc, player);
}
}
}
}
// end check
if (_isAttacked == true)
return super.onAdvEvent(event, npc, player);
if (npc.getNpcId() == GORDON && (npc.getX()-50) <= X && (npc.getX()+50) >= X && (npc.getY()-50) <= Y && (npc.getY()+50) >= Y)
{
_isWalkTo++;
if (_isWalkTo > 55)
_isWalkTo = 1;
X = WALKS[_isWalkTo-1][0];
Y = WALKS[_isWalkTo-1][1];
Z = WALKS[_isWalkTo-1][2];
npc.setWalking();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO,new L2CharPosition(X, Y, Z, 0));
}
// Test for unblock Npc
if (npc.getX() != _npcMoveX && npc.getY() != _npcMoveY)
{
_npcMoveX = npc.getX();
_npcMoveY = npc.getY();
_npcBlock = 0;
}
else if (npc.getNpcId() == GORDON)
{
_npcBlock++;
if (_npcBlock > 2)
{
npc.teleToLocation(X, Y, Z);
return super.onAdvEvent(event, npc, player);
}
if (_npcBlock > 0)
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO,new L2CharPosition(X, Y, Z, 0));
}
// End Test unblock Npc
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSpawn (L2Npc npc)
{
if (npc.getNpcId() == GORDON && _npcBlock == 0)
{
_isSpawned = true;
_isWalkTo = 1;
startQuestTimer("Start", 1000, npc, null, true);
}
return super.onSpawn(npc);
}
@Override
public String onAttack (L2Npc npc, L2PcInstance player, int damage, boolean isPet)
{
if (npc.getNpcId() == GORDON)
{
_isAttacked = true;
cancelQuestTimer("time_isAttacked", null, null);
startQuestTimer("time_isAttacked", 180000, npc, null);
if (player != null)
{
npc.setRunning();
((L2Attackable)npc).addDamageHate(player, 0, 100);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player);
}
}
return super.onAttack(npc, player, damage, isPet);
}
@Override
public String onKill (L2Npc npc, L2PcInstance killer, boolean isPet)
{
if (npc.getNpcId() == GORDON)
{
cancelQuestTimer("Start", null, null);
cancelQuestTimer("time_isAttacked", null, null);
_isSpawned = false;
}
return super.onKill(npc,killer,isPet);
}
public static void main(String[] args)
{
new Gordon(-1,"gordon","ai");
}
}
@@ -0,0 +1,443 @@
/*
* 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.individual;
import java.util.concurrent.Future;
import java.util.logging.Level;
import javolution.util.FastList;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.Config;
import com.l2jserver.gameserver.cache.HtmCache;
import com.l2jserver.gameserver.datatables.DoorTable;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
import com.l2jserver.gameserver.network.serverpackets.ExShowScreenMessage;
import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
import com.l2jserver.util.Rnd;
/**
* Ice Fairy Sirra AI
* @author Kerberos
*/
public class IceFairySirra extends L2AttackableAIScript
{
private static final int STEWARD = 32029;
private static final int SILVER_HEMOCYTE = 8057;
private static L2BossZone _sirrasZone;
private static L2PcInstance _player = null;
protected FastList<L2Npc> _allMobs = new FastList<L2Npc>();
protected Future<?> _onDeadEventTask = null;
public IceFairySirra(int id,String name,String descr)
{
super(id,name,descr);
int[] mob = {STEWARD, 22100, 22102, 22104, 29056};
this.registerMobs(mob);
this.addEventId(STEWARD, Quest.QuestEventType.QUEST_START);
this.addEventId(STEWARD, Quest.QuestEventType.ON_TALK);
this.addEventId(STEWARD, Quest.QuestEventType.ON_FIRST_TALK);
String test = loadGlobalQuestVar("Sirra_Respawn");
if (!test.equalsIgnoreCase(""))
{
long remain = Long.parseLong(test) - System.currentTimeMillis();
if (remain <= 0)
init(false);
else
{
init(true);
startQuestTimer("respawn", remain, null, null);
}
}
else
init(false);
}
public void init(boolean isBusy)
{
_sirrasZone = GrandBossManager.getInstance().getZone(105546 , -127892 , -2768);
if (_sirrasZone == null)
{
_log.warning("IceFairySirraManager: Failed to load zone");
return;
}
_sirrasZone.setZoneEnabled(false);
L2Npc steward = findTemplate(STEWARD);
if (steward != null)
steward.setBusy(isBusy);
openGates();
}
public void cleanUp()
{
init(false);
cancelQuestTimer("30MinutesRemaining",null, _player);
cancelQuestTimer("20MinutesRemaining",null, _player);
cancelQuestTimer("10MinutesRemaining",null, _player);
cancelQuestTimer("End",null, _player);
for (L2Npc mob : _allMobs)
{
try
{
mob.getSpawn().stopRespawn();
mob.deleteMe();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "IceFairySirraManager: Failed deleting mob.", e);
}
}
_allMobs.clear();
}
public L2Npc findTemplate(int npcId)
{
L2Npc npc = null;
for (L2Spawn spawn : SpawnTable.getInstance().getSpawnTable())
{
if (spawn != null && spawn.getNpcid() == npcId)
{
npc = spawn.getLastSpawn();
break;
}
}
return npc;
}
protected void openGates()
{
for (int i = 23140001; i < 23140003; i++ )
{
try
{
L2DoorInstance door = DoorTable.getInstance().getDoor(i);
if (door != null)
{
door.openMe();
}
else
{
_log.warning("IceFairySirraManager: Attempted to open undefined door. doorId: "+i);
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "IceFairySirraManager: Failed closing door", e);
}
}
}
protected void closeGates()
{
for (int i = 23140001; i < 23140003; i++ )
{
try
{
L2DoorInstance door = DoorTable.getInstance().getDoor(i);
if (door != null)
{
door.closeMe();
}
else
{
_log.warning("IceFairySirraManager: Attempted to close undefined door. doorId: "+i);
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "IceFairySirraManager: Failed closing door", e);
}
}
}
public boolean checkItems (L2PcInstance player)
{
if (player.getParty() != null)
{
for (L2PcInstance pc : player.getParty().getPartyMembers())
{
L2ItemInstance i = pc.getInventory().getItemByItemId(SILVER_HEMOCYTE);
if (i == null || i.getCount() < 10)
return false;
}
}
else
return false;
return true;
}
public void destroyItems (L2PcInstance player)
{
if (player.getParty() != null)
{
for (L2PcInstance pc : player.getParty().getPartyMembers())
{
L2ItemInstance i = pc.getInventory().getItemByItemId(SILVER_HEMOCYTE);
pc.destroyItem("Hemocytes", i.getObjectId(), 10, null, false);
}
}
else
cleanUp();
}
public void teleportInside (L2PcInstance player)
{
if (player.getParty() != null)
{
for (L2PcInstance pc : player.getParty().getPartyMembers())
{
pc.teleToLocation(113533,-126159,-3488,false);
if (_sirrasZone == null)
{
_log.warning("IceFairySirraManager: Failed to load zone");
cleanUp();
return;
}
_sirrasZone.allowPlayerEntry(pc,2103);
}
}
else
cleanUp();
}
public void screenMessage(L2PcInstance player, String text, int time)
{
if (player.getParty() != null)
{
for (L2PcInstance pc : player.getParty().getPartyMembers())
{
pc.sendPacket(new ExShowScreenMessage(text,time));
}
}
else
cleanUp();
}
public void doSpawns()
{
int[][] mobs = { {29060 , 105546 , -127892 , -2768} ,
{29056 , 102779 , -125920 , -2840},
{22100 , 111719 , -126646 , -2992},
{22102 , 109509 , -128946 , -3216},
{22104 , 109680 , -125756 , -3136}};
L2Spawn spawnDat;
L2NpcTemplate template;
try
{
for (int i = 0; i <5; i++)
{
template = NpcTable.getInstance().getTemplate(mobs[i][0]);
if (template != null)
{
spawnDat = new L2Spawn(template);
spawnDat.setAmount(1);
spawnDat.setLocx(mobs[i][1]);
spawnDat.setLocy(mobs[i][2]);
spawnDat.setLocz(mobs[i][3]);
spawnDat.setHeading(0);
spawnDat.setRespawnDelay(60);
SpawnTable.getInstance().addNewSpawn(spawnDat, false);
_allMobs.add(spawnDat.doSpawn());
spawnDat.stopRespawn();
}
else
{
_log.warning("IceFairySirraManager: Data missing in NPC table for ID: "+mobs[i][0]);
}
}
}
catch (Exception e)
{
_log.warning("IceFairySirraManager: Spawns could not be initialized: "+ e);
}
}
public String getHtmlPath(int val)
{
String pom = "";
pom = "32029-" + val;
if (val == 0)
pom = "32029";
String temp = "data/html/default/" + pom + ".htm";
if (!Config.LAZY_CACHE)
{
// If not running lazy cache the file must be in the cache or it doesnt exist
if (HtmCache.getInstance().contains(temp))
return temp;
}
else if (HtmCache.getInstance().isLoadable(temp))
return temp;
// If the file is not found, the standard message "I have nothing to say to you" is returned
return "data/html/npcdefault.htm";
}
public void sendHtml(L2Npc npc, L2PcInstance player, String filename)
{
NpcHtmlMessage html = new NpcHtmlMessage(npc.getObjectId());
html.setFile(player.getHtmlPrefix(), filename);
html.replace("%objectId%", String.valueOf(npc.getObjectId()));
player.sendPacket(html);
player.sendPacket( ActionFailed.STATIC_PACKET );
}
@Override
public String onFirstTalk (L2Npc npc, L2PcInstance player)
{
if (player.getQuestState("IceFairySirra") == null)
newQuestState(player);
player.setLastQuestNpcObject(npc.getObjectId());
String filename = "";
if (npc.isBusy())
filename = getHtmlPath(10);
else
filename = getHtmlPath(0);
sendHtml(npc, player, filename);
return null;
}
@Override
public String onAdvEvent (String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("check_condition"))
{
if (npc.isBusy())//should never happen
return super.onAdvEvent(event, npc, player);
else
{
String filename = "";
if (player.isInParty() && player.getParty().getPartyLeaderOID() == player.getObjectId())
{
if (checkItems(player) == true)
{
startQuestTimer("start",100000,null,player);
_player = player;
destroyItems(player);
player.getInventory().addItem("Scroll",8379,3,player,null);
npc.setBusy(true);
screenMessage(player,"Steward: Please wait a moment.",100000);
filename = getHtmlPath(3);
}
else
{
filename = getHtmlPath(2);
}
}
else
{
filename = getHtmlPath(1);
}
sendHtml(npc, player, filename);
}
}
else if (event.equalsIgnoreCase("start"))
{
if (_sirrasZone == null)
{
_log.warning("IceFairySirraManager: Failed to load zone");
cleanUp();
return super.onAdvEvent(event, npc, player);
}
_sirrasZone.setZoneEnabled(true);
closeGates();
doSpawns();
startQuestTimer("Party_Port",2000,null,player);
startQuestTimer("End",1802000,null,player);
}
else if (event.equalsIgnoreCase("Party_Port"))
{
teleportInside(player);
screenMessage(player,"Steward: Please restore the Queen's appearance!",10000);
startQuestTimer("30MinutesRemaining",300000,null,player);
}
else if (event.equalsIgnoreCase("30MinutesRemaining"))
{
screenMessage(player,"30 minute(s) are remaining.",10000);
startQuestTimer("20minutesremaining",600000,null,player);
}
else if (event.equalsIgnoreCase("20MinutesRemaining"))
{
screenMessage(player,"20 minute(s) are remaining.",10000);
startQuestTimer("10minutesremaining",600000,null,player);
}
else if (event.equalsIgnoreCase("10MinutesRemaining"))
{
screenMessage(player,"Steward: Waste no time! Please hurry!",10000);
}
else if (event.equalsIgnoreCase("End"))
{
screenMessage(player,"Steward: Was it indeed too much to ask.",10000);
cleanUp();
}
else if (event.equalsIgnoreCase("respawn"))
{
cleanUp();
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onKill (L2Npc npc, L2PcInstance killer, boolean isPet)
{
if (npc.getNpcId() == 29056)
{
cancelQuestTimer("30MinutesRemaining",null, _player);
cancelQuestTimer("20MinutesRemaining",null, _player);
cancelQuestTimer("10MinutesRemaining",null, _player);
cancelQuestTimer("End",null, _player);
for (L2Npc mob : _allMobs)
{
try
{
mob.getSpawn().stopRespawn();
mob.deleteMe();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "IceFairySirraManager: Failed deleting mob.", e);
}
}
_allMobs.clear();
init(true);
int respawnMinDelay = 43200000 * (int)(Config.RAID_MIN_RESPAWN_MULTIPLIER);
int respawnMaxDelay = 129600000 * (int)(Config.RAID_MAX_RESPAWN_MULTIPLIER);
int respawn_delay = Rnd.get(respawnMinDelay,respawnMaxDelay);
saveGlobalQuestVar("Sirra_Respawn", String.valueOf(System.currentTimeMillis()+respawn_delay));
startQuestTimer("respawn", respawn_delay, null, null);
screenMessage(killer,"Steward: Thank you for restoring the Queen's appearance!",10000);
}
return super.onKill(npc,killer,isPet);
}
public static void main(String[] args)
{
new IceFairySirra(-1,"IceFairySirra","ai");
}
}
@@ -0,0 +1,368 @@
/*
* 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.individual;
import java.util.List;
import javolution.util.FastList;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.L2Spawn;
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.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.util.Rnd;
/**
* Orfen AI
*
* @author Emperorc
*
*/
public class Orfen extends L2AttackableAIScript
{
private static final int[][] Pos =
{
{
43728, 17220, -4342
},
{
55024, 17368, -5412
},
{
53504, 21248, -5486
},
{
53248, 24576, -5262
}
};
private static final int[] Text =
{
1000028, // $s1. Stop kidding yourself about your own powerlessness!
1000029, // $s1. I'll make you feel what true fear is!
1000030, // You're really stupid to have challenged me. $s1! Get ready!
1000031 //$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 List<L2Attackable> _Minions = new FastList<L2Attackable>();
private static L2BossZone _Zone;
private static final byte ALIVE = 0;
private static final byte DEAD = 1;
public Orfen(int id, String name, String descr)
{
super(id, name, descr);
int[] mobs =
{
ORFEN, RAIKEL_LEOS, RIBA_IREN
};
this.registerMobs(mobs);
_IsTeleported = false;
_Zone = GrandBossManager.getInstance().getZone(Pos[0][0], Pos[0][1], Pos[0][2]);
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)
this.startQuestTimer("orfen_unlock", temp, null, null);
else
{
// the time has already expired while the server was offline. Immediately spawn Orfen.
int i = Rnd.get(10);
int x = 0;
int y = 0;
int z = 0;
if (i < 4)
{
x = Pos[1][0];
y = Pos[1][1];
z = Pos[1][2];
}
else if (i < 7)
{
x = Pos[2][0];
y = Pos[2][1];
z = Pos[2][2];
}
else
{
x = Pos[3][0];
y = Pos[3][1];
z = Pos[3][2];
}
L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, x, y, z, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(ORFEN, ALIVE);
this.spawnBoss(orfen);
}
}
else
{
int loc_x = info.getInteger("loc_x");
int loc_y = info.getInteger("loc_y");
int loc_z = info.getInteger("loc_z");
int heading = info.getInteger("heading");
int hp = info.getInteger("currentHP");
int mp = info.getInteger("currentMP");
L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, loc_x, loc_y, loc_z, heading, false, 0);
orfen.setCurrentHpMp(hp, mp);
this.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.setLocx(Pos[index][0]);
spawn.setLocy(Pos[index][1]);
spawn.setLocz(Pos[index][2]);
npc.teleToLocation(Pos[index][0], Pos[index][1], Pos[index][2]);
}
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()));
this.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);
this.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 = Rnd.get(10);
int x = 0;
int y = 0;
int z = 0;
if (i < 4)
{
x = Pos[1][0];
y = Pos[1][1];
z = Pos[1][2];
}
else if (i < 7)
{
x = Pos[2][0];
y = Pos[2][1];
z = Pos[2][2];
}
else
{
x = Pos[3][0];
y = Pos[3][1];
z = Pos[3][2];
}
L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, x, y, z, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(ORFEN, ALIVE);
this.spawnBoss(orfen);
}
else if (event.equalsIgnoreCase("check_orfen_pos"))
{
if ((_IsTeleported && npc.getCurrentHp() > npc.getMaxHp() * 0.95) || (!_Zone.isInsideZone(npc) && !_IsTeleported))
{
setSpawnPoint(npc, Rnd.get(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.getX(), npc.getY(), npc.getZ());
((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, L2Skill skill, L2Object[] targets, boolean isPet)
{
if (npc.getNpcId() == ORFEN)
{
L2Character originalCaster = isPet ? caster.getPet() : caster;
if (skill.getAggroPoints() > 0 && Rnd.get(5) == 0 && npc.isInsideRadius(originalCaster, 1000, false, false))
{
NpcSay packet = new NpcSay(npc.getObjectId(), 0, npc.getNpcId(), Text[Rnd.get(4)]);
packet.addStringParameter(caster.getName().toString());
npc.broadcastPacket(packet);
originalCaster.teleToLocation(npc.getX(), npc.getY(), npc.getZ());
npc.setTarget(originalCaster);
npc.doCast(SkillTable.getInstance().getInfo(4064, 1));
}
}
return super.onSkillSee(npc, caster, skill, targets, isPet);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isPet)
{
if (caller == null || npc == null || npc.isCastingNow())
return super.onFactionCall(npc, caller, attacker, isPet);
int npcId = npc.getNpcId();
int callerId = caller.getNpcId();
if (npcId == RAIKEL_LEOS && Rnd.get(20) == 0)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(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) && Rnd.get(10) < chance)
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
npc.setTarget(caller);
npc.doCast(SkillTable.getInstance().getInfo(4516, 1));
}
}
return super.onFactionCall(npc, caller, attacker, isPet);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
{
int npcId = npc.getNpcId();
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) && Rnd.get(10) == 0)
{
NpcSay packet = new NpcSay(npc.getObjectId(), 0, npcId, Text[Rnd.get(3)]);
packet.addStringParameter(attacker.getName().toString());
npc.broadcastPacket(packet);
attacker.teleToLocation(npc.getX(), npc.getY(), npc.getZ());
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4064, 1));
}
}
else if (npcId == RIBA_IREN)
{
if (!npc.isCastingNow() && (npc.getCurrentHp() - damage) < (npc.getMaxHp() / 2.0))
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4516, 1));
}
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isPet)
{
if (npc.getNpcId() == ORFEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(ORFEN, DEAD);
//time is 48hour +/- 20hour
long respawnTime = (long) Config.Interval_Of_Orfen_Spawn + Rnd.get(Config.Random_Of_Orfen_Spawn);
this.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);
this.cancelQuestTimer("check_minion_loc", npc, null);
this.cancelQuestTimer("check_orfen_pos", npc, null);
this.startQuestTimer("despawn_minions", 20000, null, null);
this.cancelQuestTimers("spawn_minion");
}
else if (GrandBossManager.getInstance().getBossStatus(ORFEN) == ALIVE && npc.getNpcId() == RAIKEL_LEOS)
{
_Minions.remove(npc);
this.startQuestTimer("spawn_minion", 360000, npc, null);
}
return super.onKill(npc, killer, isPet);
}
public static void main(String[] args)
{
// Quest class and state definition
new Orfen(-1, "orfen", "ai");
}
}
@@ -0,0 +1,340 @@
/*
* 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.individual;
import java.util.List;
import javolution.util.FastList;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Skill;
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.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.skills.SkillHolder;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.util.Rnd;
/**
* Queen Ant AI
*
* @author Emperorc
*
*/
public class QueenAnt extends L2AttackableAIScript
{
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 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);
private L2MonsterInstance _queen = null;
private L2MonsterInstance _larva = null;
private List<L2MonsterInstance> _nurses = new FastList<L2MonsterInstance>(5);
public QueenAnt(int questId, String name, String descr)
{
super(questId, name, descr);
registerMobs(MOBS, QuestEventType.ON_SPAWN, QuestEventType.ON_KILL, QuestEventType.ON_AGGRO_RANGE_ENTER);
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 = info.getInteger("loc_x");
int loc_y = info.getInteger("loc_y");
int loc_z = info.getInteger("loc_z");
int heading = info.getInteger("heading");
int hp = info.getInteger("currentHP");
int mp = info.getInteger("currentMP");
if (!_zone.isInsideZone(loc_x, loc_y, loc_z))
{
loc_x = QUEEN_X;
loc_y = QUEEN_Y;
loc_z = QUEEN_Z;
}
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 (Rnd.get(100) < 33)
_zone.movePlayersTo(-19480, 187344, -5600);
else if (Rnd.get(100) < 50)
_zone.movePlayersTo(-17928, 180912, -5520);
else
_zone.movePlayersTo(-23808, 182368, -5600);
GrandBossManager.getInstance().addBoss(npc);
startQuestTimer("action", 10000, npc, null, true);
startQuestTimer("heal", 1000, null, null, true);
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
_queen = npc;
_larva = (L2MonsterInstance)addSpawn(LARVA, -21600, 179482, -5846, Rnd.get(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(Rnd.nextBoolean() ? HEAL1.getSkill() : HEAL2.getSkill());
}
continue;
}
if (queenNeedHeal)
{
if (nurse.getLeader() == _larva) // skip larva's minions
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 (Rnd.get(3) == 0)
{
if (Rnd.get(2) == 0)
{
npc.broadcastPacket(new SocialAction(npc, 3));
}
else
{
npc.broadcastPacket(new SocialAction(npc, 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.getNpcId())
{
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;
}
return super.onSpawn(npc);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isPet)
{
if (caller == null || npc == null)
return super.onFactionCall(npc, caller, attacker, isPet);
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 isPet)
{
if (npc == null)
return null;
final boolean isMage;
final L2Playable character;
if (isPet)
{
isMage = false;
character = player.getPet();
}
else
{
isMage = player.isMageClass();
character = player;
}
if (character == null)
return null;
if (!Config.RAID_DISABLE_CURSE && character.getLevel() - npc.getLevel() > 8)
{
L2Skill curse = null;
if (isMage)
{
if (!character.isMuted() && Rnd.get(4) == 0)
curse = SkillTable.FrequentSkill.RAID_CURSE.getSkill();
}
else
{
if (!character.isParalyzed() && Rnd.get(4) == 0)
curse = SkillTable.FrequentSkill.RAID_CURSE2.getSkill();
}
if (curse != null)
{
npc.broadcastPacket(new MagicSkillUse(npc, character, curse.getId(), curse.getLevel(), 300, 0));
curse.getEffects(npc, character);
}
((L2Attackable) npc).stopHating(character); // for calling again
return null;
}
return super.onAggroRangeEnter(npc, player, isPet);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isPet)
{
int npcId = npc.getNpcId();
if (npcId == QUEEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(QUEEN, DEAD);
//time is 36hour +/- 17hour
long respawnTime = (long) Config.Interval_Of_QueenAnt_Spawn + Rnd.get(Config.Random_Of_QueenAnt_Spawn);
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;
}
else if (_queen != null && !_queen.isAlikeDead())
{
if (npcId == ROYAL)
{
L2MonsterInstance mob = (L2MonsterInstance)npc;
if (mob.getLeader() != null)
mob.getLeader().getMinionList().onMinionDie(mob, (280 + Rnd.get(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, isPet);
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new QueenAnt(-1, "queen_ant", "ai");
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,951 @@
/*
* 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.individual;
import java.util.logging.Logger;
import ai.group_template.L2AttackableAIScript;
import com.l2jserver.Config;
import com.l2jserver.gameserver.GameTimeController;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.DoorTable;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Effect;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
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.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.util.Rnd;
/**
* Zaken AI
*
*/
public class Zaken extends L2AttackableAIScript
{
protected static final Logger log = Logger.getLogger(Zaken.class.getName());
private int _1001 = 0; // used for first cancel of QuestTimer "1001"
private int _ai0 = 0; // used for zaken coords updater
private int _ai1 = 0; // used for X coord tracking for non-random teleporting in zaken's self teleport skill
private int _ai2 = 0; // used for Y coord tracking for non-random teleporting in zaken's self teleport skill
private int _ai3 = 0; // used for Z coord tracking for non-random teleporting in zaken's self teleport skill
private int _ai4 = 0; // used for spawning minions cycles
private int _quest0 = 0; // used for teleporting progress
private int _quest1 = 0; // used for most hated players progress
private int _quest2 = 0; // used for zaken HP check for teleport
private L2PcInstance c_quest0 = null; // 1st player used for area teleport
private L2PcInstance c_quest1 = null; // 2nd player used for area teleport
private L2PcInstance c_quest2 = null; // 3rd player used for area teleport
private L2PcInstance c_quest3 = null; // 4th player used for area teleport
private L2PcInstance c_quest4 = null; // 5th player used for area teleport
private static final int ZAKEN = 29022;
private static final int doll_blader_b = 29023;
private static final int vale_master_b = 29024;
private static final int pirates_zombie_captain_b = 29026;
private static final int pirates_zombie_b = 29027;
private static final int[] Xcoords =
{
53950, 55980, 54950, 55970, 53930, 55970, 55980, 54960, 53950, 53930, 55970, 55980, 54960, 53950, 53930
};
private static final int[] Ycoords =
{
219860, 219820, 218790, 217770, 217760, 217770, 219920, 218790, 219860, 217760, 217770, 219920, 218790, 219860, 217760
};
private static final int[] Zcoords =
{
-3488, -3488, -3488, -3488, -3488, -3216, -3216, -3216, -3216, -3216, -2944, -2944, -2944, -2944, -2944
};
//ZAKEN Status Tracking :
private static final byte ALIVE = 0; //Zaken is spawned.
private static final byte DEAD = 1; //Zaken has been killed.
private static L2BossZone _Zone;
public Zaken(int questId, String name, String descr)
{
super(questId, name, descr);
// Zaken doors handling
ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Runnable()
{
public void run()
{
try
{
if (getTimeHour() == 0)
{
DoorTable.getInstance().getDoor(21240006).openMe();
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
{
public void run()
{
try
{
DoorTable.getInstance().getDoor(21240006).closeMe();
}
catch (Throwable e)
{
log.warning("Cannot close door ID: 21240006 " + e);
}
}
}, 300000L);
}
}
catch (Throwable e)
{
log.warning("Cannot open door ID: 21240006 " + e);
}
}
}, 2000L, 600000L);
int[] mobs =
{
ZAKEN, doll_blader_b, vale_master_b, pirates_zombie_captain_b, pirates_zombie_b
};
registerMobs(mobs);
_Zone = GrandBossManager.getInstance().getZone(55312, 219168, -3223);
StatsSet info = GrandBossManager.getInstance().getStatsSet(ZAKEN);
int status = GrandBossManager.getInstance().getBossStatus(ZAKEN);
if (status == DEAD)
{
// load the unlock date and time for zaken from DB
long temp = info.getLong("respawn_time") - System.currentTimeMillis();
// if zaken 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("zaken_unlock", temp, null, null);
else
{
// the time has already expired while the server was offline. Immediately spawn zaken.
L2GrandBossInstance zaken = (L2GrandBossInstance) addSpawn(ZAKEN, 55312, 219168, -3223, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(ZAKEN, ALIVE);
spawnBoss(zaken);
}
}
else
{
int loc_x = info.getInteger("loc_x");
int loc_y = info.getInteger("loc_y");
int loc_z = info.getInteger("loc_z");
int heading = info.getInteger("heading");
int hp = info.getInteger("currentHP");
int mp = info.getInteger("currentMP");
L2GrandBossInstance zaken = (L2GrandBossInstance) addSpawn(ZAKEN, loc_x, loc_y, loc_z, heading, false, 0);
zaken.setCurrentHpMp(hp, mp);
spawnBoss(zaken);
}
}
public void spawnBoss(L2GrandBossInstance npc)
{
if (npc == null)
{
log.warning("Zaken AI failed to load, missing Zaken in grandboss_data.sql");
return;
}
GrandBossManager.getInstance().addBoss(npc);
npc.broadcastPacket(new PlaySound(1, "BS01_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
_ai0 = 0;
_ai1 = npc.getX();
_ai2 = npc.getY();
_ai3 = npc.getZ();
_quest0 = 0;
_quest1 = 0;
_quest2 = 3;
if (_Zone == null)
{
log.warning("Zaken AI failed to load, missing zone for Zaken");
return;
}
if (_Zone.isInsideZone(npc))
{
_ai4 = 1;
startQuestTimer("1003", 1700, null, null, true);
}
_1001 = 1;
startQuestTimer("1001", 1000, npc, null, true); //buffs,random teleports
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
int status = GrandBossManager.getInstance().getBossStatus(ZAKEN);
if (status == DEAD && !event.equalsIgnoreCase("zaken_unlock"))
return super.onAdvEvent(event, npc, player);
if (event.equalsIgnoreCase("1001"))
{
if (_1001 == 1)
{
_1001 = 0;
cancelQuestTimer("1001", npc, null);
}
int sk_4223 = 0;
int sk_4227 = 0;
L2Effect[] effects = npc.getAllEffects();
if (effects != null && effects.length != 0)
{
for (L2Effect e : effects)
{
if (e.getSkill().getId() == 4227)
{
sk_4227 = 1;
}
if (e.getSkill().getId() == 4223)
{
sk_4223 = 1;
}
}
}
if (getTimeHour() < 5)
{
if (sk_4223 == 1) //use night face if zaken have day face
{
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4224, 1));
_ai1 = npc.getX();
_ai2 = npc.getY();
_ai3 = npc.getZ();
}
if (sk_4227 == 0) //use zaken regeneration
{
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4227, 1));
}
if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ATTACK && _ai0 == 0)
{
int i0 = 0;
int i1 = 1;
if (((L2Attackable) npc).getMostHated() != null)
{
if ((((((L2Attackable) npc).getMostHated().getX() - _ai1) * (((L2Attackable) npc).getMostHated().getX() - _ai1)) + ((((L2Attackable) npc).getMostHated().getY() - _ai2) * (((L2Attackable) npc)
.getMostHated().getY() - _ai2))) > (1500 * 1500))
i0 = 1;
else
i0 = 0;
if (i0 == 0)
i1 = 0;
if (_quest0 > 0)
{
if (c_quest0 == null)
i0 = 0;
else if ((((c_quest0.getX() - _ai1) * (c_quest0.getX() - _ai1)) + ((c_quest0.getY() - _ai2) * (c_quest0.getY() - _ai2))) > (1500 * 1500))
i0 = 1;
else
i0 = 0;
if (i0 == 0)
i1 = 0;
}
if (_quest0 > 1)
{
if (c_quest1 == null)
i0 = 0;
else if ((((c_quest1.getX() - _ai1) * (c_quest1.getX() - _ai1)) + ((c_quest1.getY() - _ai2) * (c_quest1.getY() - _ai2))) > (1500 * 1500))
i0 = 1;
else
i0 = 0;
if (i0 == 0)
i1 = 0;
}
if (_quest0 > 2)
{
if (c_quest2 == null)
i0 = 0;
else if ((((c_quest2.getX() - _ai1) * (c_quest2.getX() - _ai1)) + ((c_quest2.getY() - _ai2) * (c_quest2.getY() - _ai2))) > (1500 * 1500))
i0 = 1;
else
i0 = 0;
if (i0 == 0)
i1 = 0;
}
if (_quest0 > 3)
{
if (c_quest3 == null)
i0 = 0;
else if ((((c_quest3.getX() - _ai1) * (c_quest3.getX() - _ai1)) + ((c_quest3.getY() - _ai2) * (c_quest3.getY() - _ai2))) > (1500 * 1500))
i0 = 1;
else
i0 = 0;
if (i0 == 0)
i1 = 0;
}
if (_quest0 > 4)
{
if (c_quest4 == null)
i0 = 0;
else if ((((c_quest4.getX() - _ai1) * (c_quest4.getX() - _ai1)) + ((c_quest4.getY() - _ai2) * (c_quest4.getY() - _ai2))) > (1500 * 1500))
i0 = 1;
else
i0 = 0;
if (i0 == 0)
i1 = 0;
}
if (i1 == 1)
{
_quest0 = 0;
int i2 = Rnd.get(15);
_ai1 = Xcoords[i2] + Rnd.get(650);
_ai2 = Ycoords[i2] + Rnd.get(650);
_ai3 = Zcoords[i2];
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4222, 1));
}
}
}
if (Rnd.get(20) < 1 && _ai0 == 0)
{
_ai1 = npc.getX();
_ai2 = npc.getY();
_ai3 = npc.getZ();
}
L2Character c_ai0 = null;
if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ATTACK && _quest1 == 0)
{
if (((L2Attackable) npc).getMostHated() != null)
{
c_ai0 = ((L2Attackable) npc).getMostHated();
_quest1 = 1;
}
}
else if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ATTACK && _quest1 != 0)
{
if (((L2Attackable) npc).getMostHated() != null)
{
if (c_ai0 == ((L2Attackable) npc).getMostHated())
{
_quest1 = (_quest1 + 1);
}
else
{
_quest1 = 1;
c_ai0 = ((L2Attackable) npc).getMostHated();
}
}
}
if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)
{
_quest1 = 0;
}
if (_quest1 > 5)
{
((L2Attackable) npc).stopHating(c_ai0);
L2Character nextTarget = ((L2Attackable) npc).getMostHated();
if (nextTarget != null)
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, nextTarget);
_quest1 = 0;
}
}
else if (sk_4223 == 0) //use day face if not night time
{
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4223, 1));
_quest2 = 3;
}
if (sk_4227 == 1) // when switching to day time, cancel zaken night regen
{
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4242, 1));
}
if (Rnd.get(40) < 1)
{
int i2 = Rnd.get(15);
_ai1 = Xcoords[i2] + Rnd.get(650);
_ai2 = Ycoords[i2] + Rnd.get(650);
_ai3 = Zcoords[i2];
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4222, 1));
}
startQuestTimer("1001", 30000, npc, null, true);
}
if (event.equalsIgnoreCase("1002"))
{
_quest0 = 0;
npc.doCast(SkillTable.getInstance().getInfo(4222, 1));
_ai0 = 0;
}
if (event.equalsIgnoreCase("1003"))
{
if (_ai4 == 1)
{
int rr = Rnd.get(15);
((L2Attackable)addSpawn(pirates_zombie_captain_b, Xcoords[rr] + Rnd.get(650), Ycoords[rr] + Rnd.get(650), Zcoords[rr], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
_ai4 = 2;
}
else if (_ai4 == 2)
{
int rr = Rnd.get(15);
((L2Attackable)addSpawn(doll_blader_b, Xcoords[rr] + Rnd.get(650), Ycoords[rr] + Rnd.get(650), Zcoords[rr], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
_ai4 = 3;
}
else if (_ai4 == 3)
{
((L2Attackable)addSpawn(vale_master_b, Xcoords[Rnd.get(15)] + Rnd.get(650), Ycoords[Rnd.get(15)] + Rnd.get(650), Zcoords[Rnd.get(15)], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, Xcoords[Rnd.get(15)] + Rnd.get(650), Ycoords[Rnd.get(15)] + Rnd.get(650), Zcoords[Rnd.get(15)], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
_ai4 = 4;
}
else if (_ai4 == 4)
{
((L2Attackable)addSpawn(pirates_zombie_b, Xcoords[Rnd.get(15)] + Rnd.get(650), Ycoords[Rnd.get(15)] + Rnd.get(650), Zcoords[Rnd.get(15)], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, Xcoords[Rnd.get(15)] + Rnd.get(650), Ycoords[Rnd.get(15)] + Rnd.get(650), Zcoords[Rnd.get(15)], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, Xcoords[Rnd.get(15)] + Rnd.get(650), Ycoords[Rnd.get(15)] + Rnd.get(650), Zcoords[Rnd.get(15)], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, Xcoords[Rnd.get(15)] + Rnd.get(650), Ycoords[Rnd.get(15)] + Rnd.get(650), Zcoords[Rnd.get(15)], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, Xcoords[Rnd.get(15)] + Rnd.get(650), Ycoords[Rnd.get(15)] + Rnd.get(650), Zcoords[Rnd.get(15)], Rnd.get(65536), false, 0)).setIsRaidMinion(true);
_ai4 = 5;
}
else if (_ai4 == 5)
{
((L2Attackable)addSpawn(doll_blader_b, 52675, 219371, -3290, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 52687, 219596, -3368, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 52672, 219740, -3418, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 52857, 219992, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 52959, 219997, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 53381, 220151, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 54236, 220948, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54885, 220144, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55264, 219860, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 55399, 220263, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55679, 220129, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 56276, 220783, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 57173, 220234, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 56267, 218826, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 56294, 219482, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 56094, 219113, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 56364, 218967, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 57113, 218079, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 56186, 217153, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55440, 218081, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 55202, 217940, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55225, 218236, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54973, 218075, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 53412, 218077, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54226, 218797, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54394, 219067, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54139, 219253, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 54262, 219480, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
_ai4 = 6;
}
else if (_ai4 == 6)
{
((L2Attackable)addSpawn(pirates_zombie_b, 53412, 218077, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54413, 217132, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 54841, 217132, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 55372, 217128, -3343, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 55893, 217122, -3488, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 56282, 217237, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 56963, 218080, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 56267, 218826, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 56294, 219482, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 56094, 219113, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 56364, 218967, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 56276, 220783, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 57173, 220234, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54885, 220144, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55264, 219860, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 55399, 220263, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55679, 220129, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 54236, 220948, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 54464, 219095, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54226, 218797, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54394, 219067, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54139, 219253, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 54262, 219480, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 53412, 218077, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55440, 218081, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 55202, 217940, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55225, 218236, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54973, 218075, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
_ai4 = 7;
}
else if (_ai4 == 7)
{
((L2Attackable)addSpawn(pirates_zombie_b, 54228, 217504, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54181, 217168, -3216, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 54714, 217123, -3168, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 55298, 217127, -3073, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 55787, 217130, -2993, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 56284, 217216, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 56963, 218080, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 56267, 218826, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 56294, 219482, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 56094, 219113, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 56364, 218967, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 56276, 220783, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 57173, 220234, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54885, 220144, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55264, 219860, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 55399, 220263, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55679, 220129, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 54236, 220948, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 54464, 219095, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54226, 218797, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(vale_master_b, 54394, 219067, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54139, 219253, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(doll_blader_b, 54262, 219480, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 53412, 218077, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 54280, 217200, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55440, 218081, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_captain_b, 55202, 217940, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 55225, 218236, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
((L2Attackable)addSpawn(pirates_zombie_b, 54973, 218075, -2944, Rnd.get(65536), false, 0)).setIsRaidMinion(true);
_ai4 = 8;
cancelQuestTimer("1003", null, null);
}
}
else if (event.equalsIgnoreCase("zaken_unlock"))
{
L2GrandBossInstance zaken = (L2GrandBossInstance) addSpawn(ZAKEN, 55312, 219168, -3223, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(ZAKEN, ALIVE);
spawnBoss(zaken);
}
else if (event.equalsIgnoreCase("CreateOnePrivateEx"))
{
((L2Attackable)addSpawn(npc.getNpcId(), npc.getX(), npc.getY(), npc.getZ(), 0, false, 0)).setIsRaidMinion(true);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isPet)
{
if (caller == null || npc == null)
return super.onFactionCall(npc, caller, attacker, isPet);
int npcId = npc.getNpcId();
int callerId = caller.getNpcId();
if (getTimeHour() < 5 && callerId != ZAKEN && npcId == ZAKEN)
{
int damage = 0; // well damage required :x
if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE && _ai0 == 0 && damage < 10 && Rnd.get((30 * 15)) < 1)//todo - damage missing
{
_ai0 = 1;
_ai1 = caller.getX();
_ai2 = caller.getY();
_ai3 = caller.getZ();
startQuestTimer("1002", 300, caller, null);
}
}
return super.onFactionCall(npc, caller, attacker, isPet);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
{
if (npc.getNpcId() == ZAKEN)
{
int skillId = skill.getId();
if (skillId == 4222)
{
npc.teleToLocation(_ai1, _ai2, _ai3);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
}
else if (skillId == 4216)
{
int i1 = Rnd.get(15);
player.teleToLocation(Xcoords[i1] + Rnd.get(650), Ycoords[i1] + Rnd.get(650), Zcoords[i1]);
((L2Attackable) npc).stopHating(player);
L2Character nextTarget = ((L2Attackable) npc).getMostHated();
if (nextTarget != null)
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, nextTarget);
}
else if (skillId == 4217)
{
int i0 = 0;
int i1 = Rnd.get(15);
player.teleToLocation(Xcoords[i1] + Rnd.get(650), Ycoords[i1] + Rnd.get(650), Zcoords[i1]);
((L2Attackable) npc).stopHating(player);
if (c_quest0 != null && _quest0 > 0 && c_quest0 != player && c_quest0.getZ() > (player.getZ() - 100) && c_quest0.getZ() < (player.getZ() + 100))
{
if ((((c_quest0.getX() - player.getX()) * (c_quest0.getX() - player.getX())) + ((c_quest0.getY() - player.getY()) * (c_quest0.getY() - player.getY()))) > (250 * 250))
{
i0 = 1;
}
else
{
i0 = 0;
}
if (i0 == 0)
{
i1 = Rnd.get(15);
c_quest0.teleToLocation(Xcoords[i1] + Rnd.get(650), Ycoords[i1] + Rnd.get(650), Zcoords[i1]);
((L2Attackable) npc).stopHating(c_quest0);
}
}
if (c_quest1 != null && _quest0 > 1 && c_quest1 != player && c_quest1.getZ() > (player.getZ() - 100) && c_quest1.getZ() < (player.getZ() + 100))
{
if ((((c_quest1.getX() - player.getX()) * (c_quest1.getX() - player.getX())) + ((c_quest1.getY() - player.getY()) * (c_quest1.getY() - player.getY()))) > (250 * 250))
{
i0 = 1;
}
else
{
i0 = 0;
}
if (i0 == 0)
{
i1 = Rnd.get(15);
c_quest1.teleToLocation(Xcoords[i1] + Rnd.get(650), Ycoords[i1] + Rnd.get(650), Zcoords[i1]);
((L2Attackable) npc).stopHating(c_quest1);
}
}
if (c_quest2 != null && _quest0 > 2 && c_quest2 != player && c_quest2.getZ() > (player.getZ() - 100) && c_quest2.getZ() < (player.getZ() + 100))
{
if ((((c_quest2.getX() - player.getX()) * (c_quest2.getX() - player.getX())) + ((c_quest2.getY() - player.getY()) * (c_quest2.getY() - player.getY()))) > (250 * 250))
{
i0 = 1;
}
else
{
i0 = 0;
}
if (i0 == 0)
{
i1 = Rnd.get(15);
c_quest2.teleToLocation(Xcoords[i1] + Rnd.get(650), Ycoords[i1] + Rnd.get(650), Zcoords[i1]);
((L2Attackable) npc).stopHating(c_quest2);
}
}
if (c_quest3 != null && _quest0 > 3 && c_quest3 != player && c_quest3.getZ() > (player.getZ() - 100) && c_quest3.getZ() < (player.getZ() + 100))
{
if ((((c_quest3.getX() - player.getX()) * (c_quest3.getX() - player.getX())) + ((c_quest3.getY() - player.getY()) * (c_quest3.getY() - player.getY()))) > (250 * 250))
{
i0 = 1;
}
else
{
i0 = 0;
}
if (i0 == 0)
{
i1 = Rnd.get(15);
c_quest3.teleToLocation(Xcoords[i1] + Rnd.get(650), Ycoords[i1] + Rnd.get(650), Zcoords[i1]);
((L2Attackable) npc).stopHating(c_quest3);
}
}
if (c_quest4 != null && _quest0 > 4 && c_quest4 != player && c_quest4.getZ() > (player.getZ() - 100) && c_quest4.getZ() < (player.getZ() + 100))
{
if ((((c_quest4.getX() - player.getX()) * (c_quest4.getX() - player.getX())) + ((c_quest4.getY() - player.getY()) * (c_quest4.getY() - player.getY()))) > (250 * 250))
{
i0 = 1;
}
else
{
i0 = 0;
}
if (i0 == 0)
{
i1 = Rnd.get(15);
c_quest4.teleToLocation(Xcoords[i1] + Rnd.get(650), Ycoords[i1] + Rnd.get(650), Zcoords[i1]);
((L2Attackable) npc).stopHating(c_quest4);
}
}
L2Character nextTarget = ((L2Attackable) npc).getMostHated();
if (nextTarget != null)
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, nextTarget);
}
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
{
int npcId = npc.getNpcId();
if (npcId == ZAKEN)
{
if (attacker.getMountType() == 1)
{
int sk_4258 = 0;
L2Effect[] effects = attacker.getAllEffects();
if (effects != null && effects.length != 0)
{
for (L2Effect e : effects)
{
if (e.getSkill().getId() == 4258)
{
sk_4258 = 1;
}
}
}
if (sk_4258 == 0)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4258, 1));
}
}
L2Character originalAttacker = isPet ? attacker.getPet() : attacker;
int hate = (int) (((damage / npc.getMaxHp()) / 0.05) * 20000);
((L2Attackable) npc).addDamageHate(originalAttacker, 0, hate);
if (Rnd.get(10) < 1)
{
int i0 = Rnd.get((15 * 15));
if (i0 < 1)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4216, 1));
}
else if (i0 < 2)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4217, 1));
}
else if (i0 < 4)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4219, 1));
}
else if (i0 < 8)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4218, 1));
}
else if (i0 < 15)
{
for (L2Character character : npc.getKnownList().getKnownCharactersInRadius(100))
{
if (character != attacker)
continue;
if (attacker != ((L2Attackable) npc).getMostHated())
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4221, 1));
}
}
}
if (Rnd.get(2) < 1)
{
if (attacker == ((L2Attackable) npc).getMostHated())
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4220, 1));
}
}
}
if (getTimeHour() < 5)
{}
else if (npc.getCurrentHp() < ((npc.getMaxHp() * _quest2) / 4.0))
{
_quest2 = (_quest2 - 1);
int i2 = Rnd.get(15);
_ai1 = Xcoords[i2] + Rnd.get(650);
_ai2 = Ycoords[i2] + Rnd.get(650);
_ai3 = Zcoords[i2];
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4222, 1));
}
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isPet)
{
int npcId = npc.getNpcId();
if (npcId == ZAKEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(ZAKEN, DEAD);
//time is 36hour +/- 17hour
long respawnTime = (long) Config.Interval_Of_Zaken_Spawn + Rnd.get(Config.Random_Of_Zaken_Spawn);
startQuestTimer("zaken_unlock", respawnTime, null, null);
cancelQuestTimer("1001", npc, null);
cancelQuestTimer("1003", npc, null);
// also save the respawn time so that the info is maintained past reboots
StatsSet info = GrandBossManager.getInstance().getStatsSet(ZAKEN);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(ZAKEN, info);
}
else if (GrandBossManager.getInstance().getBossStatus(ZAKEN) == ALIVE)
{
if (npcId != ZAKEN)
{
startQuestTimer("CreateOnePrivateEx", ((30 + Rnd.get(60)) * 1000), npc, null);
}
}
return super.onKill(npc, killer, isPet);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isPet)
{
int npcId = npc.getNpcId();
if (npcId == ZAKEN)
{
if (skill.getAggroPoints() > 0)
{
((L2Attackable) npc).addDamageHate(caster, 0, (((skill.getAggroPoints() / npc.getMaxHp()) * 10) * 150));
}
if (Rnd.get(12) < 1)
{
int i0 = Rnd.get((15 * 15));
if (i0 < 1)
{
npc.setTarget(caster);
npc.doCast(SkillTable.getInstance().getInfo(4216, 1));
}
else if (i0 < 2)
{
npc.setTarget(caster);
npc.doCast(SkillTable.getInstance().getInfo(4217, 1));
}
else if (i0 < 4)
{
npc.setTarget(caster);
npc.doCast(SkillTable.getInstance().getInfo(4219, 1));
}
else if (i0 < 8)
{
npc.setTarget(caster);
npc.doCast(SkillTable.getInstance().getInfo(4218, 1));
}
else if (i0 < 15)
{
for (L2Character character : npc.getKnownList().getKnownCharactersInRadius(100))
{
if (character != caster)
continue;
if (caster != ((L2Attackable) npc).getMostHated())
{
npc.setTarget(caster);
npc.doCast(SkillTable.getInstance().getInfo(4221, 1));
}
}
}
if (Rnd.get(2) < 1)
{
if (caster == ((L2Attackable) npc).getMostHated())
{
npc.setTarget(caster);
npc.doCast(SkillTable.getInstance().getInfo(4220, 1));
}
}
}
}
return super.onSkillSee(npc, caster, skill, targets, isPet);
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isPet)
{
int npcId = npc.getNpcId();
if (npcId == ZAKEN)
{
if (_Zone.isInsideZone(npc))
{
L2Character target = isPet ? player.getPet() : player;
((L2Attackable) npc).addDamageHate(target, 1, 200);
}
if (player.getZ() > (npc.getZ() - 100) && player.getZ() < (npc.getZ() + 100))
{
if (_quest0 < 5 && Rnd.get(3) < 1)
{
if (_quest0 == 0)
{
c_quest0 = player;
}
else if (_quest0 == 1)
{
c_quest1 = player;
}
else if (_quest0 == 2)
{
c_quest2 = player;
}
else if (_quest0 == 3)
{
c_quest3 = player;
}
else if (_quest0 == 4)
{
c_quest4 = player;
}
_quest0++;
}
if (Rnd.get(15) < 1)
{
int i0 = Rnd.get((15 * 15));
if (i0 < 1)
{
npc.setTarget(player);
npc.doCast(SkillTable.getInstance().getInfo(4216, 1));
}
else if (i0 < 2)
{
npc.setTarget(player);
npc.doCast(SkillTable.getInstance().getInfo(4217, 1));
}
else if (i0 < 4)
{
npc.setTarget(player);
npc.doCast(SkillTable.getInstance().getInfo(4219, 1));
}
else if (i0 < 8)
{
npc.setTarget(player);
npc.doCast(SkillTable.getInstance().getInfo(4218, 1));
}
else if (i0 < 15)
{
for (L2Character character : npc.getKnownList().getKnownCharactersInRadius(100))
{
if (character != player)
continue;
if (player != ((L2Attackable) npc).getMostHated())
{
npc.setTarget(player);
npc.doCast(SkillTable.getInstance().getInfo(4221, 1));
}
}
}
if (Rnd.get(2) < 1)
{
if (player == ((L2Attackable) npc).getMostHated())
{
npc.setTarget(player);
npc.doCast(SkillTable.getInstance().getInfo(4220, 1));
}
}
}
}
}
return super.onAggroRangeEnter(npc, player, isPet);
}
public int getTimeHour()
{
return (GameTimeController.getInstance().getGameTime() / 60) % 24;
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new Zaken(-1, "zaken", "ai");
}
}
@@ -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"