QuestState and QuestTimer class cleanups.

This commit is contained in:
MobiusDevelopment 2020-01-24 18:04:25 +00:00
parent 90352a0447
commit b6eb8abc18
13 changed files with 321 additions and 526 deletions

View File

@ -20,10 +20,14 @@ import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.Config;
import org.l2jmobius.gameserver.cache.HtmCache;
import org.l2jmobius.gameserver.model.actor.instance.NpcInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.quest.Quest;
import org.l2jmobius.gameserver.model.quest.QuestState;
import org.l2jmobius.gameserver.network.serverpackets.TutorialCloseHtml;
import org.l2jmobius.gameserver.network.serverpackets.TutorialEnableClientEvent;
import org.l2jmobius.gameserver.network.serverpackets.TutorialShowHtml;
public class Tutorial extends Quest
{
@ -208,7 +212,7 @@ public class Tutorial extends Quest
{
qs.showQuestionMark(12);
qs.playSound("ItemSound.quest_tutorial");
qs.onTutorialClientEvent(0);
onTutorialClientEvent(player, 0);
break;
}
}
@ -253,12 +257,12 @@ public class Tutorial extends Quest
{
case 0:
{
qs.closeTutorialHtml();
closeTutorialHtml(player);
break;
}
case 1:
{
qs.closeTutorialHtml();
closeTutorialHtml(player);
qs.playTutorialVoice("tutorial_voice_006");
qs.showQuestionMark(1);
qs.playSound("ItemSound.quest_tutorial");
@ -270,43 +274,43 @@ public class Tutorial extends Quest
{
qs.playTutorialVoice("tutorial_voice_003");
html = "tutorial_02.htm";
qs.onTutorialClientEvent(1);
onTutorialClientEvent(player, 1);
qs.set("Ex", "-5");
break;
}
case 3:
{
html = "tutorial_03.htm";
qs.onTutorialClientEvent(2);
onTutorialClientEvent(player, 2);
break;
}
case 5:
{
html = "tutorial_05.htm";
qs.onTutorialClientEvent(8);
onTutorialClientEvent(player, 8);
break;
}
case 7:
{
html = "tutorial_100.htm";
qs.onTutorialClientEvent(0);
onTutorialClientEvent(player, 0);
break;
}
case 8:
{
html = "tutorial_101.htm";
qs.onTutorialClientEvent(0);
onTutorialClientEvent(player, 0);
break;
}
case 10:
{
html = "tutorial_103.htm";
qs.onTutorialClientEvent(0);
onTutorialClientEvent(player, 0);
break;
}
case 12:
{
qs.closeTutorialHtml();
closeTutorialHtml(player);
break;
}
case 23:
@ -360,14 +364,14 @@ public class Tutorial extends Quest
qs.playTutorialVoice("tutorial_voice_004");
html = "tutorial_03.htm";
qs.playSound("ItemSound.quest_tutorial");
qs.onTutorialClientEvent(2);
onTutorialClientEvent(player, 2);
}
else if ((eventId == 2) && (player.getLevel() < 6))
{
qs.playTutorialVoice("tutorial_voice_005");
html = "tutorial_05.htm";
qs.playSound("ItemSound.quest_tutorial");
qs.onTutorialClientEvent(8);
onTutorialClientEvent(player, 8);
}
else if ((eventId == 8) && (player.getLevel() < 6))
{
@ -399,14 +403,14 @@ public class Tutorial extends Quest
qs.playSound("ItemSound.quest_tutorial");
qs.set("Die", "1");
qs.showQuestionMark(8);
qs.onTutorialClientEvent(0);
onTutorialClientEvent(player, 0);
}
else if ((eventId == 800000) && (player.getLevel() < 6) && (qs.getInt("sit") == 0))
{
qs.playTutorialVoice("tutorial_voice_018");
qs.playSound("ItemSound.quest_tutorial");
qs.set("sit", "1");
qs.onTutorialClientEvent(0);
onTutorialClientEvent(player, 0);
html = "tutorial_21z.htm";
}
else if (eventId == 40)
@ -523,7 +527,7 @@ public class Tutorial extends Quest
qs.playSound("ItemSound.quest_tutorial");
qs.set("HP", "1");
qs.showQuestionMark(10);
qs.onTutorialClientEvent(800000);
onTutorialClientEvent(player, 800000);
}
else if ((eventId == 57) && (player.getLevel() < 6) && (qs.getInt("Adena") == 0))
{
@ -574,7 +578,7 @@ public class Tutorial extends Quest
case 3:
{
html = "tutorial_09.htm";
qs.onTutorialClientEvent(1048576);
onTutorialClientEvent(player, 1048576);
break;
}
case 5:
@ -699,10 +703,32 @@ public class Tutorial extends Quest
{
return null;
}
qs.showTutorialHTML(html);
showTutorialHTML(player, html);
return null;
}
private void showTutorialHTML(PlayerInstance player, String html)
{
String text = HtmCache.getInstance().getHtm("data/scripts/ai/others/Tutorial/" + html);
if (text == null)
{
LOGGER.warning("missing html page data/scripts/ai/others/Tutorial/" + html);
text = "<html><body>File data/scripts/ai/others/Tutorial/" + html + " not found or file is empty.</body></html>";
}
player.sendPacket(new TutorialShowHtml(text));
}
private void closeTutorialHtml(PlayerInstance player)
{
player.sendPacket(TutorialCloseHtml.STATIC_PACKET);
}
private void onTutorialClientEvent(PlayerInstance player, int number)
{
player.sendPacket(new TutorialEnableClientEvent(number));
}
public static void main(String[] args)
{
new Tutorial();

View File

@ -199,7 +199,7 @@ public class Q104_SpiritOfMirrors extends Quest
return null;
}
if (st.getItemEquipped(Inventory.PAPERDOLL_RHAND) == GALLINS_OAK_WAND)
if (player.getInventory().getPaperdollItemId(Inventory.PAPERDOLL_RHAND) == GALLINS_OAK_WAND)
{
switch (npc.getNpcId())

View File

@ -342,7 +342,7 @@ public class Q212_TrialOfDuty extends Quest
break;
case 27119:
if ((cond == 2) && (st.getItemEquipped(Inventory.PAPERDOLL_RHAND) == OLD_KNIGHT_SWORD))
if ((cond == 2) && (player.getInventory().getPaperdollItemId(Inventory.PAPERDOLL_RHAND) == OLD_KNIGHT_SWORD))
{
st.set("cond", "3");
st.playSound(QuestState.SOUND_MIDDLE);

View File

@ -531,7 +531,7 @@ public class Q218_TestimonyOfLife extends Quest
break;
case 27077:
if ((st.getInt("cond") == 18) && (st.getItemEquipped(Inventory.PAPERDOLL_RHAND) == TALINS_SPEAR))
if ((st.getInt("cond") == 18) && (player.getInventory().getPaperdollItemId(Inventory.PAPERDOLL_RHAND) == TALINS_SPEAR))
{
st.set("cond", "19");
st.playSound(QuestState.SOUND_MIDDLE);

View File

@ -401,7 +401,7 @@ public class Q224_TestOfSagittarius extends Quest
case SERPENT_DEMON_KADESH:
if (st.getInt("cond") == 13)
{
if (st.getItemEquipped(Inventory.PAPERDOLL_RHAND) == CRESCENT_MOON_BOW)
if (player.getInventory().getPaperdollItemId(Inventory.PAPERDOLL_RHAND) == CRESCENT_MOON_BOW)
{
st.set("cond", "14");
st.playSound(QuestState.SOUND_MIDDLE);

View File

@ -630,7 +630,7 @@ public class Q229_TestOfWitchcraft extends Quest
}
else if ((cond == 9) && _drevanulPrinceZeruel)
{
if (st.getItemEquipped(7) == SWORD_OF_BINDING)
if (attacker.getInventory().getPaperdollItemId(7) == SWORD_OF_BINDING)
{
_swordOfBinding = true;

View File

@ -213,7 +213,7 @@ public class Q401_PathToAWarrior extends Quest
case 20038:
case 20043:
if ((st.getInt("cond") == 5) && (st.getItemEquipped(Inventory.PAPERDOLL_RHAND) == RUSTED_BRONZE_SWORD_3) && st.dropItemsAlways(POISON_SPIDER_LEG, 1, 20))
if ((st.getInt("cond") == 5) && (player.getInventory().getPaperdollItemId(Inventory.PAPERDOLL_RHAND) == RUSTED_BRONZE_SWORD_3) && st.dropItemsAlways(POISON_SPIDER_LEG, 1, 20))
{
st.set("cond", "6");
}

View File

@ -196,7 +196,7 @@ public class Q403_PathToARogue extends Quest
return null;
}
final int equippedItemId = st.getItemEquipped(Inventory.PAPERDOLL_RHAND);
final int equippedItemId = player.getInventory().getPaperdollItemId(Inventory.PAPERDOLL_RHAND);
if ((equippedItemId != NETI_BOW) || (equippedItemId != NETI_DAGGER))
{
return null;

View File

@ -17,6 +17,7 @@
package quests.Q648_AnIceMerchantsDream;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.model.actor.instance.NpcInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.quest.Quest;
@ -116,7 +117,7 @@ public class Q648_AnIceMerchantsDream extends Quest
}
case "32023-05.htm":
{
if (qs.getRandom(100) <= 25)
if (Rnd.get(100) <= 25)
{
qs.giveItems(BLACK_ICE, 1);
qs.playSound("ItemSound3.sys_enchant_sucess");
@ -229,7 +230,7 @@ public class Q648_AnIceMerchantsDream extends Quest
int chance = (int) ((npc.getNpcId() - 22050) * Config.RATE_DROP_QUEST);
chance /= 100;
int numItems = chance;
int random = qs.getRandom(100);
int random = Rnd.get(100);
if (random <= chance)
{
numItems += 1;
@ -241,7 +242,7 @@ public class Q648_AnIceMerchantsDream extends Quest
}
final int cond = qs.getInt("cond");
random = qs.getRandom(100);
random = Rnd.get(100);
if ((cond == 2) && (random <= 10))
{
qs.giveItems(HEMOCYTE, 1);

View File

@ -165,7 +165,7 @@ public class SagasSuperClass extends Quest
final NpcInstance archon = st2.addSpawn(_mob[1], xx, yy, zz);
addSpawn(st2, archon);
st2.set("spawned", "1");
st2.startQuestTimer("Archon Hellisha has despawned", 600000, archon);
startQuestTimer("Archon Hellisha has despawned", 600000, archon, st2.getPlayer());
archon.broadcastNpcSay(_text[13].replace("PLAYERNAME", st2.getPlayer().getName()));
((Attackable) archon).addDamageHate(st2.getPlayer(), 0, 99999);
archon.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, st2.getPlayer(), null);
@ -391,8 +391,8 @@ public class SagasSuperClass extends Quest
{
final NpcInstance mob1 = st.addSpawn(_mob[0], _x[0], _y[0], _z[0]);
st.set("spawned", "1");
st.startQuestTimer("Mob_1 Timer 1", 500, mob1);
st.startQuestTimer("Mob_1 has despawned", 300000, mob1);
startQuestTimer("Mob_1 Timer 1", 500, mob1, player);
startQuestTimer("Mob_1 has despawned", 300000, mob1, player);
addSpawn(st, mob1);
htmltext = "7-02.htm";
}
@ -436,10 +436,10 @@ public class SagasSuperClass extends Quest
st.set("Mob_2", String.valueOf(mob2.getObjectId()));
st.set("Quest0", "1");
st.set("Quest1", "45");
st.startRepeatingQuestTimer("Mob_3 Timer 1", 500, mob3);
st.startQuestTimer("Mob_3 has despawned", 59000, mob3);
st.startQuestTimer("Mob_2 Timer 1", 500, mob2);
st.startQuestTimer("Mob_2 has despawned", 60000, mob2);
startQuestTimer("Mob_3 Timer 1", 500, mob3, player, true);
startQuestTimer("Mob_3 has despawned", 59000, mob3, player);
startQuestTimer("Mob_2 Timer 1", 500, mob2, player);
startQuestTimer("Mob_2 has despawned", 60000, mob2, player);
htmltext = "10-02.htm";
}
else if (st.getInt("Quest1") == 45)
@ -506,7 +506,7 @@ public class SagasSuperClass extends Quest
else if (event.equals("Mob_2 Timer 1"))
{
npc.broadcastNpcSay(_text[7].replace("PLAYERNAME", player.getName()));
st.startQuestTimer("Mob_2 Timer 2", 1500, npc);
startQuestTimer("Mob_2 Timer 2", 1500, npc, player);
if (st.getInt("Quest1") == 45)
{
st.set("Quest1", "0");
@ -516,15 +516,15 @@ public class SagasSuperClass extends Quest
else if (event.equals("Mob_2 Timer 2"))
{
npc.broadcastNpcSay(_text[8].replace("PLAYERNAME", player.getName()));
st.startQuestTimer("Mob_2 Timer 3", 10000, npc);
startQuestTimer("Mob_2 Timer 3", 10000, npc, player);
return null;
}
else if (event.equals("Mob_2 Timer 3"))
{
if (st.getInt("Quest0") == 0)
{
st.startQuestTimer("Mob_2 Timer 3", 13000, npc);
if (st.getRandom(2) == 0)
startQuestTimer("Mob_2 Timer 3", 13000, npc, player);
if (Rnd.nextBoolean())
{
npc.broadcastNpcSay(_text[9].replace("PLAYERNAME", player.getName()));
}
@ -553,7 +553,7 @@ public class SagasSuperClass extends Quest
}
else
{
st.startQuestTimer("Mob_2 has despawned", 1000, npc);
startQuestTimer("Mob_2 has despawned", 1000, npc, player);
}
return null;
}

View File

@ -356,7 +356,7 @@ public class Quest extends ManagedScript
{
final QuestTimer tmp = timers.get(i);
if ((tmp != null) && tmp.isMatch(this, name, npc, player))
if ((tmp != null) && tmp.equals(this, name, npc, player))
{
timer = tmp;
break;
@ -395,7 +395,7 @@ public class Quest extends ManagedScript
{
final QuestTimer timer = qt.get(i);
if ((timer != null) && timer.isMatch(this, name, npc, player))
if ((timer != null) && timer.equals(this, name, npc, player))
{
return timer;
}
@ -422,9 +422,9 @@ public class Quest extends ManagedScript
for (int i = 0; i < qt.size(); i++)
{
final QuestTimer timer = qt.get(i);
if ((timer != null) && timer.isMatch(this, name, npc, player))
if ((timer != null) && timer.equals(this, name, npc, player))
{
timer.cancel(false);
timer.cancel();
qt.remove(timer);
return;
}
@ -452,7 +452,7 @@ public class Quest extends ManagedScript
{
if (timer != null)
{
timer.cancel(false);
timer.cancel();
}
}
@ -469,7 +469,7 @@ public class Quest extends ManagedScript
synchronized (_allEventTimers)
{
final ArrayList<QuestTimer> timers = _allEventTimers.get(timer.getName());
final ArrayList<QuestTimer> timers = _allEventTimers.get(timer.toString());
if (timers == null)
{
@ -1803,7 +1803,7 @@ public class Quest extends ManagedScript
{
for (QuestTimer timer : timers)
{
timer.cancel(false);
timer.cancel();
}
}
_allEventTimers.clear();

View File

@ -23,13 +23,10 @@ import java.util.logging.Logger;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.GameTimeController;
import org.l2jmobius.gameserver.cache.HtmCache;
import org.l2jmobius.gameserver.instancemanager.QuestManager;
import org.l2jmobius.gameserver.model.DropData;
import org.l2jmobius.gameserver.model.PlayerInventory;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.MonsterInstance;
import org.l2jmobius.gameserver.model.actor.instance.NpcInstance;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
@ -42,9 +39,6 @@ import org.l2jmobius.gameserver.network.serverpackets.PlaySound;
import org.l2jmobius.gameserver.network.serverpackets.QuestList;
import org.l2jmobius.gameserver.network.serverpackets.StatusUpdate;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.TutorialCloseHtml;
import org.l2jmobius.gameserver.network.serverpackets.TutorialEnableClientEvent;
import org.l2jmobius.gameserver.network.serverpackets.TutorialShowHtml;
import org.l2jmobius.gameserver.network.serverpackets.TutorialShowQuestionMark;
/**
@ -80,9 +74,6 @@ public class QuestState
/** List of couples (variable for quest,value of the variable for quest) */
private Map<String, String> _vars;
/** Boolean flag letting QuestStateManager know to exit quest when cleaning up */
private boolean _isExitQuestOnCleanUp = false;
/**
* Constructor of the QuestState : save the quest in the list of quests of the player.<BR/>
* <BR/>
@ -158,7 +149,6 @@ public class QuestState
/**
* Return state of the quest after its initialization.<BR>
* <BR>
* <U><I>Actions :</I></U>
* <LI>Remove drops from previous state</LI>
* <LI>Set new state of the quest</LI>
@ -166,16 +156,64 @@ public class QuestState
* <LI>Update information in database</LI>
* <LI>Send packet QuestList to client</LI>
* @param state
* @return object
*/
public Object setState(byte state)
public void setState(byte state)
{
// set new state
_state = state;
if (_state != state)
{
_state = state;
Quest.updateQuestInDb(this);
_player.sendPacket(new QuestList(_player));
}
}
/**
* Destroy element used by quest when quest is exited
* @param repeatable
*/
public void exitQuest(boolean repeatable)
{
if (isCompleted())
{
return;
}
Quest.updateQuestInDb(this);
_player.sendPacket(new QuestList(_player));
return state;
// Say quest is completed
setState(State.COMPLETED);
// Clean registered quest items
final int[] itemIdList = getQuest().getRegisteredItemIds();
if (itemIdList != null)
{
for (int element : itemIdList)
{
takeItems(element, -1);
}
}
// If quest is repeatable, delete quest from list of quest of the player and from database (quest CAN be created again => repeatable)
if (repeatable)
{
_player.delQuestState(_questName);
Quest.deleteQuestInDb(this);
_vars = null;
}
else
{
// Otherwise, delete variables for quest and update database (quest CANNOT be created again => not repeatable)
if (_vars != null)
{
for (String var : _vars.keySet())
{
unset(var);
}
}
Quest.updateQuestInDb(this);
}
}
/**
@ -184,7 +222,7 @@ public class QuestState
* @param val : String pointing out the value of the variable for quest
* @return String (equal to parameter "val")
*/
String setInternal(String var, String val)
public String setInternal(String var, String val)
{
if (_vars == null)
{
@ -212,9 +250,8 @@ public class QuestState
* If the key doesn't exist, the couple is added/created in the database</LI>
* @param var : String indicating the name of the variable for quest
* @param val : String indicating the value of the variable for quest
* @return String (equal to parameter "val")
*/
public String set(String var, String val)
public void set(String var, String val)
{
if (_vars == null)
{
@ -258,8 +295,6 @@ public class QuestState
LOGGER.finer(_player.getName() + ", " + _questName + " cond [" + val + "] is not an integer. Value stored, but no packet was sent: " + e);
}
}
return val;
}
/**
@ -355,23 +390,19 @@ public class QuestState
* <BR>
* <U><I>Concept : </I></U> Remove the variable of quest represented by "var" from the class variable Map "vars" and from the database.
* @param var : String designating the variable for the quest to be deleted
* @return String pointing out the previous value associated with the variable "var"
*/
public String unset(String var)
public void unset(String var)
{
if (_vars == null)
{
return null;
return;
}
final String old = _vars.remove(var);
if (old != null)
{
Quest.deleteQuestVarInDb(this, var);
}
return old;
}
/**
@ -392,7 +423,7 @@ public class QuestState
/**
* Return the value of the variable of quest represented by "var"
* @param var : name of the variable of quest
* @return Object
* @return String
*/
public String getString(String var)
{
@ -517,23 +548,6 @@ public class QuestState
return true;
}
/**
* Return the level of enchantment on the weapon of the player(Done specifically for weapon SA's)
* @param itemId : ID of the item to check enchantment
* @return int
*/
public int getEnchantLevel(int itemId)
{
final ItemInstance enchanteditem = _player.getInventory().getItemByItemId(itemId);
if (enchanteditem == null)
{
return 0;
}
return enchanteditem.getEnchantLevel();
}
/**
* Give item/reward to the player
* @param itemId
@ -602,109 +616,55 @@ public class QuestState
}
/**
* Reward player with items. The amount is affected by Config.RATE_QUEST_REWARD or Config.RATE_QUEST_REWARD_ADENA.
* @param itemId : Identifier of the item.
* @param itemCount : Quantity of item to reward before applying multiplier.
* Remove items from player's inventory when talking to NPC in order to have rewards.<BR>
* <BR>
* <U><I>Actions :</I></U>
* <LI>Destroy quantity of items wanted</LI>
* <LI>Send new inventory list to player</LI>
* @param itemId : Identifier of the item
* @param count : Quantity of items to destroy
*/
public void rewardItems(int itemId, int itemCount)
public void takeItems(int itemId, int count)
{
// Get object item from player's inventory list
final ItemInstance item = _player.getInventory().getItemByItemId(itemId);
if (item == null)
{
return;
}
if (_player.isProcessingTransaction())
{
_player.cancelActiveTrade();
}
// Tests on count value in order not to have negative value
if ((count < 0) || (count > item.getCount()))
{
count = item.getCount();
}
// Destroy the quantity of items wanted
if (itemId == 57)
{
giveItems(itemId, (int) (itemCount * Config.RATE_QUESTS_REWARD), 0); // TODO: RATE_QUEST_REWARD_ADENA
_player.reduceAdena("Quest", count, _player, true);
}
else
{
giveItems(itemId, (int) (itemCount * Config.RATE_QUESTS_REWARD), 0);
}
}
/**
* Drop Quest item using Config.RATE_DROP_QUEST
* @param itemId int Item Identifier of the item to be dropped
* @param count (minCount, maxCount) : int Quantity of items to be dropped
* @param neededCount Quantity of items needed for quest
* @param dropChance int Base chance of drop, same as in droplist
* @param sound boolean indicating whether to play sound
* @return boolean indicating whether player has requested number of items
*/
public boolean dropQuestItems(int itemId, int count, int neededCount, int dropChance, boolean sound)
{
return dropQuestItems(itemId, count, count, neededCount, dropChance, sound);
}
public boolean dropQuestItems(int itemId, int minCount, int maxCount, int neededCount, int dropChance, boolean sound)
{
dropChance *= Config.RATE_DROP_QUEST / (_player.getParty() != null ? _player.getParty().getMemberCount() : 1);
final int currentCount = getQuestItemsCount(itemId);
if ((neededCount > 0) && (currentCount >= neededCount))
{
return true;
}
if (currentCount >= neededCount)
{
return true;
}
int itemCount = 0;
final int random = Rnd.get(DropData.MAX_CHANCE);
while (random < dropChance)
{
// Get the item quantity dropped
if (minCount < maxCount)
// Fix for destroyed quest items
if (item.isEquipped())
{
itemCount += Rnd.get(minCount, maxCount);
}
else if (minCount == maxCount)
{
itemCount += minCount;
}
else
{
itemCount++;
_player.getInventory().unEquipItemInBodySlotAndRecord(item.getItem().getBodyPart());
}
// Prepare for next iteration if dropChance > DropData.MAX_CHANCE
dropChance -= DropData.MAX_CHANCE;
_player.destroyItemByItemId("Quest", itemId, count, _player, true);
}
if (itemCount > 0)
{
// if over neededCount, just fill the gap
if ((neededCount > 0) && ((currentCount + itemCount) > neededCount))
{
itemCount = neededCount - currentCount;
}
// Inventory slot check
if (!_player.getInventory().validateCapacityByItemId(itemId))
{
return false;
}
// Mobius: Thread.sleep?
// just wait 3-5 seconds before the drop
// try
// {
// Thread.sleep(Rnd.get(3, 5) * 1000);
// }
// catch (InterruptedException e)
// {
// }
// Give the item to Player
_player.addItem("Quest", itemId, itemCount, _player.getTarget(), true);
if (sound)
{
playSound((currentCount + itemCount) < neededCount ? "Itemsound.quest_itemget" : "Itemsound.quest_middle");
}
}
return (neededCount > 0) && ((currentCount + itemCount) >= neededCount);
// on quests, always refresh inventory
final InventoryUpdate u = new InventoryUpdate();
u.addItem(item);
_player.sendPacket(u);
}
/**
@ -924,8 +884,113 @@ public class QuestState
return reached;
}
/**
* Reward player with items. The amount is affected by Config.RATE_QUEST_REWARD or Config.RATE_QUEST_REWARD_ADENA.
* @param itemId : Identifier of the item.
* @param itemCount : Quantity of item to reward before applying multiplier.
*/
public void rewardItems(int itemId, int itemCount)
{
if (itemId == 57)
{
giveItems(itemId, (int) (itemCount * Config.RATE_QUESTS_REWARD), 0); // TODO: RATE_QUEST_REWARD_ADENA
}
else
{
giveItems(itemId, (int) (itemCount * Config.RATE_QUESTS_REWARD), 0);
}
}
/**
* Drop Quest item using Config.RATE_DROP_QUEST
* @param itemId int Item Identifier of the item to be dropped
* @param count (minCount, maxCount) : int Quantity of items to be dropped
* @param neededCount Quantity of items needed for quest
* @param dropChance int Base chance of drop, same as in droplist
* @param sound boolean indicating whether to play sound
* @return boolean indicating whether player has requested number of items
*/
public boolean dropQuestItems(int itemId, int count, int neededCount, int dropChance, boolean sound)
{
return dropQuestItems(itemId, count, count, neededCount, dropChance, sound);
}
public boolean dropQuestItems(int itemId, int minCount, int maxCount, int neededCount, int dropChance, boolean sound)
{
dropChance *= Config.RATE_DROP_QUEST / (_player.getParty() != null ? _player.getParty().getMemberCount() : 1);
final int currentCount = getQuestItemsCount(itemId);
if ((neededCount > 0) && (currentCount >= neededCount))
{
return true;
}
if (currentCount >= neededCount)
{
return true;
}
int itemCount = 0;
final int random = Rnd.get(DropData.MAX_CHANCE);
while (random < dropChance)
{
// Get the item quantity dropped
if (minCount < maxCount)
{
itemCount += Rnd.get(minCount, maxCount);
}
else if (minCount == maxCount)
{
itemCount += minCount;
}
else
{
itemCount++;
}
// Prepare for next iteration if dropChance > DropData.MAX_CHANCE
dropChance -= DropData.MAX_CHANCE;
}
if (itemCount > 0)
{
// if over neededCount, just fill the gap
if ((neededCount > 0) && ((currentCount + itemCount) > neededCount))
{
itemCount = neededCount - currentCount;
}
// Inventory slot check
if (!_player.getInventory().validateCapacityByItemId(itemId))
{
return false;
}
// Mobius: Thread.sleep?
// just wait 3-5 seconds before the drop
// try
// {
// Thread.sleep(Rnd.get(3, 5) * 1000);
// }
// catch (InterruptedException e)
// {
// }
// Give the item to Player
_player.addItem("Quest", itemId, itemCount, _player.getTarget(), true);
if (sound)
{
playSound((currentCount + itemCount) < neededCount ? "Itemsound.quest_itemget" : "Itemsound.quest_middle");
}
}
return (neededCount > 0) && ((currentCount + itemCount) >= neededCount);
}
// TODO: More radar functions need to be added when the radar class is complete.
// BEGIN STUFF THAT WILL PROBABLY BE CHANGED
public void addRadar(int x, int y, int z)
{
_player.getRadar().addMarker(x, y, z);
@ -941,60 +1006,6 @@ public class QuestState
_player.getRadar().removeAllMarkers();
}
// END STUFF THAT WILL PROBABLY BE CHANGED
/**
* Remove items from player's inventory when talking to NPC in order to have rewards.<BR>
* <BR>
* <U><I>Actions :</I></U>
* <LI>Destroy quantity of items wanted</LI>
* <LI>Send new inventory list to player</LI>
* @param itemId : Identifier of the item
* @param count : Quantity of items to destroy
*/
public void takeItems(int itemId, int count)
{
// Get object item from player's inventory list
final ItemInstance item = _player.getInventory().getItemByItemId(itemId);
if (item == null)
{
return;
}
if (_player.isProcessingTransaction())
{
_player.cancelActiveTrade();
}
// Tests on count value in order not to have negative value
if ((count < 0) || (count > item.getCount()))
{
count = item.getCount();
}
// Destroy the quantity of items wanted
if (itemId == 57)
{
_player.reduceAdena("Quest", count, _player, true);
}
else
{
// Fix for destroyed quest items
if (item.isEquipped())
{
_player.getInventory().unEquipItemInBodySlotAndRecord(item.getItem().getBodyPart());
}
_player.destroyItemByItemId("Quest", itemId, count, _player, true);
}
// on quests, always refresh inventory
final InventoryUpdate u = new InventoryUpdate();
u.addItem(item);
_player.sendPacket(u);
}
/**
* Send a packet in order to play sound at client terminal
* @param sound
@ -1014,88 +1025,6 @@ public class QuestState
_player.addExpAndSp((int) _player.calcStat(Stats.EXPSP_RATE, exp * Config.RATE_QUESTS_REWARD, null, null), (int) _player.calcStat(Stats.EXPSP_RATE, sp * Config.RATE_QUESTS_REWARD, null, null));
}
/**
* Return random value
* @param max : max value for randomisation
* @return int
*/
public int getRandom(int max)
{
return Rnd.get(max);
}
/**
* @param loc
* @return number of ticks from GameTimeController.
*/
public int getItemEquipped(int loc)
{
return _player.getInventory().getPaperdollItemId(loc);
}
/**
* Return the number of ticks from the GameTimeController
* @return int
*/
public int getGameTicks()
{
return GameTimeController.getGameTicks();
}
/**
* Return true if quest is to exited on clean up by QuestStateManager
* @return boolean
*/
public boolean isExitQuestOnCleanUp()
{
return _isExitQuestOnCleanUp;
}
/**
* @param isExitQuestOnCleanUp
*/
public void setIsExitQuestOnCleanUp(boolean isExitQuestOnCleanUp)
{
_isExitQuestOnCleanUp = isExitQuestOnCleanUp;
}
/**
* Start a timer for quest.<BR>
* <BR>
* @param name The name of the timer. Will also be the value for event of onEvent
* @param time The millisecond value the timer will elapse
*/
public void startQuestTimer(String name, long time)
{
getQuest().startQuestTimer(name, time, null, getPlayer(), false);
}
public void startQuestTimer(String name, long time, NpcInstance npc)
{
getQuest().startQuestTimer(name, time, npc, getPlayer(), false);
}
public void startRepeatingQuestTimer(String name, long time)
{
getQuest().startQuestTimer(name, time, null, getPlayer(), true);
}
public void startRepeatingQuestTimer(String name, long time, NpcInstance npc)
{
getQuest().startQuestTimer(name, time, npc, getPlayer(), true);
}
/**
* Return the QuestTimer object with the specified name
* @param name
* @return QuestTimer<BR>
* Return null if name does not exist
*/
public QuestTimer getQuestTimer(String name)
{
return getQuest().getQuestTimer(name, null, getPlayer());
}
/**
* Add spawn for player instance Return object id of newly spawned npc
* @param npcId
@ -1106,32 +1035,11 @@ public class QuestState
return addSpawn(npcId, _player.getX(), _player.getY(), _player.getZ(), 0, false, 0);
}
public NpcInstance addSpawn(int npcId, int despawnDelay)
{
return addSpawn(npcId, _player.getX(), _player.getY(), _player.getZ(), 0, false, despawnDelay);
}
public NpcInstance addSpawn(int npcId, int x, int y, int z)
{
return addSpawn(npcId, x, y, z, 0, false, 0);
}
/**
* Add spawn for player instance Will despawn after the spawn length expires Uses player's coords and heading. Adds a little randomization in the x y coords Return object id of newly spawned npc
* @param npcId
* @param creature
* @return
*/
public NpcInstance addSpawn(int npcId, Creature creature)
{
return addSpawn(npcId, creature, true, 0);
}
public NpcInstance addSpawn(int npcId, Creature creature, int despawnDelay)
{
return addSpawn(npcId, creature.getX(), creature.getY(), creature.getZ(), creature.getHeading(), true, despawnDelay);
}
/**
* Add spawn for player instance Will despawn after the spawn length expires Return object id of newly spawned npc
* @param npcId
@ -1175,61 +1083,6 @@ public class QuestState
return getQuest().addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay);
}
public String showHtmlFile(String fileName)
{
return getQuest().showHtmlFile(getPlayer(), fileName);
}
/**
* Destroy element used by quest when quest is exited
* @param repeatable
* @return QuestState
*/
public QuestState exitQuest(boolean repeatable)
{
if (isCompleted())
{
return this;
}
// Say quest is completed
setState(State.COMPLETED);
// Clean registered quest items
final int[] itemIdList = getQuest().getRegisteredItemIds();
if (itemIdList != null)
{
for (int element : itemIdList)
{
takeItems(element, -1);
}
}
// If quest is repeatable, delete quest from list of quest of the player and from database (quest CAN be created again => repeatable)
if (repeatable)
{
_player.delQuestState(_questName);
Quest.deleteQuestInDb(this);
_vars = null;
}
else
{
// Otherwise, delete variables for quest and update database (quest CANNOT be created again => not repeatable)
if (_vars != null)
{
for (String var : _vars.keySet())
{
unset(var);
}
}
Quest.updateQuestInDb(this);
}
return this;
}
public void showQuestionMark(int number)
{
_player.sendPacket(new TutorialShowQuestionMark(number));
@ -1239,40 +1092,4 @@ public class QuestState
{
_player.sendPacket(new PlaySound(2, voice, false, 0, _player.getLocation(), 0));
}
public void showTutorialHTML(String html)
{
String text = HtmCache.getInstance().getHtm("data/scripts/ai/others/Tutorial/" + html);
if (text == null)
{
LOGGER.warning("missing html page data/scripts/ai/others/Tutorial/" + html);
text = "<html><body>File data/scripts/ai/others/Tutorial/" + html + " not found or file is empty.</body></html>";
}
_player.sendPacket(new TutorialShowHtml(text));
}
public void closeTutorialHtml()
{
_player.sendPacket(TutorialCloseHtml.STATIC_PACKET);
}
public void onTutorialClientEvent(int number)
{
_player.sendPacket(new TutorialEnableClientEvent(number));
}
public void dropItem(MonsterInstance npc, PlayerInstance player, int itemId, int count)
{
npc.DropItem(player, itemId, count);
}
public NpcInstance getNpc()
{
if (_player.getTarget() instanceof NpcInstance)
{
return (NpcInstance) _player.getTarget();
}
return null;
}
}

View File

@ -24,96 +24,58 @@ import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
public class QuestTimer
{
public class ScheduleTimerTask implements Runnable
{
@Override
public void run()
{
if (!_isActive)
{
return;
}
try
{
if (!_isRepeating)
{
cancel();
}
_quest.notifyEvent(_name, _npc, _player);
}
catch (Throwable t)
{
}
}
}
boolean _isActive = true;
final String _name;
final Quest _quest;
final NpcInstance _npc;
final PlayerInstance _player;
final boolean _isRepeating;
private ScheduledFuture<?> _schedular;
private final String _name;
private final Quest _quest;
private final NpcInstance _npc;
private final PlayerInstance _player;
private final boolean _isRepeating;
private ScheduledFuture<?> _scheduler;
public QuestTimer(Quest quest, String name, long time, NpcInstance npc, PlayerInstance player, boolean repeating)
{
_name = name;
_quest = quest;
_player = player;
_name = name;
_npc = npc;
_player = player;
_isRepeating = repeating;
if (repeating)
{
_schedular = ThreadPool.scheduleAtFixedRate(new ScheduleTimerTask(), time, time); // Prepare auto end task
_scheduler = ThreadPool.scheduleAtFixedRate(new ScheduleTimerTask(), time, time); // Prepare auto end task
}
else
{
_schedular = ThreadPool.schedule(new ScheduleTimerTask(), time); // Prepare auto end task
_scheduler = ThreadPool.schedule(new ScheduleTimerTask(), time); // Prepare auto end task
}
}
public QuestTimer(Quest quest, String name, long time, NpcInstance npc, PlayerInstance player)
{
this(quest, name, time, npc, player, false);
}
public QuestTimer(QuestState qs, String name, long time)
{
this(qs.getQuest(), name, time, null, qs.getPlayer(), false);
}
public void cancel()
{
cancel(true);
}
public void cancel(boolean removeTimer)
{
_isActive = false;
if (_schedular != null)
if (_scheduler != null)
{
_schedular.cancel(false);
_scheduler.cancel(false);
_scheduler = null;
}
if (removeTimer)
{
_quest.removeQuestTimer(this);
}
_quest.removeQuestTimer(this);
}
// public method to compare if this timer matches with the key attributes passed.
// a quest and a name are required.
// null npc or player act as wildcards for the match
public boolean isMatch(Quest quest, String name, NpcInstance npc, PlayerInstance player)
/**
* public method to compare if this timer matches with the key attributes passed.
* @param quest : Quest instance to which the timer is attached
* @param name : Name of the timer
* @param npc : Npc instance attached to the desired timer (null if no npc attached)
* @param player : Player instance attached to the desired timer (null if no player attached)
* @return boolean
*/
public boolean equals(Quest quest, String name, NpcInstance npc, PlayerInstance player)
{
if ((quest == null) || (name == null))
if ((quest == null) || (quest != _quest))
{
return false;
}
if ((quest != _quest) || (name.compareToIgnoreCase(_name) != 0))
if ((name == null) || !name.equals(_name))
{
return false;
}
@ -121,39 +83,28 @@ public class QuestTimer
return (npc == _npc) && (player == _player);
}
public boolean getIsActive()
{
return _isActive;
}
public boolean getIsRepeating()
{
return _isRepeating;
}
public Quest getQuest()
{
return _quest;
}
public String getName()
{
return _name;
}
public NpcInstance getNpc()
{
return _npc;
}
public PlayerInstance getPlayer()
{
return _player;
}
@Override
public String toString()
{
return _name;
}
public class ScheduleTimerTask implements Runnable
{
@Override
public void run()
{
if (_scheduler == null)
{
return;
}
if (!_isRepeating)
{
cancel();
}
_quest.notifyEvent(_name, _npc, _player);
}
}
}