This commit is contained in:
MobiusDev
2016-10-21 21:26:21 +00:00
parent 4247fae039
commit 34fc592ced
25699 changed files with 2534454 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.fantasy_isle;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.instancemanager.HandysBlockCheckerManager;
import com.l2jmobius.gameserver.model.ArenaParticipantsHolder;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExCubeGameChangeTimeToStart;
import com.l2jmobius.gameserver.network.serverpackets.ExCubeGameRequestReady;
import com.l2jmobius.gameserver.network.serverpackets.ExCubeGameTeamList;
/**
* Handys Block Checker Event AI.
* @authors BiggBoss, Gigiikun
*/
final class HandysBlockCheckerEvent extends Quest
{
// Arena Managers
private static final int A_MANAGER_1 = 32521;
private static final int A_MANAGER_2 = 32522;
private static final int A_MANAGER_3 = 32523;
private static final int A_MANAGER_4 = 32524;
public HandysBlockCheckerEvent()
{
super(-1, HandysBlockCheckerEvent.class.getSimpleName(), "Handy's Block Checker Event");
addFirstTalkId(A_MANAGER_1, A_MANAGER_2, A_MANAGER_3, A_MANAGER_4);
HandysBlockCheckerManager.getInstance().startUpParticipantsQueue();
}
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
if ((npc == null) || (player == null))
{
return null;
}
final int arena = npc.getId() - A_MANAGER_1;
if (eventIsFull(arena))
{
player.sendPacket(SystemMessageId.YOU_CANNOT_REGISTER_BECAUSE_CAPACITY_HAS_BEEN_EXCEEDED);
return null;
}
if (HandysBlockCheckerManager.getInstance().arenaIsBeingUsed(arena))
{
player.sendPacket(SystemMessageId.THE_MATCH_IS_BEING_PREPARED_PLEASE_TRY_AGAIN_LATER);
return null;
}
if (HandysBlockCheckerManager.getInstance().addPlayerToArena(player, arena))
{
final ArenaParticipantsHolder holder = HandysBlockCheckerManager.getInstance().getHolder(arena);
final ExCubeGameTeamList tl = new ExCubeGameTeamList(holder.getRedPlayers(), holder.getBluePlayers(), arena);
player.sendPacket(tl);
if ((holder.getBlueTeamSize() >= Config.MIN_BLOCK_CHECKER_TEAM_MEMBERS) && (holder.getRedTeamSize() >= Config.MIN_BLOCK_CHECKER_TEAM_MEMBERS))
{
holder.updateEvent();
holder.broadCastPacketToTeam(new ExCubeGameRequestReady());
holder.broadCastPacketToTeam(new ExCubeGameChangeTimeToStart(10));
}
}
return null;
}
private boolean eventIsFull(int arena)
{
return HandysBlockCheckerManager.getInstance().getHolder(arena).getAllPlayers().size() == 12;
}
public static void main(String[] args)
{
if (Config.ENABLE_BLOCK_CHECKER_EVENT)
{
new HandysBlockCheckerEvent();
_log.info("Handy's Block Checker Event is enabled");
}
else
{
_log.info("Handy's Block Checker Event is disabled");
}
}
}

View File

@@ -0,0 +1,261 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.fantasy_isle;
import java.text.SimpleDateFormat;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* Fantasy Isle Parade
* @author JOJO, Pandragon
*/
final class Parade extends AbstractNpcAI
{
// @formatter:off
final int[] ACTORS =
{
32379, 0, 32379,
32379, 0, 32379,
32379, 0, 32379,
0, 0, 0,
32380, 0, 32380,
32380, 32381, 32380,
32380, 0, 32380,
32380, 32381, 32380,
0, 0, 0,
32382, 32382, 32382,
32382, 32383, 32382,
32383, 32384, 32383,
32383, 32384, 32383,
0, 0, 0,
0, 32385, 0,
32385, 0, 32385,
0, 32385, 0,
0, 0, 0,
32412, 0, 32411,
0, 0, 0,
32421, 0, 32409,
32423, 0, 32422,
0, 0, 0,
32420, 32419, 32417,
32418, 0, 32416,
0, 0, 0,
32414, 0, 32414,
0, 32413, 0,
32414, 0, 32414,
0, 0, 0,
32393, 0, 32394,
0, 32430, 0,
32392, 0, 32391,
0, 0, 0,
0, 32404, 0,
32403, 0, 32401,
0, 0, 0,
0, 32408, 0,
32406, 0, 32407,
0, 32405, 0,
0, 0, 0,
32390, 32389, 32387,
32388, 0, 32386,
0, 0, 0,
0, 32400, 0,
32397, 32398, 32396,
0, 0, 0,
0, 32450, 0,
32448, 32449, 32447,
0, 0, 0,
32380, 0, 32380,
32380, 32381, 32380,
32380, 0, 32380,
32380, 32381, 32380,
0, 0, 0,
32379, 0, 32379,
32379, 0, 32379,
32379, 0, 32379,
0, 0, 0,
0, 32415, 0
};
//(Northbound 270 degrees) Route 1
private final int[][] START1 = {{-54780, -56810, -2015, 49152},{-54860, -56810, -2015, 49152},{-54940, -56810, -2015, 49152}};
private final int[][] GOAL1 = {{-54780, -57965, -2015, 49152},{-54860, -57965, -2015, 49152},{-54940, -57965, -2015, 49152}};
//(Westbound 180 degrees) Route 2
private final int[][] START2 = {{-55715, -58900, -2015, 32768},{-55715, -58820, -2015, 32768},{-55715, -58740, -2015, 32768}};
private final int[][] GOAL2 = {{-60850, -58900, -2015, 32768},{-60850, -58820, -2015, 32768},{-60850, -58740, -2015, 32768}};
//(Southbound 90 degrees) Route 3
private final int[][] START3 = {{-61790, -57965, -2015, 16384},{-61710, -57965, -2015, 16384},{-61630, -57965, -2015, 16384}};
private final int[][] GOAL3 = {{-61790, -53890, -2116, 16384},{-61710, -53890, -2116, 16384},{-61630, -53890, -2116, 16384}};
//(Eastbound 0 degrees) Route 4
private final int[][] START4 = {{-60840, -52990, -2108, 0},{-60840, -53070, -2108, 0},{-60840, -53150, -2108, 0}};
private final int[][] GOAL4 = {{-58620, -52990, -2015, 0},{-58620, -53070, -2015, 0},{-58620, -53150, -2015, 0}};
//(To 315 degrees northeast) Route 5
private final int[][] START5 = {{-57233, -53554, -2015, 57344},{-57290, -53610, -2015, 57344},{-57346, -53667, -2015, 57344}};
private final int[][] GOAL5 = {{-55338, -55435, -2015, 57344},{-55395, -55491, -2015, 57344},{-55451, -55547, -2015, 57344}};
final int[][][] START = {START1, START2, START3, START4, START5};
final int[][][] GOAL = {GOAL1, GOAL2, GOAL3, GOAL4, GOAL5};
// @formatter:on
int npcIndex;
CopyOnWriteArrayList<L2Npc> spawns;
ScheduledFuture<?> spawnTask;
ScheduledFuture<?> deleteTask;
ScheduledFuture<?> cleanTask;
public Parade()
{
super(Parade.class.getSimpleName(), "ai/fantasy_isle");
// Starts at 8:00 and repeats every 6 hours.
final long diff = timeLeftMilli(8, 0, 0), cycle = 3600000L;
ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Start(), diff, cycle);
// Test - Starts 3 minutes after server startup and repeats every 20 minutes.
// final long diff = timeLeftMilli(8, 0, 0), cycle = 600000L;
// ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Start(), 180000L, cycle);
_log.info("Fantasy Isle: Parade starting at " + new SimpleDateFormat("yyyy/MM/dd HH:mm").format(System.currentTimeMillis() + diff) + " and is scheduled each next " + (cycle / 3600000) + " hours.");
}
void load()
{
npcIndex = 0;
spawns = new CopyOnWriteArrayList<>();
}
void clean()
{
if (spawns != null)
{
spawns.forEach(L2Npc::deleteMe);
}
spawns = null;
}
private long timeLeftMilli(int hh, int mm, int ss)
{
final int now = (GameTimeController.getInstance().getGameTicks() * 60) / 100;
int dd = ((hh * 3600) + (mm * 60) + ss) - (now % 86400);
if (dd < 0)
{
dd += 86400;
}
return (dd * 1000L) / 6L;
}
class Start implements Runnable
{
@Override
public void run()
{
load();
spawnTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Spawn(), 0, 5000);
deleteTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new Delete(), 10000, 1000);
cleanTask = ThreadPoolManager.getInstance().scheduleGeneral(new Clean(), 420000);
}
}
class Spawn implements Runnable
{
@Override
public void run()
{
for (int i = 0; i < 3; ++i)
{
if (npcIndex >= ACTORS.length)
{
spawnTask.cancel(false);
break;
}
final int npcId = ACTORS[npcIndex++];
if (npcId == 0)
{
continue;
}
for (int route = 0; route < 5; ++route)
{
final int[] start = START[route][i];
final int[] goal = GOAL[route][i];
final L2Npc actor = addSpawn(npcId, start[0], start[1], start[2], start[3], false, 0);
actor.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(goal[0], goal[1], goal[2], goal[3]));
spawns.add(actor);
}
}
}
}
class Delete implements Runnable
{
@Override
public void run()
{
if (spawns.size() <= 0)
{
return;
}
for (L2Npc actor : spawns)
{
if (actor != null)
{
if (actor.calculateDistance(actor.getXdestination(), actor.getYdestination(), 0, false, true) < (100 * 100))
{
actor.deleteMe();
spawns.remove(actor);
}
else if (!actor.isMoving())
{
actor.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(actor.getXdestination(), actor.getYdestination(), actor.getZdestination(), actor.getHeading()));
}
}
}
if (spawns.size() == 0)
{
deleteTask.cancel(false);
}
}
}
class Clean implements Runnable
{
@Override
public void run()
{
spawnTask.cancel(false);
spawnTask = null;
deleteTask.cancel(false);
deleteTask = null;
cleanTask.cancel(false);
cleanTask = null;
clean();
}
}
public static void main(String[] args)
{
new Parade();
}
}

View File

@@ -0,0 +1,523 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.fantasy_isle;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import ai.npc.AbstractNpcAI;
/**
* Talent Show AI.
* @author Kerberos
*/
final class TalentShow extends AbstractNpcAI
{
private static int MC = 32433;
// @formatter:off
private static int[] SINGERS =
{
32431, 32432
};
private static int[] CIRCUS =
{
32442, 32443, 32444, 32445, 32446
};
private static int[] INDIVIDUALS =
{
32439, 32440, 32441
};
private static int[] SHOWSTUFF =
{
32424, 32425, 32426, 32427, 32428
};
// @formatter:on
private static boolean IS_STARTED = false;
private static NpcStringId[] MESSAGES =
{
NpcStringId.HOW_COME_PEOPLE_ARE_NOT_HERE_WE_ARE_ABOUT_TO_START_THE_SHOW_HMM,
NpcStringId.UGH_I_HAVE_BUTTERFLIES_IN_MY_STOMACH_THE_SHOW_STARTS_SOON,
NpcStringId.THANK_YOU_ALL_FOR_COMING_HERE_TONIGHT,
NpcStringId.IT_IS_AN_HONOR_TO_HAVE_THE_SPECIAL_SHOW_TODAY,
NpcStringId.FANTASY_ISLE_IS_FULLY_COMMITTED_TO_YOUR_HAPPINESS,
NpcStringId.NOW_I_D_LIKE_TO_INTRODUCE_THE_MOST_BEAUTIFUL_SINGER_IN_ADEN_PLEASE_WELCOME_LEYLA_MIRA,
NpcStringId.HERE_SHE_COMES,
NpcStringId.THANK_YOU_VERY_MUCH_LEYLA,
NpcStringId.NOW_WE_RE_IN_FOR_A_REAL_TREAT,
NpcStringId.JUST_BACK_FROM_THEIR_WORLD_TOUR_PUT_YOUR_HANDS_TOGETHER_FOR_THE_FANTASY_ISLE_CIRCUS,
NpcStringId.COME_ON_EVERYONE,
NpcStringId.DID_YOU_LIKE_IT_THAT_WAS_SO_AMAZING,
NpcStringId.NOW_WE_ALSO_INVITED_INDIVIDUALS_WITH_SPECIAL_TALENTS,
NpcStringId.LET_S_WELCOME_THE_FIRST_PERSON_HERE,
NpcStringId.EMPTY3,
NpcStringId.OKAY_NOW_HERE_COMES_THE_NEXT_PERSON_COME_ON_UP_PLEASE,
NpcStringId.OH_IT_LOOKS_LIKE_SOMETHING_GREAT_IS_GOING_TO_HAPPEN_RIGHT,
NpcStringId.OH_MY,
NpcStringId.THAT_S_G_GREAT_NOW_HERE_COMES_THE_LAST_PERSON,
NpcStringId.NOW_THIS_IS_THE_END_OF_TODAY_S_SHOW,
NpcStringId.HOW_WAS_IT_I_HOPE_YOU_ALL_ENJOYED_IT,
NpcStringId.PLEASE_REMEMBER_THAT_FANTASY_ISLE_IS_ALWAYS_PLANNING_A_LOT_OF_GREAT_SHOWS_FOR_YOU,
NpcStringId.WELL_I_WISH_I_COULD_CONTINUE_ALL_NIGHT_LONG_BUT_THIS_IS_IT_FOR_TODAY_THANK_YOU,
NpcStringId.WE_LOVE_YOU
};
private class ShoutInfo
{
private final NpcStringId _npcStringId;
private final String _nextEvent;
private final int _time;
public ShoutInfo(NpcStringId npcStringId, String nextEvent, int time)
{
_npcStringId = npcStringId;
_nextEvent = nextEvent;
_time = time;
}
/**
* @return the _npcStringId
*/
public NpcStringId getNpcStringId()
{
return _npcStringId;
}
/**
* @return the _nextEvent
*/
public String getNextEvent()
{
return _nextEvent;
}
/**
* @return the _time
*/
public int getTime()
{
return _time;
}
}
private class WalkInfo
{
private final Location _charPos;
private final String _nextEvent;
private final int _time;
public WalkInfo(Location charPos, String nextEvent, int time)
{
_charPos = charPos;
_nextEvent = nextEvent;
_time = time;
}
/**
* @return the _charPos
*/
public Location getCharPos()
{
return _charPos;
}
/**
* @return the _nextEvent
*/
public String getNextEvent()
{
return _nextEvent;
}
/**
* @return the _time
*/
public int getTime()
{
return _time;
}
}
private static final Map<String, ShoutInfo> TALKS = new HashMap<>();
private static final Map<String, WalkInfo> WALKS = new HashMap<>();
private TalentShow()
{
super(TalentShow.class.getSimpleName(), "ai/fantasy_isle");
addSpawnId(32433, 32431, 32432, 32442, 32443, 32444, 32445, 32446, 32424, 32425, 32426, 32427, 32428);
load();
scheduleTimer();
}
private void load()
{
// TODO put this stuff in Routes.xml
TALKS.put("1", new ShoutInfo(MESSAGES[1], "2", 1000));
TALKS.put("2", new ShoutInfo(MESSAGES[2], "3", 6000));
TALKS.put("3", new ShoutInfo(MESSAGES[3], "4", 4000));
TALKS.put("4", new ShoutInfo(MESSAGES[4], "5", 5000));
TALKS.put("5", new ShoutInfo(MESSAGES[5], "6", 3000));
TALKS.put("8", new ShoutInfo(MESSAGES[9], "9", 5000));
TALKS.put("9", new ShoutInfo(MESSAGES[10], "10", 5000));
TALKS.put("12", new ShoutInfo(MESSAGES[12], "13", 5000));
TALKS.put("13", new ShoutInfo(MESSAGES[13], "14", 5000));
TALKS.put("15", new ShoutInfo(MESSAGES[14], "16", 5000));
TALKS.put("16", new ShoutInfo(MESSAGES[15], "17", 5000));
TALKS.put("18", new ShoutInfo(MESSAGES[17], "19", 5000));
TALKS.put("19", new ShoutInfo(MESSAGES[18], "20", 5000));
TALKS.put("21", new ShoutInfo(MESSAGES[19], "22", 5000));
TALKS.put("22", new ShoutInfo(MESSAGES[20], "23", 400));
TALKS.put("25", new ShoutInfo(MESSAGES[21], "26", 5000));
TALKS.put("26", new ShoutInfo(MESSAGES[22], "27", 5400));
WALKS.put("npc1_1", new WalkInfo(new Location(-56546, -56384, -2008, 0), "npc1_2", 1200));
WALKS.put("npc1_2", new WalkInfo(new Location(-56597, -56384, -2008, 0), "npc1_3", 1200));
WALKS.put("npc1_3", new WalkInfo(new Location(-56596, -56428, -2008, 0), "npc1_4", 1200));
WALKS.put("npc1_4", new WalkInfo(new Location(-56593, -56474, -2008, 0), "npc1_5", 1000));
WALKS.put("npc1_5", new WalkInfo(new Location(-56542, -56474, -2008, 0), "npc1_6", 1000));
WALKS.put("npc1_6", new WalkInfo(new Location(-56493, -56473, -2008, 0), "npc1_7", 2000));
WALKS.put("npc1_7", new WalkInfo(new Location(-56495, -56425, -2008, 0), "npc1_1", 4000));
WALKS.put("npc2_1", new WalkInfo(new Location(-56550, -56291, -2008, 0), "npc2_2", 1200));
WALKS.put("npc2_2", new WalkInfo(new Location(-56601, -56293, -2008, 0), "npc2_3", 1200));
WALKS.put("npc2_3", new WalkInfo(new Location(-56603, -56247, -2008, 0), "npc2_4", 1200));
WALKS.put("npc2_4", new WalkInfo(new Location(-56605, -56203, -2008, 0), "npc2_5", 1000));
WALKS.put("npc2_5", new WalkInfo(new Location(-56553, -56202, -2008, 0), "npc2_6", 1100));
WALKS.put("npc2_6", new WalkInfo(new Location(-56504, -56200, -2008, 0), "npc2_7", 2000));
WALKS.put("npc2_7", new WalkInfo(new Location(-56503, -56243, -2008, 0), "npc2_1", 4000));
WALKS.put("npc3_1", new WalkInfo(new Location(-56500, -56290, -2008, 0), "npc3_2", 1200));
WALKS.put("npc3_2", new WalkInfo(new Location(-56551, -56313, -2008, 0), "npc3_3", 1200));
WALKS.put("npc3_3", new WalkInfo(new Location(-56601, -56293, -2008, 0), "npc3_4", 1200));
WALKS.put("npc3_4", new WalkInfo(new Location(-56651, -56294, -2008, 0), "npc3_5", 1200));
WALKS.put("npc3_5", new WalkInfo(new Location(-56653, -56250, -2008, 0), "npc3_6", 1200));
WALKS.put("npc3_6", new WalkInfo(new Location(-56654, -56204, -2008, 0), "npc3_7", 1200));
WALKS.put("npc3_7", new WalkInfo(new Location(-56605, -56203, -2008, 0), "npc3_8", 1200));
WALKS.put("npc3_8", new WalkInfo(new Location(-56554, -56202, -2008, 0), "npc3_9", 1200));
WALKS.put("npc3_9", new WalkInfo(new Location(-56503, -56200, -2008, 0), "npc3_10", 1200));
WALKS.put("npc3_10", new WalkInfo(new Location(-56502, -56244, -2008, 0), "npc3_1", 900));
WALKS.put("npc4_1", new WalkInfo(new Location(-56495, -56381, -2008, 0), "npc4_2", 1200));
WALKS.put("npc4_2", new WalkInfo(new Location(-56548, -56383, -2008, 0), "npc4_3", 1200));
WALKS.put("npc4_3", new WalkInfo(new Location(-56597, -56383, -2008, 0), "npc4_4", 1200));
WALKS.put("npc4_4", new WalkInfo(new Location(-56643, -56385, -2008, 0), "npc4_5", 1200));
WALKS.put("npc4_5", new WalkInfo(new Location(-56639, -56436, -2008, 0), "npc4_6", 1200));
WALKS.put("npc4_6", new WalkInfo(new Location(-56639, -56473, -2008, 0), "npc4_7", 1200));
WALKS.put("npc4_7", new WalkInfo(new Location(-56589, -56473, -2008, 0), "npc4_8", 1200));
WALKS.put("npc4_8", new WalkInfo(new Location(-56541, -56473, -2008, 0), "npc4_9", 1200));
WALKS.put("npc4_9", new WalkInfo(new Location(-56496, -56473, -2008, 0), "npc4_10", 1200));
WALKS.put("npc4_10", new WalkInfo(new Location(-56496, -56429, -2008, 0), "npc4_1", 900));
WALKS.put("npc5_1", new WalkInfo(new Location(-56549, -56335, -2008, 0), "npc5_2", 1000));
WALKS.put("npc5_2", new WalkInfo(new Location(-56599, -56337, -2008, 0), "npc5_3", 2000));
WALKS.put("npc5_3", new WalkInfo(new Location(-56649, -56341, -2008, 0), "npc5_4", 26000));
WALKS.put("npc5_4", new WalkInfo(new Location(-56600, -56341, -2008, 0), "npc5_5", 1000));
WALKS.put("npc5_5", new WalkInfo(new Location(-56553, -56341, -2008, 0), "npc5_6", 1000));
WALKS.put("npc5_6", new WalkInfo(new Location(-56508, -56331, -2008, 0), "npc5_2", 8000));
WALKS.put("npc6_1", new WalkInfo(new Location(-56595, -56428, -2008, 0), "npc6_2", 1000));
WALKS.put("npc6_2", new WalkInfo(new Location(-56596, -56383, -2008, 0), "npc6_3", 1000));
WALKS.put("npc6_3", new WalkInfo(new Location(-56648, -56384, -2008, 0), "npc6_4", 1000));
WALKS.put("npc6_4", new WalkInfo(new Location(-56645, -56429, -2008, 0), "npc6_5", 1000));
WALKS.put("npc6_5", new WalkInfo(new Location(-56644, -56475, -2008, 0), "npc6_6", 1000));
WALKS.put("npc6_6", new WalkInfo(new Location(-56595, -56473, -2008, 0), "npc6_7", 1000));
WALKS.put("npc6_7", new WalkInfo(new Location(-56542, -56473, -2008, 0), "npc6_8", 1000));
WALKS.put("npc6_8", new WalkInfo(new Location(-56492, -56472, -2008, 0), "npc6_9", 1200));
WALKS.put("npc6_9", new WalkInfo(new Location(-56495, -56426, -2008, 0), "npc6_10", 2000));
WALKS.put("npc6_10", new WalkInfo(new Location(-56540, -56426, -2008, 0), "npc6_1", 3000));
WALKS.put("npc7_1", new WalkInfo(new Location(-56603, -56249, -2008, 0), "npc7_2", 1000));
WALKS.put("npc7_2", new WalkInfo(new Location(-56601, -56294, -2008, 0), "npc7_3", 1000));
WALKS.put("npc7_3", new WalkInfo(new Location(-56651, -56295, -2008, 0), "npc7_4", 1000));
WALKS.put("npc7_4", new WalkInfo(new Location(-56653, -56248, -2008, 0), "npc7_5", 1000));
WALKS.put("npc7_5", new WalkInfo(new Location(-56605, -56203, -2008, 0), "npc7_6", 1000));
WALKS.put("npc7_6", new WalkInfo(new Location(-56554, -56202, -2008, 0), "npc7_7", 1000));
WALKS.put("npc7_7", new WalkInfo(new Location(-56504, -56201, -2008, 0), "npc7_8", 1000));
WALKS.put("npc7_8", new WalkInfo(new Location(-56502, -56247, -2008, 0), "npc7_9", 1200));
WALKS.put("npc7_9", new WalkInfo(new Location(-56549, -56248, -2008, 0), "npc7_10", 2000));
WALKS.put("npc7_10", new WalkInfo(new Location(-56549, -56248, -2008, 0), "npc7_1", 3000));
WALKS.put("npc8_1", new WalkInfo(new Location(-56493, -56426, -2008, 0), "npc8_2", 1000));
WALKS.put("npc8_2", new WalkInfo(new Location(-56497, -56381, -2008, 0), "npc8_3", 1200));
WALKS.put("npc8_3", new WalkInfo(new Location(-56544, -56381, -2008, 0), "npc8_4", 1200));
WALKS.put("npc8_4", new WalkInfo(new Location(-56596, -56383, -2008, 0), "npc8_5", 1200));
WALKS.put("npc8_5", new WalkInfo(new Location(-56594, -56428, -2008, 0), "npc8_6", 900));
WALKS.put("npc8_6", new WalkInfo(new Location(-56645, -56429, -2008, 0), "npc8_7", 1200));
WALKS.put("npc8_7", new WalkInfo(new Location(-56647, -56384, -2008, 0), "npc8_8", 1200));
WALKS.put("npc8_8", new WalkInfo(new Location(-56649, -56362, -2008, 0), "npc8_9", 9200));
WALKS.put("npc8_9", new WalkInfo(new Location(-56654, -56429, -2008, 0), "npc8_10", 1200));
WALKS.put("npc8_10", new WalkInfo(new Location(-56644, -56474, -2008, 0), "npc8_11", 900));
WALKS.put("npc8_11", new WalkInfo(new Location(-56593, -56473, -2008, 0), "npc8_12", 1100));
WALKS.put("npc8_12", new WalkInfo(new Location(-56543, -56472, -2008, 0), "npc8_13", 1200));
WALKS.put("npc8_13", new WalkInfo(new Location(-56491, -56471, -2008, 0), "npc8_1", 1200));
WALKS.put("npc9_1", new WalkInfo(new Location(-56505, -56246, -2008, 0), "npc9_2", 1000));
WALKS.put("npc9_2", new WalkInfo(new Location(-56504, -56291, -2008, 0), "npc9_3", 1200));
WALKS.put("npc9_3", new WalkInfo(new Location(-56550, -56291, -2008, 0), "npc9_4", 1200));
WALKS.put("npc9_4", new WalkInfo(new Location(-56600, -56292, -2008, 0), "npc9_5", 1200));
WALKS.put("npc9_5", new WalkInfo(new Location(-56603, -56248, -2008, 0), "npc9_6", 900));
WALKS.put("npc9_6", new WalkInfo(new Location(-56653, -56249, -2008, 0), "npc9_7", 1200));
WALKS.put("npc9_7", new WalkInfo(new Location(-56651, -56294, -2008, 0), "npc9_8", 1200));
WALKS.put("npc9_8", new WalkInfo(new Location(-56650, -56316, -2008, 0), "npc9_9", 9200));
WALKS.put("npc9_9", new WalkInfo(new Location(-56660, -56250, -2008, 0), "npc9_10", 1200));
WALKS.put("npc9_10", new WalkInfo(new Location(-56656, -56205, -2008, 0), "npc9_11", 900));
WALKS.put("npc9_11", new WalkInfo(new Location(-56606, -56204, -2008, 0), "npc9_12", 1100));
WALKS.put("npc9_12", new WalkInfo(new Location(-56554, -56203, -2008, 0), "npc9_13", 1200));
WALKS.put("npc9_13", new WalkInfo(new Location(-56506, -56203, -2008, 0), "npc9_1", 1200));
WALKS.put("24", new WalkInfo(new Location(-56730, -56340, -2008, 0), "25", 1800));
WALKS.put("27", new WalkInfo(new Location(-56702, -56340, -2008, 0), "29", 1800));
}
private void scheduleTimer()
{
final int gameTime = GameTimeController.getInstance().getGameTime();
final int hours = (gameTime / 60) % 24;
final int minutes = gameTime % 60;
int hourDiff, minDiff;
hourDiff = 20 - hours;
if (hourDiff < 0)
{
hourDiff = 24 - (hourDiff *= -1);
}
minDiff = 30 - minutes;
if (minDiff < 0)
{
minDiff = 60 - (minDiff *= -1);
}
long diff;
hourDiff *= 3600000;
minDiff *= 60000;
diff = hourDiff + minDiff;
_log.info("Fantasy Isle: MC show script starting at " + (new SimpleDateFormat("dd/MM/yyyy HH:mm:ss")).format(System.currentTimeMillis() + diff) + " and is scheduled each next 4 hours.");
startQuestTimer("Start", diff, null, null); // first start
}
private void autoChat(L2Npc npc, NpcStringId npcString, ChatType type)
{
npc.broadcastPacket(new NpcSay(npc.getObjectId(), type, npc.getId(), npcString));
}
@Override
public String onSpawn(L2Npc npc)
{
if (IS_STARTED)
{
switch (npc.getId())
{
case 32433:
{
autoChat(npc, MESSAGES[0], ChatType.NPC_SHOUT);
startQuestTimer("1", 30000, npc, null);
break;
}
case 32431:
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56657, -56338, -2008, 33102));
startQuestTimer("social1", 6000, npc, null, true);
startQuestTimer("7", 215000, npc, null);
break;
}
case 32432:
{
startQuestTimer("social1", 6000, npc, null, true);
startQuestTimer("7", 215000, npc, null);
break;
}
case 32442:
case 32443:
case 32444:
case 32445:
case 32446:
{
startQuestTimer("11", 100000, npc, null);
break;
}
case 32424:
case 32425:
case 32426:
case 32427:
case 32428:
{
startQuestTimer("social1", 5500, npc, null);
startQuestTimer("social1", 12500, npc, null);
startQuestTimer("28", 19700, npc, null);
break;
}
}
}
return super.onSpawn(npc);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if ((event == null) || event.isEmpty())
{
_log.warning("MC_Show: Null/Empty event for npc " + npc + " and player " + player + "!");
return null;
}
if (event.equalsIgnoreCase("Start"))
{
IS_STARTED = true;
addSpawn(MC, -56698, -56430, -2008, 32768, false, 0);
startQuestTimer("Start", 14400000L, null, null); // repeat
}
else if ((npc != null) && IS_STARTED)
{
// TODO switch on event
if (event.equalsIgnoreCase("6"))
{
autoChat(npc, MESSAGES[6], ChatType.NPC_SHOUT);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56511, -56647, -2008, 36863));
npc.broadcastPacket(new PlaySound(1, "NS22_F", 0, 0, 0, 0, 0));
addSpawn(SINGERS[0], -56344, -56328, -2008, 32768, false, 224000);
addSpawn(SINGERS[1], -56552, -56245, -2008, 36863, false, 224000);
addSpawn(SINGERS[1], -56546, -56426, -2008, 28672, false, 224000);
addSpawn(SINGERS[1], -56570, -56473, -2008, 28672, false, 224000);
addSpawn(SINGERS[1], -56594, -56516, -2008, 28672, false, 224000);
addSpawn(SINGERS[1], -56580, -56203, -2008, 36863, false, 224000);
addSpawn(SINGERS[1], -56606, -56157, -2008, 36863, false, 224000);
startQuestTimer("7", 215000, npc, null);
}
else if (event.equalsIgnoreCase("7"))
{
switch (npc.getId())
{
case 32433:
{
autoChat(npc, MESSAGES[7], ChatType.NPC_SHOUT);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56698, -56430, -2008, 32768));
startQuestTimer("8", 12000, npc, null);
break;
}
default:
{
cancelQuestTimer("social1", npc, null);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56594, -56064, -2008, 32768));
break;
}
}
}
else if (event.equalsIgnoreCase("10"))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56483, -56665, -2034, 32768));
npc.broadcastPacket(new PlaySound(1, "TP05_F", 0, 0, 0, 0, 0));
startQuestTimer("npc1_1", 3000, addSpawn(CIRCUS[0], -56495, -56375, -2008, 32768, false, 101000), null);
startQuestTimer("npc2_1", 3000, addSpawn(CIRCUS[0], -56491, -56289, -2008, 32768, false, 101000), null);
startQuestTimer("npc3_1", 3000, addSpawn(CIRCUS[1], -56502, -56246, -2008, 32768, false, 101000), null);
startQuestTimer("npc4_1", 3000, addSpawn(CIRCUS[1], -56496, -56429, -2008, 32768, false, 101000), null);
startQuestTimer("npc5_1", 3500, addSpawn(CIRCUS[2], -56505, -56334, -2008, 32768, false, 101000), null);
startQuestTimer("npc6_1", 4000, addSpawn(CIRCUS[3], -56545, -56427, -2008, 32768, false, 101000), null);
startQuestTimer("npc7_1", 4000, addSpawn(CIRCUS[3], -56552, -56248, -2008, 32768, false, 101000), null);
startQuestTimer("npc8_1", 3000, addSpawn(CIRCUS[4], -56493, -56473, -2008, 32768, false, 101000), null);
startQuestTimer("npc9_1", 3000, addSpawn(CIRCUS[4], -56504, -56201, -2008, 32768, false, 101000), null);
startQuestTimer("11", 100000, npc, null);
}
else if (event.equalsIgnoreCase("11"))
{
switch (npc.getId())
{
case 32433:
{
autoChat(npc, MESSAGES[11], ChatType.NPC_SHOUT);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56698, -56430, -2008, 32768));
startQuestTimer("12", 5000, npc, null);
break;
}
default:
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56343, -56330, -2008, 32768));
break;
}
}
}
else if (event.equalsIgnoreCase("14"))
{
startQuestTimer("social1", 2000, addSpawn(INDIVIDUALS[0], -56700, -56385, -2008, 32768, false, 49000), null);
startQuestTimer("15", 7000, npc, null);
}
else if (event.equalsIgnoreCase("17"))
{
autoChat(npc, MESSAGES[16], ChatType.NPC_SHOUT);
startQuestTimer("social1", 2000, addSpawn(INDIVIDUALS[1], -56700, -56340, -2008, 32768, false, 32000), null);
startQuestTimer("18", 9000, npc, null);
}
else if (event.equalsIgnoreCase("20"))
{
startQuestTimer("social1", 2000, addSpawn(INDIVIDUALS[2], -56703, -56296, -2008, 32768, false, 13000), null);
startQuestTimer("21", 8000, npc, null);
}
else if (event.equalsIgnoreCase("23"))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56702, -56340, -2008, 32768));
startQuestTimer("24", 2800, npc, null);
addSpawn(SHOWSTUFF[0], -56672, -56406, -2000, 32768, false, 20900);
addSpawn(SHOWSTUFF[1], -56648, -56368, -2000, 32768, false, 20900);
addSpawn(SHOWSTUFF[2], -56608, -56338, -2000, 32768, false, 20900);
addSpawn(SHOWSTUFF[3], -56652, -56307, -2000, 32768, false, 20900);
addSpawn(SHOWSTUFF[4], -56672, -56272, -2000, 32768, false, 20900);
}
else if (event.equalsIgnoreCase("28"))
{
autoChat(npc, MESSAGES[23], ChatType.NPC_GENERAL);
startQuestTimer("social1", 1, npc, null);
}
else if (event.equalsIgnoreCase("29"))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(-56730, -56340, -2008, 32768));
startQuestTimer("clean_npc", 4100, npc, null);
startQuestTimer("timer_check", 60000, null, null, true);
}
else if (event.equalsIgnoreCase("social1"))
{
npc.broadcastSocialAction(1);
}
else if (event.equalsIgnoreCase("clean_npc"))
{
IS_STARTED = false;
npc.deleteMe();
}
else if (TALKS.containsKey(event))
{
final ShoutInfo si = TALKS.get(event);
if (si != null)
{
autoChat(npc, si.getNpcStringId(), ChatType.NPC_SHOUT);
startQuestTimer(si.getNextEvent(), si.getTime(), npc, null);
}
}
else if (WALKS.containsKey(event))
{
final WalkInfo wi = WALKS.get(event);
if (wi != null)
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, wi.getCharPos());
startQuestTimer(wi.getNextEvent(), wi.getTime(), npc, null);
}
}
}
return null;
}
public static void main(String[] args)
{
new TalentShow();
}
}

View File

@@ -0,0 +1,309 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import java.util.logging.Level;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.util.Rnd;
import ai.npc.AbstractNpcAI;
/**
* @author HorridoJoho, janiko, FinalDestination, lion
*/
public final class AltarsOfSacrifice extends AbstractNpcAI
{
private final class Altar
{
private final ILocational _middlePoint;
private final int[] _bossNpcIds;
private L2Npc _spawnedBoss;
protected Altar(ILocational middlePoint, int... bossNpcIds)
{
_middlePoint = middlePoint;
_bossNpcIds = bossNpcIds;
_spawnedBoss = null;
}
protected void spawnBoss() throws Exception
{
if (!hasBosses() || (_spawnedBoss != null))
{
throw new IllegalStateException();
}
final L2Spawn spawn = new L2Spawn(_bossNpcIds[Rnd.get(_bossNpcIds.length)]);
spawn.setAmount(1);
spawn.setHeading(Rnd.get(65536));
final int radius = Rnd.get(BOSS_MIN_SPAWN_RADIUS, BOSS_MAX_SPAWN_RADIUS);
final double angleRadians = Rnd.get() * 2 * Math.PI;
final int spawnX = (int) (radius * Math.cos(angleRadians)) + _middlePoint.getX();
final int spawnY = (int) (radius * Math.sin(angleRadians)) + _middlePoint.getY();
spawn.setXYZ(spawnX, spawnY, GeoData.getInstance().getHeight(spawnX, spawnY, _middlePoint.getZ()));
spawn.stopRespawn();
_spawnedBoss = spawn.spawnOne(false);
}
protected void despawnBoss()
{
if (_spawnedBoss != null)
{
_spawnedBoss.deleteMe();
_spawnedBoss = null;
}
}
protected void unload()
{
despawnBoss();
}
protected boolean hasBosses()
{
return _bossNpcIds.length > 0;
}
protected boolean isBossFighting()
{
return (_spawnedBoss != null) && _spawnedBoss.isInCombat();
}
}
private static final String EVT_SPAWN_BOSS_PRE = "spawnboss";
private static final String EVT_DESPAWN_BOSS_PRE = "despawnboss";
private static final int BOSS_MIN_SPAWN_RADIUS = 250;
private static final int BOSS_MAX_SPAWN_RADIUS = 500;
// every 240 minutes/4 hours, altars change
private static final long ALTAR_STATE_CHANGE_DELAY = 240 * 60 * 1000;
// disabling formatter here to make this easily readable
// @formatter:off
private final Altar[] _altars = new Altar[]
{
// TalkingIsland
new Altar
(
new Location(-92481, 244812, -3505)
),
// Elven
new Altar
(
new Location(40241, 53974, -3262)
),
// DarkElven
new Altar
(
new Location(1851, 21697, -3305),
25750
),
// Dwarven
new Altar
(
new Location(130133, -180968, -3271),
25800, 25782
),
// Orc
new Altar
(
new Location(-45329, -118327, -166),
25779
),
// Kamael
new Altar
(
new Location(-104031, 45059, -1417)
),
// Oren
new Altar
(
new Location(80188, 47037, -3109),
25767, 25770
),
// Gludin
new Altar
(
new Location(-86620, 151536, -3018),
25735, 25738, 25741
),
// Gludio
new Altar
(
new Location(-14152, 120674, -2935),
25744, 25747
),
// Dion
new Altar
(
new Location(16715, 148320, -3210),
25753, 25754, 25757
),
// Heine
new Altar
(
new Location(120123, 219164, -3319),
25773, 25776
),
// Giran
new Altar
(
new Location(80712, 142538, -3487),
25760, 25763, 25766
),
// Aden
new Altar
(
new Location(152720, 24714, -2083),
25793, 25794, 25797
),
// Rune
new Altar
(
new Location(28010, -49175, -1278)
),
// Goddard
new Altar
(
new Location(152274, -57706, -3383),
25787, 25790
),
// Schutgart
new Altar
(
new Location(82066, -139418, -2220),
25784
),
// Primeval
new Altar
(
new Location(10998, -24068, -3603)
),
// Dragon Valley
new Altar
(
new Location(69592, 118694, -3417)
)
};
// @formatter:on
public static void main(String[] args)
{
new AltarsOfSacrifice();
}
private AltarsOfSacrifice()
{
super("AltarsOfSacrifice", "ai/group_template");
for (int i = 0; i < _altars.length; ++i)
{
if (_altars[i].hasBosses())
{
startQuestTimer(makeSpawnBossEvt(i), ALTAR_STATE_CHANGE_DELAY, null, null);
}
}
}
private String makeSpawnBossEvt(int altarIndex)
{
return EVT_SPAWN_BOSS_PRE + altarIndex;
}
private String makeDespawnBossEvt(int altarIndex)
{
return EVT_DESPAWN_BOSS_PRE + altarIndex;
}
private boolean isSpawnBossEvt(String event)
{
return event.startsWith(EVT_SPAWN_BOSS_PRE);
}
private boolean isDespawnBossEvt(String event)
{
return event.startsWith(EVT_DESPAWN_BOSS_PRE);
}
private int getSpawnBossIndex(String event)
{
return Integer.parseInt(event.substring(EVT_SPAWN_BOSS_PRE.length()));
}
private int getDespawnBossIndex(String event)
{
return Integer.parseInt(event.substring(EVT_DESPAWN_BOSS_PRE.length()));
}
@Override
public boolean unload(boolean removeFromList)
{
_log.info(getClass().getSimpleName() + ": Unloading altars due to script unloading.");
for (Altar altar : _altars)
{
altar.unload();
}
return super.unload(removeFromList);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (isSpawnBossEvt(event))
{
final int altarIndex = getSpawnBossIndex(event);
final Altar altar = _altars[altarIndex];
try
{
altar.spawnBoss();
startQuestTimer(makeDespawnBossEvt(altarIndex), ALTAR_STATE_CHANGE_DELAY, null, null);
}
catch (Exception e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Failed to spawn altar boss.", e);
// let's try again to spawn it in 5 seconds
startQuestTimer(event, 5000, null, null);
}
}
else if (isDespawnBossEvt(event))
{
final int altarIndex = getDespawnBossIndex(event);
final Altar altar = _altars[altarIndex];
if (altar.isBossFighting())
{
// periodically check if the altar boss is fighting, only despawn when not fighting anymore
startQuestTimer(event, 5000, null, null);
}
else
{
altar.despawnBoss();
startQuestTimer(makeSpawnBossEvt(altarIndex), ALTAR_STATE_CHANGE_DELAY, null, null);
}
}
return null;
}
}

View File

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

View File

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

View File

@@ -0,0 +1,297 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import java.util.EnumMap;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Dragon Valley AI.
* @author St3eT
*/
public final class DragonValley extends AbstractNpcAI
{
// NPC
private static final int NECROMANCER_OF_THE_VALLEY = 22858;
private static final int EXPLODING_ORC_GHOST = 22818;
private static final int WRATHFUL_ORC_GHOST = 22819;
private static final int DRAKOS_ASSASSIN = 22823;
private static final int[] SUMMON_NPC =
{
22822, // Drakos Warrior
22824, // Drakos Guardian
22862, // Drakos Hunter
};
private static final int[] SPAWN_ANIMATION =
{
22826, // Scorpion Bones
22823, // Drakos Assassin
22828, // Parasitic Leech
};
private static final int[] SPOIL_REACT_MONSTER =
{
22822, // Drakos Warrior
22823, // Drakos Assassin
22824, // Drakos Guardian
22825, // Giant Scorpion Bones
22826, // Scorpion Bones
22827, // Batwing Drake
22828, // Parasitic Leech
22829, // Emerald Drake
22830, // Gem Dragon
22831, // Dragon Tracker of the Valley
22832, // Dragon Scout of the Valley
22833, // Sand Drake Tracker
22834, // Dust Dragon Tracker
22860, // Hungry Parasitic Leech
22861, // Hard Scorpion Bones
22862, // Drakos Hunter
};
// Items
private static final int GREATER_HERB_OF_MANA = 8604;
private static final int SUPERIOR_HERB_OF_MANA = 8605;
// Skills
private static final SkillHolder SELF_DESTRUCTION = new SkillHolder(6850, 1);
private static final SkillHolder MORALE_BOOST1 = new SkillHolder(6885, 1);
private static final SkillHolder MORALE_BOOST2 = new SkillHolder(6885, 2);
private static final SkillHolder MORALE_BOOST3 = new SkillHolder(6885, 3);
// Misc
private static final int MIN_DISTANCE = 1500;
private static final int MIN_MEMBERS = 3;
private static final int MIN_LVL = 80;
private static final int CLASS_LVL = 3;
private static final EnumMap<ClassId, Double> CLASS_POINTS = new EnumMap<>(ClassId.class);
{
CLASS_POINTS.put(ClassId.adventurer, 0.2);
CLASS_POINTS.put(ClassId.arcanaLord, 1.5);
CLASS_POINTS.put(ClassId.archmage, 0.3);
CLASS_POINTS.put(ClassId.cardinal, -0.6);
CLASS_POINTS.put(ClassId.dominator, 0.2);
CLASS_POINTS.put(ClassId.doombringer, 0.2);
CLASS_POINTS.put(ClassId.doomcryer, 0.1);
CLASS_POINTS.put(ClassId.dreadnought, 0.7);
CLASS_POINTS.put(ClassId.duelist, 0.2);
CLASS_POINTS.put(ClassId.elementalMaster, 1.4);
CLASS_POINTS.put(ClassId.evaSaint, -0.6);
CLASS_POINTS.put(ClassId.evaTemplar, 0.8);
CLASS_POINTS.put(ClassId.femaleSoulhound, 0.4);
CLASS_POINTS.put(ClassId.fortuneSeeker, 0.9);
CLASS_POINTS.put(ClassId.ghostHunter, 0.2);
CLASS_POINTS.put(ClassId.ghostSentinel, 0.2);
CLASS_POINTS.put(ClassId.grandKhavatari, 0.2);
CLASS_POINTS.put(ClassId.hellKnight, 0.6);
CLASS_POINTS.put(ClassId.hierophant, 0.0);
CLASS_POINTS.put(ClassId.judicator, 0.1);
CLASS_POINTS.put(ClassId.moonlightSentinel, 0.2);
CLASS_POINTS.put(ClassId.maestro, 0.7);
CLASS_POINTS.put(ClassId.maleSoulhound, 0.4);
CLASS_POINTS.put(ClassId.mysticMuse, 0.3);
CLASS_POINTS.put(ClassId.phoenixKnight, 0.6);
CLASS_POINTS.put(ClassId.sagittarius, 0.2);
CLASS_POINTS.put(ClassId.shillienSaint, -0.6);
CLASS_POINTS.put(ClassId.shillienTemplar, 0.8);
CLASS_POINTS.put(ClassId.soultaker, 0.3);
CLASS_POINTS.put(ClassId.spectralDancer, 0.4);
CLASS_POINTS.put(ClassId.spectralMaster, 1.4);
CLASS_POINTS.put(ClassId.stormScreamer, 0.3);
CLASS_POINTS.put(ClassId.swordMuse, 0.4);
CLASS_POINTS.put(ClassId.titan, 0.3);
CLASS_POINTS.put(ClassId.trickster, 0.5);
CLASS_POINTS.put(ClassId.windRider, 0.2);
}
private DragonValley()
{
super(DragonValley.class.getSimpleName(), "ai/group_template");
addAttackId(NECROMANCER_OF_THE_VALLEY);
addAttackId(SUMMON_NPC);
addKillId(NECROMANCER_OF_THE_VALLEY);
addKillId(SPOIL_REACT_MONSTER);
addSpawnId(EXPLODING_ORC_GHOST, NECROMANCER_OF_THE_VALLEY);
addSpawnId(SPOIL_REACT_MONSTER);
addSpellFinishedId(EXPLODING_ORC_GHOST);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("SELF_DESTRUCTION") && (npc != null) && !npc.isDead())
{
final L2Playable playable = npc.getVariables().getObject("playable", L2Playable.class);
if ((playable != null) && (npc.calculateDistance(playable, true, false) < 250))
{
npc.disableCoreAI(true);
npc.doCast(SELF_DESTRUCTION.getSkill());
}
else if (playable != null)
{
startQuestTimer("SELF_DESTRUCTION", 3000, npc, null);
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.getId() == NECROMANCER_OF_THE_VALLEY)
{
spawnGhost(npc, attacker, isSummon, 1);
}
else
{
if ((npc.getCurrentHp() < (npc.getMaxHp() / 2)) && (getRandom(100) < 5) && npc.isScriptValue(0))
{
npc.setScriptValue(1);
final int rnd = getRandom(3, 5);
for (int i = 0; i < rnd; i++)
{
final L2Playable playable = isSummon ? attacker.getSummon() : attacker;
final L2Npc minion = addSpawn(DRAKOS_ASSASSIN, npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), true, 0, true);
addAttackDesire(minion, playable);
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.getId() == NECROMANCER_OF_THE_VALLEY)
{
spawnGhost(npc, killer, isSummon, 20);
}
else if (((L2Attackable) npc).isSpoiled())
{
npc.dropItem(killer, getRandom(GREATER_HERB_OF_MANA, SUPERIOR_HERB_OF_MANA), 1);
manageMoraleBoost(killer, npc);
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
((L2Attackable) npc).setOnKillDelay(0);
if (npc.getId() == EXPLODING_ORC_GHOST)
{
startQuestTimer("SELF_DESTRUCTION", 3000, npc, null);
}
else if (Util.contains(SPAWN_ANIMATION, npc.getId()))
{
npc.setShowSummonAnimation(true);
}
return super.onSpawn(npc);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if (skill == SELF_DESTRUCTION.getSkill())
{
npc.doDie(player);
}
return super.onSpellFinished(npc, player, skill);
}
private void manageMoraleBoost(L2PcInstance player, L2Npc npc)
{
double points = 0;
int moraleBoostLv = 0;
if (player.isInParty() && (player.getParty().getMemberCount() >= MIN_MEMBERS) && (npc != null))
{
for (L2PcInstance member : player.getParty().getMembers())
{
if ((member.getLevel() >= MIN_LVL) && (member.getClassId().level() >= CLASS_LVL) && (npc.calculateDistance(member, true, false) < MIN_DISTANCE))
{
points += CLASS_POINTS.get(member.getClassId());
}
}
if (points >= 3)
{
moraleBoostLv = 3;
}
else if (points >= 2)
{
moraleBoostLv = 2;
}
else if (points >= 1)
{
moraleBoostLv = 1;
}
for (L2PcInstance member : player.getParty().getMembers())
{
if (npc.calculateDistance(member, true, false) < MIN_DISTANCE)
{
switch (moraleBoostLv)
{
case 1:
MORALE_BOOST1.getSkill().applyEffects(member, member);
break;
case 2:
MORALE_BOOST2.getSkill().applyEffects(member, member);
break;
case 3:
MORALE_BOOST3.getSkill().applyEffects(member, member);
break;
}
}
}
}
}
private void spawnGhost(L2Npc npc, L2PcInstance player, boolean isSummon, int chance)
{
if ((npc.getScriptValue() < 2) && (getRandom(100) < chance))
{
int val = npc.getScriptValue();
final L2Playable attacker = isSummon ? player.getSummon() : player;
final L2Npc ghost1 = addSpawn(EXPLODING_ORC_GHOST, npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), false, 0, true);
ghost1.getVariables().set("playable", attacker);
addAttackDesire(ghost1, attacker);
val++;
if ((val < 2) && (getRandomBoolean()))
{
final L2Npc ghost2 = addSpawn(WRATHFUL_ORC_GHOST, npc.getX(), npc.getY(), npc.getZ() + 20, npc.getHeading(), false, 0, false);
addAttackDesire(ghost2, attacker);
val++;
}
npc.setScriptValue(val);
}
}
public static void main(String[] args)
{
new DragonValley();
}
}

View File

@@ -0,0 +1,88 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import ai.npc.AbstractNpcAI;
/**
* Fairy Trees AI.
* @author Charus
*/
public class FairyTrees extends AbstractNpcAI
{
// NPC
private static final int SOUL_GUARDIAN = 27189; // Soul of Tree Guardian
private static final int[] MOBS =
{
27185, // Fairy Tree of Wind
27186, // Fairy Tree of Star
27187, // Fairy Tree of Twilight
27188, // Fairy Tree of Abyss
};
// Skill
private static SkillHolder VENOMOUS_POISON = new SkillHolder(4243, 1); // Venomous Poison
// Misc
private static final int MIN_DISTANCE = 1500;
private FairyTrees()
{
super(FairyTrees.class.getSimpleName(), "ai/group_template");
addKillId(MOBS);
addSpawnId(MOBS);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.calculateDistance(killer, true, false) <= MIN_DISTANCE)
{
for (int i = 0; i < 20; i++)
{
final L2Npc guardian = addSpawn(SOUL_GUARDIAN, npc, false, 30000);
final L2Playable attacker = isSummon ? killer.getSummon() : killer;
addAttackDesire(guardian, attacker);
if (getRandomBoolean())
{
guardian.setTarget(attacker);
guardian.doCast(VENOMOUS_POISON.getSkill());
}
}
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setIsNoRndWalk(true);
npc.setIsImmobilized(true);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new FairyTrees();
}
}

View File

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

View File

@@ -0,0 +1,83 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Flee Monsters AI.
* @author Pandragon, NosBit
*/
public final class FleeMonsters extends AbstractNpcAI
{
// NPCs
private static final int[] MOBS =
{
18150, // Victim
18151, // Victim
18152, // Victim
18153, // Victim
18154, // Victim
18155, // Victim
18156, // Victim
18157, // Victim
20002, // Rabbit
20432, // Elpy
22228, // Grey Elpy
25604, // Mutated Elpy
};
// Misc
private static final int FLEE_DISTANCE = 500;
private FleeMonsters()
{
super(FleeMonsters.class.getSimpleName(), "ai/group_template");
addAttackId(MOBS);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
npc.disableCoreAI(true);
npc.setRunning();
final L2Summon summon = isSummon ? attacker.getSummon() : null;
final ILocational attackerLoc = summon == null ? attacker : summon;
final double radians = Math.toRadians(Util.calculateAngleFrom(attackerLoc, npc));
final int posX = (int) (npc.getX() + (FLEE_DISTANCE * Math.cos(radians)));
final int posY = (int) (npc.getY() + (FLEE_DISTANCE * Math.sin(radians)));
final int posZ = npc.getZ();
final Location destination = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, attacker.getInstanceId());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
return super.onAttack(npc, attacker, damage, isSummon);
}
public static void main(String[] args)
{
new FleeMonsters();
}
}

View File

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

View File

@@ -0,0 +1,112 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Giant's Cave AI.
* @author Gnacik, St3eT
*/
public final class GiantsCave extends AbstractNpcAI
{
// NPC
private static final int[] SCOUTS =
{
22668, // Gamlin (Scout)
22669, // Leogul (Scout)
};
private GiantsCave()
{
super(GiantsCave.class.getSimpleName(), "ai/group_template");
addAttackId(SCOUTS);
addAggroRangeEnterId(SCOUTS);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("ATTACK") && (player != null) && (npc != null) && !npc.isDead())
{
if (npc.getId() == SCOUTS[0]) // Gamlin
{
broadcastNpcSay(npc, ChatType.NPC_SHOUT, NpcStringId.INTRUDER_DETECTED);
}
else
{
broadcastNpcSay(npc, ChatType.NPC_SHOUT, NpcStringId.OH_GIANTS_AN_INTRUDER_HAS_BEEN_DISCOVERED);
}
for (L2Character characters : npc.getKnownList().getKnownCharactersInRadius(450))
{
if ((characters != null) && (characters.isAttackable()) && (getRandomBoolean()))
{
addAttackDesire((L2Npc) characters, player);
}
}
}
else if (event.equals("CLEAR") && (npc != null) && !npc.isDead())
{
npc.setScriptValue(0);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("ATTACK", 6000, npc, attacker);
startQuestTimer("CLEAR", 120000, npc, null);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
if (getRandomBoolean())
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.YOU_GUYS_ARE_DETECTED);
}
else
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.WHAT_KIND_OF_CREATURES_ARE_YOU);
}
startQuestTimer("ATTACK", 6000, npc, player);
startQuestTimer("CLEAR", 120000, npc, null);
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
public static void main(String[] args)
{
new GiantsCave();
}
}

View File

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

View File

@@ -0,0 +1,81 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import ai.npc.AbstractNpcAI;
/**
* Isle of Prayer AI.
* @author Zoey76
*/
public final class IsleOfPrayer extends AbstractNpcAI
{
// Items
private static final int YELLOW_SEED_OF_EVIL_SHARD = 9593;
private static final int GREEN_SEED_OF_EVIL_SHARD = 9594;
private static final int BLUE_SEED_OF_EVIL_SHARD = 9595;
private static final int RED_SEED_OF_EVIL_SHARD = 9596;
// Monsters
private static final Map<Integer, ItemChanceHolder> MONSTERS = new HashMap<>();
static
{
MONSTERS.put(22257, new ItemChanceHolder(YELLOW_SEED_OF_EVIL_SHARD, 2087)); // Island Guardian
MONSTERS.put(22258, new ItemChanceHolder(YELLOW_SEED_OF_EVIL_SHARD, 2147)); // White Sand Mirage
MONSTERS.put(22259, new ItemChanceHolder(YELLOW_SEED_OF_EVIL_SHARD, 2642)); // Muddy Coral
MONSTERS.put(22260, new ItemChanceHolder(YELLOW_SEED_OF_EVIL_SHARD, 2292)); // Kleopora
MONSTERS.put(22261, new ItemChanceHolder(GREEN_SEED_OF_EVIL_SHARD, 1171)); // Seychelles
MONSTERS.put(22262, new ItemChanceHolder(GREEN_SEED_OF_EVIL_SHARD, 1173)); // Naiad
MONSTERS.put(22263, new ItemChanceHolder(GREEN_SEED_OF_EVIL_SHARD, 1403)); // Sonneratia
MONSTERS.put(22264, new ItemChanceHolder(GREEN_SEED_OF_EVIL_SHARD, 1207)); // Castalia
MONSTERS.put(22265, new ItemChanceHolder(RED_SEED_OF_EVIL_SHARD, 575)); // Chrysocolla
MONSTERS.put(22266, new ItemChanceHolder(RED_SEED_OF_EVIL_SHARD, 493)); // Pythia
MONSTERS.put(22267, new ItemChanceHolder(RED_SEED_OF_EVIL_SHARD, 770)); // Dark Water Dragon
MONSTERS.put(22268, new ItemChanceHolder(BLUE_SEED_OF_EVIL_SHARD, 987)); // Shade
MONSTERS.put(22269, new ItemChanceHolder(BLUE_SEED_OF_EVIL_SHARD, 995)); // Shade
MONSTERS.put(22270, new ItemChanceHolder(BLUE_SEED_OF_EVIL_SHARD, 1008)); // Water Dragon Detractor
MONSTERS.put(22271, new ItemChanceHolder(BLUE_SEED_OF_EVIL_SHARD, 1008)); // Water Dragon Detractor
}
private IsleOfPrayer()
{
super(IsleOfPrayer.class.getSimpleName(), "ai/group_template");
addKillId(MONSTERS.keySet());
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
final ItemChanceHolder holder = MONSTERS.get(npc.getId());
if (getRandom(10000) <= holder.getChance())
{
npc.dropItem(killer, holder);
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new IsleOfPrayer();
}
}

View File

@@ -0,0 +1,142 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.ValidateLocation;
import ai.npc.AbstractNpcAI;
/**
* Lair of Antharas AI.
* @author St3eT, UnAfraid
*/
public final class LairOfAntharas extends AbstractNpcAI
{
// NPC
final private static int KNORIKS = 22857;
final private static int DRAGON_KNIGHT = 22844;
final private static int DRAGON_KNIGHT2 = 22845;
final private static int ELITE_DRAGON_KNIGHT = 22846;
final private static int DRAGON_GUARD = 22852;
final private static int DRAGON_MAGE = 22853;
// Misc
final private static int KNIGHT_CHANCE = 30;
final private static int KNORIKS_CHANCE = 60;
final private static int KNORIKS_CHANCE2 = 50;
private LairOfAntharas()
{
super(LairOfAntharas.class.getSimpleName(), "ai/group_template");
addKillId(DRAGON_KNIGHT, DRAGON_KNIGHT2, DRAGON_GUARD, DRAGON_MAGE);
addSpawnId(DRAGON_KNIGHT, DRAGON_KNIGHT2, DRAGON_GUARD, DRAGON_MAGE);
addMoveFinishedId(DRAGON_GUARD, DRAGON_MAGE);
addAggroRangeEnterId(KNORIKS);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("CHECK_HOME") && (npc != null) && !npc.isDead())
{
if ((npc.calculateDistance(npc.getSpawn().getLocation(), false, false) > 10) && !npc.isInCombat())
{
((L2Attackable) npc).returnHome();
}
else if ((npc.getHeading() != npc.getSpawn().getHeading()) && !npc.isInCombat())
{
npc.setHeading(npc.getSpawn().getHeading());
npc.broadcastPacket(new ValidateLocation(npc));
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (npc.isScriptValue(0) && (getRandom(100) < KNORIKS_CHANCE))
{
if (getRandom(100) < KNORIKS_CHANCE2)
{
npc.setScriptValue(1);
}
broadcastNpcSay(npc, ChatType.NPC_SHOUT, NpcStringId.WHO_S_THERE_IF_YOU_DISTURB_THE_TEMPER_OF_THE_GREAT_LAND_DRAGON_ANTHARAS_I_WILL_NEVER_FORGIVE_YOU);
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
switch (npc.getId())
{
case DRAGON_KNIGHT:
{
if (getRandom(100) > KNIGHT_CHANCE)
{
final L2Npc newKnight = addSpawn(DRAGON_KNIGHT2, npc, false, 0, true);
npc.deleteMe();
broadcastNpcSay(newKnight, ChatType.NPC_SHOUT, NpcStringId.THOSE_WHO_SET_FOOT_IN_THIS_PLACE_SHALL_NOT_LEAVE_ALIVE);
addAttackDesire(newKnight, killer);
}
break;
}
case DRAGON_KNIGHT2:
{
if (getRandom(100) > KNIGHT_CHANCE)
{
final L2Npc eliteKnight = addSpawn(ELITE_DRAGON_KNIGHT, npc, false, 0, true);
npc.deleteMe();
broadcastNpcSay(eliteKnight, ChatType.NPC_SHOUT, NpcStringId.IF_YOU_WISH_TO_SEE_HELL_I_WILL_GRANT_YOU_YOUR_WISH);
addAttackDesire(eliteKnight, killer);
}
break;
}
case DRAGON_GUARD:
case DRAGON_MAGE:
{
cancelQuestTimer("CHECK_HOME", npc, null);
break;
}
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
final L2Attackable mob = (L2Attackable) npc;
mob.setOnKillDelay(0);
if ((npc.getId() == DRAGON_GUARD) || (npc.getId() == DRAGON_MAGE))
{
mob.setIsNoRndWalk(true);
startQuestTimer("CHECK_HOME", 10000, npc, null, true);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new LairOfAntharas();
}
}

View File

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

View File

@@ -0,0 +1,294 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.L2EffectType;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Monastery of Silence AI.
* @author Kerberos, nonom
*/
public final class MonasteryOfSilence extends AbstractNpcAI
{
// NPCs
private static final int CAPTAIN = 18910; // Solina Knight Captain
private static final int KNIGHT = 18909; // Solina Knights
private static final int SCARECROW = 18912; // Scarecrow
private static final int GUIDE = 22789; // Guide Solina
private static final int SEEKER = 22790; // Seeker Solina
private static final int SAVIOR = 22791; // Savior Solina
private static final int ASCETIC = 22793; // Ascetic Solina
private static final int[] DIVINITY_CLAN =
{
22794, // Divinity Judge
22795, // Divinity Manager
};
// Skills
private static final SkillHolder ORDEAL_STRIKE = new SkillHolder(6303, 1); // Trial of the Coup
private static final SkillHolder LEADER_STRIKE = new SkillHolder(6304, 1); // Shock
private static final SkillHolder SAVER_STRIKE = new SkillHolder(6305, 1); // Sacred Gnosis
private static final SkillHolder SAVER_BLEED = new SkillHolder(6306, 1); // Solina Strike
private static final SkillHolder LEARNING_MAGIC = new SkillHolder(6308, 1); // Opus of the Wave
private static final SkillHolder STUDENT_CANCEL = new SkillHolder(6310, 1); // Loss of Quest
private static final SkillHolder WARRIOR_THRUSTING = new SkillHolder(6311, 1); // Solina Thrust
private static final SkillHolder KNIGHT_BLESS = new SkillHolder(6313, 1); // Solina Bless
// Misc
private static final NpcStringId[] DIVINITY_MSG =
{
NpcStringId.S1_WHY_WOULD_YOU_CHOOSE_THE_PATH_OF_DARKNESS,
NpcStringId.S1_HOW_DARE_YOU_DEFY_THE_WILL_OF_EINHASAD
};
private static final NpcStringId[] SOLINA_KNIGHTS_MSG =
{
NpcStringId.PUNISH_ALL_THOSE_WHO_TREAD_FOOTSTEPS_IN_THIS_PLACE,
NpcStringId.WE_ARE_THE_SWORD_OF_TRUTH_THE_SWORD_OF_SOLINA,
NpcStringId.WE_RAISE_OUR_BLADES_FOR_THE_GLORY_OF_SOLINA
};
private MonasteryOfSilence()
{
super(MonasteryOfSilence.class.getSimpleName(), "ai/group_template");
addSkillSeeId(DIVINITY_CLAN);
addAttackId(KNIGHT, CAPTAIN, GUIDE, SEEKER, ASCETIC);
addNpcHateId(GUIDE, SEEKER, SAVIOR, ASCETIC);
addAggroRangeEnterId(GUIDE, SEEKER, SAVIOR, ASCETIC);
addSpawnId(SCARECROW);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "TRAINING":
{
for (L2Character character : npc.getKnownList().getKnownCharactersInRadius(400))
{
if ((getRandom(100) < 30) && character.isNpc() && !character.isDead() && !character.isInCombat())
{
if ((character.getId() == CAPTAIN) && (getRandom(100) < 10) && npc.isScriptValue(0))
{
final L2Npc captain = (L2Npc) character;
broadcastNpcSay(captain, ChatType.NPC_GENERAL, SOLINA_KNIGHTS_MSG[getRandom(SOLINA_KNIGHTS_MSG.length)]);
captain.setScriptValue(1);
startQuestTimer("TIMER", 10000, captain, null);
}
else if (character.getId() == KNIGHT)
{
character.setRunning();
((L2Attackable) character).addDamageHate(npc, 0, 100);
character.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, npc, null);
}
}
}
break;
}
case "DO_CAST":
{
if ((npc != null) && (player != null) && (getRandom(100) < 3))
{
if (npc.checkDoCastConditions(STUDENT_CANCEL.getSkill()))
{
npc.setTarget(player);
npc.doCast(STUDENT_CANCEL.getSkill());
}
npc.setScriptValue(0);
}
break;
}
case "TIMER":
{
if (npc != null)
{
npc.setScriptValue(0);
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
final L2Attackable mob = (L2Attackable) npc;
switch (npc.getId())
{
case KNIGHT:
{
if ((getRandom(100) < 10) && (mob.getMostHated() == player) && mob.checkDoCastConditions(WARRIOR_THRUSTING.getSkill()))
{
npc.setTarget(player);
npc.doCast(WARRIOR_THRUSTING.getSkill());
}
break;
}
case CAPTAIN:
{
if ((getRandom(100) < 20) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) && npc.isScriptValue(0))
{
if (npc.checkDoCastConditions(KNIGHT_BLESS.getSkill()))
{
npc.setTarget(npc);
npc.doCast(KNIGHT_BLESS.getSkill());
}
npc.setScriptValue(1);
broadcastNpcSay(npc, ChatType.GENERAL, NpcStringId.FOR_THE_GLORY_OF_SOLINA);
addAttackDesire(addSpawn(KNIGHT, npc), player);
}
break;
}
case GUIDE:
{
if ((getRandom(100) < 3) && (mob.getMostHated() == player) && npc.checkDoCastConditions(ORDEAL_STRIKE.getSkill()))
{
npc.setTarget(player);
npc.doCast(ORDEAL_STRIKE.getSkill());
}
break;
}
case SEEKER:
{
if ((getRandom(100) < 33) && (mob.getMostHated() == player) && npc.checkDoCastConditions(SAVER_STRIKE.getSkill()))
{
npc.setTarget(npc);
npc.doCast(SAVER_STRIKE.getSkill());
}
break;
}
case ASCETIC:
{
if ((mob.getMostHated() == player) && npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("DO_CAST", 20000, npc, player);
}
break;
}
}
return super.onAttack(npc, player, damage, isSummon);
}
@Override
public boolean onNpcHate(L2Attackable mob, L2PcInstance player, boolean isSummon)
{
return player.getActiveWeaponInstance() != null;
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (player.getActiveWeaponInstance() != null)
{
SkillHolder skill = null;
switch (npc.getId())
{
case GUIDE:
{
if (getRandom(100) < 3)
{
skill = LEADER_STRIKE;
}
break;
}
case SEEKER:
{
skill = SAVER_BLEED;
break;
}
case SAVIOR:
{
skill = LEARNING_MAGIC;
break;
}
case ASCETIC:
{
if (getRandom(100) < 3)
{
skill = STUDENT_CANCEL;
}
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("DO_CAST", 20000, npc, player);
}
break;
}
}
if ((skill != null) && npc.checkDoCastConditions(skill.getSkill()))
{
npc.setTarget(player);
npc.doCast(skill.getSkill());
}
if (!npc.isInCombat())
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.YOU_CANNOT_CARRY_A_WEAPON_WITHOUT_AUTHORIZATION);
}
addAttackDesire(npc, player);
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (skill.hasEffectType(L2EffectType.AGGRESSION) && (targets.length != 0))
{
for (L2Object obj : targets)
{
if (obj.equals(npc))
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, DIVINITY_MSG[getRandom(DIVINITY_MSG.length)], caster.getName());
addAttackDesire(npc, caster);
break;
}
}
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setIsInvul(true);
npc.disableCoreAI(true);
startQuestTimer("TRAINING", 30000, npc, null, true);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new MonasteryOfSilence();
}
}

View File

@@ -0,0 +1,50 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* @author UnAfraid
*/
public final class NonLethalableNpcs extends AbstractNpcAI
{
private static final int[] NPCS =
{
35062, // Headquarters
};
public NonLethalableNpcs()
{
super(NonLethalableNpcs.class.getSimpleName(), "ai/group_template");
addSpawnId(NPCS);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setLethalable(false);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new NonLethalableNpcs();
}
}

View File

@@ -0,0 +1,72 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* AI for handle Non-Talking NPCs.
* @author St3eT
*/
public final class NonTalkingNpcs extends AbstractNpcAI
{
// @formatter:off
private static final int[] NONTALKINGNPCS =
{
18684, 18685, 18686, // Red Star Stone
18687, 18688, 18689, // Blue Star Stone
18690, 18691, 18692, // Green Star Stone
18848, 18849, 18926, // Jinia Guild
18927, // Fire
18933, // Fire Feed
31202, 31203, 31204, 31205, 31206, 31207, 31208, 31209, 31266, 31593, 31758, 31955, // Town pets
31557, // Mercenary Sentry
31606, // Alice de Catrina
31671, 31672, 31673, 31674, // Patrol
32026, // Hestui Guard
32030, // Garden Sculpture
32031, // Ice Fairy Sculpture
32032, // Strange Machine
32306, // Native's Corpse
32619, 32620, 32621, // NPC's without name
32715, 32716, 32717, // Lilith's group
32718, 32719, 32720, 32721, // Anakim's group
18839, // Wild Maguen
18915, // Divine Furnace
};
// @formatter:on
public NonTalkingNpcs()
{
super(NonTalkingNpcs.class.getSimpleName(), "ai/group_template");
addSpawnId(NONTALKINGNPCS);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setTalking(false);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new NonTalkingNpcs();
}
}

View File

@@ -0,0 +1,60 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import ai.npc.AbstractNpcAI;
/**
* Pavel Archaic AI.
* @author Gnacik, St3eT
*/
public final class PavelArchaic extends AbstractNpcAI
{
private static final int SAFETY_DEVICE = 18917; // Pavel Safety Device
private static final int PINCER_GOLEM = 22801; // Cruel Pincer Golem
private static final int PINCER_GOLEM2 = 22802; // Cruel Pincer Golem
private static final int PINCER_GOLEM3 = 22803; // Cruel Pincer Golem
private static final int JACKHAMMER_GOLEM = 22804; // Horrifying Jackhammer Golem
private PavelArchaic()
{
super(PavelArchaic.class.getSimpleName(), "ai/group_template");
addKillId(SAFETY_DEVICE, PINCER_GOLEM, JACKHAMMER_GOLEM);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (getRandom(100) < 70)
{
final L2Npc golem1 = addSpawn(PINCER_GOLEM2, npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), false, 0, false);
addAttackDesire(golem1, killer);
final L2Npc golem2 = addSpawn(PINCER_GOLEM3, npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), false, 0, false);
addAttackDesire(golem2, killer);
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new PavelArchaic();
}
}

View File

@@ -0,0 +1,97 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* AI for mobs in Plains of Dion (near Floran Village).
* @author Gladicek
*/
public final class PlainsOfDion extends AbstractNpcAI
{
private static final int DELU_LIZARDMEN[] =
{
21104, // Delu Lizardman Supplier
21105, // Delu Lizardman Special Agent
21107, // Delu Lizardman Commander
};
private static final NpcStringId[] MONSTERS_MSG =
{
NpcStringId.S1_HOW_DARE_YOU_INTERRUPT_OUR_FIGHT_HEY_GUYS_HELP,
NpcStringId.S1_HEY_WE_RE_HAVING_A_DUEL_HERE,
NpcStringId.THE_DUEL_IS_OVER_ATTACK,
NpcStringId.FOUL_KILL_THE_COWARD,
NpcStringId.HOW_DARE_YOU_INTERRUPT_A_SACRED_DUEL_YOU_MUST_BE_TAUGHT_A_LESSON
};
private static final NpcStringId[] MONSTERS_ASSIST_MSG =
{
NpcStringId.DIE_YOU_COWARD,
NpcStringId.KILL_THE_COWARD,
NpcStringId.WHAT_ARE_YOU_LOOKING_AT
};
private PlainsOfDion()
{
super(PlainsOfDion.class.getSimpleName(), "ai/group_template");
addAttackId(DELU_LIZARDMEN);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
if (npc.isScriptValue(0))
{
final int i = getRandom(5);
if (i < 2)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, MONSTERS_MSG[i], player.getName());
}
else
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, MONSTERS_MSG[i]);
}
for (L2Character obj : npc.getKnownList().getKnownCharactersInRadius(npc.getTemplate().getClanHelpRange()))
{
if (obj.isMonster() && Util.contains(DELU_LIZARDMEN, obj.getId()) && !obj.isAttackingNow() && !obj.isDead() && GeoData.getInstance().canSeeTarget(npc, obj))
{
final L2Npc monster = (L2Npc) obj;
addAttackDesire(monster, player);
broadcastNpcSay(monster, ChatType.NPC_GENERAL, MONSTERS_ASSIST_MSG[getRandom(3)]);
}
}
npc.setScriptValue(1);
}
return super.onAttack(npc, player, damage, isSummon);
}
public static void main(String[] args)
{
new PlainsOfDion();
}
}

View File

@@ -0,0 +1,242 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import ai.npc.AbstractNpcAI;
/**
* Plains of Lizardmen AI.
* @author Gnacik, malyelfik
*/
public final class PlainsOfLizardman extends AbstractNpcAI
{
// NPCs
private static final int INVISIBLE_NPC = 18919;
private static final int TANTA_GUARD = 18862;
private static final int FANTASY_MUSHROOM = 18864;
private static final int STICKY_MUSHROOM = 18865;
private static final int RAINBOW_FROG = 18866;
private static final int ENERGY_PLANT = 18868;
private static final int TANTA_SCOUT = 22768;
private static final int TANTA_MAGICIAN = 22773;
private static final int TANTA_SUMMONER = 22774;
private static final int[] TANTA_LIZARDMEN =
{
22768, // Tanta Lizardman Scout
22769, // Tanta Lizardman Warrior
22770, // Tanta Lizardman Soldier
22771, // Tanta Lizardman Berserker
22772, // Tanta Lizardman Archer
22773, // Tanta Lizardman Magician
22774, // Tanta Lizardman Summoner
};
// Skills
private static final SkillHolder STUN_EFFECT = new SkillHolder(6622, 1);
private static final SkillHolder DEMOTIVATION_HEX = new SkillHolder(6425, 1);
private static final SkillHolder FANTASY_MUSHROOM_SKILL = new SkillHolder(6427, 1);
private static final SkillHolder RAINBOW_FROG_SKILL = new SkillHolder(6429, 1);
private static final SkillHolder STICKY_MUSHROOM_SKILL = new SkillHolder(6428, 1);
private static final SkillHolder ENERGY_PLANT_SKILL = new SkillHolder(6430, 1);
// Buffs
private static final SkillHolder[] BUFFS =
{
new SkillHolder(6625, 1), // Energy of Life
new SkillHolder(6626, 2), // Energy of Life's Power
new SkillHolder(6627, 3), // Energy of Life's Highest Power
new SkillHolder(6628, 1), // Energy of Mana
new SkillHolder(6629, 2), // Energy of Mana's Power
new SkillHolder(6630, 3), // Energy of Mana's Highest Power
new SkillHolder(6631, 1), // Energy of Power
new SkillHolder(6633, 1), // Energy of Attack Speed
new SkillHolder(6635, 1), // Energy of Crt Rate
new SkillHolder(6636, 1), // Energy of Moving Speed
new SkillHolder(6638, 1), // Aura of Mystery
new SkillHolder(6639, 1), // Bane of Auras - Damage
new SkillHolder(6640, 1), // Energizing Aura
new SkillHolder(6674, 1), // Energy of Range Increment
};
// Misc
// @formatter:off
private static final int[] BUFF_LIST =
{
6, 7, 8, 11, 13
};
// @formatter:on
private PlainsOfLizardman()
{
super(PlainsOfLizardman.class.getSimpleName(), "ai/group_template");
addAttackId(FANTASY_MUSHROOM, RAINBOW_FROG, STICKY_MUSHROOM, ENERGY_PLANT, TANTA_SUMMONER);
addKillId(TANTA_LIZARDMEN);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("fantasy_mushroom") && (npc != null) && (player != null))
{
npc.doCast(FANTASY_MUSHROOM_SKILL.getSkill());
for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(200))
{
if ((target != null) && target.isAttackable())
{
final L2Npc monster = (L2Npc) target;
npc.setTarget(monster);
npc.doCast(STUN_EFFECT.getSkill());
addAttackDesire(monster, player);
}
}
npc.doDie(player);
}
return null;
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
switch (npc.getId())
{
case TANTA_SUMMONER:
if (!npc.isAffectedBySkill(DEMOTIVATION_HEX.getSkillId()))
{
npc.doCast(DEMOTIVATION_HEX.getSkill());
}
break;
case RAINBOW_FROG:
castSkill(npc, attacker, RAINBOW_FROG_SKILL);
break;
case ENERGY_PLANT:
castSkill(npc, attacker, ENERGY_PLANT_SKILL);
break;
case STICKY_MUSHROOM:
castSkill(npc, attacker, STICKY_MUSHROOM_SKILL);
break;
case FANTASY_MUSHROOM:
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
npc.setIsInvul(true);
for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(1000))
{
if ((target != null) && target.isAttackable())
{
final L2Attackable monster = (L2Attackable) target;
if ((monster.getId() == TANTA_MAGICIAN) || (monster.getId() == TANTA_SCOUT))
{
target.setIsRunning(true);
target.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(npc.getX(), npc.getY(), npc.getZ(), 0));
}
}
}
startQuestTimer("fantasy_mushroom", 4000, npc, attacker);
}
break;
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
// Tanta Guard
if (getRandom(1000) == 0)
{
addAttackDesire(addSpawn(TANTA_GUARD, npc), killer);
}
// Invisible buff npc
final int random = getRandom(100);
final L2Npc buffer = addSpawn(INVISIBLE_NPC, npc.getLocation(), false, 6000);
buffer.setTarget(killer);
if (random <= 42)
{
castRandomBuff(buffer, 7, 45, BUFFS[0], BUFFS[1], BUFFS[2]);
}
if (random <= 11)
{
castRandomBuff(buffer, 8, 60, BUFFS[3], BUFFS[4], BUFFS[5]);
castRandomBuff(buffer, 3, 6, BUFFS[9], BUFFS[10], BUFFS[12]);
}
if (random <= 25)
{
buffer.doCast(BUFFS[BUFF_LIST[getRandom(BUFF_LIST.length)]].getSkill());
}
if (random <= 10)
{
buffer.doCast(BUFFS[13].getSkill());
}
if (random <= 1)
{
final int i = getRandom(100);
if (i <= 34)
{
buffer.doCast(BUFFS[6].getSkill());
buffer.doCast(BUFFS[7].getSkill());
buffer.doCast(BUFFS[8].getSkill());
}
else if (i < 67)
{
buffer.doCast(BUFFS[13].getSkill());
}
else
{
buffer.doCast(BUFFS[2].getSkill());
buffer.doCast(BUFFS[5].getSkill());
}
}
return super.onKill(npc, killer, isSummon);
}
private void castRandomBuff(L2Npc npc, int chance1, int chance2, SkillHolder... buffs)
{
final int rand = getRandom(100);
if (rand <= chance1)
{
npc.doCast(buffs[2].getSkill());
}
else if (rand <= chance2)
{
npc.doCast(buffs[1].getSkill());
}
else
{
npc.doCast(buffs[0].getSkill());
}
}
@Override
protected void castSkill(L2Npc npc, L2Playable target, SkillHolder skill)
{
npc.doDie(target);
super.castSkill(addSpawn(INVISIBLE_NPC, npc, false, 6000), target, skill);
}
public static void main(String[] args)
{
new PlainsOfLizardman();
}
}

View File

@@ -0,0 +1,61 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import ai.npc.AbstractNpcAI;
/**
* Angel spawns...when one of the angels in the keys dies, the other angel will spawn.
*/
public final class PolymorphingAngel extends AbstractNpcAI
{
private static final Map<Integer, Integer> ANGELSPAWNS = new HashMap<>();
static
{
ANGELSPAWNS.put(20830, 20859);
ANGELSPAWNS.put(21067, 21068);
ANGELSPAWNS.put(21062, 21063);
ANGELSPAWNS.put(20831, 20860);
ANGELSPAWNS.put(21070, 21071);
}
private PolymorphingAngel()
{
super(PolymorphingAngel.class.getSimpleName(), "ai/group_template");
addKillId(ANGELSPAWNS.keySet());
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
final L2Attackable newNpc = (L2Attackable) addSpawn(ANGELSPAWNS.get(npc.getId()), npc);
newNpc.setRunning();
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new PolymorphingAngel();
}
}

View File

@@ -0,0 +1,118 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import ai.npc.AbstractNpcAI;
/**
* Polymorphing on attack monsters AI.
* @author Slyce
*/
public final class PolymorphingOnAttack extends AbstractNpcAI
{
private static final Map<Integer, List<Integer>> MOBSPAWNS = new HashMap<>();
static
{
MOBSPAWNS.put(21258, Arrays.asList(21259, 100, 100, -1)); // Fallen Orc Shaman -> Sharp Talon Tiger (always polymorphs)
MOBSPAWNS.put(21261, Arrays.asList(21262, 100, 20, 0)); // Ol Mahum Transcender 1st stage
MOBSPAWNS.put(21262, Arrays.asList(21263, 100, 10, 1)); // Ol Mahum Transcender 2nd stage
MOBSPAWNS.put(21263, Arrays.asList(21264, 100, 5, 2)); // Ol Mahum Transcender 3rd stage
MOBSPAWNS.put(21265, Arrays.asList(21271, 100, 33, 0)); // Cave Ant Larva -> Cave Ant
MOBSPAWNS.put(21266, Arrays.asList(21269, 100, 100, -1)); // Cave Ant Larva -> Cave Ant (always polymorphs)
MOBSPAWNS.put(21267, Arrays.asList(21270, 100, 100, -1)); // Cave Ant Larva -> Cave Ant Soldier (always polymorphs)
MOBSPAWNS.put(21271, Arrays.asList(21272, 66, 10, 1)); // Cave Ant -> Cave Ant Soldier
MOBSPAWNS.put(21272, Arrays.asList(21273, 33, 5, 2)); // Cave Ant Soldier -> Cave Noble Ant
MOBSPAWNS.put(21521, Arrays.asList(21522, 100, 30, -1)); // Claws of Splendor
MOBSPAWNS.put(21527, Arrays.asList(21528, 100, 30, -1)); // Anger of Splendor
MOBSPAWNS.put(21533, Arrays.asList(21534, 100, 30, -1)); // Alliance of Splendor
MOBSPAWNS.put(21537, Arrays.asList(21538, 100, 30, -1)); // Fang of Splendor
}
protected static final NpcStringId[][] MOBTEXTS =
{
new NpcStringId[]
{
NpcStringId.ENOUGH_FOOLING_AROUND_GET_READY_TO_DIE,
NpcStringId.YOU_IDIOT_I_VE_JUST_BEEN_TOYING_WITH_YOU,
NpcStringId.NOW_THE_FUN_STARTS
},
new NpcStringId[]
{
NpcStringId.I_MUST_ADMIT_NO_ONE_MAKES_MY_BLOOD_BOIL_QUITE_LIKE_YOU_DO,
NpcStringId.NOW_THE_BATTLE_BEGINS,
NpcStringId.WITNESS_MY_TRUE_POWER
},
new NpcStringId[]
{
NpcStringId.PREPARE_TO_DIE,
NpcStringId.I_LL_DOUBLE_MY_STRENGTH,
NpcStringId.YOU_HAVE_MORE_SKILL_THAN_I_THOUGHT
}
};
private PolymorphingOnAttack()
{
super(PolymorphingOnAttack.class.getSimpleName(), "ai/group_template");
addAttackId(MOBSPAWNS.keySet());
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.isVisible() && !npc.isDead())
{
final List<Integer> tmp = MOBSPAWNS.get(npc.getId());
if (tmp != null)
{
if ((npc.getCurrentHp() <= ((npc.getMaxHp() * tmp.get(1)) / 100.0)) && (getRandom(100) < tmp.get(2)))
{
if (tmp.get(3) >= 0)
{
final NpcStringId npcString = MOBTEXTS[tmp.get(3)][getRandom(MOBTEXTS[tmp.get(3)].length)];
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), ChatType.NPC_GENERAL, npc.getName(), npcString));
}
npc.deleteMe();
final L2Attackable newNpc = (L2Attackable) addSpawn(tmp.get(0), npc.getX(), npc.getY(), npc.getZ() + 10, npc.getHeading(), false, 0, true);
final L2Character originalAttacker = isSummon ? attacker.getSummon() : attacker;
newNpc.setRunning();
newNpc.addDamageHate(originalAttacker, 0, 500);
newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, originalAttacker);
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
public static void main(String[] args)
{
new PolymorphingOnAttack();
}
}

View File

@@ -0,0 +1,513 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.handler.IItemHandler;
import com.l2jmobius.gameserver.handler.ItemHandler;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Primeval Isle AI.
* @author St3eT
*/
public final class PrimevalIsle extends AbstractNpcAI
{
// NPC
private static final int EGG = 18344; // Ancient Egg
private static final int SAILREN = 29065; // Sailren
private static final int ORNIT = 22742; // Ornithomimus
private static final int DEINO = 22743; // Deinonychus
private static final int[] SPRIGNANT =
{
18345, // Sprigant (Anesthesia)
18346, // Sprigant (Deadly Poison)
};
private static final int[] MONSTERS =
{
22196, // Velociraptor
22198, // Velociraptor
22200, // Ornithomimus
22202, // Ornithomimus
22203, // Deinonychus
22205, // Deinonychus
22208, // Pachycephalosaurus
22210, // Pachycephalosaurus
22211, // Wild Strider
22213, // Wild Strider
22223, // Velociraptor
22224, // Ornithomimus
22225, // Deinonychus
22226, // Pachycephalosaurus
22227, // Wild Strider
22742, // Ornithomimus
22743, // Deinonychus
};
private static final int[] TREX =
{
22215, // Tyrannosaurus
22216, // Tyrannosaurus
22217, // Tyrannosaurus
};
private static final int[] VEGETABLE =
{
22200, // Ornithomimus
22201, // Ornithomimus
22202, // Ornithomimus
22203, // Deinonychus
22204, // Deinonychus
22205, // Deinonychus
22224, // Ornithomimus
22225, // Deinonychus
};
// Item
private static final int DEINONYCHUS = 14828; // Deinonychus Mesozoic Stone
// Skill
private static final SkillHolder ANESTHESIA = new SkillHolder(5085, 1); // Anesthesia
private static final SkillHolder DEADLY_POISON = new SkillHolder(5086, 1); // Deadly Poison
private static final SkillHolder SELFBUFF1 = new SkillHolder(5087, 1); // Berserk
private static final SkillHolder SELFBUFF2 = new SkillHolder(5087, 2); // Berserk
private static final SkillHolder LONGRANGEDMAGIC1 = new SkillHolder(5120, 1); // Stun
private static final SkillHolder PHYSICALSPECIAL1 = new SkillHolder(5083, 4); // Stun
private static final SkillHolder PHYSICALSPECIAL2 = new SkillHolder(5081, 4); // Silence
private static final SkillHolder PHYSICALSPECIAL3 = new SkillHolder(5082, 4); // NPC Spinning, Slashing Trick
private static final SkillHolder CREW_SKILL = new SkillHolder(6172, 1); // Presentation - Tyranno
private static final SkillHolder INVIN_BUFF_ON = new SkillHolder(5225, 1); // Invincible
private PrimevalIsle()
{
super(PrimevalIsle.class.getSimpleName(), "ai/group_template");
addSpawnId(TREX);
addSpawnId(SPRIGNANT);
addSpawnId(MONSTERS);
addAggroRangeEnterId(TREX);
addSpellFinishedId(TREX);
addAttackId(EGG);
addAttackId(TREX);
addAttackId(MONSTERS);
addKillId(EGG, SAILREN, DEINO, ORNIT);
addSeeCreatureId(TREX);
addSeeCreatureId(MONSTERS);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if (skill.getId() == CREW_SKILL.getSkillId())
{
startQuestTimer("START_INVUL", 4000, npc, null);
final L2Npc target = (L2Npc) npc.getTarget();
if (target != null)
{
target.doDie(npc);
}
}
if (npc.isInCombat())
{
final L2Attackable mob = (L2Attackable) npc;
final L2Character target = mob.getMostHated();
if (((npc.getCurrentHp() / npc.getMaxHp()) * 100) < 60)
{
if (skill.getId() == SELFBUFF1.getSkillId())
{
npc.setScriptValue(3);
if ((target != null))
{
npc.setTarget(target);
mob.setIsRunning(true);
mob.addDamageHate(target, 0, 555);
mob.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
}
}
}
else if (((npc.getCurrentHp() / npc.getMaxHp()) * 100) < 30)
{
if (skill.getId() == SELFBUFF1.getSkillId())
{
npc.setScriptValue(1);
if ((target != null))
{
npc.setTarget(target);
mob.setIsRunning(true);
mob.addDamageHate(target, 0, 555);
mob.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
}
}
else if (skill.getId() == SELFBUFF2.getSkillId())
{
npc.setScriptValue(5);
if ((target != null))
{
npc.setTarget(target);
mob.setIsRunning(true);
mob.addDamageHate(target, 0, 555);
mob.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
}
}
}
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "USE_SKILL":
{
if ((npc != null) && !npc.isDead())
{
npc.doCast((npc.getId() == SPRIGNANT[0] ? ANESTHESIA.getSkill() : DEADLY_POISON.getSkill()));
startQuestTimer("USE_SKILL", 15000, npc, null);
}
break;
}
case "GHOST_DESPAWN":
{
if ((npc != null) && !npc.isDead())
{
if (!npc.isInCombat())
{
npc.deleteMe();
}
else
{
startQuestTimer("GHOST_DESPAWN", 1800000, npc, null);
}
}
break;
}
case "TREX_ATTACK":
{
if ((npc != null) && (player != null))
{
npc.setScriptValue(0);
if (player.isInsideRadius(npc, 800, true, false))
{
npc.setTarget(player);
npc.doCast(LONGRANGEDMAGIC1.getSkill());
addAttackDesire(npc, player);
}
}
break;
}
case "START_INVUL":
{
if ((npc != null) && !npc.isDead())
{
npc.doCast(INVIN_BUFF_ON.getSkill());
startQuestTimer("START_INVUL_2", 30000, npc, null);
}
break;
}
case "START_INVUL_2":
{
if ((npc != null) && !npc.isDead())
{
INVIN_BUFF_ON.getSkill().applyEffects(npc, npc);
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
{
if (Util.contains(MONSTERS, npc.getId()))
{
if (creature.isPlayer())
{
final L2Attackable mob = (L2Attackable) npc;
final int ag_type = npc.getTemplate().getParameters().getInt("ag_type", 0);
final int probPhysicalSpecial1 = npc.getTemplate().getParameters().getInt("ProbPhysicalSpecial1", 0);
final int probPhysicalSpecial2 = npc.getTemplate().getParameters().getInt("ProbPhysicalSpecial2", 0);
final SkillHolder physicalSpecial1 = npc.getTemplate().getParameters().getObject("PhysicalSpecial1", SkillHolder.class);
final SkillHolder physicalSpecial2 = npc.getTemplate().getParameters().getObject("PhysicalSpecial2", SkillHolder.class);
if (((getRandom(100) < 30) && (npc.getId() == DEINO)) || ((npc.getId() == ORNIT) && npc.isScriptValue(0)))
{
mob.clearAggroList();
npc.setScriptValue(1);
npc.setRunning();
final int distance = 3000;
final int heading = Util.calculateHeadingFrom(creature, npc);
final double angle = Util.convertHeadingToDegree(heading);
final double radian = Math.toRadians(angle);
final double sin = Math.sin(radian);
final double cos = Math.cos(radian);
final int newX = (int) (npc.getX() + (cos * distance));
final int newY = (int) (npc.getY() + (sin * distance));
final Location loc = GeoData.getInstance().moveCheck(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceId());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc, 0);
}
else if (ag_type == 1)
{
if (getRandom(100) <= (probPhysicalSpecial1 * npc.getVariables().getInt("SKILL_MULTIPLER")))
{
if (!npc.isSkillDisabled(physicalSpecial1.getSkillId()))
{
npc.setTarget(creature);
npc.doCast(physicalSpecial1.getSkill());
}
}
else if (getRandom(100) <= (probPhysicalSpecial2 * npc.getVariables().getInt("SKILL_MULTIPLER")))
{
if (!npc.isSkillDisabled(physicalSpecial2.getSkill()))
{
npc.setTarget(creature);
npc.doCast(physicalSpecial2.getSkill());
}
}
}
}
}
else if (Util.contains(VEGETABLE, creature.getId()))
{
npc.setTarget(creature);
npc.doCast(CREW_SKILL.getSkill());
npc.setIsRunning(true);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, creature);
}
return super.onSeeCreature(npc, creature, isSummon);
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
broadcastNpcSay(npc, ChatType.NPC_GENERAL, "?");
((L2Attackable) npc).clearAggroList();
startQuestTimer("TREX_ATTACK", 6000, npc, player);
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.getId() == EGG)
{
if ((getRandom(100) <= 80) && npc.isScriptValue(0))
{
npc.setScriptValue(1);
final L2Playable playable = isSummon ? attacker.getSummon() : attacker;
for (L2Character characters : npc.getKnownList().getKnownCharactersInRadius(500))
{
if ((characters != null) && (characters.isAttackable()) && (getRandomBoolean()))
{
final L2Attackable monster = (L2Attackable) characters;
addAttackDesire(monster, playable);
}
}
}
}
else if (Util.contains(TREX, npc.getId()))
{
final L2Attackable mob = (L2Attackable) npc;
final L2Character target = mob.getMostHated();
if (((npc.getCurrentHp() / npc.getMaxHp()) * 100) <= 30)
{
if (npc.isScriptValue(3))
{
if (!npc.isSkillDisabled(SELFBUFF1.getSkill()))
{
npc.doCast(SELFBUFF1.getSkill());
}
}
else if (npc.isScriptValue(1))
{
if (!npc.isSkillDisabled(SELFBUFF2.getSkill()))
{
npc.doCast(SELFBUFF2.getSkill());
}
}
}
else if ((((npc.getCurrentHp() / npc.getMaxHp()) * 100) <= 60) && (npc.isScriptValue(3)))
{
if (!npc.isSkillDisabled(SELFBUFF1.getSkill()))
{
npc.doCast(SELFBUFF1.getSkill());
}
}
if (Util.calculateDistance(npc, attacker, true, false) > 100)
{
if (!npc.isSkillDisabled(LONGRANGEDMAGIC1.getSkill()) && (getRandom(100) <= (10 * npc.getScriptValue())))
{
npc.setTarget(attacker);
npc.doCast(LONGRANGEDMAGIC1.getSkill());
}
}
else
{
if (!npc.isSkillDisabled(LONGRANGEDMAGIC1.getSkill()) && (getRandom(100) <= (10 * npc.getScriptValue())))
{
npc.setTarget(target);
npc.doCast(LONGRANGEDMAGIC1.getSkill());
}
if (!npc.isSkillDisabled(PHYSICALSPECIAL1.getSkill()) && (getRandom(100) <= (5 * npc.getScriptValue())))
{
npc.setTarget(target);
npc.doCast(PHYSICALSPECIAL1.getSkill());
}
if (!npc.isSkillDisabled(PHYSICALSPECIAL2.getSkill()) && (getRandom(100) <= (3 * npc.getScriptValue())))
{
npc.setTarget(target);
npc.doCast(PHYSICALSPECIAL2.getSkill());
}
if (!npc.isSkillDisabled(PHYSICALSPECIAL3.getSkill()) && (getRandom(100) <= (5 * npc.getScriptValue())))
{
npc.setTarget(target);
npc.doCast(PHYSICALSPECIAL3.getSkill());
}
}
}
else
{
L2Character target = null;
final int probPhysicalSpecial1 = npc.getTemplate().getParameters().getInt("ProbPhysicalSpecial1", 0);
final int probPhysicalSpecial2 = npc.getTemplate().getParameters().getInt("ProbPhysicalSpecial2", 0);
final SkillHolder selfRangeBuff1 = npc.getTemplate().getParameters().getObject("SelfRangeBuff1", SkillHolder.class);
final SkillHolder physicalSpecial1 = npc.getTemplate().getParameters().getObject("PhysicalSpecial1", SkillHolder.class);
final SkillHolder physicalSpecial2 = npc.getTemplate().getParameters().getObject("PhysicalSpecial2", SkillHolder.class);
if (((npc.getCurrentHp() / npc.getMaxHp()) * 100) <= 50)
{
npc.getVariables().set("SKILL_MULTIPLER", 2);
}
else
{
npc.getVariables().set("SKILL_MULTIPLER", 1);
}
if ((((npc.getCurrentHp() / npc.getMaxHp()) * 100) <= 30) && (npc.getVariables().getInt("SELFBUFF_USED") == 0))
{
final L2Attackable mob = (L2Attackable) npc;
target = mob.getMostHated();
mob.clearAggroList();
if (!npc.isSkillDisabled(selfRangeBuff1.getSkillId()))
{
npc.getVariables().set("SELFBUFF_USED", 1);
npc.doCast(selfRangeBuff1.getSkill());
npc.setIsRunning(true);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
}
}
if (target != null)
{
if (getRandom(100) <= (probPhysicalSpecial1 * npc.getVariables().getInt("SKILL_MULTIPLER")))
{
if (!npc.isSkillDisabled(physicalSpecial1.getSkill()))
{
npc.setTarget(target);
npc.doCast(physicalSpecial1.getSkill());
}
}
if (getRandom(100) <= (probPhysicalSpecial2 * npc.getVariables().getInt("SKILL_MULTIPLER")))
{
if (!npc.isSkillDisabled(physicalSpecial2.getSkill()))
{
npc.setTarget(target);
npc.doCast(physicalSpecial2.getSkill());
}
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if ((npc.getId() == DEINO) || ((npc.getId() == ORNIT) && !npc.isScriptValue(1)))
{
return super.onKill(npc, killer, isSummon);
}
if ((npc.getId() == SAILREN) || (getRandom(100) < 3))
{
final L2PcInstance player = npc.getId() == SAILREN ? getRandomPartyMember(killer) : killer;
if (player.getInventory().getSize(false) <= (player.getInventoryLimit() * 0.8))
{
giveItems(player, DEINONYCHUS, 1);
final L2ItemInstance summonItem = player.getInventory().getItemByItemId(DEINONYCHUS);
final IItemHandler handler = ItemHandler.getInstance().getHandler(summonItem.getEtcItem());
if ((handler != null) && !player.hasPet())
{
handler.useItem(player, summonItem, true);
}
showOnScreenMsg(player, NpcStringId.LIFE_STONE_FROM_THE_BEGINNING_ACQUIRED, 2, 6000);
}
else
{
showOnScreenMsg(player, NpcStringId.WHEN_INVENTORY_WEIGHT_NUMBER_ARE_MORE_THAN_80_THE_LIFE_STONE_FROM_THE_BEGINNING_CANNOT_BE_ACQUIRED, 2, 6000);
}
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
if (Util.contains(SPRIGNANT, npc.getId()))
{
startQuestTimer("USE_SKILL", 15000, npc, null);
}
else if (Util.contains(TREX, npc.getId()))
{
final int collectGhost = npc.getTemplate().getParameters().getInt("CollectGhost", 0);
final int collectDespawn = npc.getTemplate().getParameters().getInt("CollectGhostDespawnTime", 30);
if (collectGhost == 1)
{
startQuestTimer("GHOST_DESPAWN", collectDespawn * 60000, npc, null);
}
}
else
{
npc.getVariables().set("SELFBUFF_USED", 0);
npc.getVariables().set("SKILL_MULTIPLER", 1);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new PrimevalIsle();
}
}

View File

@@ -0,0 +1,159 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Prison Guards AI.
* @author St3eT
*/
public final class PrisonGuards extends AbstractNpcAI
{
// NPCs
private static final int GUARD_HEAD = 18367; // Prison Guard
private static final int GUARD = 18368; // Prison Guard
// Item
private static final int STAMP = 10013; // Race Stamp
// Skills
private static final int TIMER = 5239; // Event Timer
private static final SkillHolder STONE = new SkillHolder(4578, 1); // Petrification
private static final SkillHolder SILENCE = new SkillHolder(4098, 9); // Silence
private PrisonGuards()
{
super(PrisonGuards.class.getSimpleName(), "ai/group_template");
addAttackId(GUARD_HEAD, GUARD);
addSpawnId(GUARD_HEAD, GUARD);
addNpcHateId(GUARD);
addSkillSeeId(GUARD);
addSpellFinishedId(GUARD_HEAD, GUARD);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("CLEAR_STATUS"))
{
npc.setScriptValue(0);
}
else if (event.equals("CHECK_HOME"))
{
if ((npc.calculateDistance(npc.getSpawn().getLocation(), false, false) > 10) && !npc.isInCombat() && !npc.isDead())
{
npc.teleToLocation(npc.getSpawn().getLocation());
}
startQuestTimer("CHECK_HOME", 30000, npc, null);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
if (npc.getId() == GUARD_HEAD)
{
if (player.isAffectedBySkill(TIMER))
{
if ((getRandom(100) < 10) && (npc.calculateDistance(player, true, false) < 100))
{
if ((getQuestItemsCount(player, STAMP) <= 3) && npc.isScriptValue(0))
{
giveItems(player, STAMP, 1);
npc.setScriptValue(1);
startQuestTimer("CLEAR_STATUS", 600000, npc, null);
}
}
}
else
{
npc.setTarget(player);
npc.doCast(STONE.getSkill());
broadcastNpcSay(npc, ChatType.GENERAL, NpcStringId.IT_S_NOT_EASY_TO_OBTAIN);
}
}
else
{
if (!player.isAffectedBySkill(TIMER) && (npc.calculateDistance(npc.getSpawn().getLocation(), false, false) < 2000))
{
npc.setTarget(player);
npc.doCast(STONE.getSkill());
broadcastNpcSay(npc, ChatType.GENERAL, NpcStringId.YOU_RE_OUT_OF_YOUR_MIND_COMING_HERE);
}
}
return super.onAttack(npc, player, damage, isSummon);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (!caster.isAffectedBySkill(TIMER))
{
npc.setTarget(caster);
npc.doCast(SILENCE.getSkill());
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if ((skill == SILENCE.getSkill()) || (skill == STONE.getSkill()))
{
((L2Attackable) npc).clearAggroList();
npc.setTarget(npc);
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public boolean onNpcHate(L2Attackable mob, L2PcInstance player, boolean isSummon)
{
return player.isAffectedBySkill(TIMER);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.getId() == GUARD_HEAD)
{
npc.setIsImmobilized(true);
npc.setIsInvul(true);
}
else
{
npc.setIsNoRndWalk(true);
cancelQuestTimer("CHECK_HOME", npc, null);
startQuestTimer("CHECK_HOME", 30000, npc, null);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new PrisonGuards();
}
}

View File

@@ -0,0 +1,121 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* Manages spawn of NPCs having several random spawn points.
* @author GKR
*/
public final class RandomSpawn extends AbstractNpcAI
{
private static final Map<Integer, Location[]> SPAWN_POINTS = new HashMap<>();
static
{
// Keltas
SPAWN_POINTS.put(22341, new Location[]
{
new Location(-27136, 250938, -3523),
new Location(-29658, 252897, -3523),
new Location(-27237, 251943, -3527),
new Location(-28868, 250113, -3479)
});
// Keymaster
SPAWN_POINTS.put(22361, new Location[]
{
new Location(14091, 250533, -1940),
new Location(15762, 252440, -2015),
new Location(19836, 256212, -2090),
new Location(21940, 254107, -2010),
new Location(17299, 252943, -2015),
});
// Typhoon
SPAWN_POINTS.put(25539, new Location[]
{
new Location(-20641, 255370, -3235),
new Location(-16157, 250993, -3058),
new Location(-18269, 250721, -3151),
new Location(-16532, 254864, -3223),
new Location(-19055, 253489, -3440),
new Location(-9684, 254256, -3148),
new Location(-6209, 251924, -3189),
new Location(-10547, 251359, -2929),
new Location(-7254, 254997, -3261),
new Location(-4883, 253171, -3322)
});
// Mutated Elpy
SPAWN_POINTS.put(25604, new Location[]
{
new Location(-46080, 246368, -14183),
new Location(-44816, 246368, -14183),
new Location(-44224, 247440, -14184),
new Location(-44896, 248464, -14183),
new Location(-46064, 248544, -14183),
new Location(-46720, 247424, -14183)
});
}
public RandomSpawn()
{
super(RandomSpawn.class.getSimpleName(), "ai/group_template");
addSpawnId(SPAWN_POINTS.keySet());
}
@Override
public final String onSpawn(L2Npc npc)
{
final Location[] spawnlist = SPAWN_POINTS.get(npc.getId());
final Location loc = spawnlist[getRandom(spawnlist.length)];
if (!npc.isInsideRadius(loc, 200, false, false))
{
npc.getSpawn().setLocation(loc);
ThreadPoolManager.getInstance().scheduleGeneral(new Teleport(npc, loc), 100);
}
return super.onSpawn(npc);
}
private static class Teleport implements Runnable
{
private final L2Npc _npc;
private final Location _loc;
public Teleport(L2Npc npc, Location loc)
{
_npc = npc;
_loc = loc;
}
@Override
public void run()
{
_npc.teleToLocation(_loc, false);
}
}
public static void main(String[] args)
{
new RandomSpawn();
}
}

View File

@@ -0,0 +1,119 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Range Guard AI.
* @author St3eT.
*/
public final class RangeGuard extends AbstractNpcAI
{
// Skill
private static final SkillHolder ULTIMATE_DEFENSE = new SkillHolder(5044, 3); // NPC Ultimate Defense
//@formatter:off
private static final int[] NOT_ALLOWED_SKILLS =
{
15, 28, // Charm / Aggression
51, 65, // Lure / Horror
106, 115, // Veil / Power Break
122, 127, // Hex / Hamstring
254, 352, // Spoil / Shield Bash
353, 358, // Shield Slam / Bluff
402, 403, // Arrest / Shackle
412, 485, // Sand Bomb / Disarm
501, 511, // Violent Temper / Temptation
522, 531, // Real Target / Critical Wound
680, 695, // Divine Knight Hate / Divine Wizard Divine Cloud
696, 716, // Divine Wizard Surrender to Divine / Zaken Hold
775, 792, // Weapon Blockade / Betrayal Mark
1042, 1049, // Hold Undead / Requiem
1069, 1071, // Sleep / Surrender To Water
1072, 1074, // Sleeping Cloud / Surrender To Wind
1083, 1097, // Surrender To Fire / Dreaming Spirit
1092, 1064, // Fear / Silence
1160, 1164, // Slow / Curse Weakness
1169, 1170, // Curse Fear / Anchor
1201, 1206, // Dryad Root / Wind Shackle
1222, 1223, // Curse Chaos / Surrender To Earth
1224, 1263, // Surrender To Poison / Curse Gloom
1269, 1336, // Curse Disease / Curse of Doom
1337, 1338, // Curse of Abyss / Arcane Chaos
1358, 1359, // Block Shield / Block Wind Walk
1386, 1394, // Arcane Disruption / Trance
1396, 1445, // Magical BackFire / Surrender to Dark
1446, 1447, // Shadow Bind / Voice Bind
1481, 1482, // Oblivion / Weak Constitution
1483, 1484, // Thin Skin / Enervation
1485, 1486, // Spite / Mental Impoverish
1511, 1524, // Curse of Life Flow / Surrender to the Divine
1529, // Soul Web
};
//@formatter:on
// Misc
private static final int MIN_DISTANCE = 150;
private RangeGuard()
{
super(RangeGuard.class.getSimpleName(), "ai/group_template");
for (L2NpcTemplate template : NpcData.getInstance().getAllNpcOfClassType("L2Monster"))
{
if (template.getParameters().getInt("LongRangeGuardRate", -1) > 0)
{
addAttackId(template.getId());
}
}
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon, Skill skill)
{
final L2Playable playable = (isSummon) ? attacker.getSummon() : attacker;
final int longRangeGuardRate = npc.getTemplate().getParameters().getInt("LongRangeGuardRate");
final double distance = Util.calculateDistance(npc, playable, true, false);
if (npc.isAffectedBySkill(ULTIMATE_DEFENSE.getSkillId()) && (distance <= MIN_DISTANCE))
{
npc.stopSkillEffects(true, ULTIMATE_DEFENSE.getSkillId());
}
else if ((distance > MIN_DISTANCE) && !npc.isSkillDisabled(ULTIMATE_DEFENSE.getSkillId()) && !((skill != null) && Util.contains(NOT_ALLOWED_SKILLS, skill.getId())) && (getRandom(100) < longRangeGuardRate))
{
final L2Object target = npc.getTarget();
npc.setTarget(npc);
npc.doCast(ULTIMATE_DEFENSE.getSkill());
npc.setTarget(target);
}
return super.onAttack(npc, attacker, damage, isSummon, skill);
}
public static void main(String[] args)
{
new RangeGuard();
}
}

View File

@@ -0,0 +1,91 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import ai.npc.AbstractNpcAI;
/**
* Remnants AI.
* @author DS
*/
public final class Remnants extends AbstractNpcAI
{
private static final int[] NPCS =
{
18463,
18464,
18465
};
private static final int SKILL_HOLY_WATER = 2358;
// TODO: Find retail strings.
// private static final String MSG = "The holy water affects Remnants Ghost. You have freed his soul.";
// private static final String MSG_DEREK = "The holy water affects Derek. You have freed his soul.";
private Remnants()
{
super(Remnants.class.getSimpleName(), "ai/group_template");
addSpawnId(NPCS);
addSkillSeeId(NPCS);
// Do not override onKill for Derek here. Let's make global Hellbound manipulations in Engine where it is possible.
}
@Override
public final String onSpawn(L2Npc npc)
{
npc.setIsMortal(false);
return super.onSpawn(npc);
}
@Override
public final String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (skill.getId() == SKILL_HOLY_WATER)
{
if (!npc.isDead())
{
if ((targets.length > 0) && (targets[0] == npc))
{
if (npc.getCurrentHp() < (npc.getMaxHp() * 0.02)) // Lower, than 2%
{
npc.doDie(caster);
//@formatter:off
/*if (npc.getNpcId() == DEREK)
{
caster.sendMessage(MSG_DEREK);
}
else
{
caster.sendMessage(MSG);
}*/
//@formatter:on
}
}
}
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
public static void main(String[] args)
{
new Remnants();
}
}

View File

@@ -0,0 +1,54 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import ai.npc.AbstractNpcAI;
/**
* Sandstorms AI.
* @author Ectis
*/
public class Sandstorms extends AbstractNpcAI
{
// NPCs
private static final int SANDSTORM = 32350;
// Skills
private static final SkillHolder GUST = new SkillHolder(5435, 1); // Gust
public Sandstorms()
{
super(Sandstorms.class.getSimpleName(), "ai/group_template");
addAggroRangeEnterId(SANDSTORM); // Sandstorm
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
npc.setTarget(player);
npc.doCast(GUST.getSkill());
return super.onAggroRangeEnter(npc, player, isSummon);
}
public static void main(String[] args)
{
new Sandstorms();
}
}

View File

@@ -0,0 +1,61 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* See Through Silent Move AI.
* @author Gigiikun
*/
public class SeeThroughSilentMove extends AbstractNpcAI
{
//@formatter:off
private static final int[] MONSTERS =
{
18001, 18002, 22199, 22215, 22216, 22217, 22327, 22746, 22747, 22748,
22749, 22750, 22751, 22752, 22753, 22754, 22755, 22756, 22757, 22758,
22759, 22760, 22761, 22762, 22763, 22764, 22765, 22794, 22795, 22796,
22797, 22798, 22799, 22800, 22843, 22857, 25725, 25726, 25727, 29009,
29010, 29011, 29012, 29013
};
//@formatter:on
private SeeThroughSilentMove()
{
super(SeeThroughSilentMove.class.getSimpleName(), "ai/group_template");
addSpawnId(MONSTERS);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.isAttackable())
{
((L2Attackable) npc).setSeeThroughSilentMove(true);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new SeeThroughSilentMove();
}
}

View File

@@ -0,0 +1,330 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SpawnTable;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Sel Mahum Training Ground AI for drill groups.
* @author GKR
*/
public final class SelMahumDrill extends AbstractNpcAI
{
private static final int[] MAHUM_CHIEFS =
{
22775, // Sel Mahum Drill Sergeant
22776, // Sel Mahum Training Officer
22778, // Sel Mahum Drill Sergeant
};
private static final int[] MAHUM_SOLDIERS =
{
22780, // Sel Mahum Recruit
22782, // Sel Mahum Recruit
22783, // Sel Mahum Soldier
22784, // Sel Mahum Recruit
22785, // Sel Mahum Soldier
};
private static final int[] CHIEF_SOCIAL_ACTIONS =
{
1,
4,
5,
7
};
private static final Actions[] SOLDIER_SOCIAL_ACTIONS =
{
Actions.SCE_TRAINING_ACTION_A,
Actions.SCE_TRAINING_ACTION_B,
Actions.SCE_TRAINING_ACTION_C,
Actions.SCE_TRAINING_ACTION_D
};
private static final NpcStringId[] CHIEF_FSTRINGS =
{
NpcStringId.HOW_DARE_YOU_ATTACK_MY_RECRUITS,
NpcStringId.WHO_IS_DISRUPTING_THE_ORDER
};
private static final NpcStringId[] SOLDIER_FSTRINGS =
{
NpcStringId.THE_DRILLMASTER_IS_DEAD,
NpcStringId.LINE_UP_THE_RANKS
};
// Chiefs event broadcast range
private static final int TRAINING_RANGE = 1000;
private static enum Actions
{
SCE_TRAINING_ACTION_A(4, -1, 2, 2333),
SCE_TRAINING_ACTION_B(1, -1, 2, 4333),
SCE_TRAINING_ACTION_C(6, 5, 4, 1000),
SCE_TRAINING_ACTION_D(7, -1, 2, 1000);
private final int _socialActionId;
private final int _altSocialActionId;
private final int _repeatCount;
private final int _repeatInterval;
private Actions(int socialActionId, int altSocialActionId, int repeatCount, int repeatInterval)
{
_socialActionId = socialActionId;
_altSocialActionId = altSocialActionId;
_repeatCount = repeatCount;
_repeatInterval = repeatInterval;
}
protected int getSocialActionId()
{
return _socialActionId;
}
protected int getAltSocialActionId()
{
return _altSocialActionId;
}
protected int getRepeatCount()
{
return _repeatCount;
}
protected int getRepeatInterval()
{
return _repeatInterval;
}
}
private SelMahumDrill()
{
super(SelMahumDrill.class.getSimpleName(), "ai/group_template");
addAttackId(MAHUM_CHIEFS);
addAttackId(MAHUM_SOLDIERS);
addKillId(MAHUM_CHIEFS);
addEventReceivedId(MAHUM_CHIEFS);
addEventReceivedId(MAHUM_SOLDIERS);
addSpawnId(MAHUM_CHIEFS);
addSpawnId(MAHUM_SOLDIERS);
// Start global return home timer
startQuestTimer("return_home", 120000, null, null, true);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "do_social_action":
{
if ((npc != null) && !npc.isDead())
{
if (Util.contains(MAHUM_CHIEFS, npc.getId()))
{
if ((npc.getVariables().getInt("BUSY_STATE") == 0) && (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE) && npc.staysInSpawnLoc())
{
final int idx = getRandom(6);
if (idx <= (CHIEF_SOCIAL_ACTIONS.length - 1))
{
npc.broadcastSocialAction(CHIEF_SOCIAL_ACTIONS[idx]);
npc.getVariables().set("SOCIAL_ACTION_NEXT_INDEX", idx); // Pass social action index to soldiers via script value
npc.broadcastEvent("do_social_action", TRAINING_RANGE, null);
}
}
startQuestTimer("do_social_action", 15000, npc, null);
}
else if (Util.contains(MAHUM_SOLDIERS, npc.getId()))
{
handleSocialAction(npc, SOLDIER_SOCIAL_ACTIONS[npc.getVariables().getInt("SOCIAL_ACTION_NEXT_INDEX")], false);
}
}
break;
}
case "reset_busy_state":
{
if (npc != null)
{
npc.getVariables().remove("BUSY_STATE");
npc.disableCoreAI(false);
}
break;
}
case "return_home":
{
for (int npcId : MAHUM_SOLDIERS)
{
for (L2Spawn npcSpawn : SpawnTable.getInstance().getSpawns(npcId))
{
final L2Npc soldier = npcSpawn.getLastSpawn();
if ((soldier != null) && !soldier.isDead() && (npcSpawn.getName() != null) && npcSpawn.getName().startsWith("smtg_drill_group") && !soldier.staysInSpawnLoc() && ((soldier.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE) || (soldier.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)))
{
soldier.setHeading(npcSpawn.getHeading());
soldier.teleToLocation(npcSpawn.getLocation(), false);
}
}
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
// group hate
for (L2Character ch : npc.getKnownList().getKnownCharacters())
{
if (!ch.isInCombat() && ch.isMonster() && (((L2Npc) ch).getSpawn().getName() == npc.getSpawn().getName()))
{
((L2MonsterInstance) ch).addDamageHate(attacker, 0, 1000);
}
}
if ((getRandom(10) < 1) && (Util.contains(MAHUM_SOLDIERS, npc.getId())))
{
npc.broadcastEvent("ATTACKED", 1000, null);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
{
if ((receiver != null) && !receiver.isDead() && receiver.isInMySpawnGroup(sender))
{
switch (eventName)
{
case "do_social_action":
{
if (Util.contains(MAHUM_SOLDIERS, receiver.getId()))
{
final int actionIndex = sender.getVariables().getInt("SOCIAL_ACTION_NEXT_INDEX");
receiver.getVariables().set("SOCIAL_ACTION_NEXT_INDEX", actionIndex);
handleSocialAction(receiver, SOLDIER_SOCIAL_ACTIONS[actionIndex], true);
}
break;
}
case "CHIEF_DIED":
{
if (Util.contains(MAHUM_SOLDIERS, receiver.getId()))
{
if (getRandom(4) < 1)
{
broadcastNpcSay(receiver, ChatType.NPC_GENERAL, SOLDIER_FSTRINGS[getRandom(2)]);
}
if (receiver.canBeAttacked())
{
((L2Attackable) receiver).clearAggroList();
}
receiver.disableCoreAI(true);
receiver.getVariables().set("BUSY_STATE", 1);
receiver.setIsRunning(true);
receiver.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location((receiver.getX() + getRandom(-800, 800)), (receiver.getY() + getRandom(-800, 800)), receiver.getZ(), receiver.getHeading()));
startQuestTimer("reset_busy_state", 5000, receiver, null);
}
break;
}
case "ATTACKED":
{
if (Util.contains(MAHUM_CHIEFS, receiver.getId()))
{
broadcastNpcSay(receiver, ChatType.NPC_GENERAL, CHIEF_FSTRINGS[getRandom(2)]);
}
break;
}
}
}
return super.onEventReceived(eventName, sender, receiver, reference);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
npc.broadcastEvent("CHIEF_DIED", TRAINING_RANGE, null);
return null;
}
@Override
public String onSpawn(L2Npc npc)
{
if (Util.contains(MAHUM_CHIEFS, npc.getId()))
{
startQuestTimer("do_social_action", 15000, npc, null);
}
else if ((getRandom(18) < 1) && Util.contains(MAHUM_SOLDIERS, npc.getId()))
{
npc.getVariables().set("SOCIAL_ACTION_ALT_BEHAVIOR", 1);
}
// Restore AI handling by core
npc.disableCoreAI(false);
return super.onSpawn(npc);
}
private void handleSocialAction(L2Npc npc, Actions action, boolean firstCall)
{
if ((npc.getVariables().getInt("BUSY_STATE") != 0) || (npc.getAI().getIntention() != CtrlIntention.AI_INTENTION_ACTIVE) || !npc.staysInSpawnLoc())
{
return;
}
final int socialActionId = (npc.getVariables().getInt("SOCIAL_ACTION_ALT_BEHAVIOR") == 0) ? action.getSocialActionId() : action.getAltSocialActionId();
if (socialActionId < 0)
{
return;
}
if (firstCall)
{
npc.getVariables().set("SOCIAL_ACTION_REMAINED_COUNT", action.getRepeatCount());
}
npc.broadcastSocialAction(socialActionId);
final int remainedCount = npc.getVariables().getInt("SOCIAL_ACTION_REMAINED_COUNT");
if (remainedCount > 0)
{
npc.getVariables().set("SOCIAL_ACTION_REMAINED_COUNT", (remainedCount - 1));
startQuestTimer("do_social_action", action.getRepeatInterval(), npc, null);
}
}
public static void main(String[] args)
{
new SelMahumDrill();
}
}

View File

@@ -0,0 +1,403 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SkillData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Sel Mahum Training Ground AI for squads and chefs.
* @author GKR
*/
public final class SelMahumSquad extends AbstractNpcAI
{
// NPC's
private static final int CHEF = 18908;
private static final int FIRE = 18927;
private static final int STOVE = 18933;
private static final int OHS_Weapon = 15280;
private static final int THS_Weapon = 15281;
// Sel Mahum Squad Leaders
private static final int[] SQUAD_LEADERS =
{
22786,
22787,
22788
};
private static final NpcStringId[] CHEF_FSTRINGS =
{
NpcStringId.I_BROUGHT_THE_FOOD,
NpcStringId.COME_AND_EAT
};
private static final int FIRE_EFFECT_BURN = 1;
private static final int FIRE_EFFECT_NONE = 2;
private static final int MAHUM_EFFECT_EAT = 1;
private static final int MAHUM_EFFECT_SLEEP = 2;
private static final int MAHUM_EFFECT_NONE = 3;
private SelMahumSquad()
{
super(SelMahumSquad.class.getSimpleName(), "ai/group_template");
addAttackId(CHEF);
addAttackId(SQUAD_LEADERS);
addEventReceivedId(CHEF, FIRE, STOVE);
addEventReceivedId(SQUAD_LEADERS);
addFactionCallId(SQUAD_LEADERS);
addKillId(CHEF);
addMoveFinishedId(SQUAD_LEADERS);
addNodeArrivedId(CHEF);
addSkillSeeId(STOVE);
addSpawnId(CHEF, FIRE);
addSpawnId(SQUAD_LEADERS);
addSpellFinishedId(CHEF);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "chef_disable_reward":
{
npc.getVariables().set("REWARD_TIME_GONE", 1);
break;
}
case "chef_heal_player":
{
healPlayer(npc, player);
break;
}
case "chef_remove_invul":
{
if (npc.isMonster())
{
npc.setIsInvul(false);
npc.getVariables().remove("INVUL_REMOVE_TIMER_STARTED");
if ((player != null) && !player.isDead() && npc.getKnownList().knowsThePlayer(player))
{
addAttackDesire(npc, player);
}
}
break;
}
case "chef_set_invul":
{
if (!npc.isDead())
{
npc.setIsInvul(true);
}
break;
}
case "fire":
{
startQuestTimer("fire", 30000 + getRandom(5000), npc, null);
npc.setDisplayEffect(FIRE_EFFECT_NONE);
if (getRandom(GameTimeController.getInstance().isNight() ? 2 : 4) < 1)
{
npc.setDisplayEffect(FIRE_EFFECT_BURN); // fire burns
npc.broadcastEvent("SCE_CAMPFIRE_START", 600, null);
}
else
{
npc.setDisplayEffect(FIRE_EFFECT_NONE); // fire goes out
npc.broadcastEvent("SCE_CAMPFIRE_END", 600, null);
}
break;
}
case "fire_arrived":
{
// myself.i_quest0 = 1;
npc.setIsRunning(false);
npc.setTarget(npc);
if (npc.isNoRndWalk())
{
npc.doCast(SkillData.getInstance().getSkill(6331, 1));
npc.setDisplayEffect(MAHUM_EFFECT_SLEEP);
}
if (npc.getVariables().getInt("BUSY_STATE") == 1) // Eating
{
npc.doCast(SkillData.getInstance().getSkill(6332, 1));
npc.setDisplayEffect(MAHUM_EFFECT_EAT);
}
startQuestTimer("remove_effects", 300000, npc, null);
break;
}
case "notify_dinner":
{
npc.broadcastEvent("SCE_DINNER_EAT", 600, null);
break;
}
case "remove_effects":
{
// myself.i_quest0 = 0;
npc.setIsRunning(true);
npc.setDisplayEffect(MAHUM_EFFECT_NONE);
break;
}
case "reset_full_bottle_prize":
{
npc.getVariables().remove("FULL_BARREL_REWARDING_PLAYER");
break;
}
case "return_from_fire":
{
if (npc.isMonster() && !npc.isDead())
{
((L2MonsterInstance) npc).returnHome();
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon, Skill skill)
{
if ((npc.getId() == CHEF) && (npc.getVariables().getInt("BUSY_STATE") == 0))
{
if (npc.getVariables().getInt("INVUL_REMOVE_TIMER_STARTED") == 0)
{
startQuestTimer("chef_remove_invul", 180000, npc, attacker);
startQuestTimer("chef_disable_reward", 60000, npc, null);
npc.getVariables().set("INVUL_REMOVE_TIMER_STARTED", 1);
}
startQuestTimer("chef_heal_player", 1000, npc, attacker);
startQuestTimer("chef_set_invul", 60000, npc, null);
npc.getVariables().set("BUSY_STATE", 1);
}
else if (Util.contains(SQUAD_LEADERS, npc.getId()))
{
handlePreAttackMotion(npc);
}
return super.onAttack(npc, attacker, damage, isSummon, skill);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
{
handlePreAttackMotion(npc);
return super.onFactionCall(npc, caller, attacker, isSummon);
}
@Override
public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
{
switch (eventName)
{
case "SCE_DINNER_CHECK":
{
if (receiver.getId() == FIRE)
{
receiver.setDisplayEffect(FIRE_EFFECT_BURN);
final L2Npc stove = addSpawn(STOVE, receiver.getX(), receiver.getY(), receiver.getZ() + 100, 0, false, 0);
stove.setSummoner(receiver);
startQuestTimer("notify_dinner", 2000, receiver, null); // @SCE_DINNER_EAT
broadcastNpcSay(sender, ChatType.NPC_GENERAL, CHEF_FSTRINGS[getRandom(2)], 1250);
}
break;
}
case "SCE_CAMPFIRE_START":
{
if (!receiver.isNoRndWalk() && !receiver.isDead() && (receiver.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) && Util.contains(SQUAD_LEADERS, receiver.getId()))
{
receiver.setIsNoRndWalk(true); // Moving to fire - i_ai0 = 1
receiver.setIsRunning(true);
final Location loc = sender.getPointInRange(100, 200);
loc.setHeading(receiver.getHeading());
receiver.stopMove(null);
receiver.getVariables().set("DESTINATION_X", loc.getX());
receiver.getVariables().set("DESTINATION_Y", loc.getY());
receiver.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc);
}
break;
}
case "SCE_CAMPFIRE_END":
{
if ((receiver.getId() == STOVE) && (receiver.getSummoner() == sender))
{
receiver.deleteMe();
}
else if ((receiver.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) && Util.contains(SQUAD_LEADERS, receiver.getId()))
{
receiver.setIsNoRndWalk(false);
receiver.getVariables().remove("BUSY_STATE");
receiver.setRHandId(THS_Weapon);
startQuestTimer("return_from_fire", 3000, receiver, null);
}
break;
}
case "SCE_DINNER_EAT":
{
if (!receiver.isDead() && (receiver.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) && (receiver.getVariables().getInt("BUSY_STATE", 0) == 0) && Util.contains(SQUAD_LEADERS, receiver.getId()))
{
if (receiver.isNoRndWalk()) // i_ai0 == 1
{
receiver.setRHandId(THS_Weapon);
}
receiver.setIsNoRndWalk(true); // Moving to fire - i_ai0 = 1
receiver.getVariables().set("BUSY_STATE", 1); // Eating - i_ai3 = 1
receiver.setIsRunning(true);
broadcastNpcSay(receiver, ChatType.NPC_GENERAL, (getRandom(3) < 1) ? NpcStringId.LOOKS_DELICIOUS : NpcStringId.LET_S_GO_EAT);
final Location loc = sender.getPointInRange(100, 200);
loc.setHeading(receiver.getHeading());
receiver.stopMove(null);
receiver.getVariables().set("DESTINATION_X", loc.getX());
receiver.getVariables().set("DESTINATION_Y", loc.getY());
receiver.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc);
}
break;
}
case "SCE_SOUP_FAILURE":
{
if (Util.contains(SQUAD_LEADERS, receiver.getId()))
{
receiver.getVariables().set("FULL_BARREL_REWARDING_PLAYER", reference.getObjectId()); // TODO: Use it in 289 quest
startQuestTimer("reset_full_bottle_prize", 180000, receiver, null);
}
break;
}
}
return super.onEventReceived(eventName, sender, receiver, reference);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.isMonster() && (npc.getVariables().getInt("REWARD_TIME_GONE") == 0))
{
((L2MonsterInstance) npc).dropItem(killer, 15492, 1);
}
cancelQuestTimer("chef_remove_invul", npc, null);
cancelQuestTimer("chef_disable_reward", npc, null);
cancelQuestTimer("chef_heal_player", npc, null);
cancelQuestTimer("chef_set_invul", npc, null);
return super.onKill(npc, killer, isSummon);
}
@Override
public void onMoveFinished(L2Npc npc)
{
// Npc moves to fire
if (npc.isNoRndWalk() && (npc.getX() == npc.getVariables().getInt("DESTINATION_X")) && (npc.getY() == npc.getVariables().getInt("DESTINATION_Y")))
{
npc.setRHandId(OHS_Weapon);
startQuestTimer("fire_arrived", 3000, npc, null);
}
}
@Override
public void onNodeArrived(L2Npc npc)
{
npc.broadcastEvent("SCE_DINNER_CHECK", 300, null);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if ((npc.getId() == STOVE) && (skill.getId() == 9075) && Util.contains(targets, npc))
{
npc.doCast(SkillData.getInstance().getSkill(6688, 1));
npc.broadcastEvent("SCE_SOUP_FAILURE", 600, caster);
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.getId() == CHEF)
{
npc.setIsInvul(false);
}
else if (npc.getId() == FIRE)
{
startQuestTimer("fire", 1000, npc, null);
}
else if (Util.contains(SQUAD_LEADERS, npc.getId()))
{
npc.setDisplayEffect(3);
npc.setIsNoRndWalk(false);
}
return super.onSpawn(npc);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if ((skill != null) && (skill.getId() == 6330))
{
healPlayer(npc, player);
}
return super.onSpellFinished(npc, player, skill);
}
private void healPlayer(L2Npc npc, L2PcInstance player)
{
if ((player != null) && !player.isDead() && (npc.getVariables().getInt("INVUL_REMOVE_TIMER_STARTED") != 1) && ((npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ATTACK) || (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_CAST)))
{
npc.setTarget(player);
npc.doCast(SkillData.getInstance().getSkill(6330, 1));
}
else
{
cancelQuestTimer("chef_set_invul", npc, null);
npc.getVariables().remove("BUSY_STATE");
npc.getVariables().remove("INVUL_REMOVE_TIMER_STARTED");
npc.setIsRunning(false);
}
}
private void handlePreAttackMotion(L2Npc attacked)
{
cancelQuestTimer("remove_effects", attacked, null);
attacked.getVariables().remove("BUSY_STATE");
attacked.setIsNoRndWalk(false);
attacked.setDisplayEffect(MAHUM_EFFECT_NONE);
if (attacked.getRightHandItem() == OHS_Weapon)
{
attacked.setRHandId(THS_Weapon);
}
// TODO: Check about i_quest0
}
public static void main(String[] args)
{
new SelMahumSquad();
}
}

View File

@@ -0,0 +1,208 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Silent Valley AI
* @author malyelfik
*/
public final class SilentValley extends AbstractNpcAI
{
// Skills
private static final SkillHolder BETRAYAL = new SkillHolder(6033, 1); // Treasure Seeker's Betrayal
private static final SkillHolder BLAZE = new SkillHolder(4157, 10); // NPC Blaze - Magic
// Item
private static final int SACK = 13799; // Treasure Sack of the Ancient Giants
// Chance
private static final int SPAWN_CHANCE = 2;
private static final int CHEST_DIE_CHANCE = 5;
// Monsters
private static final int CHEST = 18693; // Treasure Chest of the Ancient Giants
private static final int GUARD1 = 18694; // Treasure Chest Guard
private static final int GUARD2 = 18695; // Treasure Chest Guard
private static final int[] MOBS =
{
20965, // Chimera Piece
20966, // Changed Creation
20967, // Past Creature
20968, // Nonexistent Man
20969, // Giant's Shadow
20970, // Soldier of Ancient Times
20971, // Warrior of Ancient Times
20972, // Shaman of Ancient Times
20973, // Forgotten Ancient People
};
private SilentValley()
{
super(SilentValley.class.getSimpleName(), "ai/group_template");
addAttackId(MOBS);
addAttackId(CHEST, GUARD1, GUARD2);
addEventReceivedId(GUARD1, GUARD2);
addKillId(MOBS);
addSeeCreatureId(MOBS);
addSeeCreatureId(GUARD1, GUARD2);
addSpawnId(CHEST, GUARD2);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if ((npc != null) && !npc.isDead())
{
switch (event)
{
case "CLEAR":
npc.doDie(null);
break;
case "CLEAR_EVENT":
npc.broadcastEvent("CLEAR_ALL_INSTANT", 2000, null);
npc.doDie(null);
break;
case "SPAWN_CHEST":
addSpawn(CHEST, npc.getX() - 100, npc.getY(), npc.getZ() - 100, 0, false, 0);
break;
}
}
return null;
}
@Override
public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon)
{
switch (npc.getId())
{
case CHEST:
{
if (!isSummon && npc.isScriptValue(0))
{
npc.setScriptValue(1);
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.YOU_WILL_BE_CURSED_FOR_SEEKING_THE_TREASURE);
npc.setTarget(player);
npc.doCast(BETRAYAL.getSkill());
}
else if (isSummon || (getRandom(100) < CHEST_DIE_CHANCE))
{
npc.dropItem(player, SACK, 1);
npc.broadcastEvent("CLEAR_ALL", 2000, null);
npc.doDie(null);
cancelQuestTimer("CLEAR_EVENT", npc, null);
}
break;
}
case GUARD1:
case GUARD2:
{
npc.setTarget(player);
npc.doCast(BLAZE.getSkill());
addAttackDesire(npc, player);
break;
}
default:
{
if (isSummon)
{
addAttackDesire(npc, player);
}
}
}
return super.onAttack(npc, player, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (getRandom(1000) < SPAWN_CHANCE)
{
final int newZ = npc.getZ() + 100;
addSpawn(GUARD2, npc.getX() + 100, npc.getY(), newZ, 0, false, 0);
addSpawn(GUARD1, npc.getX() - 100, npc.getY(), newZ, 0, false, 0);
addSpawn(GUARD1, npc.getX(), npc.getY() + 100, newZ, 0, false, 0);
addSpawn(GUARD1, npc.getX(), npc.getY() - 100, newZ, 0, false, 0);
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
{
if (creature.isPlayable())
{
final L2PcInstance player = (isSummon) ? ((L2Summon) creature).getOwner() : creature.getActingPlayer();
if ((npc.getId() == GUARD1) || (npc.getId() == GUARD2))
{
npc.setTarget(player);
npc.doCast(BLAZE.getSkill());
addAttackDesire(npc, player);
}
else if (creature.isAffectedBySkill(BETRAYAL.getSkillId()))
{
addAttackDesire(npc, player);
}
}
return super.onSeeCreature(npc, creature, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.getId() == CHEST)
{
npc.setIsInvul(true);
startQuestTimer("CLEAR_EVENT", 300000, npc, null);
}
else
{
startQuestTimer("SPAWN_CHEST", 10000, npc, null);
}
return super.onSpawn(npc);
}
@Override
public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
{
if ((receiver != null) && !receiver.isDead())
{
switch (eventName)
{
case "CLEAR_ALL":
startQuestTimer("CLEAR", 60000, receiver, null);
break;
case "CLEAR_ALL_INSTANT":
receiver.doDie(null);
break;
}
}
return super.onEventReceived(eventName, sender, receiver, reference);
}
public static void main(String[] args)
{
new SilentValley();
}
}

View File

@@ -0,0 +1,242 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import java.util.List;
import com.l2jmobius.gameserver.datatables.SkillData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.util.Broadcast;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Stakato Nest AI.
* @author Gnacik
*/
public final class StakatoNest extends AbstractNpcAI
{
// @formatter:off
// List of all mobs just for register
private static final int[] STAKATO_MOBS =
{
18793, 18794, 18795, 18796, 18797, 18798, 22617, 22618, 22619, 22620,
22621, 22622, 22623, 22624, 22625, 22626, 22627, 22628, 22629, 22630,
22631, 22632, 22633, 25667
};
// Coocons
private static final int[] COCOONS =
{
18793, 18794, 18795, 18796, 18797, 18798
};
// @formatter:on
// Cannibalistic Stakato Leader
private static final int STAKATO_LEADER = 22625;
// Spike Stakato Nurse
private static final int STAKATO_NURSE = 22630;
// Spike Stakato Nurse (Changed)
private static final int STAKATO_NURSE_2 = 22631;
// Spiked Stakato Baby
private static final int STAKATO_BABY = 22632;
// Spiked Stakato Captain
private static final int STAKATO_CAPTAIN = 22629;
// Female Spiked Stakato
private static final int STAKATO_FEMALE = 22620;
// Male Spiked Stakato
private static final int STAKATO_MALE = 22621;
// Male Spiked Stakato (Changed)
private static final int STAKATO_MALE_2 = 22622;
// Spiked Stakato Guard
private static final int STAKATO_GUARD = 22619;
// Cannibalistic Stakato Chief
private static final int STAKATO_CHIEF = 25667;
// Growth Accelerator
private static final int GROWTH_ACCELERATOR = 2905;
// Small Stakato Cocoon
private static final int SMALL_COCOON = 14833;
// Large Stakato Cocoon
private static final int LARGE_COCOON = 14834;
private StakatoNest()
{
super(StakatoNest.class.getSimpleName(), "ai/group_template");
registerMobs(STAKATO_MOBS);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
if ((mob.getId() == STAKATO_LEADER) && (getRandom(1000) < 100) && (mob.getCurrentHp() < (mob.getMaxHp() * 0.3)))
{
final L2MonsterInstance _follower = checkMinion(npc);
if (_follower != null)
{
final double _hp = _follower.getCurrentHp();
if (_hp > (_follower.getMaxHp() * 0.3))
{
mob.abortAttack();
mob.abortCast();
mob.setHeading(Util.calculateHeadingFrom(mob, _follower));
mob.doCast(SkillData.getInstance().getSkill(4484, 1));
mob.setCurrentHp(mob.getCurrentHp() + _hp);
_follower.doDie(_follower);
_follower.deleteMe();
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
final L2MonsterInstance monster;
switch (npc.getId())
{
case STAKATO_NURSE:
monster = checkMinion(npc);
if (monster != null)
{
Broadcast.toSelfAndKnownPlayers(npc, new MagicSkillUse(npc, 2046, 1, 1000, 0));
for (int i = 0; i < 3; i++)
{
final L2Npc spawned = addSpawn(STAKATO_CAPTAIN, monster, true);
addAttackDesire(spawned, killer);
}
}
break;
case STAKATO_BABY:
monster = ((L2MonsterInstance) npc).getLeader();
if ((monster != null) && !monster.isDead())
{
startQuestTimer("nurse_change", 5000, monster, killer);
}
break;
case STAKATO_MALE:
monster = checkMinion(npc);
if (monster != null)
{
Broadcast.toSelfAndKnownPlayers(npc, new MagicSkillUse(npc, 2046, 1, 1000, 0));
for (int i = 0; i < 3; i++)
{
final L2Npc spawned = addSpawn(STAKATO_GUARD, monster, true);
addAttackDesire(spawned, killer);
}
}
break;
case STAKATO_FEMALE:
monster = ((L2MonsterInstance) npc).getLeader();
if ((monster != null) && !monster.isDead())
{
startQuestTimer("male_change", 5000, monster, killer);
}
break;
case STAKATO_CHIEF:
if (killer.isInParty())
{
final List<L2PcInstance> party = killer.getParty().getMembers();
for (L2PcInstance member : party)
{
giveCocoon(member, npc);
}
}
else
{
giveCocoon(killer, npc);
}
break;
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (Util.contains(COCOONS, npc.getId()) && Util.contains(targets, npc) && (skill.getId() == GROWTH_ACCELERATOR))
{
npc.doDie(caster);
final L2Npc spawned = addSpawn(STAKATO_CHIEF, npc.getX(), npc.getY(), npc.getZ(), Util.calculateHeadingFrom(npc, caster), false, 0, true);
addAttackDesire(spawned, caster);
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public final String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if ((npc == null) || (player == null) || npc.isDead())
{
return null;
}
int npcId = 0;
switch (event)
{
case "nurse_change":
npcId = STAKATO_NURSE_2;
break;
case "male_change":
npcId = STAKATO_MALE_2;
break;
}
if (npcId > 0)
{
npc.getSpawn().decreaseCount(npc);
npc.deleteMe();
final L2Npc spawned = addSpawn(npcId, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), false, 0, true);
addAttackDesire(spawned, player);
}
return super.onAdvEvent(event, npc, player);
}
private static L2MonsterInstance checkMinion(L2Npc npc)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
if (mob.hasMinions())
{
final List<L2MonsterInstance> minion = mob.getMinionList().getSpawnedMinions();
if ((minion != null) && !minion.isEmpty() && (minion.get(0) != null) && !minion.get(0).isDead())
{
return minion.get(0);
}
}
return null;
}
private static void giveCocoon(L2PcInstance player, L2Npc npc)
{
player.addItem("StakatoCocoon", ((getRandom(100) > 80) ? LARGE_COCOON : SMALL_COCOON), 1, npc, true);
}
public static void main(String[] args)
{
new StakatoNest();
}
}

View File

@@ -0,0 +1,104 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import ai.npc.AbstractNpcAI;
/**
* Summon Pc AI.<br>
* Summon the player to the NPC on attack.
* @author Zoey76
*/
public final class SummonPc extends AbstractNpcAI
{
// NPCs
private static final int PORTA = 20213;
private static final int PERUM = 20221;
// Skill
private static final SkillHolder SUMMON_PC = new SkillHolder(4161, 1);
private SummonPc()
{
super(SummonPc.class.getSimpleName(), "ai/group_template");
addAttackId(PORTA, PERUM);
addSpellFinishedId(PORTA, PERUM);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
final int chance = getRandom(100);
final boolean attacked = npc.getVariables().getBoolean("attacked", false);
if ((npc.calculateDistance(attacker, true, false) > 300) && !attacked)
{
if (chance < 50)
{
if ((SUMMON_PC.getSkill().getMpConsume() < npc.getCurrentMp()) && (SUMMON_PC.getSkill().getHpConsume() < npc.getCurrentHp()) && !npc.isSkillDisabled(SUMMON_PC.getSkill()))
{
npc.setTarget(attacker);
npc.doCast(SUMMON_PC.getSkill());
}
if ((SUMMON_PC.getSkill().getMpConsume() < npc.getCurrentMp()) && (SUMMON_PC.getSkill().getHpConsume() < npc.getCurrentHp()) && !npc.isSkillDisabled(SUMMON_PC.getSkill()))
{
npc.setTarget(attacker);
npc.doCast(SUMMON_PC.getSkill());
npc.getVariables().set("attacked", true);
}
}
}
else if ((npc.calculateDistance(attacker, true, false) > 100) && !attacked)
{
final L2Attackable monster = (L2Attackable) npc;
if (monster.getMostHated() != null)
{
if (((monster.getMostHated() == attacker) && (chance < 50)) || (chance < 10))
{
if ((SUMMON_PC.getSkill().getMpConsume() < npc.getCurrentMp()) && (SUMMON_PC.getSkill().getHpConsume() < npc.getCurrentHp()) && !npc.isSkillDisabled(SUMMON_PC.getSkill()))
{
npc.setTarget(attacker);
npc.doCast(SUMMON_PC.getSkill());
npc.getVariables().set("attacked", true);
}
}
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if ((skill.getId() == SUMMON_PC.getSkillId()) && !npc.isDead() && npc.getVariables().getBoolean("attacked", false))
{
player.teleToLocation(npc);
npc.getVariables().set("attacked", false);
}
return super.onSpellFinished(npc, player, skill);
}
public static void main(String[] args)
{
new SummonPc();
}
}

View File

@@ -0,0 +1,137 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Turek Orcs AI - flee and return with assistance
* @author GKR
*/
public final class TurekOrcs extends AbstractNpcAI
{
// NPC's
private static final int[] MOBS =
{
20494, // Turek War Hound
20495, // Turek Orc Warlord
20497, // Turek Orc Skirmisher
20498, // Turek Orc Supplier
20499, // Turek Orc Footman
20500, // Turek Orc Sentinel
};
private TurekOrcs()
{
super(TurekOrcs.class.getSimpleName(), "ai/group_template");
addAttackId(MOBS);
addEventReceivedId(MOBS);
addMoveFinishedId(MOBS);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("checkState") && !npc.isDead() && (npc.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK))
{
if ((npc.getCurrentHp() > (npc.getMaxHp() * 0.7)) && (npc.getVariables().getInt("state") == 2))
{
npc.getVariables().set("state", 3);
((L2Attackable) npc).returnHome();
}
else
{
npc.getVariables().remove("state");
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (!npc.getVariables().hasVariable("isHit"))
{
npc.getVariables().set("isHit", 1);
}
else if ((npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) && (npc.getCurrentHp() > (npc.getMaxHp() * 0.3)) && (attacker.getCurrentHp() > (attacker.getMaxHp() * 0.25)) && npc.hasAIValue("fleeX") && npc.hasAIValue("fleeY") && npc.hasAIValue("fleeZ") && (npc.getVariables().getInt("state") == 0) && (getRandom(100) < 10))
{
// Say and flee
broadcastNpcSay(npc, ChatType.GENERAL, NpcStringId.getNpcStringId(getRandom(1000007, 1000027)));
npc.disableCoreAI(true); // to avoid attacking behaviour, while flee
npc.setIsRunning(true);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(npc.getAIValue("fleeX"), npc.getAIValue("fleeY"), npc.getAIValue("fleeZ")));
npc.getVariables().set("state", 1);
npc.getVariables().set("attacker", attacker.getObjectId());
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
{
if (eventName.equals("WARNING") && !receiver.isDead() && (receiver.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) && (reference != null) && (reference.getActingPlayer() != null) && !reference.getActingPlayer().isDead())
{
receiver.getVariables().set("state", 3);
receiver.setIsRunning(true);
((L2Attackable) receiver).addDamageHate(reference.getActingPlayer(), 0, 99999);
receiver.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, reference.getActingPlayer());
}
return super.onEventReceived(eventName, sender, receiver, reference);
}
@Override
public void onMoveFinished(L2Npc npc)
{
// NPC reaches flee point
if (npc.getVariables().getInt("state") == 1)
{
if ((npc.getX() == npc.getAIValue("fleeX")) && (npc.getY() == npc.getAIValue("fleeY")))
{
npc.disableCoreAI(false);
startQuestTimer("checkState", 15000, npc, null);
npc.getVariables().set("state", 2);
npc.broadcastEvent("WARNING", 400, L2World.getInstance().getPlayer(npc.getVariables().getInt("attacker")));
}
else
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(npc.getAIValue("fleeX"), npc.getAIValue("fleeY"), npc.getAIValue("fleeZ")));
}
}
else if ((npc.getVariables().getInt("state") == 3) && npc.staysInSpawnLoc())
{
npc.disableCoreAI(false);
npc.getVariables().remove("state");
}
}
public static void main(String[] args)
{
new TurekOrcs();
}
}

View File

@@ -0,0 +1,215 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.QuestState;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
import quests.Q00605_AllianceWithKetraOrcs.Q00605_AllianceWithKetraOrcs;
import quests.Q00606_BattleAgainstVarkaSilenos.Q00606_BattleAgainstVarkaSilenos;
import quests.Q00607_ProveYourCourageKetra.Q00607_ProveYourCourageKetra;
import quests.Q00608_SlayTheEnemyCommanderKetra.Q00608_SlayTheEnemyCommanderKetra;
import quests.Q00609_MagicalPowerOfWaterPart1.Q00609_MagicalPowerOfWaterPart1;
import quests.Q00610_MagicalPowerOfWaterPart2.Q00610_MagicalPowerOfWaterPart2;
import quests.Q00611_AllianceWithVarkaSilenos.Q00611_AllianceWithVarkaSilenos;
import quests.Q00612_BattleAgainstKetraOrcs.Q00612_BattleAgainstKetraOrcs;
import quests.Q00613_ProveYourCourageVarka.Q00613_ProveYourCourageVarka;
import quests.Q00614_SlayTheEnemyCommanderVarka.Q00614_SlayTheEnemyCommanderVarka;
import quests.Q00615_MagicalPowerOfFirePart1.Q00615_MagicalPowerOfFirePart1;
import quests.Q00616_MagicalPowerOfFirePart2.Q00616_MagicalPowerOfFirePart2;
/**
* Varka Silenos Barracks and Ketra Orc Outpost AI.
* @author malyelfik
*/
public class VarkaKetra extends AbstractNpcAI
{
// Monsters
private static final int[] KETRA =
{
21324, // Ketra Orc Footman
21325, // Ketra's War Hound
21327, // Ketra Orc Raider
21328, // Ketra Orc Scout
21329, // Ketra Orc Shaman
21331, // Ketra Orc Warrior
21332, // Ketra Orc Lieutenant
21334, // Ketra Orc Medium
21335, // Ketra Orc Elite Soldier
21336, // Ketra Orc White Captain
21338, // Ketra Orc Seer
21339, // Ketra Orc General
21340, // Ketra Orc Battalion Commander
21342, // Ketra Orc Grand Seer
21343, // Ketra Commander
21344, // Ketra Elite Guard
21345, // Ketra's Head Shaman
21346, // Ketra's Head Guard
21347, // Ketra Prophet
21348, // Prophet's Guard
21349, // Prophet's Aide
25299, // Ketra's Hero Hekaton (Raid Boss)
25302, // Ketra's Commander Tayr (Raid Boss)
25305, // Ketra's Chief Brakki (Raid Boss)
25306, // Soul of Fire Nastron (Raid Boss)
};
private static final int[] VARKA =
{
21350, // Varka Silenos Recruit
21351, // Varka Silenos Footman
21353, // Varka Silenos Scout
21354, // Varka Silenos Hunter
21355, // Varka Silenos Shaman
21357, // Varka Silenos Priest
21358, // Varka Silenos Warrior
21360, // Varka Silenos Medium
21361, // Varka Silenos Magus
21362, // Varka Silenos Officer
21364, // Varka Silenos Seer
21365, // Varka Silenos Great Magus
21366, // Varka Silenos General
21368, // Varka Silenos Great Seer
21369, // Varka's Commander
21370, // Varka's Elite Guard
21371, // Varka's Head Magus
21372, // Varka's Head Guard
21373, // Varka's Prophet
21374, // Prophet's Guard
21375, // Disciple of Prophet
25309, // Varka's Hero Shadith (Raid Boss)
25312, // Varka's Commander Mos (Raid Boss)
25315, // Varka's Chief Horus (Raid Boss)
25316, // Soul of Water Ashutar (Raid Boss)
};
// Items
private static final int[] KETRA_MARKS =
{
7211, // Mark of Ketra's Alliance - Level 1
7212, // Mark of Ketra's Alliance - Level 2
7213, // Mark of Ketra's Alliance - Level 3
7214, // Mark of Ketra's Alliance - Level 4
7215, // Mark of Ketra's Alliance - Level 5
};
private static final int[] VARKA_MARKS =
{
7221, // Mark of Varka's Alliance - Level 1
7222, // Mark of Varka's Alliance - Level 2
7223, // Mark of Varka's Alliance - Level 3
7224, // Mark of Varka's Alliance - Level 4
7225, // Mark of Varka's Alliance - Level 5
};
// Quests
private static final String[] KETRA_QUESTS =
{
Q00605_AllianceWithKetraOrcs.class.getSimpleName(),
Q00606_BattleAgainstVarkaSilenos.class.getSimpleName(),
Q00607_ProveYourCourageKetra.class.getSimpleName(),
Q00608_SlayTheEnemyCommanderKetra.class.getSimpleName(),
Q00609_MagicalPowerOfWaterPart1.class.getSimpleName(),
Q00610_MagicalPowerOfWaterPart2.class.getSimpleName()
};
private static final String[] VARKA_QUESTS =
{
Q00611_AllianceWithVarkaSilenos.class.getSimpleName(),
Q00612_BattleAgainstKetraOrcs.class.getSimpleName(),
Q00613_ProveYourCourageVarka.class.getSimpleName(),
Q00614_SlayTheEnemyCommanderVarka.class.getSimpleName(),
Q00615_MagicalPowerOfFirePart1.class.getSimpleName(),
Q00616_MagicalPowerOfFirePart2.class.getSimpleName()
};
private VarkaKetra()
{
super(VarkaKetra.class.getSimpleName(), "ai/group_template");
addKillId(KETRA);
addKillId(VARKA);
addNpcHateId(KETRA);
addNpcHateId(VARKA);
}
@Override
public void actionForEachPlayer(L2PcInstance player, L2Npc npc, boolean isSummon)
{
if (Util.checkIfInRange(1500, player, npc, false))
{
if (Util.contains(KETRA, npc.getId()) && hasAtLeastOneQuestItem(player, KETRA_MARKS))
{
decreaseAlliance(player, KETRA_MARKS);
exitQuests(player, KETRA_QUESTS);
}
else if (Util.contains(VARKA, npc.getId()) && hasAtLeastOneQuestItem(player, VARKA_MARKS))
{
decreaseAlliance(player, VARKA_MARKS);
exitQuests(player, VARKA_QUESTS);
}
}
}
private final void decreaseAlliance(L2PcInstance player, int[] marks)
{
for (int i = 0; i < marks.length; i++)
{
if (hasQuestItems(player, marks[i]))
{
takeItems(player, marks[i], -1);
if (i > 0)
{
giveItems(player, marks[i - 1], 1);
}
return;
}
}
}
private final void exitQuests(L2PcInstance player, String[] quests)
{
for (String quest : quests)
{
final QuestState qs = player.getQuestState(quest);
if ((qs != null) && qs.isStarted())
{
qs.exitQuest(true);
}
}
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
executeForEachPlayer(killer, npc, isSummon, true, false);
return super.onKill(npc, killer, isSummon);
}
@Override
public boolean onNpcHate(L2Attackable mob, L2PcInstance player, boolean isSummon)
{
if (Util.contains(KETRA, mob.getId()))
{
return !hasAtLeastOneQuestItem(player, KETRA_MARKS);
}
return !hasAtLeastOneQuestItem(player, VARKA_MARKS);
}
public static void main(String[] args)
{
new VarkaKetra();
}
}

View File

@@ -0,0 +1,140 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.group_template;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Warrior Fishing Block AI.
* @author Zoey76
*/
public final class WarriorFishingBlock extends AbstractNpcAI
{
// Monsters
private static final int[] MONSTERS =
{
18319, // Caught Frog
18320, // Caught Undine
18321, // Caught Rakul
18322, // Caught Sea Giant
18323, // Caught Sea Horse Soldier
18324, // Caught Homunculus
18325, // Caught Flava
18326, // Caught Gigantic Eye
};
// NPC Strings
private static final NpcStringId[] NPC_STRINGS_ON_SPAWN =
{
NpcStringId.CROAK_CROAK_FOOD_LIKE_S1_IN_THIS_PLACE,
NpcStringId.S1_HOW_LUCKY_I_AM,
NpcStringId.PRAY_THAT_YOU_CAUGHT_A_WRONG_FISH_S1
};
private static final NpcStringId[] NPC_STRINGS_ON_ATTACK =
{
NpcStringId.DO_YOU_KNOW_WHAT_A_FROG_TASTES_LIKE,
NpcStringId.I_WILL_SHOW_YOU_THE_POWER_OF_A_FROG,
NpcStringId.I_WILL_SWALLOW_AT_A_MOUTHFUL
};
private static final NpcStringId[] NPC_STRINGS_ON_KILL =
{
NpcStringId.UGH_NO_CHANCE_HOW_COULD_THIS_ELDER_PASS_AWAY_LIKE_THIS,
NpcStringId.CROAK_CROAK_A_FROG_IS_DYING,
NpcStringId.A_FROG_TASTES_BAD_YUCK
};
// Misc
private static final int CHANCE_TO_SHOUT_ON_ATTACK = 33;
private static final int DESPAWN_TIME = 50; // 50 seconds to despawn
public WarriorFishingBlock()
{
super(WarriorFishingBlock.class.getSimpleName(), "ai/group_template");
addAttackId(MONSTERS);
addKillId(MONSTERS);
addSpawnId(MONSTERS);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "SPAWN":
{
final L2Object obj = npc.getTarget();
if ((obj == null) || !obj.isPlayer())
{
npc.decayMe();
}
else
{
final L2PcInstance target = obj.getActingPlayer();
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NPC_STRINGS_ON_SPAWN[getRandom(NPC_STRINGS_ON_SPAWN.length)], target.getName());
((L2Attackable) npc).addDamageHate(target, 0, 2000);
npc.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, target);
npc.addAttackerToAttackByList(target);
startQuestTimer("DESPAWN", DESPAWN_TIME * 1000, npc, target);
}
break;
}
case "DESPAWN":
{
npc.decayMe();
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (getRandom(100) < CHANCE_TO_SHOUT_ON_ATTACK)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NPC_STRINGS_ON_ATTACK[getRandom(NPC_STRINGS_ON_ATTACK.length)]);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NPC_STRINGS_ON_KILL[getRandom(NPC_STRINGS_ON_KILL.length)]);
cancelQuestTimer("DESPAWN", npc, killer);
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
startQuestTimer("SPAWN", 2000, npc, null);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new WarriorFishingBlock();
}
}

View File

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

View File

@@ -0,0 +1,35 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Group Template AI:<br>
* This folder contains AI scripts for group templates.<br>
* That is, if many different mobs share the same behavior, a group AI script can be created for all of them.<br>
* Such group templates ought to be here.<br>
* <br>
* Group templates can be sub-classed.<br>
* In other words, a group may inherit from another group.<br>
* For example, one group template might define mobs that cast spells.<br>
* Another template may then define the AI for mobs that cast spells AND use shots.<br>
* In that case, instead of rewriting all the attack and spell-use AI, we can inherit from the first group template, then add the new behaviors, and split up the NPC registrations appropriately.<br>
* <br>
* "NPC registrations" refers to the addition of NPCs in the various events of the scripts, such as onAttack, onKill, etc.<br>
* Those are done by using methods such as addKillId(..) etc.<br>
* @see quests
* @author Fulminus, Zoey76
*/
package ai.group_template;

View File

@@ -0,0 +1,192 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.ArrayList;
import java.util.Map;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import ai.npc.AbstractNpcAI;
/**
* Anais AI.
* @author nonom
*/
final class Anais extends AbstractNpcAI
{
// NPCs
private static final int ANAIS = 25701;
private static final int DIVINE_BURNER = 18915;
private static final int GRAIL_WARD = 18929;
// Skill
private static SkillHolder DIVINE_NOVA = new SkillHolder(6326, 1);
// Instances
ArrayList<L2Npc> _divineBurners = new ArrayList<>(4);
private L2PcInstance _nextTarget = null;
private L2Npc _current = null;
private int _pot = 0;
private Anais()
{
super(Anais.class.getSimpleName(), "ai/individual");
addAttackId(ANAIS);
addSpawnId(DIVINE_BURNER);
addKillId(GRAIL_WARD);
}
private void burnerOnAttack(int pot, L2Npc anais)
{
final L2Npc npc = _divineBurners.get(pot);
npc.setDisplayEffect(1);
npc.setIsRunning(false);
if (pot < 4)
{
_current = npc;
if (getQuestTimer("CHECK", anais, null) == null)
{
startQuestTimer("CHECK", 3000, anais, null);
}
}
else
{
cancelQuestTimer("CHECK", anais, null);
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "CHECK":
{
if (!npc.isAttackingNow())
{
cancelQuestTimer("CHECK", npc, null);
}
if ((_current != null) || (_pot < 4))
{
final Map<Integer, L2PcInstance> players = npc.getKnownList().getKnownPlayers();
final L2PcInstance target = players.get(getRandom(players.size() - 1));
_nextTarget = target;
if (_nextTarget == null)
{
_nextTarget = (L2PcInstance) npc.getTarget();
}
final L2Npc b = _divineBurners.get(_pot);
_pot = _pot + 1;
b.setDisplayEffect(1);
b.setIsRunning(false);
final L2Npc ward = addSpawn(GRAIL_WARD, new Location(b.getX(), b.getY(), b.getZ()), true, 0);
((L2Attackable) ward).addDamageHate(_nextTarget, 0, 999);
ward.setIsRunning(true);
ward.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, _nextTarget, null);
startQuestTimer("GUARD_ATTACK", 1000, ward, _nextTarget, true);
startQuestTimer("SUICIDE", 20000, ward, null);
ward.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, _nextTarget);
}
break;
}
case "GUARD_ATTACK":
{
if (_nextTarget != null)
{
final double distance = npc.calculateDistance(_nextTarget, false, false);
if (distance < 100)
{
npc.doCast(DIVINE_NOVA.getSkill());
}
else if (distance > 2000)
{
npc.doDie(null);
cancelQuestTimer("GUARD_ATTACK", npc, player);
}
}
break;
}
case "SUICIDE":
{
npc.doCast(DIVINE_NOVA.getSkill());
cancelQuestTimer("GUARD_ATTACK", npc, _nextTarget);
if (_current != null)
{
_current.setDisplayEffect(2);
_current.setIsRunning(false);
_current = null;
}
npc.doDie(null);
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (_pot == 0)
{
burnerOnAttack(0, npc);
}
else if ((npc.getCurrentHp() <= (npc.getMaxRecoverableHp() * 0.75)) && (_pot == 1))
{
burnerOnAttack(1, npc);
}
else if ((npc.getCurrentHp() <= (npc.getMaxRecoverableHp() * 0.5)) && (_pot == 2))
{
burnerOnAttack(2, npc);
}
else if ((npc.getCurrentHp() <= (npc.getMaxRecoverableHp() * 0.25)) && (_pot == 3))
{
burnerOnAttack(3, npc);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
_divineBurners.add(npc);
return super.onSpawn(npc);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
npc.doCast(DIVINE_NOVA.getSkill());
cancelQuestTimer("GUARD_ATTACK", npc, _nextTarget);
cancelQuestTimer("CHECK", npc, null);
if (_current != null)
{
_current.setDisplayEffect(2);
_current.setIsRunning(false);
_current = null;
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new Anais();
}
}

View File

@@ -0,0 +1,8 @@
<html><body>Heart of Warding:<br>
You are overcome by a voice, a voice so powerful you are helpless as it speaks.<br>
<font color="LEVEL">Do not expect Shilen's authority will diminish<br>
while false gods freely roam.<br>
Leave, and<br>
prepare to face the return of Antharas.</font><br>
(Challenging Antharas is not currently available.)
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Heart of Warding:<br>
You are overcome by a voice, a voice so powerful you are helpless as it speaks:<br>
<font color="LEVEL">Do not expect that you might challenge Antharas at your own convenience.<br>
When the time is right, Shilen's authority will judge you.</font><br>
(Currently, other members are challenging Antharas.)
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Heart of Warding:<br>
A voice that can shatter your entire body is resonating in your head:<br>
<font color="LEVEL">Do not dare to face Shilen's authority<br>
without the most determined preparation.</font><br>
(Only those who have the Portal Stone can challenge Antharas.)
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Heart of Warding:<br>
You are overcome by a voice, a voice so powerful you are helpless as it speaks:<br>
<font color="LEVEL">No matter how many gather to follow false gods,<br>
Shilen's authority is too great.</font><br>
(The number of participants are above the allowed number in challenging Antharas.)
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Heart of Warding:<br>
You are overcome by a voice, a voice so powerful you are helpless as it speaks:<br>
<font color="LEVEL">You seek death and defeat by coming here without your leader! You appear before Shilen's authority<br>
and you tempt Shilen's wrath!</font><br>
(The players who belong to an association can only enter through the Association Leader.)
</body></html>

View File

@@ -0,0 +1,12 @@
<html><body>Heart of Warding:<br>
You are overcome by a voice, a voice so powerful you are helpless as it speaks:<br>
<font color="LEVEL">A terrible creature <br>
fell to the earth from above <br>
in order to vent a mother's spite,<br>
cursed and forsaken by her own children.<br>
Dark Pilgrim of the Holy Land,<br>
Do you dare face the Land Dragon Antharas?</font><br>
(A maximum of 200 people can challenge Antharas.)<br>
<a action="bypass -h npc_%objectId%_Quest Antharas enter">Move to Antharas' Nest</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
<html><head><body>Angelic Vortex:<br>
The Angelic Vortex emits a faint light which twinkles out. The vortex becomes inactive. It seems like, in order to go to the place where the Angelic Vortex is leading, you will need some special object.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Angelic Vortex:<br>
The Angelic Vortex emits a faint light, in the midst of which an image appears. A giant that normally appears as a stone statue has come alive and is fighting with many people. Even angels have joined the fray. It seems that the angels are angry at the humans who have broken the seal of the stone statue.<br>
It appears impossible to cross over to that place right now. You have no choice but to wait until the fight is over.<br>
<a action="bypass -h npc_%objectId%_Quest Baium 31862-04.html">Ask about the stone statue that has come alive.</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Angelic Vortex:<br>
The Angelic Vortex emits a faint light, in the midst of which an image appears. A large, open space... but the gigantic, human-like stone statue is no longer there.<br>
It seems that while the statue is not visible, one could cross over to that place.<br>
<a action="bypass -h npc_%objectId%_Quest Baium 31862-04.html">Ask about the stone statue.</a>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Angelic Vortex:<br>
In ancient times a mighty emperor named Baium became so enamored of his own power that he began to fancy himself a god. He conscripted all of his people to build an awesome tower that reached almost to heaven.<br>
The gods were not amused. They struck him down, cursed him with immortality and imprisoned him in his own tower for eternity! A statue of the foolish emperor stands there to this day.<br>
Occasionally, the old emperor himself is woken up by those who seek his power. Unfortunately, when Baium is disturbed, so are the angels who guard him.<br>
Although the angels are certainly no friend of Baium, they regard Humans with equal disdain.<font color="LEVEL"> Ultimate success against Baium depends upon the defeat of the guardian angels.</font><br>
This is all I can tell you. Good luck!
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Angelic Vortex:<br>
The Angelic Vortex emits a faint light, and in the midst of the light an image appears. In the deepest part of a spacious area, a gigantic stone statue is visible. The statue has a human-like appearance and is in a seated position, as though it was being held by some invisible force against its will.<br>
<a action="bypass -h npc_%objectId%_Quest Baium enter">Go where the Angelic Vortex leads.</a>
</body></html>

View File

@@ -0,0 +1,793 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual.Baium;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.CategoryType;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.enums.MountType;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.type.L2NoRestartZone;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.Earthquake;
import com.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Baium AI.
* @author St3eT
*/
public final class Baium extends AbstractNpcAI
{
// NPCs
private static final int BAIUM = 29020; // Baium
private static final int BAIUM_STONE = 29025; // Baium
private static final int ANG_VORTEX = 31862; // Angelic Vortex
private static final int ARCHANGEL = 29021; // Archangel
private static final int TELE_CUBE = 31842; // Teleportation Cubic
// Skills
private static final SkillHolder BAIUM_ATTACK = new SkillHolder(4127, 1); // Baium: General Attack
private static final SkillHolder ENERGY_WAVE = new SkillHolder(4128, 1); // Wind Of Force
private static final SkillHolder EARTH_QUAKE = new SkillHolder(4129, 1); // Earthquake
private static final SkillHolder THUNDERBOLT = new SkillHolder(4130, 1); // Striking of Thunderbolt
private static final SkillHolder GROUP_HOLD = new SkillHolder(4131, 1); // Stun
private static final SkillHolder SPEAR_ATTACK = new SkillHolder(4132, 1); // Spear: Pound the Ground
private static final SkillHolder ANGEL_HEAL = new SkillHolder(4133, 1); // Angel Heal
private static final SkillHolder HEAL_OF_BAIUM = new SkillHolder(4135, 1); // Baium Heal
private static final SkillHolder BAIUM_PRESENT = new SkillHolder(4136, 1); // Baium's Gift
private static final SkillHolder ANTI_STRIDER = new SkillHolder(4258, 1); // Hinder Strider
// Items
private static final int FABRIC = 4295; // Blooded Fabric
// Zone
private static final L2NoRestartZone zone = ZoneManager.getInstance().getZoneById(70051, L2NoRestartZone.class); // Baium zone
// Status
private static final int ALIVE = 0;
private static final int WAITING = 1;
private static final int IN_FIGHT = 2;
private static final int DEAD = 3;
// Locations
private static final Location BAIUM_GIFT_LOC = new Location(115910, 17337, 10105);
private static final Location BAIUM_LOC = new Location(116033, 17447, 10107, -25348);
private static final Location TELEPORT_CUBIC_LOC = new Location(115017, 15549, 10090);
private static final Location TELEPORT_IN_LOC = new Location(114077, 15882, 10078);
private static final Location[] TELEPORT_OUT_LOC =
{
new Location(108784, 16000, -4928),
new Location(113824, 10448, -5164),
new Location(115488, 22096, -5168),
};
private static final Location[] ARCHANGEL_LOC =
{
new Location(115792, 16608, 10136, 0),
new Location(115168, 17200, 10136, 0),
new Location(115780, 15564, 10136, 13620),
new Location(114880, 16236, 10136, 5400),
new Location(114239, 17168, 10136, -1992)
};
// Misc
private L2GrandBossInstance _baium = null;
private static long _lastAttack = 0;
private Baium()
{
super(Baium.class.getSimpleName(), "ai/individual");
addFirstTalkId(ANG_VORTEX);
addTalkId(ANG_VORTEX, TELE_CUBE, BAIUM_STONE);
addStartNpc(ANG_VORTEX, TELE_CUBE, BAIUM_STONE);
addAttackId(BAIUM, ARCHANGEL);
addKillId(BAIUM);
addSeeCreatureId(BAIUM);
addSpellFinishedId(BAIUM);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(BAIUM);
final int curr_hp = info.getInt("currentHP");
final int curr_mp = info.getInt("currentMP");
final int loc_x = info.getInt("loc_x");
final int loc_y = info.getInt("loc_y");
final int loc_z = info.getInt("loc_z");
final int heading = info.getInt("heading");
final long respawnTime = info.getLong("respawn_time");
switch (getStatus())
{
case WAITING:
{
setStatus(ALIVE);
}
case ALIVE:
{
addSpawn(BAIUM_STONE, BAIUM_LOC, false, 0);
break;
}
case IN_FIGHT:
{
_baium = (L2GrandBossInstance) addSpawn(BAIUM, loc_x, loc_y, loc_z, heading, false, 0);
_baium.setCurrentHpMp(curr_hp, curr_mp);
_lastAttack = System.currentTimeMillis();
addBoss(_baium);
for (Location loc : ARCHANGEL_LOC)
{
final L2Npc archangel = addSpawn(ARCHANGEL, loc, false, 0, true);
startQuestTimer("SELECT_TARGET", 5000, archangel, null);
}
startQuestTimer("CHECK_ATTACK", 60000, _baium, null);
break;
}
case DEAD:
{
final long remain = respawnTime - System.currentTimeMillis();
if (remain > 0)
{
startQuestTimer("CLEAR_STATUS", remain, null, null);
}
else
{
notifyEvent("CLEAR_STATUS", null, null);
}
break;
}
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "31862-04.html":
{
return event;
}
case "enter":
{
String htmltext = null;
if (getStatus() == DEAD)
{
htmltext = "31862-03.html";
}
else if (getStatus() == IN_FIGHT)
{
htmltext = "31862-02.html";
}
else if (!hasQuestItems(player, FABRIC))
{
htmltext = "31862-01.html";
}
else
{
takeItems(player, FABRIC, 1);
player.teleToLocation(TELEPORT_IN_LOC);
}
return htmltext;
}
case "teleportOut":
{
final Location destination = TELEPORT_OUT_LOC[getRandom(TELEPORT_OUT_LOC.length)];
player.teleToLocation(destination.getX() + getRandom(100), destination.getY() + getRandom(100), destination.getZ());
break;
}
case "wakeUp":
{
if (getStatus() == ALIVE)
{
npc.deleteMe();
setStatus(IN_FIGHT);
_baium = (L2GrandBossInstance) addSpawn(BAIUM, BAIUM_LOC, false, 0);
_baium.disableCoreAI(true);
addBoss(_baium);
_lastAttack = System.currentTimeMillis();
startQuestTimer("WAKEUP_ACTION", 50, _baium, null);
startQuestTimer("MANAGE_EARTHQUAKE", 2000, _baium, null);
startQuestTimer("SOCIAL_ACTION", 10000, _baium, player);
startQuestTimer("CHECK_ATTACK", 60000, _baium, null);
}
break;
}
case "WAKEUP_ACTION":
{
if (npc != null)
{
zone.broadcastPacket(new SocialAction(_baium.getObjectId(), 2));
}
break;
}
case "MANAGE_EARTHQUAKE":
{
if (npc != null)
{
zone.broadcastPacket(new Earthquake(npc.getX(), npc.getY(), npc.getZ(), 40, 10));
zone.broadcastPacket(new PlaySound("BS02_A"));
}
break;
}
case "SOCIAL_ACTION":
{
if (npc != null)
{
zone.broadcastPacket(new SocialAction(npc.getObjectId(), 3));
startQuestTimer("PLAYER_PORT", 6000, npc, player);
}
break;
}
case "PLAYER_PORT":
{
if (npc != null)
{
if ((player != null) && player.isInsideRadius(npc, 16000, true, false))
{
player.teleToLocation(BAIUM_GIFT_LOC);
startQuestTimer("PLAYER_KILL", 3000, npc, player);
}
else
{
final L2PcInstance randomPlayer = getRandomPlayer(npc);
if (randomPlayer != null)
{
randomPlayer.teleToLocation(BAIUM_GIFT_LOC);
startQuestTimer("PLAYER_KILL", 3000, npc, randomPlayer);
}
else
{
startQuestTimer("PLAYER_KILL", 3000, npc, null);
}
}
}
break;
}
case "PLAYER_KILL":
{
if ((player != null) && player.isInsideRadius(npc, 16000, true, false))
{
zone.broadcastPacket(new SocialAction(npc.getObjectId(), 1));
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.HOW_DARE_YOU_WAKE_ME_NOW_YOU_SHALL_DIE, player.getName());
npc.setTarget(player);
npc.doCast(BAIUM_PRESENT.getSkill());
}
for (L2PcInstance insidePlayer : zone.getPlayersInside())
{
if (insidePlayer.isHero())
{
zone.broadcastPacket(new ExShowScreenMessage(NpcStringId.NOT_EVEN_THE_GODS_THEMSELVES_COULD_TOUCH_ME_BUT_YOU_S1_YOU_DARE_CHALLENGE_ME_IGNORANT_MORTAL, 2, 4000, insidePlayer.getName()));
break;
}
}
startQuestTimer("SPAWN_ARCHANGEL", 8000, npc, player);
break;
}
case "SPAWN_ARCHANGEL":
{
_baium.disableCoreAI(false);
for (Location loc : ARCHANGEL_LOC)
{
final L2Npc archangel = addSpawn(ARCHANGEL, loc, false, 0, true);
startQuestTimer("SELECT_TARGET", 5000, archangel, null);
}
if ((player != null) && !player.isDead())
{
addAttackDesire(npc, player);
}
else
{
final L2PcInstance randomPlayer = getRandomPlayer(npc);
if (randomPlayer != null)
{
addAttackDesire(npc, randomPlayer);
}
}
break;
}
case "SELECT_TARGET":
{
if (npc != null)
{
final L2Attackable mob = (L2Attackable) npc;
final L2Character mostHated = mob.getMostHated();
if ((_baium == null) || _baium.isDead())
{
mob.deleteMe();
break;
}
if ((mostHated != null) && mostHated.isPlayer() && zone.isInsideZone(mostHated))
{
if (mob.getTarget() != mostHated)
{
mob.clearAggroList();
}
addAttackDesire(mob, mostHated);
}
else
{
boolean found = false;
for (L2Character creature : mob.getKnownList().getKnownCharactersInRadius(1000))
{
if ((creature != null) && creature.isPlayable() && zone.isInsideZone(creature) && !creature.isDead())
{
if (mob.getTarget() != creature)
{
mob.clearAggroList();
}
addAttackDesire(mob, creature);
found = true;
break;
}
}
if (!found)
{
if (mob.isInsideRadius(_baium, 40, true, false))
{
if (mob.getTarget() != _baium)
{
mob.clearAggroList();
}
addAttackDesire(mob, _baium);
}
else
{
mob.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, _baium);
}
}
}
startQuestTimer("SELECT_TARGET", 5000, npc, null);
}
break;
}
case "CHECK_ATTACK":
{
if ((npc != null) && ((_lastAttack + 1800000) < System.currentTimeMillis()))
{
cancelQuestTimers("SELECT_TARGET");
notifyEvent("CLEAR_ZONE", null, null);
addSpawn(BAIUM_STONE, BAIUM_LOC, false, 0);
setStatus(ALIVE);
}
else if (npc != null)
{
if (((_lastAttack + 300000) < System.currentTimeMillis()) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.75)))
{
npc.setTarget(npc);
npc.doCast(HEAL_OF_BAIUM.getSkill());
}
startQuestTimer("CHECK_ATTACK", 60000, npc, null);
}
break;
}
case "CLEAR_STATUS":
{
setStatus(ALIVE);
addSpawn(BAIUM_STONE, BAIUM_LOC, false, 0);
break;
}
case "CLEAR_ZONE":
{
for (L2Character charInside : zone.getCharactersInside())
{
if (charInside != null)
{
if (charInside.isNpc())
{
charInside.deleteMe();
}
else if (charInside.isPlayer())
{
notifyEvent("teleportOut", null, (L2PcInstance) charInside);
}
}
}
break;
}
case "RESPAWN_BAIUM":
{
if (getStatus() == DEAD)
{
setRespawn(0);
cancelQuestTimer("CLEAR_STATUS", null, null);
notifyEvent("CLEAR_STATUS", null, null);
}
else
{
player.sendMessage(getClass().getSimpleName() + ": You cant respawn Baium while Baium is alive!");
}
break;
}
case "ABORT_FIGHT":
{
if (getStatus() == IN_FIGHT)
{
_baium = null;
notifyEvent("CLEAR_ZONE", null, null);
notifyEvent("CLEAR_STATUS", null, null);
player.sendMessage(getClass().getSimpleName() + ": Aborting fight!");
}
else
{
player.sendMessage(getClass().getSimpleName() + ": You cant abort attack right now!");
}
cancelQuestTimers("CHECK_ATTACK");
cancelQuestTimers("SELECT_TARGET");
break;
}
case "DESPAWN_MINIONS":
{
if (getStatus() == IN_FIGHT)
{
for (L2Character charInside : zone.getCharactersInside())
{
if ((charInside != null) && charInside.isNpc() && (charInside.getId() == ARCHANGEL))
{
charInside.deleteMe();
}
}
if (player != null)
{
player.sendMessage(getClass().getSimpleName() + ": All archangels has been deleted!");
}
}
else if (player != null)
{
player.sendMessage(getClass().getSimpleName() + ": You cant despawn archangels right now!");
}
break;
}
case "MANAGE_SKILLS":
{
if (npc != null)
{
manageSkills(npc);
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon, Skill skill)
{
_lastAttack = System.currentTimeMillis();
if (npc.getId() == BAIUM)
{
if ((attacker.getMountType() == MountType.STRIDER) && !attacker.isAffectedBySkill(ANTI_STRIDER.getSkillId()) && !npc.isSkillDisabled(ANTI_STRIDER.getSkill()))
{
npc.setTarget(attacker);
npc.doCast(ANTI_STRIDER.getSkill());
}
if (skill == null)
{
refreshAiParams(attacker, npc, damage * 1000);
}
else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.25))
{
refreshAiParams(attacker, npc, (damage / 3) * 100);
}
else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.5))
{
refreshAiParams(attacker, npc, damage * 20);
}
else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.75))
{
refreshAiParams(attacker, npc, damage * 10);
}
else
{
refreshAiParams(attacker, npc, (damage / 3) * 20);
}
manageSkills(npc);
}
else
{
final L2Attackable mob = (L2Attackable) npc;
final L2Character mostHated = mob.getMostHated();
if ((getRandom(100) < 10) && mob.checkDoCastConditions(SPEAR_ATTACK.getSkill()))
{
if ((mostHated != null) && (npc.calculateDistance(mostHated, true, false) < 1000) && zone.isCharacterInZone(mostHated))
{
mob.setTarget(mostHated);
mob.doCast(SPEAR_ATTACK.getSkill());
}
else if (zone.isCharacterInZone(attacker))
{
mob.setTarget(attacker);
mob.doCast(SPEAR_ATTACK.getSkill());
}
}
if ((getRandom(100) < 5) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) && mob.checkDoCastConditions(ANGEL_HEAL.getSkill()))
{
npc.setTarget(npc);
npc.doCast(ANGEL_HEAL.getSkill());
}
}
return super.onAttack(npc, attacker, damage, isSummon, skill);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (zone.isCharacterInZone(killer))
{
setStatus(DEAD);
addSpawn(TELE_CUBE, TELEPORT_CUBIC_LOC, false, 900000);
zone.broadcastPacket(new PlaySound("BS01_D"));
final long respawnTime = (Config.BAIUM_SPAWN_INTERVAL + getRandom(-Config.BAIUM_SPAWN_RANDOM, Config.BAIUM_SPAWN_RANDOM)) * 3600000;
setRespawn(respawnTime);
startQuestTimer("CLEAR_STATUS", respawnTime, null, null);
startQuestTimer("CLEAR_ZONE", 900000, null, null);
cancelQuestTimer("CHECK_ATTACK", npc, null);
cancelQuestTimers("SELECT_TARGET");
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
{
if (!zone.isInsideZone(creature) || (creature.isNpc() && (creature.getId() == BAIUM_STONE)))
{
return super.onSeeCreature(npc, creature, isSummon);
}
if (creature.isInCategory(CategoryType.CLERIC_GROUP))
{
if (npc.getCurrentHp() < (npc.getMaxHp() * 0.25))
{
refreshAiParams(creature, npc, 10000);
}
else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.5))
{
refreshAiParams(creature, npc, 10000, 6000);
}
else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.75))
{
refreshAiParams(creature, npc, 10000, 3000);
}
else
{
refreshAiParams(creature, npc, 10000, 2000);
}
}
else
{
refreshAiParams(creature, npc, 10000, 1000);
}
manageSkills(npc);
return super.onSeeCreature(npc, creature, isSummon);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
startQuestTimer("MANAGE_SKILLS", 1000, npc, null);
if (!zone.isCharacterInZone(npc) && (_baium != null))
{
_baium.teleToLocation(BAIUM_LOC);
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public boolean unload(boolean removeFromList)
{
if (_baium != null)
{
_baium.deleteMe();
}
return super.unload(removeFromList);
}
private final void refreshAiParams(L2Character attacker, L2Npc npc, int damage)
{
refreshAiParams(attacker, npc, damage, damage);
}
private final void refreshAiParams(L2Character attacker, L2Npc npc, int damage, int aggro)
{
final int newAggroVal = damage + getRandom(3000);
final int aggroVal = aggro + 1000;
final NpcVariables vars = npc.getVariables();
for (int i = 0; i < 3; i++)
{
if (attacker == vars.getObject("c_quest" + i, L2Character.class))
{
if (vars.getInt("i_quest" + i) < aggroVal)
{
vars.set("i_quest" + i, newAggroVal);
}
return;
}
}
final int index = Util.getIndexOfMinValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2"));
vars.set("i_quest" + index, newAggroVal);
vars.set("c_quest" + index, attacker);
}
private int getStatus()
{
return GrandBossManager.getInstance().getBossStatus(BAIUM);
}
private void addBoss(L2GrandBossInstance grandboss)
{
GrandBossManager.getInstance().addBoss(grandboss);
}
private void setStatus(int status)
{
GrandBossManager.getInstance().setBossStatus(BAIUM, status);
}
private void setRespawn(long respawnTime)
{
GrandBossManager.getInstance().getStatsSet(BAIUM).set("respawn_time", System.currentTimeMillis() + respawnTime);
}
private void manageSkills(L2Npc npc)
{
if (npc.isCastingNow() || npc.isCoreAIDisabled() || !npc.isInCombat())
{
return;
}
final NpcVariables vars = npc.getVariables();
for (int i = 0; i < 3; i++)
{
final L2Character attacker = vars.getObject("c_quest" + i, L2Character.class);
if ((attacker == null) || (npc.calculateDistance(attacker, true, false) > 9000) || attacker.isDead())
{
vars.set("i_quest" + i, 0);
}
}
final int index = Util.getIndexOfMaxValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2"));
final L2Character player = vars.getObject("c_quest" + index, L2Character.class);
final int i2 = vars.getInt("i_quest" + index);
if ((i2 > 0) && (getRandom(100) < 70))
{
vars.set("i_quest" + index, 500);
}
SkillHolder skillToCast = null;
if ((player != null) && !player.isDead())
{
if (npc.getCurrentHp() > (npc.getMaxHp() * 0.75))
{
if (getRandom(100) < 10)
{
skillToCast = ENERGY_WAVE;
}
else if (getRandom(100) < 10)
{
skillToCast = EARTH_QUAKE;
}
else
{
skillToCast = BAIUM_ATTACK;
}
}
else if (npc.getCurrentHp() > (npc.getMaxHp() * 0.5))
{
if (getRandom(100) < 10)
{
skillToCast = GROUP_HOLD;
}
else if (getRandom(100) < 10)
{
skillToCast = ENERGY_WAVE;
}
else if (getRandom(100) < 10)
{
skillToCast = EARTH_QUAKE;
}
else
{
skillToCast = BAIUM_ATTACK;
}
}
else if (npc.getCurrentHp() > (npc.getMaxHp() * 0.25))
{
if (getRandom(100) < 10)
{
skillToCast = THUNDERBOLT;
}
else if (getRandom(100) < 10)
{
skillToCast = GROUP_HOLD;
}
else if (getRandom(100) < 10)
{
skillToCast = ENERGY_WAVE;
}
else if (getRandom(100) < 10)
{
skillToCast = EARTH_QUAKE;
}
else
{
skillToCast = BAIUM_ATTACK;
}
}
else if (getRandom(100) < 10)
{
skillToCast = THUNDERBOLT;
}
else if (getRandom(100) < 10)
{
skillToCast = GROUP_HOLD;
}
else if (getRandom(100) < 10)
{
skillToCast = ENERGY_WAVE;
}
else if (getRandom(100) < 10)
{
skillToCast = EARTH_QUAKE;
}
else
{
skillToCast = BAIUM_ATTACK;
}
}
if ((skillToCast != null) && npc.checkDoCastConditions(skillToCast.getSkill()))
{
npc.setTarget(player);
npc.doCast(skillToCast.getSkill());
}
}
private L2PcInstance getRandomPlayer(L2Npc npc)
{
for (L2Character creature : npc.getKnownList().getKnownCharactersInRadius(2000))
{
if ((creature != null) && creature.isPlayer() && zone.isInsideZone(creature) && !creature.isDead())
{
return (L2PcInstance) creature;
}
}
return null;
}
public static void main(String[] args)
{
new Baium();
}
}

View File

@@ -0,0 +1,99 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.SystemMessageId;
import ai.npc.AbstractNpcAI;
/**
* Ballista AI.
* @author St3eT
*/
final class Ballista extends AbstractNpcAI
{
// NPCs
private static final int[] BALLISTA =
{
35685, // Shanty Fortress
35723, // Southern Fortress
35754, // Hive Fortress
35792, // Valley Fortress
35823, // Ivory Fortress
35854, // Narsell Fortress
35892, // Bayou Fortress
35923, // White Sands Fortress
35961, // Borderland Fortress
35999, // Swamp Fortress
36030, // Archaic Fortress
36068, // Floran Fortress
36106, // Cloud Mountain)
36137, // Tanor Fortress
36168, // Dragonspine Fortress
36206, // Antharas's Fortress
36244, // Western Fortress
36282, // Hunter's Fortress
36313, // Aaru Fortress
36351, // Demon Fortress
36389, // Monastic Fortress
};
// Skill
private static final SkillHolder BOMB = new SkillHolder(2342, 1); // Ballista Bomb
// Misc
private static final int MIN_CLAN_LV = 5;
private Ballista()
{
super(Ballista.class.getSimpleName(), "ai/individual");
addSkillSeeId(BALLISTA);
addSpawnId(BALLISTA);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if ((skill != null) && (caster.getTarget() == npc) && (getRandom(100) < 40) && (skill == BOMB.getSkill()))
{
if (npc.getFort().getSiege().isInProgress() && (caster.getClan() != null) && (caster.getClan().getLevel() >= MIN_CLAN_LV))
{
caster.getClan().addReputationScore(Config.BALLISTA_POINTS, true);
caster.sendPacket(SystemMessageId.THE_BALLISTA_HAS_BEEN_SUCCESSFULLY_DESTROYED_THE_CLAN_S_REPUTATION_WILL_BE_INCREASED);
}
npc.doDie(caster);
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.disableCoreAI(true);
npc.setIsMortal(false);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new Ballista();
}
}

View File

@@ -0,0 +1,833 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.TeleportWhereType;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.L2EffectType;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.network.serverpackets.DoorStatusUpdate;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
import com.l2jmobius.gameserver.network.serverpackets.SpecialCamera;
import com.l2jmobius.gameserver.network.serverpackets.StaticObject;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Beleth's AI.
* @author Treat, Sahar
*/
final class Beleth extends AbstractNpcAI
{
// Status
private static final int ALIVE = 0;
private static final int INIT = 1;
private static final int FIGHT = 2;
private static final int DEAD = 3;
// NPCs
private static final int REAL_BELETH = 29118;
private static final int FAKE_BELETH = 29119;
private static final int STONE_COFFIN = 32470;
private static final int ELF = 29128;
private static final int WHIRPOOL = 29125;
// Zones
private static final L2ZoneType ZONE = ZoneManager.getInstance().getZoneById(12018);
private static final Location BELETH_SPAWN = new Location(16323, 213059, -9357, 49152);
// Skills
private static final SkillHolder BLEED = new SkillHolder(5495, 1);
private static final SkillHolder FIREBALL = new SkillHolder(5496, 1);
private static final SkillHolder HORN_OF_RISING = new SkillHolder(5497, 1);
private static final SkillHolder LIGHTENING = new SkillHolder(5499, 1);
// Doors
private static final int DOOR1 = 20240001;
private static final int DOOR2 = 20240002;
private static final int DOOR3 = 20240003;
// Items
private static final ItemHolder RING = new ItemHolder(10314, 1);
// Variables
private L2Npc _camera1;
private L2Npc _camera2;
private L2Npc _camera3;
private L2Npc _camera4;
private L2Npc _whirpool;
private L2Npc _beleth;
private L2Npc _priest;
private L2Npc _stone;
private L2PcInstance _killer;
private int _allowedObjId;
private int _killedCount;
private long _lastAttack;
private final List<L2Npc> _minions = new CopyOnWriteArrayList<>();
private Beleth()
{
super(Beleth.class.getSimpleName(), "ai/individual");
addEnterZoneId(ZONE.getId());
registerMobs(REAL_BELETH, FAKE_BELETH);
addStartNpc(STONE_COFFIN);
addTalkId(STONE_COFFIN);
addFirstTalkId(ELF);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(REAL_BELETH);
final int status = GrandBossManager.getInstance().getBossStatus(REAL_BELETH);
if (status == DEAD)
{
final long time = info.getLong("respawn_time") - System.currentTimeMillis();
if (time > 0)
{
startQuestTimer("BELETH_UNLOCK", time, null, null);
}
else
{
GrandBossManager.getInstance().setBossStatus(REAL_BELETH, ALIVE);
}
}
else if (status != ALIVE)
{
GrandBossManager.getInstance().setBossStatus(REAL_BELETH, ALIVE);
}
DoorData.getInstance().getDoor(DOOR1).openMe();
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "BELETH_UNLOCK":
{
GrandBossManager.getInstance().setBossStatus(REAL_BELETH, ALIVE);
DoorData.getInstance().getDoor(DOOR1).openMe();
break;
}
case "CAST":
{
if (!npc.isDead() && !npc.isCastingNow())
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
npc.doCast(FIREBALL.getSkill());
}
break;
}
case "SPAWN1":
{
ZONE.getCharactersInside().forEach(c ->
{
c.disableAllSkills();
c.setIsInvul(true);
c.setIsImmobilized(true);
});
_camera1 = addSpawn(29120, new Location(16323, 213142, -9357));
_camera2 = addSpawn(29121, new Location(16323, 210741, -9357));
_camera3 = addSpawn(29122, new Location(16323, 213170, -9357));
_camera4 = addSpawn(29123, new Location(16323, 214917, -9356));
ZONE.broadcastPacket(new PlaySound(1, "BS07_A", 1, _camera1.getObjectId(), _camera1.getX(), _camera1.getY(), _camera1.getZ()));
ZONE.broadcastPacket(new SpecialCamera(_camera1, 400, 75, -25, 0, 2500, 0, 0, 1, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(_camera1, 400, 75, -25, 0, 2500, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN2", 300, null, null);
break;
}
case "SPAWN2":
{
ZONE.broadcastPacket(new SpecialCamera(_camera1, 1800, -45, -45, 5000, 5000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN3", 4900, null, null);
break;
}
case "SPAWN3":
{
ZONE.broadcastPacket(new SpecialCamera(_camera1, 2500, -120, -45, 5000, 5000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN4", 4900, null, null);
break;
}
case "SPAWN4":
{
ZONE.broadcastPacket(new SpecialCamera(_camera2, 2200, 130, 0, 0, 1500, -20, 15, 1, 0, 0));
startQuestTimer("SPAWN5", 1400, null, null);
break;
}
case "SPAWN5":
{
ZONE.broadcastPacket(new SpecialCamera(_camera2, 2300, 100, 0, 2000, 4500, 0, 10, 1, 0, 0));
startQuestTimer("SPAWN6", 2500, null, null);
break;
}
case "SPAWN6":
{
final L2DoorInstance door = DoorData.getInstance().getDoor(DOOR1);
door.closeMe();
ZONE.broadcastPacket(new StaticObject(door, false));
ZONE.broadcastPacket(new DoorStatusUpdate(door));
startQuestTimer("SPAWN7", 1700, null, null);
break;
}
case "SPAWN7":
{
ZONE.broadcastPacket(new SpecialCamera(_camera4, 1500, 210, 0, 0, 1500, 0, 0, 1, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(_camera4, 900, 255, 0, 5000, 6500, 0, 10, 1, 0, 0));
startQuestTimer("SPAWN8", 6000, null, null);
break;
}
case "SPAWN8":
{
_whirpool = addSpawn(WHIRPOOL, new Location(16323, 214917, -9356));
ZONE.broadcastPacket(new SpecialCamera(_camera4, 900, 255, 0, 0, 1500, 0, 10, 1, 0, 0));
startQuestTimer("SPAWN9", 1000, null, null);
break;
}
case "SPAWN9":
{
ZONE.broadcastPacket(new SpecialCamera(_camera4, 1000, 255, 0, 7000, 17000, 0, 25, 1, 0, 0));
startQuestTimer("SPAWN10", 3000, null, null);
break;
}
case "SPAWN10":
{
_beleth = addSpawn(REAL_BELETH, new Location(16321, 214211, -9352, 49369));
_beleth.disableAllSkills();
_beleth.setIsInvul(true);
_beleth.setIsImmobilized(true);
startQuestTimer("SPAWN11", 200, null, null);
break;
}
case "SPAWN11":
{
ZONE.broadcastPacket(new SocialAction(_beleth.getObjectId(), 1));
for (int i = 0; i < 6; i++)
{
final int x = (int) ((150 * Math.cos(i * 1.046666667)) + 16323);
final int y = (int) ((150 * Math.sin(i * 1.046666667)) + 213059);
final L2Npc minion = addSpawn(FAKE_BELETH, new Location(x, y, -9357, 49152));
minion.setShowSummonAnimation(true);
minion.decayMe();
_minions.add(minion);
}
startQuestTimer("SPAWN12", 6800, null, null);
break;
}
case "SPAWN12":
{
ZONE.broadcastPacket(new SpecialCamera(_beleth, 0, 270, -5, 0, 4000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN13", 3500, null, null);
break;
}
case "SPAWN13":
{
ZONE.broadcastPacket(new SpecialCamera(_beleth, 800, 270, 10, 3000, 6000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN14", 5000, null, null);
break;
}
case "SPAWN14":
{
ZONE.broadcastPacket(new SpecialCamera(_camera3, 100, 270, 15, 0, 5000, 0, 0, 1, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(_camera3, 100, 270, 15, 0, 5000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN15", 100, null, null);
break;
}
case "SPAWN15":
{
ZONE.broadcastPacket(new SpecialCamera(_camera3, 100, 270, 15, 3000, 6000, 0, 5, 1, 0, 0));
startQuestTimer("SPAWN16", 1400, null, null);
break;
}
case "SPAWN16":
{
_beleth.teleToLocation(BELETH_SPAWN);
startQuestTimer("SPAWN17", 200, null, null);
break;
}
case "SPAWN17":
{
ZONE.broadcastPacket(new MagicSkillUse(_beleth, _beleth, 5532, 1, 2000, 0));
startQuestTimer("SPAWN18", 2000, null, null);
break;
}
case "SPAWN18":
{
ZONE.broadcastPacket(new SpecialCamera(_camera3, 700, 270, 20, 1500, 8000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN19", 6900, null, null);
break;
}
case "SPAWN19":
{
ZONE.broadcastPacket(new SpecialCamera(_camera3, 40, 260, 0, 0, 4000, 0, 0, 1, 0, 0));
for (L2Npc fakeBeleth : _minions)
{
fakeBeleth.spawnMe();
fakeBeleth.disableAllSkills();
fakeBeleth.setIsInvul(true);
fakeBeleth.setIsImmobilized(true);
}
startQuestTimer("SPAWN20", 3000, null, null);
break;
}
case "SPAWN20":
{
ZONE.broadcastPacket(new SpecialCamera(_camera3, 40, 280, 0, 0, 4000, 5, 0, 1, 0, 0));
startQuestTimer("SPAWN21", 3000, null, null);
break;
}
case "SPAWN21":
{
ZONE.broadcastPacket(new SpecialCamera(_camera3, 5, 250, 5, 0, 13000, 20, 15, 1, 0, 0));
startQuestTimer("SPAWN22", 1000, null, null);
break;
}
case "SPAWN22":
{
ZONE.broadcastPacket(new SocialAction(_beleth.getObjectId(), 3));
startQuestTimer("SPAWN23", 4000, null, null);
break;
}
case "SPAWN23":
{
ZONE.broadcastPacket(new MagicSkillUse(_beleth, _beleth, 5533, 1, 2000, 0));
startQuestTimer("SPAWN24", 6800, null, null);
break;
}
case "SPAWN24":
{
_beleth.deleteMe();
_beleth = null;
for (L2Npc fakeBeleth : _minions)
{
fakeBeleth.deleteMe();
}
_minions.clear();
_camera1.deleteMe();
_camera2.deleteMe();
_camera3.deleteMe();
_camera4.deleteMe();
for (L2Character c : ZONE.getCharactersInside())
{
c.enableAllSkills();
c.setIsInvul(false);
c.setIsImmobilized(false);
}
_lastAttack = System.currentTimeMillis();
startQuestTimer("CHECK_ATTACK", 60000, null, null);
startQuestTimer("SPAWN25", 60000, null, null);
break;
}
case "SPAWN25":
{
_minions.clear();
int a = 0;
for (int i = 0; i < 16; i++)
{
a++;
final int x = (int) ((650 * Math.cos(i * 0.39)) + 16323);
final int y = (int) ((650 * Math.sin(i * 0.39)) + 213170);
npc = addSpawn(FAKE_BELETH, new Location(x, y, -9357, 49152));
_minions.add(npc);
if (a >= 2)
{
npc.setIsOverloaded(true);
a = 0;
}
}
final int[] xm = new int[16];
final int[] ym = new int[16];
for (int i = 0; i < 4; i++)
{
xm[i] = (int) ((1700 * Math.cos((i * 1.57) + 0.78)) + 16323);
ym[i] = (int) ((1700 * Math.sin((i * 1.57) + 0.78)) + 213170);
npc = addSpawn(FAKE_BELETH, new Location(xm[i], ym[i], -9357, 49152));
npc.setIsImmobilized(true);
_minions.add(npc);
}
xm[4] = (xm[0] + xm[1]) / 2;
ym[4] = (ym[0] + ym[1]) / 2;
npc = addSpawn(FAKE_BELETH, new Location(xm[4], ym[4], -9357, 49152));
npc.setIsImmobilized(true);
_minions.add(npc);
xm[5] = (xm[1] + xm[2]) / 2;
ym[5] = (ym[1] + ym[2]) / 2;
npc = addSpawn(FAKE_BELETH, new Location(xm[5], ym[5], -9357, 49152));
npc.setIsImmobilized(true);
_minions.add(npc);
xm[6] = (xm[2] + xm[3]) / 2;
ym[6] = (ym[2] + ym[3]) / 2;
npc = addSpawn(FAKE_BELETH, new Location(xm[6], ym[6], -9357, 49152));
npc.setIsImmobilized(true);
_minions.add(npc);
xm[7] = (xm[3] + xm[0]) / 2;
ym[7] = (ym[3] + ym[0]) / 2;
npc = addSpawn(FAKE_BELETH, new Location(xm[7], ym[7], -9357, 49152));
npc.setIsImmobilized(true);
_minions.add(npc);
xm[8] = (xm[0] + xm[4]) / 2;
ym[8] = (ym[0] + ym[4]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[8], ym[8], -9357, 49152)));
xm[9] = (xm[4] + xm[1]) / 2;
ym[9] = (ym[4] + ym[1]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[9], ym[9], -9357, 49152)));
xm[10] = (xm[1] + xm[5]) / 2;
ym[10] = (ym[1] + ym[5]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[10], ym[10], -9357, 49152)));
xm[11] = (xm[5] + xm[2]) / 2;
ym[11] = (ym[5] + ym[2]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[11], ym[11], -9357, 49152)));
xm[12] = (xm[2] + xm[6]) / 2;
ym[12] = (ym[2] + ym[6]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[12], ym[12], -9357, 49152)));
xm[13] = (xm[6] + xm[3]) / 2;
ym[13] = (ym[6] + ym[3]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[13], ym[13], -9357, 49152)));
xm[14] = (xm[3] + xm[7]) / 2;
ym[14] = (ym[3] + ym[7]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[14], ym[14], -9357, 49152)));
xm[15] = (xm[7] + xm[0]) / 2;
ym[15] = (ym[7] + ym[0]) / 2;
_minions.add(addSpawn(FAKE_BELETH, new Location(xm[15], ym[15], -9357, 49152)));
_allowedObjId = _minions.get(getRandom(_minions.size())).getObjectId();
break;
}
case "SPAWN_REAL":
{
_beleth = addSpawn(REAL_BELETH, new Location(16323, 213170, -9357, 49152));
break;
}
case "SPAWN26":
{
_beleth.doDie(null);
_camera1 = addSpawn(29122, new Location(16323, 213170, -9357));
_camera1.broadcastPacket(new PlaySound(1, "BS07_D", 1, _camera1.getObjectId(), _camera1.getX(), _camera1.getY(), _camera1.getZ()));
ZONE.broadcastPacket(new SpecialCamera(_camera1, 400, 290, 25, 0, 10000, 0, 0, 1, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(_camera1, 400, 290, 25, 0, 10000, 0, 0, 1, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(_camera1, 400, 110, 25, 4000, 10000, 0, 0, 1, 0, 0));
ZONE.broadcastPacket(new SocialAction(_beleth.getObjectId(), 5));
startQuestTimer("SPAWN27", 4000, null, null);
break;
}
case "SPAWN27":
{
ZONE.broadcastPacket(new SpecialCamera(_camera1, 400, 295, 25, 4000, 5000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN28", 4500, null, null);
break;
}
case "SPAWN28":
{
ZONE.broadcastPacket(new SpecialCamera(_camera1, 400, 295, 10, 4000, 11000, 0, 25, 1, 0, 0));
startQuestTimer("SPAWN29", 9000, null, null);
break;
}
case "SPAWN29":
{
ZONE.broadcastPacket(new SpecialCamera(_camera1, 250, 90, 25, 0, 1000, 0, 0, 1, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(_camera1, 250, 90, 25, 0, 10000, 0, 0, 1, 0, 0));
startQuestTimer("SPAWN30", 2000, null, null);
break;
}
case "SPAWN30":
{
_priest.spawnMe();
_beleth.deleteMe();
_camera2 = addSpawn(29121, new Location(14056, 213170, -9357));
startQuestTimer("SPAWN31", 3500, null, null);
break;
}
case "SPAWN31":
{
ZONE.broadcastPacket(new SpecialCamera(_camera2, 800, 180, 0, 0, 4000, 0, 10, 1, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(_camera2, 800, 180, 0, 0, 4000, 0, 10, 1, 0, 0));
final L2DoorInstance door2 = DoorData.getInstance().getDoor(DOOR2);
door2.openMe();
ZONE.broadcastPacket(new StaticObject(door2, false));
ZONE.broadcastPacket(new DoorStatusUpdate(door2));
DoorData.getInstance().getDoor(DOOR3).openMe();
_camera1.deleteMe();
_camera2.deleteMe();
_whirpool.deleteMe();
for (L2Character c : ZONE.getCharactersInside())
{
c.enableAllSkills();
c.setIsInvul(false);
c.setIsImmobilized(false);
}
break;
}
case "CHECK_ATTACK":
{
if ((_lastAttack + 900000) < System.currentTimeMillis())
{
GrandBossManager.getInstance().setBossStatus(REAL_BELETH, ALIVE);
for (L2Character charInside : ZONE.getCharactersInside())
{
if (charInside != null)
{
if (charInside.isNpc())
{
charInside.deleteMe();
}
else if (charInside.isPlayer())
{
charInside.teleToLocation(MapRegionManager.getInstance().getTeleToLocation(charInside, TeleportWhereType.TOWN));
}
}
}
cancelQuestTimer("CHECK_ATTACK", null, null);
}
else
{
startQuestTimer("CHECK_ATTACK", 60000, null, null);
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onEnterZone(L2Character character, L2ZoneType zone)
{
if (character.isPlayer() && (GrandBossManager.getInstance().getBossStatus(REAL_BELETH) == INIT))
{
if (_priest != null)
{
_priest.deleteMe();
}
if (_stone != null)
{
_stone.deleteMe();
}
GrandBossManager.getInstance().setBossStatus(REAL_BELETH, FIGHT);
startQuestTimer("SPAWN1", 300000, null, null);
}
return super.onEnterZone(character, zone);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance player, Skill skill, L2Object[] targets, boolean isSummon)
{
if (!npc.isDead() && (npc.getId() == REAL_BELETH) && !npc.isCastingNow() && skill.hasEffectType(L2EffectType.HEAL) && (getRandom(100) < 80))
{
npc.setTarget(player);
npc.doCast(HORN_OF_RISING.getSkill());
}
return null;
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (!npc.isDead() && !npc.isCastingNow())
{
if ((getRandom(100) < 40) && !npc.getKnownList().getKnownPlayersInRadius(200).isEmpty())
{
npc.doCast(BLEED.getSkill());
return null;
}
npc.setTarget(player);
npc.doCast(FIREBALL.getSkill());
}
return null;
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
if (!npc.isDead() && !npc.isCastingNow())
{
if (!player.isDead())
{
final double distance2 = npc.calculateDistance(player, false, false);
if ((distance2 > 890) && !npc.isMovementDisabled())
{
npc.setTarget(player);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, player);
startQuestTimer("CAST", (int) (((distance2 - 890) / (npc.isRunning() ? npc.getRunSpeed() : npc.getWalkSpeed())) * 1000), npc, null);
}
else if (distance2 < 890)
{
npc.setTarget(player);
npc.doCast(FIREBALL.getSkill());
}
return null;
}
if ((getRandom(100) < 40) && !npc.getKnownList().getKnownPlayersInRadius(200).isEmpty())
{
npc.doCast(LIGHTENING.getSkill());
return null;
}
for (L2PcInstance plr : npc.getKnownList().getKnownPlayersInRadius(950))
{
npc.setTarget(plr);
npc.doCast(FIREBALL.getSkill());
return null;
}
((L2Attackable) npc).clearAggroList();
}
return null;
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setRunning();
if (!npc.getKnownList().getKnownPlayersInRadius(300).isEmpty() && (getRandom(100) < 60))
{
npc.doCast(BLEED.getSkill());
}
if (npc.getId() == REAL_BELETH)
{
npc.getSpawn().setRespawnDelay(0);
}
return null;
}
@Override
public String onTalk(L2Npc npc, L2PcInstance player)
{
String html;
if ((_killer != null) && (player.getObjectId() == _killer.getObjectId()))
{
_killer = null;
giveItems(player, RING);
html = "32470a.htm";
}
else
{
html = "32470b.htm";
}
return HtmCache.getInstance().getHtm(player.getHtmlPrefix(), "data/html/default/" + html);
}
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
return onTalk(npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (getRandom(100) < 40)
{
return null;
}
final double distance = npc.calculateDistance(attacker, false, false);
if ((distance > 500) || (getRandom(100) < 80))
{
for (L2Npc beleth : _minions)
{
if ((beleth != null) && !beleth.isDead() && Util.checkIfInRange(900, beleth, attacker, false) && !beleth.isCastingNow())
{
beleth.setTarget(attacker);
beleth.doCast(FIREBALL.getSkill());
}
}
if ((_beleth != null) && !_beleth.isDead() && Util.checkIfInRange(900, _beleth, attacker, false) && !_beleth.isCastingNow())
{
_beleth.setTarget(attacker);
_beleth.doCast(FIREBALL.getSkill());
}
}
else if (!npc.isDead() && !npc.isCastingNow())
{
if (!npc.getKnownList().getKnownPlayersInRadius(200).isEmpty())
{
npc.doCast(LIGHTENING.getSkill());
return null;
}
((L2Attackable) npc).clearAggroList();
}
return null;
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.getId() == REAL_BELETH)
{
cancelQuestTimer("CHECK_ATTACK", null, null);
setBelethKiller(killer);
GrandBossManager.getInstance().setBossStatus(REAL_BELETH, DEAD);
final long respawnTime = (Config.BELETH_SPAWN_INTERVAL + getRandom(-Config.BELETH_SPAWN_RANDOM, Config.BELETH_SPAWN_RANDOM)) * 3600000;
final StatsSet info = GrandBossManager.getInstance().getStatsSet(REAL_BELETH);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(REAL_BELETH, info);
startQuestTimer("BELETH_UNLOCK", respawnTime, null, null);
deleteAll();
npc.deleteMe();
for (L2Character c : ZONE.getCharactersInside())
{
c.disableAllSkills();
c.setIsInvul(true);
c.setIsImmobilized(true);
}
_beleth = addSpawn(REAL_BELETH, new Location(16323, 213170, -9357, 49152));
_beleth.disableAllSkills();
_beleth.setIsInvul(true);
_beleth.setIsImmobilized(true);
_priest = addSpawn(ELF, new Location(_beleth));
_priest.setShowSummonAnimation(true);
_priest.decayMe();
_stone = addSpawn(STONE_COFFIN, new Location(12470, 215607, -9381, 49152));
startQuestTimer("SPAWN26", 1000, null, null);
}
else if (npc.getObjectId() == _allowedObjId)
{
deleteAll();
_killedCount++;
if (_killedCount >= 5)
{
startQuestTimer("SPAWN_REAL", 60000, null, null);
}
else
{
startQuestTimer("SPAWN25", 60000, null, null);
}
}
return null;
}
private void setBelethKiller(L2PcInstance killer)
{
if (killer.getParty() != null)
{
if (killer.getParty().getCommandChannel() != null)
{
_killer = killer.getParty().getCommandChannel().getLeader();
}
else
{
_killer = killer.getParty().getLeader();
}
}
else
{
_killer = killer;
}
}
private void deleteAll()
{
_minions.stream().filter(n -> !n.isDead()).forEach(n ->
{
n.abortCast();
n.setTarget(null);
n.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
n.deleteMe();
});
_allowedObjId = 0;
}
public static void main(String[] args)
{
new Beleth();
}
}

View File

@@ -0,0 +1,224 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import ai.npc.AbstractNpcAI;
/**
* Core AI.
* @author DrLecter, Emperorc
*/
final class Core extends AbstractNpcAI
{
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;
private final List<L2Attackable> _minions = new CopyOnWriteArrayList<>();
private Core()
{
super(Core.class.getSimpleName(), "ai/individual");
registerMobs(CORE, DEATH_KNIGHT, DOOM_WRAITH, SUSCEPTOR);
_firstAttacked = false;
final StatsSet info = GrandBossManager.getInstance().getStatsSet(CORE);
if (GrandBossManager.getInstance().getBossStatus(CORE) == DEAD)
{
final long temp = info.getLong("respawn_time") - System.currentTimeMillis();
if (temp > 0)
{
startQuestTimer("core_unlock", temp, null, null);
}
else
{
final L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, 17726, 108915, -6480, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(CORE, ALIVE);
spawnBoss(core);
}
}
else
{
final String test = loadGlobalQuestVar("Core_Attacked");
if (test.equalsIgnoreCase("true"))
{
_firstAttacked = true;
}
final int loc_x = info.getInt("loc_x");
final int loc_y = info.getInt("loc_y");
final int loc_z = info.getInt("loc_z");
final int heading = info.getInt("heading");
final int hp = info.getInt("currentHP");
final int mp = info.getInt("currentMP");
final L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, loc_x, loc_y, loc_z, heading, false, 0);
core.setCurrentHpMp(hp, mp);
spawnBoss(core);
}
}
@Override
public void saveGlobalData()
{
saveGlobalQuestVar("Core_Attacked", Boolean.toString(_firstAttacked));
}
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++)
{
final int x = 16800 + (i * 360);
mob = (L2Attackable) addSpawn(DEATH_KNIGHT, x, 110000, npc.getZ(), 280 + getRandom(40), false, 0);
mob.setIsRaidMinion(true);
_minions.add(mob);
mob = (L2Attackable) addSpawn(DEATH_KNIGHT, x, 109000, npc.getZ(), 280 + getRandom(40), false, 0);
mob.setIsRaidMinion(true);
_minions.add(mob);
final int x2 = 16800 + (i * 600);
mob = (L2Attackable) addSpawn(DOOM_WRAITH, x2, 109300, npc.getZ(), 280 + getRandom(40), false, 0);
mob.setIsRaidMinion(true);
_minions.add(mob);
}
for (int i = 0; i < 4; i++)
{
final int x = 16800 + (i * 450);
mob = (L2Attackable) addSpawn(SUSCEPTOR, x, 110300, npc.getZ(), 280 + getRandom(40), false, 0);
mob.setIsRaidMinion(true);
_minions.add(mob);
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("core_unlock"))
{
final L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, 17726, 108915, -6480, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(CORE, ALIVE);
spawnBoss(core);
}
else if (event.equalsIgnoreCase("spawn_minion"))
{
final L2Attackable mob = (L2Attackable) addSpawn(npc.getId(), npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), false, 0);
mob.setIsRaidMinion(true);
_minions.add(mob);
}
else if (event.equalsIgnoreCase("despawn_minions"))
{
_minions.forEach(m -> m.decayMe());
_minions.clear();
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.getId() == CORE)
{
if (_firstAttacked)
{
if (getRandom(100) == 0)
{
npc.broadcastPacket(new NpcSay(npc.getObjectId(), ChatType.NPC_GENERAL, npc.getId(), NpcStringId.REMOVING_INTRUDERS));
}
}
else
{
_firstAttacked = true;
npc.broadcastPacket(new NpcSay(npc.getObjectId(), ChatType.NPC_GENERAL, npc.getId(), NpcStringId.A_NON_PERMITTED_TARGET_HAS_BEEN_DISCOVERED));
npc.broadcastPacket(new NpcSay(npc.getObjectId(), ChatType.NPC_GENERAL, npc.getId(), NpcStringId.INTRUDER_REMOVAL_SYSTEM_INITIATED));
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.getId() == CORE)
{
final int objId = npc.getObjectId();
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, objId, npc.getX(), npc.getY(), npc.getZ()));
npc.broadcastPacket(new NpcSay(objId, ChatType.NPC_GENERAL, npc.getId(), NpcStringId.A_FATAL_ERROR_HAS_OCCURRED));
npc.broadcastPacket(new NpcSay(objId, ChatType.NPC_GENERAL, npc.getId(), NpcStringId.SYSTEM_IS_BEING_SHUT_DOWN));
npc.broadcastPacket(new NpcSay(objId, ChatType.NPC_GENERAL, npc.getId(), NpcStringId.DOT_DOT_DOT_DOT_DOT_DOT));
_firstAttacked = false;
GrandBossManager.getInstance().setBossStatus(CORE, DEAD);
// Calculate Min and Max respawn times randomly.
final long respawnTime = (Config.CORE_SPAWN_INTERVAL + getRandom(-Config.CORE_SPAWN_RANDOM, Config.CORE_SPAWN_RANDOM)) * 3600000;
startQuestTimer("core_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
final StatsSet info = GrandBossManager.getInstance().getStatsSet(CORE);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(CORE, info);
startQuestTimer("despawn_minions", 20000, null, null);
cancelQuestTimers("spawn_minion");
}
else if ((GrandBossManager.getInstance().getBossStatus(CORE) == ALIVE) && _minions.contains(npc))
{
_minions.remove(npc);
startQuestTimer("spawn_minion", 60000, npc, null);
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
if (npc.getId() == CORE)
{
npc.setIsImmobilized(true);
}
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new Core();
}
}

View File

@@ -0,0 +1,105 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* AI for Kamaloka (33) - Crimson Hatu Otis
* @author Gladicek
*/
final class CrimsonHatuOtis extends AbstractNpcAI
{
// Npc
private static final int CRIMSON_HATU_OTIS = 18558;
// Skills
private static SkillHolder BOSS_SPINING_SLASH = new SkillHolder(4737, 1);
private static SkillHolder BOSS_HASTE = new SkillHolder(4175, 1);
private CrimsonHatuOtis()
{
super(CrimsonHatuOtis.class.getSimpleName(), "ai/individual");
addAttackId(CRIMSON_HATU_OTIS);
addKillId(CRIMSON_HATU_OTIS);
}
@Override
public final String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "SKILL":
{
if (npc.isDead())
{
cancelQuestTimer("SKILL", npc, null);
return null;
}
npc.setTarget(player);
npc.doCast(BOSS_SPINING_SLASH.getSkill());
startQuestTimer("SKILL", 60000, npc, null);
break;
}
case "BUFF":
{
if (npc.isScriptValue(2))
{
npc.setTarget(npc);
npc.doCast(BOSS_HASTE.getSkill());
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (npc.isScriptValue(0))
{
npc.setScriptValue(1);
startQuestTimer("SKILL", 5000, npc, null);
}
else if (npc.isScriptValue(1) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)))
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.I_VE_HAD_IT_UP_TO_HERE_WITH_YOU_I_LL_TAKE_CARE_OF_YOU);
npc.setScriptValue(2);
startQuestTimer("BUFF", 1000, npc, null);
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance player, boolean isSummon)
{
cancelQuestTimer("SKILL", npc, null);
cancelQuestTimer("BUFF", npc, null);
return super.onKill(npc, player, isSummon);
}
public static void main(String[] args)
{
new CrimsonHatuOtis();
}
}

View File

@@ -0,0 +1,242 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import ai.npc.AbstractNpcAI;
/**
* Dark Water Dragon's AI.
*/
final class DarkWaterDragon extends AbstractNpcAI
{
private static final int DRAGON = 22267;
private static final int SHADE1 = 22268;
private static final int SHADE2 = 22269;
private static final int FAFURION = 18482;
private static final int DETRACTOR1 = 22270;
private static final int DETRACTOR2 = 22271;
private static final Set<Integer> SECOND_SPAWN = ConcurrentHashMap.newKeySet(); // Used to track if second Shades were already spawned
private static Set<Integer> MY_TRACKING_SET = ConcurrentHashMap.newKeySet(); // Used to track instances of npcs
private static Map<Integer, L2PcInstance> ID_MAP = new ConcurrentHashMap<>(); // Used to track instances of npcs
private DarkWaterDragon()
{
super(DarkWaterDragon.class.getSimpleName(), "ai/individual");
final int[] mobs =
{
DRAGON,
SHADE1,
SHADE2,
FAFURION,
DETRACTOR1,
DETRACTOR2
};
addKillId(mobs);
addAttackId(mobs);
addSpawnId(mobs);
MY_TRACKING_SET.clear();
SECOND_SPAWN.clear();
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (npc != null)
{
if (event.equalsIgnoreCase("first_spawn")) // timer to start timer "1"
{
startQuestTimer("1", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("second_spawn")) // timer to start timer "2"
{
startQuestTimer("2", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("third_spawn")) // timer to start timer "3"
{
startQuestTimer("3", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("fourth_spawn")) // timer to start timer "4"
{
startQuestTimer("4", 40000, npc, null, true); // spawns detractor every 40 seconds
}
else if (event.equalsIgnoreCase("1")) // spawns a detractor
{
addSpawn(DETRACTOR1, npc.getX() + 100, npc.getY() + 100, npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("2")) // spawns a detractor
{
addSpawn(DETRACTOR2, npc.getX() + 100, npc.getY() - 100, npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("3")) // spawns a detractor
{
addSpawn(DETRACTOR1, npc.getX() - 100, npc.getY() + 100, npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("4")) // spawns a detractor
{
addSpawn(DETRACTOR2, npc.getX() - 100, npc.getY() - 100, npc.getZ(), 0, false, 40000);
}
else if (event.equalsIgnoreCase("fafurion_despawn")) // Fafurion Kindred disappears and drops reward
{
cancelQuestTimer("fafurion_poison", npc, null);
cancelQuestTimer("1", npc, null);
cancelQuestTimer("2", npc, null);
cancelQuestTimer("3", npc, null);
cancelQuestTimer("4", npc, null);
MY_TRACKING_SET.remove(npc.getObjectId());
player = ID_MAP.remove(npc.getObjectId());
if (player != null)
{
((L2Attackable) npc).doItemDrop(NpcData.getInstance().getTemplate(18485), player);
}
npc.deleteMe();
}
else if (event.equalsIgnoreCase("fafurion_poison")) // Reduces Fafurions hp like it is poisoned
{
if (npc.getCurrentHp() <= 500)
{
cancelQuestTimer("fafurion_despawn", npc, null);
cancelQuestTimer("first_spawn", npc, null);
cancelQuestTimer("second_spawn", npc, null);
cancelQuestTimer("third_spawn", npc, null);
cancelQuestTimer("fourth_spawn", npc, null);
cancelQuestTimer("1", npc, null);
cancelQuestTimer("2", npc, null);
cancelQuestTimer("3", npc, null);
cancelQuestTimer("4", npc, null);
MY_TRACKING_SET.remove(npc.getObjectId());
ID_MAP.remove(npc.getObjectId());
}
npc.reduceCurrentHp(500, npc, null); // poison kills Fafurion if he is not healed
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
final int npcId = npc.getId();
final int npcObjId = npc.getObjectId();
if (npcId == DRAGON)
{
if (!MY_TRACKING_SET.contains(npcObjId)) // this allows to handle multiple instances of npc
{
MY_TRACKING_SET.add(npcObjId);
// Spawn first 5 shades on first attack on Dark Water Dragon
final L2Character originalAttacker = isSummon ? attacker.getSummon() : attacker;
spawnShade(originalAttacker, SHADE1, npc.getX() + 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() + 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() - 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() - 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() - 150, npc.getY() + 150, npc.getZ());
}
else if ((npc.getCurrentHp() < (npc.getMaxHp() / 2.0)) && !(SECOND_SPAWN.contains(npcObjId)))
{
SECOND_SPAWN.add(npcObjId);
// Spawn second 5 shades on half hp of on Dark Water Dragon
final L2Character originalAttacker = isSummon ? attacker.getSummon() : attacker;
spawnShade(originalAttacker, SHADE2, npc.getX() + 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() + 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() - 100, npc.getY() + 100, npc.getZ());
spawnShade(originalAttacker, SHADE1, npc.getX() - 100, npc.getY() - 100, npc.getZ());
spawnShade(originalAttacker, SHADE2, npc.getX() - 150, npc.getY() + 150, npc.getZ());
}
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
final int npcId = npc.getId();
final int npcObjId = npc.getObjectId();
if (npcId == DRAGON)
{
MY_TRACKING_SET.remove(npcObjId);
SECOND_SPAWN.remove(npcObjId);
final L2Attackable faf = (L2Attackable) addSpawn(FAFURION, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0); // spawns Fafurion Kindred when Dard Water Dragon is dead
ID_MAP.put(faf.getObjectId(), killer);
}
else if (npcId == FAFURION)
{
cancelQuestTimer("fafurion_poison", npc, null);
cancelQuestTimer("fafurion_despawn", npc, null);
cancelQuestTimer("first_spawn", npc, null);
cancelQuestTimer("second_spawn", npc, null);
cancelQuestTimer("third_spawn", npc, null);
cancelQuestTimer("fourth_spawn", npc, null);
cancelQuestTimer("1", npc, null);
cancelQuestTimer("2", npc, null);
cancelQuestTimer("3", npc, null);
cancelQuestTimer("4", npc, null);
MY_TRACKING_SET.remove(npcObjId);
ID_MAP.remove(npcObjId);
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
final int npcId = npc.getId();
final int npcObjId = npc.getObjectId();
if ((npcId == FAFURION) && !MY_TRACKING_SET.contains(npcObjId))
{
MY_TRACKING_SET.add(npcObjId);
// Spawn 4 Detractors on spawn of Fafurion
final int x = npc.getX();
final int y = npc.getY();
addSpawn(DETRACTOR2, x + 100, y + 100, npc.getZ(), 0, false, 40000);
addSpawn(DETRACTOR1, x + 100, y - 100, npc.getZ(), 0, false, 40000);
addSpawn(DETRACTOR2, x - 100, y + 100, npc.getZ(), 0, false, 40000);
addSpawn(DETRACTOR1, x - 100, y - 100, npc.getZ(), 0, false, 40000);
startQuestTimer("first_spawn", 2000, npc, null);
startQuestTimer("second_spawn", 4000, npc, null);
startQuestTimer("third_spawn", 8000, npc, null);
startQuestTimer("fourth_spawn", 10000, npc, null);
startQuestTimer("fafurion_poison", 3000, npc, null, true);
startQuestTimer("fafurion_despawn", 120000, npc, null);
}
return super.onSpawn(npc);
}
public void spawnShade(L2Character attacker, int npcId, int x, int y, int z)
{
final L2Npc shade = addSpawn(npcId, x, y, z, 0, false, 0);
shade.setRunning();
((L2Attackable) shade).addDamageHate(attacker, 0, 999);
shade.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
}
public static void main(String[] args)
{
new DarkWaterDragon();
}
}

View File

@@ -0,0 +1,67 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import ai.npc.AbstractNpcAI;
/**
* Simple AI that manages special conditions for Divine Beast summon.
* @author UnAfraid
*/
final class DivineBeast extends AbstractNpcAI
{
private static final int DIVINE_BEAST = 14870;
private static final int TRANSFORMATION_ID = 258;
private static final int CHECK_TIME = 2 * 1000;
private DivineBeast()
{
super(DivineBeast.class.getSimpleName(), "ai");
addSummonSpawnId(DIVINE_BEAST);
}
@Override
public void onSummonSpawn(L2Summon summon)
{
startQuestTimer("VALIDATE_TRANSFORMATION", CHECK_TIME, null, summon.getActingPlayer(), true);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if ((player == null) || !player.hasServitor())
{
cancelQuestTimer(event, npc, player);
}
else if (player.getTransformationId() != TRANSFORMATION_ID)
{
cancelQuestTimer(event, npc, player);
player.getSummon().unSummon(player);
}
return super.onAdvEvent(event, npc, player);
}
public static void main(String[] args)
{
new DivineBeast();
}
}

View File

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

View File

@@ -0,0 +1,143 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.util.MinionList;
import ai.npc.AbstractNpcAI;
/**
* Manages minion's spawn, idle despawn and Teleportation Cube spawn.
* @author GKR
*/
final class Epidos extends AbstractNpcAI
{
private static final int[] EPIDOSES =
{
25609,
25610,
25611,
25612
};
private static final int[] MINIONS =
{
25605,
25606,
25607,
25608
};
private static final int[] MINIONS_COUNT =
{
3,
6,
11
};
private final Map<Integer, Double> _lastHp = new ConcurrentHashMap<>();
private Epidos()
{
super(Epidos.class.getSimpleName(), "ai/individual");
addKillId(EPIDOSES);
addSpawnId(EPIDOSES);
}
@Override
public final String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("check_minions"))
{
if ((getRandom(1000) > 250) && _lastHp.containsKey(npc.getObjectId()))
{
final int hpDecreasePercent = (int) (((_lastHp.get(npc.getObjectId()) - npc.getCurrentHp()) * 100) / npc.getMaxHp());
int minionsCount = 0;
final int spawnedMinions = ((L2MonsterInstance) npc).getMinionList().countSpawnedMinions();
if ((hpDecreasePercent > 5) && (hpDecreasePercent <= 15) && (spawnedMinions <= 9))
{
minionsCount = MINIONS_COUNT[0];
}
else if ((((hpDecreasePercent > 1) && (hpDecreasePercent <= 5)) || ((hpDecreasePercent > 15) && (hpDecreasePercent <= 30))) && (spawnedMinions <= 6))
{
minionsCount = MINIONS_COUNT[1];
}
else if (spawnedMinions == 0)
{
minionsCount = MINIONS_COUNT[2];
}
for (int i = 0; i < minionsCount; i++)
{
MinionList.spawnMinion((L2MonsterInstance) npc, MINIONS[Arrays.binarySearch(EPIDOSES, npc.getId())]);
}
_lastHp.put(npc.getObjectId(), npc.getCurrentHp());
}
startQuestTimer("check_minions", 10000, npc, null);
}
else if (event.equalsIgnoreCase("check_idle"))
{
if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE)
{
npc.deleteMe();
}
else
{
startQuestTimer("check_idle", 600000, npc, null);
}
}
return null;
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.isInsideRadius(-45474, 247450, -13994, 2000, true, false))
{
addSpawn(32376, -45482, 246277, -14184, 0, false, 0, false);
}
_lastHp.remove(npc.getObjectId());
return super.onKill(npc, killer, isSummon);
}
@Override
public final String onSpawn(L2Npc npc)
{
startQuestTimer("check_minions", 10000, npc, null);
startQuestTimer("check_idle", 600000, npc, null);
_lastHp.put(npc.getObjectId(), (double) npc.getMaxHp());
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new Epidos();
}
}

View File

@@ -0,0 +1,77 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import ai.npc.AbstractNpcAI;
/**
* Eva's Gift Box AI.
* @author St3eT
*/
final class EvasGiftBox extends AbstractNpcAI
{
// NPC
private static final int BOX = 32342; // Eva's Gift Box
// Skill
private static final int BUFF = 1073; // Kiss of Eva
// Items
private static final ItemHolder CORAL = new ItemHolder(9692, 1); // Red Coral
private static final ItemHolder CRYSTAL = new ItemHolder(9693, 1); // Crystal Fragment
private EvasGiftBox()
{
super(EvasGiftBox.class.getSimpleName(), "ai/individual");
addKillId(BOX);
addSpawnId(BOX);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (killer.isAffectedBySkill(BUFF))
{
if (getRandomBoolean())
{
npc.dropItem(killer, CRYSTAL);
}
if (getRandom(100) < 33)
{
npc.dropItem(killer, CORAL);
}
}
return super.onKill(npc, killer, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.setIsNoRndWalk(true);
((L2Attackable) npc).setOnKillDelay(0);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new EvasGiftBox();
}
}

View File

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

View File

@@ -0,0 +1,62 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import ai.npc.AbstractNpcAI;
/**
* Gordon AI
* @author TOFIZ, malyelfik
*/
final class Gordon extends AbstractNpcAI
{
private static final int GORDON = 29095;
private Gordon()
{
super(Gordon.class.getSimpleName(), "ai/individual");
addSpawnId(GORDON);
addSeeCreatureId(GORDON);
}
@Override
public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
{
if (creature.isPlayer() && ((L2PcInstance) creature).isCursedWeaponEquipped())
{
addAttackDesire(npc, creature);
}
return super.onSeeCreature(npc, creature, isSummon);
}
@Override
public String onSpawn(L2Npc npc)
{
((L2Attackable) npc).setCanReturnToSpawnPoint(false);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new Gordon();
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* Grove Robber's AI.<br>
* <ul>
* <li>Grove Robber Summoner</li>
* <li>Grove Robber Megician</li>
* </ul>
* @author Zealar
*/
final class GraveRobbers extends AbstractNpcAI
{
private static final int GRAVE_ROBBER_SUMMONER = 22678;
private static final int GRAVE_ROBBER_MEGICIAN = 22679;
private GraveRobbers()
{
super(GraveRobbers.class.getSimpleName(), "ai/individual");
addSpawnId(GRAVE_ROBBER_SUMMONER, GRAVE_ROBBER_MEGICIAN);
}
@Override
public String onSpawn(L2Npc npc)
{
spawnMinions(npc, "Privates" + getRandom(1, 2));
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new GraveRobbers();
}
}

View File

@@ -0,0 +1,350 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SkillData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.type.L2BossZone;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import ai.npc.AbstractNpcAI;
/**
* Orfen's AI
* @author Emperorc
*/
final class Orfen extends AbstractNpcAI
{
private static final Location[] POS =
{
new Location(43728, 17220, -4342),
new Location(55024, 17368, -5412),
new Location(53504, 21248, -5486),
new Location(53248, 24576, -5262)
};
private static final NpcStringId[] TEXT =
{
NpcStringId.S1_STOP_KIDDING_YOURSELF_ABOUT_YOUR_OWN_POWERLESSNESS,
NpcStringId.S1_I_LL_MAKE_YOU_FEEL_WHAT_TRUE_FEAR_IS,
NpcStringId.YOU_RE_REALLY_STUPID_TO_HAVE_CHALLENGED_ME_S1_GET_READY,
NpcStringId.S1_DO_YOU_THINK_THAT_S_GOING_TO_WORK
};
private static final int ORFEN = 29014;
// private static final int RAIKEL = 29015;
private static final int RAIKEL_LEOS = 29016;
// private static final int RIBA = 29017;
private static final int RIBA_IREN = 29018;
private static boolean _IsTeleported;
private static final List<L2Attackable> MINIONS = new CopyOnWriteArrayList<>();
private static L2BossZone ZONE;
private static final byte ALIVE = 0;
private static final byte DEAD = 1;
private Orfen()
{
super(Orfen.class.getSimpleName(), "ai/individual");
final int[] mobs =
{
ORFEN,
RAIKEL_LEOS,
RIBA_IREN
};
registerMobs(mobs);
_IsTeleported = false;
ZONE = GrandBossManager.getInstance().getZone(POS[0]);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(ORFEN);
if (GrandBossManager.getInstance().getBossStatus(ORFEN) == DEAD)
{
// load the unlock date and time for Orfen from DB
final long temp = info.getLong("respawn_time") - System.currentTimeMillis();
// if Orfen is locked until a certain time, mark it so and start the unlock timer
// the unlock time has not yet expired.
if (temp > 0)
{
startQuestTimer("orfen_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Immediately spawn Orfen.
final int i = getRandom(10);
Location loc;
if (i < 4)
{
loc = POS[1];
}
else if (i < 7)
{
loc = POS[2];
}
else
{
loc = POS[3];
}
final L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, loc, false, 0);
GrandBossManager.getInstance().setBossStatus(ORFEN, ALIVE);
spawnBoss(orfen);
}
}
else
{
final int loc_x = info.getInt("loc_x");
final int loc_y = info.getInt("loc_y");
final int loc_z = info.getInt("loc_z");
final int heading = info.getInt("heading");
final int hp = info.getInt("currentHP");
final int mp = info.getInt("currentMP");
final L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, loc_x, loc_y, loc_z, heading, false, 0);
orfen.setCurrentHpMp(hp, mp);
spawnBoss(orfen);
}
}
public void setSpawnPoint(L2Npc npc, int index)
{
((L2Attackable) npc).clearAggroList();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
final L2Spawn spawn = npc.getSpawn();
spawn.setLocation(POS[index]);
npc.teleToLocation(POS[index], false);
}
public void spawnBoss(L2GrandBossInstance npc)
{
GrandBossManager.getInstance().addBoss(npc);
npc.broadcastPacket(new PlaySound(1, "BS01_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
startQuestTimer("check_orfen_pos", 10000, npc, null, true);
// Spawn minions
final int x = npc.getX();
final int y = npc.getY();
L2Attackable mob;
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x + 100, y + 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x + 100, y - 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x - 100, y + 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
mob = (L2Attackable) addSpawn(RAIKEL_LEOS, x - 100, y - 100, npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
startQuestTimer("check_minion_loc", 10000, npc, null, true);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("orfen_unlock"))
{
final int i = getRandom(10);
Location loc;
if (i < 4)
{
loc = POS[1];
}
else if (i < 7)
{
loc = POS[2];
}
else
{
loc = POS[3];
}
final L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, loc, false, 0);
GrandBossManager.getInstance().setBossStatus(ORFEN, ALIVE);
spawnBoss(orfen);
}
else if (event.equalsIgnoreCase("check_orfen_pos"))
{
if ((_IsTeleported && (npc.getCurrentHp() > (npc.getMaxHp() * 0.95))) || (!ZONE.isInsideZone(npc) && !_IsTeleported))
{
setSpawnPoint(npc, getRandom(3) + 1);
_IsTeleported = false;
}
else if (_IsTeleported && !ZONE.isInsideZone(npc))
{
setSpawnPoint(npc, 0);
}
}
else if (event.equalsIgnoreCase("check_minion_loc"))
{
for (int i = 0; i < MINIONS.size(); i++)
{
final L2Attackable mob = MINIONS.get(i);
if (!npc.isInsideRadius(mob, 3000, false, false))
{
mob.teleToLocation(npc.getLocation());
((L2Attackable) npc).clearAggroList();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
}
}
}
else if (event.equalsIgnoreCase("despawn_minions"))
{
for (int i = 0; i < MINIONS.size(); i++)
{
final L2Attackable mob = MINIONS.get(i);
if (mob != null)
{
mob.decayMe();
}
}
MINIONS.clear();
}
else if (event.equalsIgnoreCase("spawn_minion"))
{
final L2Attackable mob = (L2Attackable) addSpawn(RAIKEL_LEOS, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0);
mob.setIsRaidMinion(true);
MINIONS.add(mob);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon)
{
if (npc.getId() == ORFEN)
{
final L2Character originalCaster = isSummon ? caster.getSummon() : caster;
if ((skill.getEffectPoint() > 0) && (getRandom(5) == 0) && npc.isInsideRadius(originalCaster, 1000, false, false))
{
final NpcSay packet = new NpcSay(npc.getObjectId(), ChatType.NPC_GENERAL, npc.getId(), TEXT[getRandom(4)]);
packet.addStringParameter(caster.getName().toString());
npc.broadcastPacket(packet);
originalCaster.teleToLocation(npc.getLocation());
npc.setTarget(originalCaster);
npc.doCast(SkillData.getInstance().getSkill(4064, 1));
}
}
return super.onSkillSee(npc, caster, skill, targets, isSummon);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
{
if ((caller == null) || (npc == null) || npc.isCastingNow())
{
return super.onFactionCall(npc, caller, attacker, isSummon);
}
final int npcId = npc.getId();
final int callerId = caller.getId();
if ((npcId == RAIKEL_LEOS) && (getRandom(20) == 0))
{
npc.setTarget(attacker);
npc.doCast(SkillData.getInstance().getSkill(4067, 4));
}
else if (npcId == RIBA_IREN)
{
int chance = 1;
if (callerId == ORFEN)
{
chance = 9;
}
if ((callerId != RIBA_IREN) && (caller.getCurrentHp() < (caller.getMaxHp() / 2.0)) && (getRandom(10) < chance))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
npc.setTarget(caller);
npc.doCast(SkillData.getInstance().getSkill(4516, 1));
}
}
return super.onFactionCall(npc, caller, attacker, isSummon);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
final int npcId = npc.getId();
if (npcId == ORFEN)
{
if (!_IsTeleported && ((npc.getCurrentHp() - damage) < (npc.getMaxHp() / 2)))
{
_IsTeleported = true;
setSpawnPoint(npc, 0);
}
else if (npc.isInsideRadius(attacker, 1000, false, false) && !npc.isInsideRadius(attacker, 300, false, false) && (getRandom(10) == 0))
{
final NpcSay packet = new NpcSay(npc.getObjectId(), ChatType.NPC_GENERAL, npcId, TEXT[getRandom(3)]);
packet.addStringParameter(attacker.getName().toString());
npc.broadcastPacket(packet);
attacker.teleToLocation(npc.getLocation());
npc.setTarget(attacker);
npc.doCast(SkillData.getInstance().getSkill(4064, 1));
}
}
else if ((npcId == RIBA_IREN) && !npc.isCastingNow() && ((npc.getCurrentHp() - damage) < (npc.getMaxHp() / 2.0)))
{
npc.setTarget(attacker);
npc.doCast(SkillData.getInstance().getSkill(4516, 1));
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.getId() == ORFEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(ORFEN, DEAD);
// Calculate Min and Max respawn times randomly.
final long respawnTime = (Config.ORFEN_SPAWN_INTERVAL + getRandom(-Config.ORFEN_SPAWN_RANDOM, Config.ORFEN_SPAWN_RANDOM)) * 3600000;
startQuestTimer("orfen_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
final StatsSet info = GrandBossManager.getInstance().getStatsSet(ORFEN);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(ORFEN, info);
cancelQuestTimer("check_minion_loc", npc, null);
cancelQuestTimer("check_orfen_pos", npc, null);
startQuestTimer("despawn_minions", 20000, null, null);
cancelQuestTimers("spawn_minion");
}
else if ((GrandBossManager.getInstance().getBossStatus(ORFEN) == ALIVE) && (npc.getId() == RAIKEL_LEOS))
{
MINIONS.remove(npc);
startQuestTimer("spawn_minion", 360000, npc, null);
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new Orfen();
}
}

View File

@@ -0,0 +1,403 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.CommonSkill;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.type.L2BossZone;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import ai.npc.AbstractNpcAI;
/**
* Queen Ant's AI
* @author Emperorc
*/
final class QueenAnt extends AbstractNpcAI
{
private static final int QUEEN = 29001;
private static final int LARVA = 29002;
private static final int NURSE = 29003;
private static final int GUARD = 29004;
private static final int ROYAL = 29005;
private static final int[] MOBS =
{
QUEEN,
LARVA,
NURSE,
GUARD,
ROYAL
};
private static final Location OUST_LOC_1 = new Location(-19480, 187344, -5600);
private static final Location OUST_LOC_2 = new Location(-17928, 180912, -5520);
private static final Location OUST_LOC_3 = new Location(-23808, 182368, -5600);
private static final int QUEEN_X = -21610;
private static final int QUEEN_Y = 181594;
private static final int QUEEN_Z = -5734;
// QUEEN Status Tracking :
private static final byte ALIVE = 0; // Queen Ant is spawned.
private static final byte DEAD = 1; // Queen Ant has been killed.
private static L2BossZone _zone;
private static SkillHolder HEAL1 = new SkillHolder(4020, 1);
private static SkillHolder HEAL2 = new SkillHolder(4024, 1);
L2MonsterInstance _queen = null;
private L2MonsterInstance _larva = null;
private final List<L2MonsterInstance> _nurses = new CopyOnWriteArrayList<>();
ScheduledFuture<?> _task = null;
private QueenAnt()
{
super(QueenAnt.class.getSimpleName(), "ai/individual");
addSpawnId(MOBS);
addKillId(MOBS);
addAggroRangeEnterId(MOBS);
addFactionCallId(NURSE);
_zone = GrandBossManager.getInstance().getZone(QUEEN_X, QUEEN_Y, QUEEN_Z);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
if (GrandBossManager.getInstance().getBossStatus(QUEEN) == DEAD)
{
// load the unlock date and time for queen ant from DB
final long temp = info.getLong("respawn_time") - System.currentTimeMillis();
// if queen ant is locked until a certain time, mark it so and start the unlock timer
// the unlock time has not yet expired.
if (temp > 0)
{
startQuestTimer("queen_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Immediately spawn queen ant.
final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, QUEEN_X, QUEEN_Y, QUEEN_Z, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE);
spawnBoss(queen);
}
}
else
{
final int loc_x = QUEEN_X;
final int loc_y = QUEEN_Y;
final int loc_z = QUEEN_Z;
final int heading = info.getInt("heading");
final int hp = info.getInt("currentHP");
final int mp = info.getInt("currentMP");
final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, loc_x, loc_y, loc_z, heading, false, 0);
queen.setCurrentHpMp(hp, mp);
spawnBoss(queen);
}
}
private void spawnBoss(L2GrandBossInstance npc)
{
GrandBossManager.getInstance().addBoss(npc);
if (getRandom(100) < 33)
{
_zone.movePlayersTo(OUST_LOC_1);
}
else if (getRandom(100) < 50)
{
_zone.movePlayersTo(OUST_LOC_2);
}
else
{
_zone.movePlayersTo(OUST_LOC_3);
}
GrandBossManager.getInstance().addBoss(npc);
startQuestTimer("action", 10000, npc, null, true);
startQuestTimer("heal", 1000, null, null, true);
npc.broadcastPacket(new PlaySound(1, "BS01_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
_queen = npc;
_larva = (L2MonsterInstance) addSpawn(LARVA, -21600, 179482, -5846, getRandom(360), false, 0);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("heal"))
{
boolean notCasting;
final boolean larvaNeedHeal = (_larva != null) && (_larva.getCurrentHp() < _larva.getMaxHp());
final boolean queenNeedHeal = (_queen != null) && (_queen.getCurrentHp() < _queen.getMaxHp());
for (L2MonsterInstance nurse : _nurses)
{
if ((nurse == null) || nurse.isDead() || nurse.isCastingNow())
{
continue;
}
notCasting = nurse.getAI().getIntention() != CtrlIntention.AI_INTENTION_CAST;
if (larvaNeedHeal)
{
if ((nurse.getTarget() != _larva) || notCasting)
{
nurse.setTarget(_larva);
nurse.useMagic(getRandomBoolean() ? HEAL1.getSkill() : HEAL2.getSkill());
}
continue;
}
if (queenNeedHeal)
{
if (nurse.getLeader() == _larva)
{
continue;
}
if ((nurse.getTarget() != _queen) || notCasting)
{
nurse.setTarget(_queen);
nurse.useMagic(HEAL1.getSkill());
}
continue;
}
// if nurse not casting - remove target
if (notCasting && (nurse.getTarget() != null))
{
nurse.setTarget(null);
}
}
}
else if (event.equalsIgnoreCase("action") && (npc != null))
{
if (getRandom(3) == 0)
{
if (getRandom(2) == 0)
{
npc.broadcastSocialAction(3);
}
else
{
npc.broadcastSocialAction(4);
}
}
}
else if (event.equalsIgnoreCase("queen_unlock"))
{
final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, QUEEN_X, QUEEN_Y, QUEEN_Z, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE);
spawnBoss(queen);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSpawn(L2Npc npc)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
switch (npc.getId())
{
case LARVA:
{
mob.setIsImmobilized(true);
mob.setIsMortal(false);
mob.setIsRaidMinion(true);
break;
}
case NURSE:
{
mob.disableCoreAI(true);
mob.setIsRaidMinion(true);
_nurses.add(mob);
break;
}
case ROYAL:
case GUARD:
{
mob.setIsRaidMinion(true);
break;
}
case QUEEN:
{
_task = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new QueenAntTask(), 5 * 1000, 5 * 1000);
break;
}
}
return super.onSpawn(npc);
}
@Override
public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
{
if ((caller == null) || (npc == null))
{
return super.onFactionCall(npc, caller, attacker, isSummon);
}
if (!npc.isCastingNow() && (npc.getAI().getIntention() != CtrlIntention.AI_INTENTION_CAST) && (caller.getCurrentHp() < caller.getMaxHp()))
{
npc.setTarget(caller);
((L2Attackable) npc).useMagic(HEAL1.getSkill());
}
return null;
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if ((npc == null) || (player.isGM() && player.isInvisible()))
{
return null;
}
final boolean isMage;
final L2Playable character;
if (isSummon)
{
isMage = false;
character = player.getSummon();
}
else
{
isMage = player.isMageClass();
character = player;
}
if (character == null)
{
return null;
}
if (!Config.RAID_DISABLE_CURSE && ((character.getLevel() - npc.getLevel()) > 8))
{
Skill curse = null;
if (isMage)
{
if (!character.isMuted() && (getRandom(4) == 0))
{
curse = CommonSkill.RAID_CURSE.getSkill();
}
}
else if (!character.isParalyzed() && (getRandom(4) == 0))
{
curse = CommonSkill.RAID_CURSE2.getSkill();
}
if (curse != null)
{
npc.broadcastPacket(new MagicSkillUse(npc, character, curse.getId(), curse.getLevel(), 300, 0));
curse.applyEffects(npc, character);
}
((L2Attackable) npc).stopHating(character); // for calling again
return null;
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
final int npcId = npc.getId();
if (npcId == QUEEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(QUEEN, DEAD);
// Calculate Min and Max respawn times randomly.
final long respawnTime = (Config.QUEEN_ANT_SPAWN_INTERVAL + getRandom(-Config.QUEEN_ANT_SPAWN_RANDOM, Config.QUEEN_ANT_SPAWN_RANDOM)) * 3600000;
startQuestTimer("queen_unlock", respawnTime, null, null);
cancelQuestTimer("action", npc, null);
cancelQuestTimer("heal", null, null);
// also save the respawn time so that the info is maintained past reboots
final StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(QUEEN, info);
_nurses.clear();
_larva.deleteMe();
_larva = null;
_queen = null;
if (_task != null)
{
_task.cancel(false);
_task = null;
}
}
else if ((_queen != null) && !_queen.isAlikeDead())
{
if (npcId == ROYAL)
{
if (((L2MonsterInstance) npc).getLeader() != null)
{
((L2MonsterInstance) npc).getLeader().getMinionList().onMinionDie((L2MonsterInstance) npc, (280 + getRandom(40)) * 1000);
}
}
else if (npcId == NURSE)
{
final L2MonsterInstance mob = (L2MonsterInstance) npc;
_nurses.remove(mob);
if (mob.getLeader() != null)
{
mob.getLeader().getMinionList().onMinionDie(mob, 10000);
}
}
}
return super.onKill(npc, killer, isSummon);
}
private class QueenAntTask implements Runnable
{
public QueenAntTask()
{
// Constructor stub
}
@Override
public void run()
{
if ((_queen == null) || _queen.isDead())
{
_task.cancel(false);
_task = null;
}
else if (_queen.calculateDistance(QUEEN_X, QUEEN_Y, QUEEN_Z, false, false) > 2000.)
{
_queen.clearAggroList();
_queen.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(QUEEN_X, QUEEN_Y, QUEEN_Z, 0));
}
}
}
public static void main(String[] args)
{
new QueenAnt();
}
}

View File

@@ -0,0 +1,116 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.type.L2EffectZone;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Queen Shyeed AI
* @author malyelfik
*/
final class QueenShyeed extends AbstractNpcAI
{
// NPC
private static final int SHYEED = 25671;
private static final Location SHYEED_LOC = new Location(79634, -55428, -6104, 0);
// Respawn
private static final int RESPAWN = 86400000; // 24 h
private static final int RANDOM_RESPAWN = 43200000; // 12 h
// Zones
private static final L2EffectZone MOB_BUFF_ZONE = ZoneManager.getInstance().getZoneById(200103, L2EffectZone.class);
private static final L2EffectZone MOB_BUFF_DISPLAY_ZONE = ZoneManager.getInstance().getZoneById(200104, L2EffectZone.class);
private static final L2EffectZone PC_BUFF_ZONE = ZoneManager.getInstance().getZoneById(200105, L2EffectZone.class);
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "respawn":
{
spawnShyeed();
break;
}
case "despawn":
{
if (!npc.isDead())
{
npc.deleteMe();
startRespawn();
}
break;
}
}
return null;
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
broadcastNpcSay(npc, ChatType.NPC_GENERAL, NpcStringId.SHYEED_S_CRY_IS_STEADILY_DYING_DOWN);
startRespawn();
PC_BUFF_ZONE.setEnabled(true);
return super.onKill(npc, killer, isSummon);
}
private QueenShyeed()
{
super(QueenShyeed.class.getSimpleName(), "ai/individual");
addKillId(SHYEED);
spawnShyeed();
}
private void spawnShyeed()
{
final String respawn = loadGlobalQuestVar("Respawn");
final long remain = !respawn.isEmpty() ? Long.parseLong(respawn) - System.currentTimeMillis() : 0;
if (remain > 0)
{
startQuestTimer("respawn", remain, null, null);
return;
}
final L2Npc npc = addSpawn(SHYEED, SHYEED_LOC, false, 0);
startQuestTimer("despawn", 10800000, npc, null);
PC_BUFF_ZONE.setEnabled(false);
MOB_BUFF_ZONE.setEnabled(true);
MOB_BUFF_DISPLAY_ZONE.setEnabled(true);
}
private void startRespawn()
{
final int respawnTime = RESPAWN - getRandom(RANDOM_RESPAWN);
saveGlobalQuestVar("Respawn", Long.toString(System.currentTimeMillis() + respawnTime));
startQuestTimer("respawn", respawnTime, null, null);
MOB_BUFF_ZONE.setEnabled(false);
MOB_BUFF_DISPLAY_ZONE.setEnabled(false);
}
public static void main(String[] args)
{
new QueenShyeed();
}
}

View File

@@ -0,0 +1,49 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* Ragna Orc Commander AI.
* @author Zealar
*/
final class RagnaOrcCommander extends AbstractNpcAI
{
private static final int RAGNA_ORC_COMMANDER = 22694;
private RagnaOrcCommander()
{
super(RagnaOrcCommander.class.getSimpleName(), "ai/individual");
addSpawnId(RAGNA_ORC_COMMANDER);
}
@Override
public String onSpawn(L2Npc npc)
{
spawnMinions(npc, "Privates1");
spawnMinions(npc, getRandomBoolean() ? "Privates2" : "Privates3");
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RagnaOrcCommander();
}
}

View File

@@ -0,0 +1,48 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import ai.npc.AbstractNpcAI;
/**
* Ragna Orc Hero AI.
* @author Zealar
*/
final class RagnaOrcHero extends AbstractNpcAI
{
private static final int RAGNA_ORC_HERO = 22693;
private RagnaOrcHero()
{
super(RagnaOrcHero.class.getSimpleName(), "ai/individual");
addSpawnId(RAGNA_ORC_HERO);
}
@Override
public String onSpawn(L2Npc npc)
{
spawnMinions(npc, getRandom(100) < 70 ? "Privates1" : "Privates2");
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RagnaOrcHero();
}
}

View File

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

View File

@@ -0,0 +1,4 @@
<html><body>Shilen's Stone Statue:<br>
Wait.. It doesn't seem as though you are the one destined for the front lines in this battle. I was supposed to open a passage to Sailren's lair only to the leader of one party. If you wish to teleport, bring your party leader to me or return here as a party leader.<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-01a.html">Prep for battle.</a>
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>Shilen's Stone Statue:<br>
You know that in the past, Mother Shilen paid a great sacrifice to lock Sailren here.<br>
Afterward, she created a stone likeness of herself and bestowed upon it the power to seal, making it a guardian of this place to ensure that Sailren remained imprisoned.<br>
I am that stone statue of Shilen.<br>
Mother Shilen also entrusted the power to seal to those who wield the sacred ax Gazkh.<br>
I will only open the gate for those who have Gazkh and their friends. When the seal is at its weakest, however, I allow a warrior to enter in order to minimize the sacrifice.<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-02a.html">Listen to the conditions to enter in detail.</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Shilen's Stone Statue:<br>
You have the heart to fight Sailren, of that there can be no doubt. But if you do not have Gazkh given to you by Shilen, Sailren will certainly kill you. If you want to teleport within, complete my quest and obtain Gazkh.<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-01a.html">Prep for battle.</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Shilen's Stone Statue:<br>
Only a party whose leader weilds Gazkh can enter Sailren's Stronghold and battle the creature.<br>
Be aware that any party member who is far away at the time of entry cannot enter the Stronghold. Nor can another party enter until the first party has exited.<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-03a.html">Learn more about Sailren's power and how to fight it.</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Shilen's Stone Statue:<br>
Shilen's protection is not with you -- go away! You are not qualified to fight against Sailren...<br>
If you want to enter Sailren's nest, then you should find a party leader who can fight against Sailren and join his party. Or you can complete my quest to become a party leader, form your own party, and then return here.<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-01a.html">Listen to the entry requirements and battle method.</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Shilen's Stone Statue:<br>
There are not many of them, but Sailren is protected by its dinosaur followers. Combined with my enchantment and the power of the other statues, we are restraining Sailren and its followers from escaping. But as they begin to break free of our control, their power and magic also begins to extend beyond the Lost Nest, affecting even the Primeval Plains!<br>
If the powers of the Stone Statues are completely broken, Sailren and its followers will escape and this island and everything on it will perish.<br>
Alas, Shilen is not here to protect us! In order to re-seal that horrifying dinosaur, you must defeat its followers first, and then work as a team to defeat Sailren.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Shilen's Stone Statue:<br>
Currently the magic power of Sailren and its followers is very strong. I do not think you can win solely with your own power, especially given how weak the seal stones have become.<br>
My counsel is that you first recover the power to seal and wait 'til Sailren's strength lessens a bit. Then you will have your best chance of entering the nest and defeating this ancient evil.<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-01a.html">Prep for battle.</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Shilen's Stone Statue:<br>
There is another brave party fighting against Sailren right now, so I cannot teleport you into the nest. When they return, I will teleport you.<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-01a.html">Prep for battle.</a>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Stone Statue of Shilen:<br>
(The statue is worn in places by wind and rain -- proof that it has stood guard here a long, long time. Despite its weatherbeaten appearance, it feels somehow dignified and majestic. Standing before it, you sense a presence.)<br>
You, outsider... Why have you come here to this statue? For I am Mother Shilen's avatar and the last guard of Sailren!<br>
<a action="bypass -h npc_%objectId%_Quest Sailren 32109-01.html">Prep for battle.</a><br>
<a action="bypass -h npc_%objectId%_Quest Sailren enter">"I wish to participate in clearing out Sailren and its followers."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest.</a>
</body></html>

View File

@@ -0,0 +1,328 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual.Sailren;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.TeleportWhereType;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2RaidBossInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.zone.type.L2NoRestartZone;
import com.l2jmobius.gameserver.network.serverpackets.SpecialCamera;
import ai.npc.AbstractNpcAI;
/**
* Sailren AI.
* @author St3eT
*/
public final class Sailren extends AbstractNpcAI
{
// NPCs
private static final int STATUE = 32109; // Shilen's Stone Statue
private static final int MOVIE_NPC = 32110; // Invisible NPC for movie
private static final int SAILREN = 29065; // Sailren
private static final int VELOCIRAPTOR = 22218; // Velociraptor
private static final int PTEROSAUR = 22199; // Pterosaur
private static final int TREX = 22217; // Tyrannosaurus
private static final int CUBIC = 32107; // Teleportation Cubic
// Item
private static final int GAZKH = 8784; // Gazkh
// Skill
private static final SkillHolder ANIMATION = new SkillHolder(5090, 1);
// Zone
private static final L2NoRestartZone zone = ZoneManager.getInstance().getZoneById(70049, L2NoRestartZone.class);
// Misc
private static final int RESPAWN = 1; // Respawn time (in hours)
private static final int MAX_TIME = 3200; // Max time for Sailren fight (in minutes)
private static Status STATUS = Status.ALIVE;
private static int _killCount = 0;
private static long _lastAttack = 0;
private static enum Status
{
ALIVE,
IN_FIGHT,
DEAD
}
private Sailren()
{
super(Sailren.class.getSimpleName(), "ai/individual");
addStartNpc(STATUE, CUBIC);
addTalkId(STATUE, CUBIC);
addFirstTalkId(STATUE);
addKillId(VELOCIRAPTOR, PTEROSAUR, TREX, SAILREN);
addAttackId(VELOCIRAPTOR, PTEROSAUR, TREX, SAILREN);
final long remain = GlobalVariablesManager.getInstance().getLong("SailrenRespawn", 0) - System.currentTimeMillis();
if (remain > 0)
{
STATUS = Status.DEAD;
startQuestTimer("CLEAR_STATUS", remain, null, null);
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "32109-01.html":
case "32109-01a.html":
case "32109-02a.html":
case "32109-03a.html":
{
return event;
}
case "enter":
{
String htmltext = null;
if (!player.isInParty())
{
htmltext = "32109-01.html";
}
else if (STATUS == Status.DEAD)
{
htmltext = "32109-04.html";
}
else if (STATUS == Status.IN_FIGHT)
{
htmltext = "32109-05.html";
}
else if (!player.getParty().isLeader(player))
{
htmltext = "32109-03.html";
}
else if (!hasQuestItems(player, GAZKH))
{
htmltext = "32109-02.html";
}
else
{
takeItems(player, GAZKH, 1);
STATUS = Status.IN_FIGHT;
_lastAttack = System.currentTimeMillis();
for (L2PcInstance member : player.getParty().getMembers())
{
if (member.isInsideRadius(npc, 1000, true, false))
{
member.teleToLocation(27549, -6638, -2008);
}
}
startQuestTimer("SPAWN_VELOCIRAPTOR", 60000, null, null);
startQuestTimer("TIME_OUT", MAX_TIME * 1000, null, null);
startQuestTimer("CHECK_ATTACK", 120000, null, null);
}
return htmltext;
}
case "teleportOut":
{
player.teleToLocation(TeleportWhereType.TOWN);
break;
}
case "SPAWN_VELOCIRAPTOR":
{
for (int i = 0; i < 3; i++)
{
addSpawn(VELOCIRAPTOR, 27313 + getRandom(150), -6766 + getRandom(150), -1975, 0, false, 0);
}
break;
}
case "SPAWN_SAILREN":
{
final L2RaidBossInstance sailren = (L2RaidBossInstance) addSpawn(SAILREN, 27549, -6638, -2008, 0, false, 0);
final L2Npc movieNpc = addSpawn(MOVIE_NPC, sailren.getX(), sailren.getY(), sailren.getZ() + 30, 0, false, 26000);
sailren.setIsInvul(true);
sailren.setIsImmobilized(true);
zone.broadcastPacket(new SpecialCamera(movieNpc, 60, 110, 30, 4000, 1500, 20000, 0, 65, 1, 0, 0));
startQuestTimer("ATTACK", 24600, sailren, null);
startQuestTimer("ANIMATION", 2000, movieNpc, null);
startQuestTimer("CAMERA_1", 4100, movieNpc, null);
break;
}
case "ANIMATION":
{
if (npc != null)
{
npc.setTarget(npc);
npc.doCast(ANIMATION.getSkill());
startQuestTimer("ANIMATION", 2000, npc, null);
}
break;
}
case "CAMERA_1":
{
zone.broadcastPacket(new SpecialCamera(npc, 100, 180, 30, 3000, 1500, 20000, 0, 50, 1, 0, 0));
startQuestTimer("CAMERA_2", 3000, npc, null);
break;
}
case "CAMERA_2":
{
zone.broadcastPacket(new SpecialCamera(npc, 150, 270, 25, 3000, 1500, 20000, 0, 30, 1, 0, 0));
startQuestTimer("CAMERA_3", 3000, npc, null);
break;
}
case "CAMERA_3":
{
zone.broadcastPacket(new SpecialCamera(npc, 160, 360, 20, 3000, 1500, 20000, 10, 15, 1, 0, 0));
startQuestTimer("CAMERA_4", 3000, npc, null);
break;
}
case "CAMERA_4":
{
zone.broadcastPacket(new SpecialCamera(npc, 160, 450, 10, 3000, 1500, 20000, 0, 10, 1, 0, 0));
startQuestTimer("CAMERA_5", 3000, npc, null);
break;
}
case "CAMERA_5":
{
zone.broadcastPacket(new SpecialCamera(npc, 160, 560, 0, 3000, 1500, 20000, 0, 10, 1, 0, 0));
startQuestTimer("CAMERA_6", 7000, npc, null);
break;
}
case "CAMERA_6":
{
zone.broadcastPacket(new SpecialCamera(npc, 70, 560, 0, 500, 1500, 7000, -15, 20, 1, 0, 0));
break;
}
case "ATTACK":
{
npc.setIsInvul(false);
npc.setIsImmobilized(false);
break;
}
case "CLEAR_STATUS":
{
STATUS = Status.ALIVE;
break;
}
case "TIME_OUT":
{
if (STATUS == Status.IN_FIGHT)
{
STATUS = Status.ALIVE;
}
for (L2Character charInside : zone.getCharactersInside())
{
if (charInside != null)
{
if (charInside.isPlayer())
{
charInside.teleToLocation(TeleportWhereType.TOWN);
}
else if (charInside.isNpc())
{
charInside.deleteMe();
}
}
}
break;
}
case "CHECK_ATTACK":
{
if (!zone.getPlayersInside().isEmpty() && ((_lastAttack + 600000) < System.currentTimeMillis()))
{
cancelQuestTimer("TIME_OUT", null, null);
notifyEvent("TIME_OUT", null, null);
}
else
{
startQuestTimer("CHECK_ATTACK", 120000, null, null);
}
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (zone.isCharacterInZone(attacker))
{
_lastAttack = System.currentTimeMillis();
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (zone.isCharacterInZone(killer))
{
switch (npc.getId())
{
case SAILREN:
{
STATUS = Status.DEAD;
addSpawn(CUBIC, 27644, -6638, -2008, 0, false, 300000);
final long respawnTime = RESPAWN * 3600000;
GlobalVariablesManager.getInstance().set("SailrenRespawn", System.currentTimeMillis() + respawnTime);
cancelQuestTimer("CHECK_ATTACK", null, null);
cancelQuestTimer("TIME_OUT", null, null);
startQuestTimer("CLEAR_STATUS", respawnTime, null, null);
startQuestTimer("TIME_OUT", 300000, null, null);
break;
}
case VELOCIRAPTOR:
{
_killCount++;
if (_killCount == 3)
{
final L2Npc pterosaur = addSpawn(PTEROSAUR, 27313, -6766, -1975, 0, false, 0);
addAttackDesire(pterosaur, killer);
_killCount = 0;
}
break;
}
case PTEROSAUR:
{
final L2Npc trex = addSpawn(TREX, 27313, -6766, -1975, 0, false, 0);
addAttackDesire(trex, killer);
break;
}
case TREX:
{
startQuestTimer("SPAWN_SAILREN", 180000, null, null);
break;
}
}
}
return super.onKill(npc, killer, isSummon);
}
@Override
public boolean unload(boolean removeFromList)
{
if (STATUS == Status.IN_FIGHT)
{
_log.info(getClass().getSimpleName() + ": Script is being unloaded while Sailren is active, clearing zone.");
notifyEvent("TIME_OUT", null, null);
}
return super.unload(removeFromList);
}
public static void main(String[] args)
{
new Sailren();
}
}

View File

@@ -0,0 +1,280 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.ArrayList;
import java.util.Collection;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.datatables.SkillData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2DecoyInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.util.Util;
import com.l2jmobius.util.Rnd;
import ai.npc.AbstractNpcAI;
/**
* @author Micr0, Zerox
*/
final class ScarletVanHalisha extends AbstractNpcAI
{
private L2Character _target;
private Skill _skill;
private long _lastRangedSkillTime;
private final int _rangedSkillMinCoolTime = 60000; // 1 minute
// NPCs
private static final int HALISHA2 = 29046;
private static final int HALISHA3 = 29047;
public ScarletVanHalisha()
{
super(ScarletVanHalisha.class.getSimpleName(), "ai/individual");
addAttackId(HALISHA2, HALISHA3);
addKillId(HALISHA2, HALISHA3);
addSpellFinishedId(HALISHA2, HALISHA3);
registerMobs(HALISHA2, HALISHA3);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "attack":
{
if (npc != null)
{
getSkillAI(npc);
}
break;
}
case "random_target":
{
_target = getRandomTarget(npc, null);
break;
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
getSkillAI(npc);
return super.onSpellFinished(npc, player, skill);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
startQuestTimer("random_Target", 5000, npc, null, true);
startQuestTimer("attack", 500, npc, null, true);
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
cancelQuestTimers("attack");
cancelQuestTimers("random_Target");
return super.onKill(npc, killer, isSummon);
}
private Skill getRndSkills(L2Npc npc)
{
switch (npc.getId())
{
case HALISHA2:
{
if (Rnd.get(100) < 10)
{
return SkillData.getInstance().getSkill(5015, 2);
}
else if (Rnd.get(100) < 10)
{
return SkillData.getInstance().getSkill(5015, 5);
}
else if (Rnd.get(100) < 2)
{
return SkillData.getInstance().getSkill(5016, 1);
}
else
{
return SkillData.getInstance().getSkill(5014, 2);
}
}
case HALISHA3:
{
if (Rnd.get(100) < 10)
{
return SkillData.getInstance().getSkill(5015, 3);
}
else if (Rnd.get(100) < 10)
{
return SkillData.getInstance().getSkill(5015, 6);
}
else if (Rnd.get(100) < 10)
{
return SkillData.getInstance().getSkill(5015, 2);
}
else if (((_lastRangedSkillTime + _rangedSkillMinCoolTime) < System.currentTimeMillis()) && (Rnd.get(100) < 10))
{
return SkillData.getInstance().getSkill(5019, 1);
}
else if (((_lastRangedSkillTime + _rangedSkillMinCoolTime) < System.currentTimeMillis()) && (Rnd.get(100) < 10))
{
return SkillData.getInstance().getSkill(5018, 1);
}
else if (Rnd.get(100) < 2)
{
return SkillData.getInstance().getSkill(5016, 1);
}
else
{
return SkillData.getInstance().getSkill(5014, 3);
}
}
}
return SkillData.getInstance().getSkill(5014, 1);
}
private synchronized void getSkillAI(L2Npc npc)
{
if (npc.isInvul() || npc.isCastingNow())
{
return;
}
if ((Rnd.get(100) < 30) || (_target == null) || _target.isDead())
{
_skill = getRndSkills(npc);
_target = getRandomTarget(npc, _skill);
}
final L2Character target = _target;
Skill skill = _skill;
if (skill == null)
{
skill = getRndSkills(npc);
}
if (npc.isPhysicalMuted())
{
return;
}
if ((target == null) || target.isDead())
{
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;
npc.doCast(skill);
}
else
{
npc.getAI().setIntention(AI_INTENTION_FOLLOW, target, null);
npc.getAI().setIntention(AI_INTENTION_ATTACK, target, null);
npc.setIsCastingNow(false);
}
}
private L2Character getRandomTarget(L2Npc npc, Skill skill)
{
final Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
final ArrayList<L2Character> result = new ArrayList<>();
{
for (L2Object obj : objs)
{
if (obj.isPlayable() || (obj instanceof L2DecoyInstance))
{
if (obj.isPlayer() && obj.getActingPlayer().isInvisible())
{
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.isPlayable() || (obj instanceof L2DecoyInstance))
{
int skillRange = 150;
if (skill != null)
{
switch (skill.getId())
{
case 5014:
{
skillRange = 150;
break;
}
case 5015:
{
skillRange = 400;
break;
}
case 5016:
{
skillRange = 200;
break;
}
case 5018:
case 5019:
{
_lastRangedSkillTime = System.currentTimeMillis();
skillRange = 550;
break;
}
}
}
if (Util.checkIfInRange(skillRange, npc, obj, true) && !((L2Character) obj).isDead())
{
result.add((L2Character) obj);
}
}
}
}
if (!result.isEmpty() && (result.size() != 0))
{
final Object[] characters = result.toArray();
return (L2Character) characters[Rnd.get(characters.length)];
}
return null;
}
public static void main(String[] args)
{
new ScarletVanHalisha();
}
}

View File

@@ -0,0 +1,176 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.ListenerRegisterType;
import com.l2jmobius.gameserver.model.events.annotations.Id;
import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import com.l2jmobius.gameserver.model.events.annotations.RegisterType;
import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureAttacked;
import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureKill;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import ai.npc.AbstractNpcAI;
/**
* Sin Eater AI.
* @author St3eT.
*/
final class SinEater extends AbstractNpcAI
{
// NPCs
private static final int SIN_EATER = 12564;
private SinEater()
{
super(SinEater.class.getSimpleName(), "ai/individual");
addSummonSpawnId(SIN_EATER);
addSummonTalkId(SIN_EATER);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.equals("TALK") && (player != null) && (player.getSummon() != null))
{
if (getRandom(100) < 30)
{
final int random = getRandom(100);
final L2Summon summon = player.getSummon();
if (random < 20)
{
broadcastSummonSay(summon, NpcStringId.YAWWWWN_IT_S_SO_BORING_HERE_WE_SHOULD_GO_AND_FIND_SOME_ACTION);
}
else if (random < 40)
{
broadcastSummonSay(summon, NpcStringId.HEY_IF_YOU_CONTINUE_TO_WASTE_TIME_YOU_WILL_NEVER_FINISH_YOUR_PENANCE);
}
else if (random < 60)
{
broadcastSummonSay(summon, NpcStringId.I_KNOW_YOU_DON_T_LIKE_ME_THE_FEELING_IS_MUTUAL);
}
else if (random < 80)
{
broadcastSummonSay(summon, NpcStringId.I_NEED_A_DRINK);
}
else
{
broadcastSummonSay(summon, NpcStringId.OH_THIS_IS_DRAGGING_ON_TOO_LONG_AT_THIS_RATE_I_WON_T_MAKE_IT_HOME_BEFORE_THE_SEVEN_SEALS_ARE_BROKEN);
}
}
startQuestTimer("TALK", 60000, null, player);
}
return super.onAdvEvent(event, npc, player);
}
@RegisterEvent(EventType.ON_CREATURE_KILL)
@RegisterType(ListenerRegisterType.NPC)
@Id(SIN_EATER)
public void onCreatureKill(OnCreatureKill event)
{
final int random = getRandom(100);
final L2Summon summon = (L2Summon) event.getTarget();
if (random < 30)
{
broadcastSummonSay(summon, NpcStringId.OH_THIS_IS_JUST_GREAT_WHAT_ARE_YOU_GOING_TO_DO_NOW);
}
else if (random < 70)
{
broadcastSummonSay(summon, NpcStringId.YOU_INCONSIDERATE_MORON_CAN_T_YOU_EVEN_TAKE_CARE_OF_LITTLE_OLD_ME);
}
else
{
broadcastSummonSay(summon, NpcStringId.OH_NO_THE_MAN_WHO_EATS_ONE_S_SINS_HAS_DIED_PENITENCE_IS_FURTHER_AWAY);
}
}
@RegisterEvent(EventType.ON_CREATURE_ATTACKED)
@RegisterType(ListenerRegisterType.NPC)
@Id(SIN_EATER)
public void onCreatureAttacked(OnCreatureAttacked event)
{
if (getRandom(100) < 30)
{
final int random = getRandom(100);
final L2Summon summon = (L2Summon) event.getTarget();
if (random < 35)
{
broadcastSummonSay(summon, NpcStringId.OH_THAT_SMARTS);
}
else if (random < 70)
{
broadcastSummonSay(summon, NpcStringId.HEY_MASTER_PAY_ATTENTION_I_M_DYING_OVER_HERE);
}
else
{
broadcastSummonSay(summon, NpcStringId.WHAT_HAVE_I_DONE_TO_DESERVE_THIS);
}
}
}
@Override
public void onSummonSpawn(L2Summon summon)
{
broadcastSummonSay(summon, getRandomBoolean() ? NpcStringId.HEY_IT_SEEMS_LIKE_YOU_NEED_MY_HELP_DOESN_T_IT : NpcStringId.ALMOST_GOT_IT_OUCH_STOP_DAMN_THESE_BLOODY_MANACLES);
startQuestTimer("TALK", 60000, null, summon.getOwner());
}
@Override
public void onSummonTalk(L2Summon summon)
{
if (getRandom(100) < 10)
{
final int random = getRandom(100);
if (random < 25)
{
broadcastSummonSay(summon, NpcStringId.USING_A_SPECIAL_SKILL_HERE_COULD_TRIGGER_A_BLOODBATH);
}
else if (random < 50)
{
broadcastSummonSay(summon, NpcStringId.HEY_WHAT_DO_YOU_EXPECT_OF_ME);
}
else if (random < 75)
{
broadcastSummonSay(summon, NpcStringId.UGGGGGH_PUSH_IT_S_NOT_COMING_OUT);
}
else
{
broadcastSummonSay(summon, NpcStringId.AH_I_MISSED_THE_MARK);
}
}
}
private void broadcastSummonSay(L2Summon summon, NpcStringId npcstringId)
{
summon.broadcastPacket(new NpcSay(summon.getObjectId(), ChatType.NPC_GENERAL, summon.getId(), npcstringId));
}
public static void main(String[] args)
{
new SinEater();
}
}

View File

@@ -0,0 +1,93 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import ai.npc.AbstractNpcAI;
/**
* Manages Sin Wardens disappearing and chat.
* @author GKR
*/
final class SinWardens extends AbstractNpcAI
{
private static final int[] SIN_WARDEN_MINIONS =
{
22424,
22425,
22426,
22427,
22428,
22429,
22430,
22432,
22433,
22434,
22435,
22436,
22437,
22438
};
private final Map<Integer, Integer> killedMinionsCount = new ConcurrentHashMap<>();
private SinWardens()
{
super(SinWardens.class.getSimpleName(), "ai/individual");
addKillId(SIN_WARDEN_MINIONS);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
if (npc.isMinion())
{
final L2MonsterInstance master = ((L2MonsterInstance) npc).getLeader();
if ((master != null) && !master.isDead())
{
int killedCount = killedMinionsCount.containsKey(master.getObjectId()) ? killedMinionsCount.get(master.getObjectId()) : 0;
killedCount++;
if (killedCount == 5)
{
master.broadcastPacket(new NpcSay(master.getObjectId(), ChatType.NPC_GENERAL, master.getId(), NpcStringId.WE_MIGHT_NEED_NEW_SLAVES_I_LL_BE_BACK_SOON_SO_WAIT));
master.doDie(killer);
killedMinionsCount.remove(master.getObjectId());
}
else
{
killedMinionsCount.put(master.getObjectId(), killedCount);
}
}
}
return super.onKill(npc, killer, isSummon);
}
public static void main(String[] args)
{
new SinWardens();
}
}

View File

@@ -0,0 +1,564 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual;
import java.util.ArrayList;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SkillData;
import com.l2jmobius.gameserver.enums.MountType;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.type.L2BossZone;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
import com.l2jmobius.gameserver.network.serverpackets.SpecialCamera;
import com.l2jmobius.gameserver.util.Util;
import ai.npc.AbstractNpcAI;
/**
* Valakas' AI.
* @author Tryskell
*/
public final class Valakas extends AbstractNpcAI
{
// NPC
private static final int VALAKAS = 29028;
// Skills
private static final SkillHolder VALAKAS_LAVA_SKIN = new SkillHolder(4680, 1);
private static final int VALAKAS_REGENERATION = 4691;
private static final SkillHolder[] VALAKAS_REGULAR_SKILLS =
{
new SkillHolder(4681, 1), // Valakas Trample
new SkillHolder(4682, 1), // Valakas Trample
new SkillHolder(4683, 1), // Valakas Dragon Breath
new SkillHolder(4689, 1), // Valakas Fear TODO: has two levels only level one is used.
};
private static final SkillHolder[] VALAKAS_LOWHP_SKILLS =
{
new SkillHolder(4681, 1), // Valakas Trample
new SkillHolder(4682, 1), // Valakas Trample
new SkillHolder(4683, 1), // Valakas Dragon Breath
new SkillHolder(4689, 1), // Valakas Fear TODO: has two levels only level one is used.
new SkillHolder(4690, 1), // Valakas Meteor Storm
};
private static final SkillHolder[] VALAKAS_AOE_SKILLS =
{
new SkillHolder(4683, 1), // Valakas Dragon Breath
new SkillHolder(4684, 1), // Valakas Dragon Breath
new SkillHolder(4685, 1), // Valakas Tail Stomp
new SkillHolder(4686, 1), // Valakas Tail Stomp
new SkillHolder(4688, 1), // Valakas Stun
new SkillHolder(4689, 1), // Valakas Fear TODO: has two levels only level one is used.
new SkillHolder(4690, 1), // Valakas Meteor Storm
};
// Locations
private static final Location TELEPORT_CUBE_LOCATIONS[] =
{
new Location(214880, -116144, -1644),
new Location(213696, -116592, -1644),
new Location(212112, -116688, -1644),
new Location(211184, -115472, -1664),
new Location(210336, -114592, -1644),
new Location(211360, -113904, -1644),
new Location(213152, -112352, -1644),
new Location(214032, -113232, -1644),
new Location(214752, -114592, -1644),
new Location(209824, -115568, -1421),
new Location(210528, -112192, -1403),
new Location(213120, -111136, -1408),
new Location(215184, -111504, -1392),
new Location(215456, -117328, -1392),
new Location(213200, -118160, -1424)
};
private static final Location VALAKAS_HIDDEN_LOC = new Location(220963, -104895, -1620);
private static final Location ATTACKER_REMOVE = new Location(150037, -57255, -2976);
private static final Location VALAKAS_LAIR = new Location(212852, -114842, -1632);
private static final Location VALAKAS_REGENERATION_LOC = new Location(-105200, -253104, -15264);
// Valakas status.
private static final byte DORMANT = 0; // Valakas is spawned and no one has entered yet. Entry is unlocked.
private static final byte WAITING = 1; // Valakas is spawned and someone has entered, triggering a 30 minute window for additional people to enter. Entry is unlocked.
private static final byte FIGHTING = 2; // Valakas is engaged in battle, annihilating his foes. Entry is locked.
private static final byte DEAD = 3; // Valakas has been killed. Entry is locked.
// Misc
private long _timeTracker = 0; // Time tracker for last attack on Valakas.
private L2Playable _actualVictim; // Actual target of Valakas.
private static L2BossZone ZONE;
private Valakas()
{
super(Valakas.class.getSimpleName(), "ai/individual");
registerMobs(VALAKAS);
ZONE = GrandBossManager.getInstance().getZone(212852, -114842, -1632);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(VALAKAS);
final int status = GrandBossManager.getInstance().getBossStatus(VALAKAS);
if (status == DEAD)
{
// load the unlock date and time for valakas from DB
final long temp = info.getLong("respawn_time") - System.currentTimeMillis();
if (temp > 0)
{
// The time has not yet expired. Mark Valakas as currently locked (dead).
startQuestTimer("valakas_unlock", temp, null, null);
}
else
{
// The time has expired while the server was offline. Spawn valakas in his cave as DORMANT.
final L2Npc valakas = addSpawn(VALAKAS, VALAKAS_REGENERATION_LOC, false, 0);
valakas.teleToLocation(VALAKAS_HIDDEN_LOC);
GrandBossManager.getInstance().setBossStatus(VALAKAS, DORMANT);
GrandBossManager.getInstance().addBoss((L2GrandBossInstance) valakas);
valakas.setIsInvul(true);
valakas.setRunning();
valakas.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
}
}
else
{
final int loc_x = info.getInt("loc_x");
final int loc_y = info.getInt("loc_y");
final int loc_z = info.getInt("loc_z");
final int heading = info.getInt("heading");
final int hp = info.getInt("currentHP");
final int mp = info.getInt("currentMP");
final L2Npc valakas = addSpawn(VALAKAS, loc_x, loc_y, loc_z, heading, false, 0);
valakas.teleToLocation(VALAKAS_HIDDEN_LOC);
GrandBossManager.getInstance().addBoss((L2GrandBossInstance) valakas);
valakas.setCurrentHpMp(hp, mp);
valakas.setRunning();
// Start timers.
if (status == FIGHTING)
{
// stores current time for inactivity task.
_timeTracker = System.currentTimeMillis();
startQuestTimer("regen_task", 60000, valakas, null, true);
startQuestTimer("skill_task", 2000, valakas, null, true);
}
else
{
valakas.setIsInvul(true);
valakas.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
// Start timer to lock entry after 30 minutes
if (status == WAITING)
{
startQuestTimer("beginning", Config.VALAKAS_WAIT_TIME * 60000, valakas, null);
}
}
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (npc != null)
{
if (event.equalsIgnoreCase("beginning"))
{
// Stores current time
_timeTracker = System.currentTimeMillis();
// Teleport Valakas to his lair.
npc.teleToLocation(VALAKAS_LAIR);
// Sound + socialAction.
for (L2PcInstance plyr : ZONE.getPlayersInside())
{
plyr.sendPacket(new PlaySound(1, "B03_A", 0, 0, 0, 0, 0));
plyr.sendPacket(new SocialAction(npc.getObjectId(), 3));
}
// Launch the cinematic, and tasks (regen + skill).
startQuestTimer("spawn_1", 1700, npc, null); // 1700
startQuestTimer("spawn_2", 3200, npc, null); // 1500
startQuestTimer("spawn_3", 6500, npc, null); // 3300
startQuestTimer("spawn_4", 9400, npc, null); // 2900
startQuestTimer("spawn_5", 12100, npc, null); // 2700
startQuestTimer("spawn_6", 12430, npc, null); // 330
startQuestTimer("spawn_7", 15430, npc, null); // 3000
startQuestTimer("spawn_8", 16830, npc, null); // 1400
startQuestTimer("spawn_9", 23530, npc, null); // 6700 - end of cinematic
startQuestTimer("spawn_10", 26000, npc, null); // 2500 - AI + unlock
}
// Regeneration && inactivity task
else if (event.equalsIgnoreCase("regen_task"))
{
// Inactivity task - 15min
if ((GrandBossManager.getInstance().getBossStatus(VALAKAS) == FIGHTING) && ((_timeTracker + 900000) < System.currentTimeMillis()))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
npc.teleToLocation(VALAKAS_REGENERATION_LOC);
GrandBossManager.getInstance().setBossStatus(VALAKAS, DORMANT);
npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp());
// Drop all players from the zone.
ZONE.oustAllPlayers();
// Cancel skill_task and regen_task.
cancelQuestTimer("regen_task", npc, null);
cancelQuestTimer("skill_task", npc, null);
return null;
}
// Verify if "Valakas Regeneration" skill is active.
final BuffInfo info = npc.getEffectList().getBuffInfoBySkillId(VALAKAS_REGENERATION);
final int lvl = info != null ? info.getSkill().getLevel() : 0;
// Current HPs are inferior to 25% ; apply lvl 4 of regen skill.
if ((npc.getCurrentHp() < (npc.getMaxHp() / 4)) && (lvl != 4))
{
npc.setTarget(npc);
npc.doCast(SkillData.getInstance().getSkill(VALAKAS_REGENERATION, 4));
}
// Current HPs are inferior to 50% ; apply lvl 3 of regen skill.
else if ((npc.getCurrentHp() < ((npc.getMaxHp() * 2) / 4.0)) && (lvl != 3))
{
npc.setTarget(npc);
npc.doCast(SkillData.getInstance().getSkill(VALAKAS_REGENERATION, 3));
}
// Current HPs are inferior to 75% ; apply lvl 2 of regen skill.
else if ((npc.getCurrentHp() < ((npc.getMaxHp() * 3) / 4.0)) && (lvl != 2))
{
npc.setTarget(npc);
npc.doCast(SkillData.getInstance().getSkill(VALAKAS_REGENERATION, 2));
}
// Apply lvl 1.
else if (lvl != 1)
{
npc.setTarget(npc);
npc.doCast(SkillData.getInstance().getSkill(VALAKAS_REGENERATION, 1));
}
}
// Spawn cinematic, regen_task and choose of skill.
else if (event.equalsIgnoreCase("spawn_1"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1800, 180, -1, 1500, 15000, 10000, 0, 0, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_2"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1300, 180, -5, 3000, 15000, 10000, 0, -5, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_3"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 500, 180, -8, 600, 15000, 10000, 0, 60, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_4"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 800, 180, -8, 2700, 15000, 10000, 0, 30, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_5"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 200, 250, 70, 0, 15000, 10000, 30, 80, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_6"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1100, 250, 70, 2500, 15000, 10000, 30, 80, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_7"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 700, 150, 30, 0, 15000, 10000, -10, 60, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_8"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1200, 150, 20, 2900, 15000, 10000, -10, 30, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_9"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 750, 170, -10, 3400, 15000, 4000, 10, -15, 1, 0, 0));
}
else if (event.equalsIgnoreCase("spawn_10"))
{
GrandBossManager.getInstance().setBossStatus(VALAKAS, FIGHTING);
npc.setIsInvul(false);
startQuestTimer("regen_task", 60000, npc, null, true);
startQuestTimer("skill_task", 2000, npc, null, true);
}
// Death cinematic, spawn of Teleport Cubes.
else if (event.equalsIgnoreCase("die_1"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 2000, 130, -1, 0, 15000, 10000, 0, 0, 1, 1, 0));
}
else if (event.equalsIgnoreCase("die_2"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1100, 210, -5, 3000, 15000, 10000, -13, 0, 1, 1, 0));
}
else if (event.equalsIgnoreCase("die_3"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1300, 200, -8, 3000, 15000, 10000, 0, 15, 1, 1, 0));
}
else if (event.equalsIgnoreCase("die_4"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1000, 190, 0, 500, 15000, 10000, 0, 10, 1, 1, 0));
}
else if (event.equalsIgnoreCase("die_5"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1700, 120, 0, 2500, 15000, 10000, 12, 40, 1, 1, 0));
}
else if (event.equalsIgnoreCase("die_6"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1700, 20, 0, 700, 15000, 10000, 10, 10, 1, 1, 0));
}
else if (event.equalsIgnoreCase("die_7"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1700, 10, 0, 1000, 15000, 10000, 20, 70, 1, 1, 0));
}
else if (event.equalsIgnoreCase("die_8"))
{
ZONE.broadcastPacket(new SpecialCamera(npc, 1700, 10, 0, 300, 15000, 250, 20, -20, 1, 1, 0));
for (Location loc : TELEPORT_CUBE_LOCATIONS)
{
addSpawn(31759, loc, false, 900000);
}
startQuestTimer("remove_players", 900000, null, null);
}
else if (event.equalsIgnoreCase("skill_task"))
{
callSkillAI(npc);
}
}
else
{
if (event.equalsIgnoreCase("valakas_unlock"))
{
final L2Npc valakas = addSpawn(VALAKAS, VALAKAS_REGENERATION_LOC, false, 0);
valakas.teleToLocation(VALAKAS_HIDDEN_LOC);
GrandBossManager.getInstance().addBoss((L2GrandBossInstance) valakas);
GrandBossManager.getInstance().setBossStatus(VALAKAS, DORMANT);
}
else if (event.equalsIgnoreCase("remove_players"))
{
ZONE.oustAllPlayers();
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSpawn(L2Npc npc)
{
npc.disableCoreAI(true);
return super.onSpawn(npc);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
if (!ZONE.isInsideZone(attacker))
{
attacker.doDie(attacker);
return null;
}
if (npc.isInvul())
{
return null;
}
if (GrandBossManager.getInstance().getBossStatus(VALAKAS) != FIGHTING)
{
attacker.teleToLocation(ATTACKER_REMOVE);
return null;
}
// Debuff strider-mounted players.
if ((attacker.getMountType() == MountType.STRIDER) && !attacker.isAffectedBySkill(4258))
{
npc.setTarget(attacker);
npc.doCast(SkillData.getInstance().getSkill(4258, 1));
}
_timeTracker = System.currentTimeMillis();
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
// Cancel skill_task and regen_task.
cancelQuestTimer("regen_task", npc, null);
cancelQuestTimer("skill_task", npc, null);
// Launch death animation.
ZONE.broadcastPacket(new PlaySound(1, "B03_D", 0, 0, 0, 0, 0));
ZONE.broadcastPacket(new SpecialCamera(npc, 1200, 20, -10, 0, 10000, 13000, 0, 0, 0, 0, 0));
startQuestTimer("die_1", 300, npc, null); // 300
startQuestTimer("die_2", 600, npc, null); // 300
startQuestTimer("die_3", 3800, npc, null); // 3200
startQuestTimer("die_4", 8200, npc, null); // 4400
startQuestTimer("die_5", 8700, npc, null); // 500
startQuestTimer("die_6", 13300, npc, null); // 4600
startQuestTimer("die_7", 14000, npc, null); // 700
startQuestTimer("die_8", 16500, npc, null); // 2500
GrandBossManager.getInstance().setBossStatus(VALAKAS, DEAD);
// Calculate Min and Max respawn times randomly.
final long respawnTime = (Config.VALAKAS_SPAWN_INTERVAL + getRandom(-Config.VALAKAS_SPAWN_RANDOM, Config.VALAKAS_SPAWN_RANDOM)) * 3600000;
startQuestTimer("valakas_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
final StatsSet info = GrandBossManager.getInstance().getStatsSet(VALAKAS);
info.set("respawn_time", System.currentTimeMillis() + respawnTime);
GrandBossManager.getInstance().setStatsSet(VALAKAS, info);
return super.onKill(npc, killer, isSummon);
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
return null;
}
private void callSkillAI(L2Npc npc)
{
if (npc.isInvul() || npc.isCastingNow())
{
return;
}
// Pickup a target if no or dead victim. 10% luck he decides to reconsiders his target.
if ((_actualVictim == null) || _actualVictim.isDead() || !npc.getKnownList().knowsObject(_actualVictim) || (getRandom(10) == 0))
{
_actualVictim = getRandomTarget(npc);
}
// If result is still null, Valakas will roam. Don't go deeper in skill AI.
if (_actualVictim == null)
{
if (getRandom(10) == 0)
{
final int x = npc.getX();
final int y = npc.getY();
final int z = npc.getZ();
final int posX = x + getRandom(-1400, 1400);
final int posY = y + getRandom(-1400, 1400);
if (GeoData.getInstance().canMove(x, y, z, posX, posY, z, npc.getInstanceId()))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(posX, posY, z, 0));
}
}
return;
}
final Skill skill = getRandomSkill(npc).getSkill();
// Cast the skill or follow the target.
if (Util.checkIfInRange((skill.getCastRange() < 600) ? 600 : skill.getCastRange(), npc, _actualVictim, true))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
npc.setIsCastingNow(true);
npc.setTarget(_actualVictim);
npc.doCast(skill);
}
else
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, _actualVictim, null);
npc.setIsCastingNow(false);
}
}
/**
* Pick a random skill.<br>
* Valakas will mostly use utility skills. If Valakas feels surrounded, he will use AoE skills.<br>
* Lower than 50% HPs, he will begin to use Meteor skill.
* @param npc valakas
* @return a skill holder
*/
private SkillHolder getRandomSkill(L2Npc npc)
{
final int hpRatio = (int) ((npc.getCurrentHp() / npc.getMaxHp()) * 100);
// Valakas Lava Skin has priority.
if ((hpRatio < 75) && (getRandom(150) == 0) && !npc.isAffectedBySkill(VALAKAS_LAVA_SKIN.getSkillId()))
{
return VALAKAS_LAVA_SKIN;
}
// Valakas will use mass spells if he feels surrounded.
if (Util.getPlayersCountInRadius(1200, npc, false, false) >= 20)
{
return VALAKAS_AOE_SKILLS[getRandom(VALAKAS_AOE_SKILLS.length)];
}
if (hpRatio > 50)
{
return VALAKAS_REGULAR_SKILLS[getRandom(VALAKAS_REGULAR_SKILLS.length)];
}
return VALAKAS_LOWHP_SKILLS[getRandom(VALAKAS_LOWHP_SKILLS.length)];
}
/**
* Pickup a random L2Playable from the zone, deads targets aren't included.
* @param npc
* @return a random L2Playable.
*/
private L2Playable getRandomTarget(L2Npc npc)
{
final List<L2Playable> result = new ArrayList<>();
for (L2Character obj : npc.getKnownList().getKnownCharacters())
{
if ((obj == null) || obj.isPet())
{
continue;
}
else if (!obj.isDead() && obj.isPlayable())
{
result.add((L2Playable) obj);
}
}
return result.isEmpty() ? null : result.get(getRandom(result.size()));
}
public static void main(String[] args)
{
new Valakas();
}
}

View File

@@ -0,0 +1,3 @@
<html><body>Teleportation Cubic:<br>
<a action="bypass -h npc_%objectId%_Quest Venom">Leave the prison.</a><br>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>
When attacking a castle, its defenses can easily be paralyzed.... What if that demon escapes?
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>
The roar of that scary demon in the dungeon always makes me want to run away! I know the dungeon is well-built, but if its defenses are broken, it could collapse!<br><p>
<a action="bypass -h npc_%objectId%_Quest Venom">Teleport to the dungeon</a>
</body></html>

View File

@@ -0,0 +1,426 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.individual.Venom;
import java.util.ArrayList;
import java.util.List;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.TeleportWhereType;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.impl.sieges.castle.OnCastleSiegeFinish;
import com.l2jmobius.gameserver.model.events.impl.sieges.castle.OnCastleSiegeStart;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.NpcStringId;
import ai.npc.AbstractNpcAI;
/**
* Venom AI on Rune Castle.
* @author nonom, MELERIX
*/
final class Venom extends AbstractNpcAI
{
private static final int CASTLE = 8; // Rune
private static final int VENOM = 29054;
private static final int TELEPORT_CUBE = 29055;
private static final int DUNGEON_KEEPER = 35506;
private static final byte ALIVE = 0;
private static final byte DEAD = 1;
private static final int HOURS_BEFORE = 24;
private static final Location[] TARGET_TELEPORTS =
{
new Location(12860, -49158, 976),
new Location(14878, -51339, 1024),
new Location(15674, -49970, 864),
new Location(15696, -48326, 864),
new Location(14873, -46956, 1024),
new Location(12157, -49135, -1088),
new Location(12875, -46392, -288),
new Location(14087, -46706, -288),
new Location(14086, -51593, -288),
new Location(12864, -51898, -288),
new Location(15538, -49153, -1056),
new Location(17001, -49149, -1064)
};
private static final Location TRHONE = new Location(11025, -49152, -537);
private static final Location DUNGEON = new Location(11882, -49216, -3008);
private static final Location TELEPORT = new Location(12589, -49044, -3008);
private static final Location CUBE = new Location(12047, -49211, -3009);
private static final SkillHolder VENOM_STRIKE = new SkillHolder(4993, 1);
private static final SkillHolder SONIC_STORM = new SkillHolder(4994, 1);
private static final SkillHolder VENOM_TELEPORT = new SkillHolder(4995, 1);
private static final SkillHolder RANGE_TELEPORT = new SkillHolder(4996, 1);
private L2Npc _venom;
private L2Npc _massymore;
private Location _loc;
private boolean _aggroMode = false;
private boolean _prisonIsOpen = false;
// @formatter:off
private static final int[] TARGET_TELEPORTS_OFFSET =
{
650, 100, 100, 100, 100, 650, 200, 200, 200, 200, 200, 650
};
// @formatter:on
private static List<L2PcInstance> _targets = new ArrayList<>();
private Venom()
{
super(Venom.class.getSimpleName(), "ai/individual");
addStartNpc(DUNGEON_KEEPER, TELEPORT_CUBE);
addFirstTalkId(DUNGEON_KEEPER, TELEPORT_CUBE);
addTalkId(DUNGEON_KEEPER, TELEPORT_CUBE);
addSpawnId(VENOM, DUNGEON_KEEPER);
addSpellFinishedId(VENOM);
addAttackId(VENOM);
addKillId(VENOM);
addAggroRangeEnterId(VENOM);
setCastleSiegeStartId(this::onSiegeStart, CASTLE);
setCastleSiegeFinishId(this::onSiegeFinish, CASTLE);
final long currentTime = System.currentTimeMillis();
final long startSiegeDate = CastleManager.getInstance().getCastleById(CASTLE).getSiegeDate().getTimeInMillis();
if ((currentTime > (startSiegeDate - (HOURS_BEFORE * 360000))) && (currentTime < startSiegeDate))
{
_prisonIsOpen = true;
}
}
@Override
public String onTalk(L2Npc npc, L2PcInstance talker)
{
switch (npc.getId())
{
case TELEPORT_CUBE:
{
talker.teleToLocation(TeleportWhereType.TOWN);
break;
}
case DUNGEON_KEEPER:
{
if (_prisonIsOpen)
{
talker.teleToLocation(TELEPORT);
}
else
{
return "35506-02.html";
}
break;
}
}
return super.onTalk(npc, talker);
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "tower_check":
{
if (CastleManager.getInstance().getCastleById(CASTLE).getSiege().getControlTowerCount() <= 1)
{
changeLocation(MoveTo.THRONE);
broadcastNpcSay(_massymore, ChatType.NPC_SHOUT, NpcStringId.OH_NO_THE_DEFENSES_HAVE_FAILED_IT_IS_TOO_DANGEROUS_TO_REMAIN_INSIDE_THE_CASTLE_FLEE_EVERY_MAN_FOR_HIMSELF);
cancelQuestTimer("tower_check", npc, null);
startQuestTimer("raid_check", 10000, npc, null, true);
}
break;
}
case "raid_check":
{
if (!npc.isInsideZone(ZoneId.SIEGE) && !npc.isTeleporting())
{
npc.teleToLocation(_loc);
}
break;
}
case "cube_despawn":
{
if (npc != null)
{
npc.deleteMe();
}
break;
}
}
return event;
}
@Override
public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
{
if (isSummon)
{
return super.onAggroRangeEnter(npc, player, isSummon);
}
if (_aggroMode && (_targets.size() < 10) && (getRandom(3) < 1) && !player.isDead())
{
_targets.add(player);
}
return super.onAggroRangeEnter(npc, player, isSummon);
}
public void onSiegeStart(OnCastleSiegeStart event)
{
_aggroMode = true;
_prisonIsOpen = false;
if ((_venom != null) && !_venom.isDead())
{
_venom.setCurrentHp(_venom.getMaxHp());
_venom.setCurrentMp(_venom.getMaxMp());
_venom.enableSkill(VENOM_TELEPORT.getSkill());
_venom.enableSkill(RANGE_TELEPORT.getSkill());
startQuestTimer("tower_check", 30000, _venom, null, true);
}
}
public void onSiegeFinish(OnCastleSiegeFinish event)
{
_aggroMode = false;
if ((_venom != null) && !_venom.isDead())
{
changeLocation(MoveTo.PRISON);
_venom.disableSkill(VENOM_TELEPORT.getSkill(), -1);
_venom.disableSkill(RANGE_TELEPORT.getSkill(), -1);
}
updateStatus(ALIVE);
cancelQuestTimer("tower_check", _venom, null);
cancelQuestTimer("raid_check", _venom, null);
}
@Override
public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
{
switch (skill.getId())
{
case 4222:
{
npc.teleToLocation(_loc);
break;
}
case 4995:
{
teleportTarget(player);
((L2Attackable) npc).stopHating(player);
break;
}
case 4996:
{
teleportTarget(player);
((L2Attackable) npc).stopHating(player);
if ((_targets != null) && (_targets.size() > 0))
{
for (L2PcInstance target : _targets)
{
final long x = player.getX() - target.getX();
final long y = player.getY() - target.getY();
final long z = player.getZ() - target.getZ();
final long range = 250;
if (((x * x) + (y * y) + (z * z)) <= (range * range))
{
teleportTarget(target);
((L2Attackable) npc).stopHating(target);
}
}
_targets.clear();
}
break;
}
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public final String onSpawn(L2Npc npc)
{
switch (npc.getId())
{
case DUNGEON_KEEPER:
{
_massymore = npc;
break;
}
case VENOM:
{
_venom = npc;
_loc = _venom.getLocation();
_venom.disableSkill(VENOM_TELEPORT.getSkill(), -1);
_venom.disableSkill(RANGE_TELEPORT.getSkill(), -1);
_venom.doRevive();
broadcastNpcSay(npc, ChatType.NPC_SHOUT, NpcStringId.WHO_DARES_TO_COVET_THE_THRONE_OF_OUR_CASTLE_LEAVE_IMMEDIATELY_OR_YOU_WILL_PAY_THE_PRICE_OF_YOUR_AUDACITY_WITH_YOUR_VERY_OWN_BLOOD);
((L2Attackable) _venom).setCanReturnToSpawnPoint(false);
if (checkStatus() == DEAD)
{
_venom.deleteMe();
}
break;
}
}
if (checkStatus() == DEAD)
{
npc.deleteMe();
}
else
{
npc.doRevive();
}
return super.onSpawn(npc);
}
@Override
public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
{
final double distance = npc.calculateDistance(attacker, false, false);
if (_aggroMode && (getRandom(100) < 25))
{
npc.setTarget(attacker);
npc.doCast(VENOM_TELEPORT.getSkill());
}
else if (_aggroMode && (npc.getCurrentHp() < (npc.getMaxHp() / 3)) && (getRandom(100) < 25) && !npc.isCastingNow())
{
npc.setTarget(attacker);
npc.doCast(RANGE_TELEPORT.getSkill());
}
else if ((distance > 300) && (getRandom(100) < 10) && !npc.isCastingNow())
{
npc.setTarget(attacker);
npc.doCast(VENOM_STRIKE.getSkill());
}
else if ((getRandom(100) < 10) && !npc.isCastingNow())
{
npc.setTarget(attacker);
npc.doCast(SONIC_STORM.getSkill());
}
return super.onAttack(npc, attacker, damage, isSummon);
}
@Override
public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
{
updateStatus(DEAD);
broadcastNpcSay(npc, ChatType.NPC_SHOUT, NpcStringId.IT_S_NOT_OVER_YET_IT_WON_T_BE_OVER_LIKE_THIS_NEVER);
if (!CastleManager.getInstance().getCastleById(CASTLE).getSiege().isInProgress())
{
final L2Npc cube = addSpawn(TELEPORT_CUBE, CUBE, false, 0);
startQuestTimer("cube_despawn", 120000, cube, null);
}
cancelQuestTimer("raid_check", npc, null);
return super.onKill(npc, killer, isSummon);
}
/**
* Alters the Venom location
* @param loc enum
*/
private void changeLocation(MoveTo loc)
{
switch (loc)
{
case THRONE:
{
_venom.teleToLocation(TRHONE, false);
break;
}
case PRISON:
{
if ((_venom == null) || _venom.isDead() || _venom.isDecayed())
{
_venom = addSpawn(VENOM, DUNGEON, false, 0);
}
else
{
_venom.teleToLocation(DUNGEON, false);
}
cancelQuestTimer("raid_check", _venom, null);
cancelQuestTimer("tower_check", _venom, null);
break;
}
}
_loc.setLocation(_venom.getLocation());
}
private void teleportTarget(L2PcInstance player)
{
if ((player != null) && !player.isDead())
{
final int rnd = getRandom(11);
player.teleToLocation(TARGET_TELEPORTS[rnd], TARGET_TELEPORTS_OFFSET[rnd]);
player.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
}
}
/**
* Checks if Venom is Alive or Dead
* @return status
*/
private int checkStatus()
{
int checkStatus = ALIVE;
if (GlobalVariablesManager.getInstance().hasVariable("VenomStatus"))
{
checkStatus = GlobalVariablesManager.getInstance().getInt("VenomStatus");
}
else
{
GlobalVariablesManager.getInstance().set("VenomStatus", 0);
}
return checkStatus;
}
/**
* Update the Venom status
* @param status the new status. 0 = ALIVE, 1 = DEAD.
*/
private void updateStatus(int status)
{
GlobalVariablesManager.getInstance().set("VenomStatus", Integer.toString(status));
}
private enum MoveTo
{
THRONE,
PRISON
}
public static void main(String[] args)
{
new Venom();
}
}

View File

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

View File

@@ -0,0 +1,7 @@
<html><body>Mercenary Supplier Abercrombie:<br>
As usual, the delivery of supplies are very unreliable in this godforsaken swampland! My life is totally miserable! The monsters around here are a real pain! I should've known when they sent me out here to the northernmost corner of nowhere... Dammit! What am I doing here!? They don't pay me enough! I don't know what my bosses are thinking!<br>
When Sighardt led the mercenary army, things like this never happened! Challenges always existed, but at least life was liveable!<br>
Did you want an item? Hold on, give me a moment. I must check the list. By the way, you brought a chit didn't you?<br>
<a action="bypass -h npc_%objectId%_multisell 526">"I want to trade a chit of Golden Ram for an item."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Mercenary Supplier Abercrombie:<br>
Everyone's talking about the excellence you showed in battle again today! You're winning all the bonuses! Ha! It's good to see someone succeed in this godforsaken place!<br>
Now tell me! Is there anything in particular you want? Although only a few types of supplies are available, I'll see what I can do. By the way, you prepared a chit didn't you?<br>
<a action="bypass -h npc_%objectId%_multisell 521">"I want to trade a chit of Golden Ram for an item."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Mercenary Supplier Abercrombie:<br>
Jeesh! Why are you turning into such a pain?! Can't you see I'm busy? It's more than enough for me to deal with the mercenaries! I don't have the time to deal with an outsider like you!<br>
If you want to serve in our Golden Ram Mercenary force, why don't you go see Kadoon. What a life! What kind of fortune can I make here? Sigh! What a life!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,65 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.npc.Abercrombie;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import ai.npc.AbstractNpcAI;
/**
* Mercenary Supplier Abercrombie AI.
* @author Zoey76
*/
public final class Abercrombie extends AbstractNpcAI
{
// NPC
private static final int ABERCROMBIE = 31555;
// Items
private static final int GOLDEN_RAM_BADGE_RECRUIT = 7246;
private static final int GOLDEN_RAM_BADGE_SOLDIER = 7247;
public Abercrombie()
{
super(Abercrombie.class.getSimpleName(), "ai/npc");
addFirstTalkId(ABERCROMBIE);
}
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
final String htmltext;
if (hasQuestItems(player, GOLDEN_RAM_BADGE_SOLDIER))
{
htmltext = "31555-07.html";
}
else if (hasQuestItems(player, GOLDEN_RAM_BADGE_RECRUIT))
{
htmltext = "31555-01.html";
}
else
{
htmltext = "31555-09.html";
}
return htmltext;
}
public static void main(String[] args)
{
new Abercrombie();
}
}

View File

@@ -0,0 +1,134 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ai.npc;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.MinionHolder;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.util.Broadcast;
/**
* Abstract NPC AI class for datapack based AIs.
* @author UnAfraid, Zoey76
*/
public abstract class AbstractNpcAI extends Quest
{
public AbstractNpcAI(String name, String descr)
{
super(-1, name, descr);
}
/**
* Simple on first talk event handler.
*/
@Override
public String onFirstTalk(L2Npc npc, L2PcInstance player)
{
return npc.getId() + ".html";
}
/**
* Registers the following events to the current script:<br>
* <ul>
* <li>ON_ATTACK</li>
* <li>ON_KILL</li>
* <li>ON_SPAWN</li>
* <li>ON_SPELL_FINISHED</li>
* <li>ON_SKILL_SEE</li>
* <li>ON_FACTION_CALL</li>
* <li>ON_AGGR_RANGE_ENTER</li>
* </ul>
* @param mobs
*/
public void registerMobs(int... mobs)
{
addAttackId(mobs);
addKillId(mobs);
addSpawnId(mobs);
addSpellFinishedId(mobs);
addSkillSeeId(mobs);
addAggroRangeEnterId(mobs);
addFactionCallId(mobs);
}
/**
* Broadcasts NpcSay packet to all known players with custom string.
* @param npc
* @param type
* @param text
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, String text)
{
Broadcast.toKnownPlayers(npc, new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), text));
}
/**
* Broadcasts NpcSay packet to all known players with npc string id.
* @param npc
* @param type
* @param stringId
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, NpcStringId stringId)
{
Broadcast.toKnownPlayers(npc, new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), stringId));
}
/**
* Broadcasts NpcSay packet to all known players with npc string id.
* @param npc
* @param type
* @param stringId
* @param parameters
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, NpcStringId stringId, String... parameters)
{
final NpcSay say = new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), stringId);
if (parameters != null)
{
for (String parameter : parameters)
{
say.addStringParameter(parameter);
}
}
Broadcast.toKnownPlayers(npc, say);
}
/**
* Broadcasts NpcSay packet to all known players with npc string id in specific radius.
* @param npc
* @param type
* @param stringId
* @param radius
*/
protected void broadcastNpcSay(L2Npc npc, ChatType type, NpcStringId stringId, int radius)
{
Broadcast.toKnownPlayersInRadius(npc, new NpcSay(npc.getObjectId(), type, npc.getTemplate().getDisplayId(), stringId), radius);
}
public void spawnMinions(L2Npc npc, String spawnName)
{
for (MinionHolder is : npc.getTemplate().getParameters().getMinionList(spawnName))
{
addMinion((L2MonsterInstance) npc, is.getId());
}
}
}

View File

@@ -0,0 +1,4 @@
<html><body>Alarm System:<br>
As the alarm rings, a window for the passcode pops up. On the screen you see the number 120, which begins counting down. It looks like the alarm system will be activated in about 2 minutes unless the passcode is successfully entered.<br>
<a action="bypass -h Quest Alarm 2">Enter the passcode.</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Alarm System:<br>
The alarm is ringing loudly. You should leave here immediately.<br>
(Another person has already undertaken the quest.)
</body></html>

View File

@@ -0,0 +1,42 @@
<html><body>Alarm System:<br>
########################<br>
Enter the passcode for communication.<br>
Passcode :|<br>
########################<br>
The first number is...
<table border="0" border color="white" width="65" height="65">
<tr>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">1</a>
</td>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">2</a>
</td>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 3">3</a>
</td>
</tr>
<tr>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">4</a>
</td>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">5</a>
</td>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">6</a>
</td>
</tr>
<tr>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">7</a>
</td>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">8</a>
</td>
<td width="20" height="20" align="center">
<a action="bypass -h Quest Alarm 32367-184_04.html">9</a>
</td>
</tr>
</table>
</body></html>

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