PDA

Просмотр полной версии : Как НЕ надо писать квесты


Gaikotsu
14.02.2016, 19:13
Сидел сегодня, писал реализацию квеста 10742 (https://l2central.info/wiki/%D0%9C%D0%BE%D0%B9_%D0%BC%D0%B8%D0%BB%D1%8B%D0%B9_ %D0%A0%D0%B8%D0%BA%D0%B8)

И чет черт попутал позырить, как же этот квест у L2Scripts реализован, в той шарной сборке Артеи.

Ну... вобщем самое цензурное что мне в голову пришло после того как я "это" увидел это слово "п...ц"...

Ну вобщем сами смотрите, как не стоит писать

Код:



package quests;

import java.util.List;

import l2s.commons.threading.RunnableImpl;
import l2s.commons.util.Rnd;
import l2s.gameserver.Config;
import l2s.gameserver.ThreadPoolManager;
import l2s.gameserver.ai.CtrlIntention;
import l2s.gameserver.model.GameObjectsStorage;
import l2s.gameserver.model.Player;
import l2s.gameserver.model.instances.NpcInstance;
import l2s.gameserver.model.quest.Quest;
import l2s.gameserver.model.quest.QuestState;
import l2s.gameserver.network.l2.s2c.ExSendUIEventPacket;
import l2s.gameserver.network.l2.s2c.ExShowScreenMessage;
import l2s.gameserver.network.l2.s2c.ExShowScreenMessage. ScreenMessageAlign;
import l2s.gameserver.network.l2.components.NpcString;
import l2s.gameserver.scripts.ScriptFile;
import l2s.gameserver.utils.Location;
import l2s.gameserver.utils.NpcUtils;

/**
* @author blacksmoke
*/
public class _10742_AFurryFriend extends Quest implements ScriptFile
{
private static final int Leira = 33952;
private static final int KikusCave = 33995;
private static final int Ricky = 19552;
private static final int Kiku = 23453;

protected static Location[] POINTS =
{
new Location(-78152, 237352, -3569),
new Location(-79176, 236792, -3440),
new Location(-80072, 237064, -3311),
new Location(-80440, 237320, -3313)
};

public _10742_AFurryFriend()
{
super(false);
addStartNpc(Leira);
addTalkId(Leira, KikusCave);
addLevelCheck(11, 20);
addClassIdCheck(182, 183);
}

@Override
public String onEvent(String event, QuestState qs, NpcInstance npc)
{
NpcInstance ricky = GameObjectsStorage.getByNpcId(Ricky);
String htmltext = event;
switch(event)
{
case "quest_ac":
qs.setState(STARTED);
qs.setCond(1);
qs.playSound(SOUND_ACCEPT);
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.FOLLOW_RICKY, 4500, ScreenMessageAlign.TOP_CENTER));
ricky = NpcUtils.spawnSingle(Ricky, new Location(-78138, 237328, -3548));
ricky.setRunning();
ThreadPoolManager.getInstance().schedule(new RickyMoveTask(ricky), 1000L);
htmltext = "33952-3.htm";
break;

case "quest_cont":
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.TAKE_RICKY_TO_LEIRA_ IN_UNDER_2_MINUTES, 4500, ScreenMessageAlign.TOP_CENTER));
ricky = NpcUtils.spawnSingle(Ricky, new Location(qs.getPlayer().getX(), qs.getPlayer().getY(), qs.getPlayer().getZ()));

if(seeRicky(ricky, qs.getPlayer()) == null)
{
// TODO: Ricky's title don't work
ricky.setTitle(qs.getPlayer().getName());
ricky.setRunning();
ricky.setFollowTarget(qs.getPlayer());
ricky.getAI().setIntention(CtrlIntention.AI_INTENT ION_FOLLOW, qs.getPlayer(), 50);
}

ThreadPoolManager.getInstance().schedule(new CheckRickyDistance(GameObjectsStorage.getByNpcId(R icky), GameObjectsStorage.getByNpcId(Leira), qs), 500L);
qs.getPlayer().sendPacket(new ExSendUIEventPacket(qs.getPlayer(), 0, 0, 120, 0, NpcString.REMAINING_TIME));
qs.startQuestTimer("despawnRicky", 120 * 1000L, ricky);
htmltext = "33995-3.htm";
break;

case "despawnRicky":
if(ricky != null)
{
ricky.deleteMe();
}
break;
}

return htmltext;
}

@Override
public String onTalk(NpcInstance npc, QuestState qs)
{
if(qs.isCompleted())
{
return "completed";
}
String htmltext = "noquest";
final int cond = qs.getCond();

switch(npc.getNpcId())
{
case Leira:
switch(cond)
{
case 0:
if(checkStartCondition(qs.getPlayer()))
{
htmltext = "33952-1.htm";
}
break;

case 2:
htmltext = "33952-4.htm";
qs.giveItems(57, 2500);
qs.addExpAndSp(52516, 5);
qs.exitCurrentQuest(false);
qs.playSound(SOUND_FINISH);
break;

default:
htmltext = "noqu.htm";
break;
}
break;

case KikusCave:
if(cond == 1)
{
final NpcInstance ricky = GameObjectsStorage.getByNpcId(Ricky);
if(ricky == null)
{
htmltext = "33995-1.htm";
}
else
{
final NpcInstance kiku = qs.addSpawn(Kiku, qs.getPlayer().getX() - Rnd.get(50), qs.getPlayer().getY() - Rnd.get(50), qs.getPlayer().getZ());
kiku.getAggroList().addDamageHate(qs.getPlayer(), 0, 10000);
kiku.setAggressionTarget(qs.getPlayer());
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.RICKY_IS_NOT_HERENTR Y_SEARCHING_ANOTHER_KIKUS_CAVE, 4500, ScreenMessageAlign.TOP_CENTER));
htmltext = "33995-2.htm";
}
}
break;
}
return htmltext;
}

class CheckRickyDistance implements Runnable
{
final NpcInstance ricky;
final NpcInstance leira;
final QuestState qs;

public CheckRickyDistance(NpcInstance npcRicky, NpcInstance npcLeira, QuestState state)
{
ricky = npcRicky;
leira = npcLeira;
qs = state;
}

@Override
public void run()
{
while (true)
{
if((ricky != null) && (leira != null) && (ricky.getDistance(leira) around = npc.getAroundNpc(Config.FOLLOW_RANGE * 2, 300);

if((around != null) && !around.isEmpty())
{
for (NpcInstance n : around)
{
if(((n.getNpcId() == Ricky) && (n.getFollowTarget() != null)) && (n.getFollowTarget().getObjectId() == player.getObjectId()))
{
return n;
}
}
}

return null;
}

@Override
public void onLoad()
{
//
}

@Override
public void onReload()
{
//
}

@Override
public void onShutdown()
{
//
}
}


Сразу видно как минимум 2 мега-косяка

1. вся работа с нпс, которого надо притащить к другому нпс идет через GameObjectsStorage.getByNpcId, т.е. всегда берется первый попавшися в хранилище объектов нпс с этим ид. к чему это приведет, если квест паралельно в одно время делают больше одного игрока, вы думаю уже осознали.

2. Таски CheckRickyDistance и RickyMoveTask - это "п...ц" в квадрате - while(true), слипание трида...

чисто ради примера, вот какая у меня реализация получилась - не скажу что тоже идеал, но все же мне думаю за нее краснеть не придется

.bbCodeBlock-requirementsList" data-xf-click="toggle">

2 требования to view hidden content



Вы должны нажать кнопку "Мне нравится", чтобы увидеть скрытое содержимое.


Скрытый текст, вам нужно 50 сообщений, у вас 0 сообщений.

mAnGoL
14.02.2016, 19:20
Однозначно +. Сейчас набегут чудо кОдиры чтобы квест захапать)

Gaikotsu
14.02.2016, 19:23
а толку

там есть вещи в других классах, на которые ссылается квест, которых нет в оригинальном овере, так что тому кто захочет заличить - поведение всего этого придется самому реализовывать.

вон к примеру за маленьким таким подключением AI WalkerAI лежат несколько десятков кб кода, которые отвечают за полную реализацию любых бродящих по заданным маршрутам мирных неписей и мобов.

ChaosPaladin
14.02.2016, 20:33
Однозначно +. Сейчас набегут чудо кОдиры чтобы квест захапать)


Думаю его уже давно захапали

L2J_DataPack/L2J_DataPack/dist/game/data/scripts/quests/Q10742_AFurryFriend at ertheia · L2J/L2J_DataPack · GitHub (https://github.com/L2J/L2J_DataPack/tree/ertheia/L2J_DataPack/dist/game/data/scripts/quests/Q10742_AFurryFriend)

melcor
14.02.2016, 21:21
Жесть, и их сборки берут по 20к. Жаль клиентов.

ツsmile10ツ
14.02.2016, 22:01
Немножко оффтопа по этому поводу



Жесть, и их сборки берут по 20к. Жаль клиентов.


[2:48:42] ADMIN Lineage-sib: поможешь )С ПЕРЕНОСАМ БД ЗАПЛАЧУ[2:49:17] smile10: Заплачешь? Ну лан[2:49:32] smile10: )00[2:49:53] Enmity: чё ему[2:49:57] Enmity: перенести надо[2:50:00] Enmity: куда откуда зачем[2:50:09] smile10: ХЗ ШОТА НА ИНТЕРЛЮДАХ Х1200 НАВЕРНА[2:50:16] Enmity: скажи[2:50:19] Enmity: фришки не чиним[2:51:05] smile10: руоффы чиним[2:51:06] smile10: изи[2:51:09] smile10: особенно корейские[2:51:12] Enmity: байдкоды[2:51:17] Enmity: от профессионалов[2:56:17] smile10: НПЕ в хтмлки и многое другое. Выбирая жопакоде девелопмент вы получаете полное отсутствие проблем по работе кода, максимально опциональную и гибкую настройку сервера, а так же многое другое, чего не описать словами. Выбирая Жопакоде - вы выбираете качество, гарантию, стабильность и уверенность в завтрашнем дне. Выбирай с умом.[2:56:31] Enmity: збс[2:56:34] Enmity: не купят[2:56:50] smile10: Ну бля[2:56:55] smile10: у скриптов же прокатило[2:56:58] Enmity: бля[2:57:00] Enmity: а правда ведь

*Immortal Pony*
15.02.2016, 00:48
Код:



package quests;

import java.util.List;

import l2s.commons.threading.RunnableImpl;
import l2s.commons.util.Rnd;
import l2s.gameserver.Config;
import l2s.gameserver.ThreadPoolManager;
import l2s.gameserver.ai.CtrlIntention;
import l2s.gameserver.model.GameObjectsStorage;
import l2s.gameserver.model.Player;
import l2s.gameserver.model.instances.NpcInstance;
import l2s.gameserver.model.quest.Quest;
import l2s.gameserver.model.quest.QuestState;
import l2s.gameserver.network.l2.s2c.ExSendUIEventPacket;
import l2s.gameserver.network.l2.s2c.ExShowScreenMessage;
import l2s.gameserver.network.l2.s2c.ExShowScreenMessage. ScreenMessageAlign;
import l2s.gameserver.network.l2.components.NpcString;
import l2s.gameserver.scripts.ScriptFile;
import l2s.gameserver.utils.Location;
import l2s.gameserver.utils.NpcUtils;

/**
* @author blacksmoke
*/
public class _10742_AFurryFriend extends Quest implements ScriptFile
{
private static final int Leira = 33952;
private static final int KikusCave = 33995;
private static int KikusCout;
private static final int Ricky = 19552;
private static final int Kiku = 23453;

protected static Location[] POINTS =
{
new Location(-78152, 237352, -3569),
new Location(-79176, 236792, -3440),
new Location(-80072, 237064, -3311),
new Location(-80440, 237320, -3313)
};

public _10742_AFurryFriend()
{
super(false);
addStartNpc(Leira);
addTalkId(Leira, KikusCave);
addLevelCheck(11, 20);
addClassIdCheck(182, 183);
}

@Override
public String onEvent(String event, QuestState qs, NpcInstance npc)
{
NpcInstance ricky = GameObjectsStorage.getByNpcId(Ricky);
String htmltext = event;
switch(event)
{
case "quest_ac":
qs.setState(STARTED);
qs.setCond(1);
qs.playSound(SOUND_ACCEPT);
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.FOLLOW_RICKY, 4500, ScreenMessageAlign.TOP_CENTER));
ricky = NpcUtils.spawnSingle(Ricky, new Location(-78138, 237328, -3548));
ricky.setRunning();
ThreadPoolManager.getInstance().schedule(new RickyMoveTask(ricky), 1000L);
htmltext = "33952-3.htm";
KikusCout = 0;
break;

case "quest_cont":
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.TAKE_RICKY_TO_LEIRA_ IN_UNDER_2_MINUTES, 4500, ScreenMessageAlign.TOP_CENTER));
ricky = NpcUtils.spawnSingle(Ricky, new Location(qs.getPlayer().getX(), qs.getPlayer().getY(), qs.getPlayer().getZ()));

if(seeRicky(ricky, qs.getPlayer()) == null)
{
// TODO: Ricky's title don't work
ricky.setTitle(qs.getPlayer().getName());
ricky.setRunning();
ricky.setFollowTarget(qs.getPlayer());
ricky.getAI().setIntention(CtrlIntention.AI_INTENT ION_FOLLOW, qs.getPlayer(), 50);
}

ThreadPoolManager.getInstance().schedule(new CheckRickyDistance(GameObjectsStorage.getByNpcId(R icky), GameObjectsStorage.getByNpcId(Leira), qs), 500L);
qs.getPlayer().sendPacket(new ExSendUIEventPacket(qs.getPlayer(), 0, 0, 120, 0, NpcString.REMAINING_TIME));
qs.startQuestTimer("despawnRicky", 120 * 1000L, ricky);
htmltext = "33995-3.htm";
break;

case "despawnRicky":
if(ricky != null)
{
KikusCout = 0;
ricky.deleteMe();
}
break;
}

return htmltext;
}

@Override
public String onTalk(NpcInstance npc, QuestState qs)
{
if(qs.isCompleted())
{
return "completed";
}
String htmltext = "noquest";
final int cond = qs.getCond();

switch(npc.getNpcId())
{
case Leira:
switch(cond)
{
case 0:
if(checkStartCondition(qs.getPlayer()))
{
htmltext = "33952-1.htm";
}
break;

case 2:
htmltext = "33952-4.htm";
qs.giveItems(57, 2500);
qs.addExpAndSp(52516, 5);
qs.exitCurrentQuest(false);
qs.playSound(SOUND_FINISH);
break;

default:
htmltext = "noqu.htm";
break;
}
break;

case KikusCave:
if(cond == 1)
{
if (qs.get("RikkyCave") == null)
qs.set("RikkyCave", Rnd.get(0, 2));

final NpcInstance ricky = GameObjectsStorage.getByNpcId(Ricky);
if(ricky == null && KikusCout == Integer.valueOf(qs.get("RikkyCave")))
{
KikusCout = 0;
qs.unset("RikkyCave");
htmltext = "33995-1.htm";
}
else
{
if (ricky == null)
{
final NpcInstance kiku = qs.addSpawn(Kiku, qs.getPlayer().getX() - Rnd.get(50), qs.getPlayer().getY() - Rnd.get(50), qs.getPlayer().getZ());
kiku.getAggroList().addDamageHate(qs.getPlayer(), 0, 10000);
kiku.setAggressionTarget(qs.getPlayer());
}
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.RICKY_IS_NOT_HERENTR Y_SEARCHING_ANOTHER_KIKUS_CAVE, 4500, ScreenMessageAlign.TOP_CENTER));
htmltext = "33995-2.htm";
KikusCout++;
}
}
break;
}
return htmltext;
}

class CheckRickyDistance implements Runnable
{
final NpcInstance ricky;
final NpcInstance leira;
final QuestState qs;

public CheckRickyDistance(NpcInstance npcRicky, NpcInstance npcLeira, QuestState state)
{
ricky = npcRicky;
leira = npcLeira;
qs = state;
}

@Override
public void run()
{
while (true)
{
if((ricky != null) && (leira != null) && (ricky.getDistance(leira) around = npc.getAroundNpc(Config.FOLLOW_RANGE * 2, 300);

if((around != null) && !around.isEmpty())
{
for (NpcInstance n : around)
{
if(((n.getNpcId() == Ricky) && (n.getFollowTarget() != null)) && (n.getFollowTarget().getObjectId() == player.getObjectId()))
{
return n;
}
}
}

return null;
}

@Override
public void onLoad()
{
//
}

@Override
public void onReload()
{
//
}

@Override
public void onShutdown()
{
//
}
}

mAnGoL
15.02.2016, 00:52
Код:



package quests;

import java.util.List;

import l2s.commons.threading.RunnableImpl;
import l2s.commons.util.Rnd;
import l2s.gameserver.Config;
import l2s.gameserver.ThreadPoolManager;
import l2s.gameserver.ai.CtrlIntention;
import l2s.gameserver.model.GameObjectsStorage;
import l2s.gameserver.model.Player;
import l2s.gameserver.model.instances.NpcInstance;
import l2s.gameserver.model.quest.Quest;
import l2s.gameserver.model.quest.QuestState;
import l2s.gameserver.network.l2.s2c.ExSendUIEventPacket;
import l2s.gameserver.network.l2.s2c.ExShowScreenMessage;
import l2s.gameserver.network.l2.s2c.ExShowScreenMessage. ScreenMessageAlign;
import l2s.gameserver.network.l2.components.NpcString;
import l2s.gameserver.scripts.ScriptFile;
import l2s.gameserver.utils.Location;
import l2s.gameserver.utils.NpcUtils;

/**
* @author blacksmoke
*/
public class _10742_AFurryFriend extends Quest implements ScriptFile
{
private static final int Leira = 33952;
private static final int KikusCave = 33995;
private static int KikusCout;
private static final int Ricky = 19552;
private static final int Kiku = 23453;

protected static Location[] POINTS =
{
new Location(-78152, 237352, -3569),
new Location(-79176, 236792, -3440),
new Location(-80072, 237064, -3311),
new Location(-80440, 237320, -3313)
};

public _10742_AFurryFriend()
{
super(false);
addStartNpc(Leira);
addTalkId(Leira, KikusCave);
addLevelCheck(11, 20);
addClassIdCheck(182, 183);
}

@Override
public String onEvent(String event, QuestState qs, NpcInstance npc)
{
NpcInstance ricky = GameObjectsStorage.getByNpcId(Ricky);
String htmltext = event;
switch(event)
{
case "quest_ac":
qs.setState(STARTED);
qs.setCond(1);
qs.playSound(SOUND_ACCEPT);
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.FOLLOW_RICKY, 4500, ScreenMessageAlign.TOP_CENTER));
ricky = NpcUtils.spawnSingle(Ricky, new Location(-78138, 237328, -3548));
ricky.setRunning();
ThreadPoolManager.getInstance().schedule(new RickyMoveTask(ricky), 1000L);
htmltext = "33952-3.htm";
KikusCout = 0;
break;

case "quest_cont":
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.TAKE_RICKY_TO_LEIRA_ IN_UNDER_2_MINUTES, 4500, ScreenMessageAlign.TOP_CENTER));
ricky = NpcUtils.spawnSingle(Ricky, new Location(qs.getPlayer().getX(), qs.getPlayer().getY(), qs.getPlayer().getZ()));

if(seeRicky(ricky, qs.getPlayer()) == null)
{
// TODO: Ricky's title don't work
ricky.setTitle(qs.getPlayer().getName());
ricky.setRunning();
ricky.setFollowTarget(qs.getPlayer());
ricky.getAI().setIntention(CtrlIntention.AI_INTENT ION_FOLLOW, qs.getPlayer(), 50);
}

ThreadPoolManager.getInstance().schedule(new CheckRickyDistance(GameObjectsStorage.getByNpcId(R icky), GameObjectsStorage.getByNpcId(Leira), qs), 500L);
qs.getPlayer().sendPacket(new ExSendUIEventPacket(qs.getPlayer(), 0, 0, 120, 0, NpcString.REMAINING_TIME));
qs.startQuestTimer("despawnRicky", 120 * 1000L, ricky);
htmltext = "33995-3.htm";
break;

case "despawnRicky":
if(ricky != null)
{
KikusCout = 0;
ricky.deleteMe();
}
break;
}

return htmltext;
}

@Override
public String onTalk(NpcInstance npc, QuestState qs)
{
if(qs.isCompleted())
{
return "completed";
}
String htmltext = "noquest";
final int cond = qs.getCond();

switch(npc.getNpcId())
{
case Leira:
switch(cond)
{
case 0:
if(checkStartCondition(qs.getPlayer()))
{
htmltext = "33952-1.htm";
}
break;

case 2:
htmltext = "33952-4.htm";
qs.giveItems(57, 2500);
qs.addExpAndSp(52516, 5);
qs.exitCurrentQuest(false);
qs.playSound(SOUND_FINISH);
break;

default:
htmltext = "noqu.htm";
break;
}
break;

case KikusCave:
if(cond == 1)
{
if (qs.get("RikkyCave") == null)
qs.set("RikkyCave", Rnd.get(0, 2));

final NpcInstance ricky = GameObjectsStorage.getByNpcId(Ricky);
if(ricky == null && KikusCout == Integer.valueOf(qs.get("RikkyCave")))
{
KikusCout = 0;
qs.unset("RikkyCave");
htmltext = "33995-1.htm";
}
else
{
if (ricky == null)
{
final NpcInstance kiku = qs.addSpawn(Kiku, qs.getPlayer().getX() - Rnd.get(50), qs.getPlayer().getY() - Rnd.get(50), qs.getPlayer().getZ());
kiku.getAggroList().addDamageHate(qs.getPlayer(), 0, 10000);
kiku.setAggressionTarget(qs.getPlayer());
}
qs.getPlayer().sendPacket(new ExShowScreenMessage(NpcString.RICKY_IS_NOT_HERENTR Y_SEARCHING_ANOTHER_KIKUS_CAVE, 4500, ScreenMessageAlign.TOP_CENTER));
htmltext = "33995-2.htm";
KikusCout++;
}
}
break;
}
return htmltext;
}

class CheckRickyDistance implements Runnable
{
final NpcInstance ricky;
final NpcInstance leira;
final QuestState qs;

public CheckRickyDistance(NpcInstance npcRicky, NpcInstance npcLeira, QuestState state)
{
ricky = npcRicky;
leira = npcLeira;
qs = state;
}

@Override
public void run()
{
while (true)
{
if((ricky != null) && (leira != null) && (ricky.getDistance(leira) around = npc.getAroundNpc(Config.FOLLOW_RANGE * 2, 300);

if((around != null) && !around.isEmpty())
{
for (NpcInstance n : around)
{
if(((n.getNpcId() == Ricky) && (n.getFollowTarget() != null)) && (n.getFollowTarget().getObjectId() == player.getObjectId()))
{
return n;
}
}
}

return null;
}

@Override
public void onLoad()
{
//
}

@Override
public void onReload()
{
//
}

@Override
public void onShutdown()
{
//
}
}






Ага, новый трид запилили с while(true).