Chronicle 4 branch.

This commit is contained in:
MobiusDev
2017-07-19 21:24:06 +00:00
parent 9a69bec286
commit 3a0bf3539a
13496 changed files with 641683 additions and 0 deletions

View File

View File

View File

@@ -0,0 +1,100 @@
# # # # # # # # # # #
# Chest AI implementation.
# Written by Fulminus
# # # # # # # # # # #
import sys
from com.l2jmobius.gameserver.ai import CtrlIntention
from com.l2jmobius.gameserver.model.quest import QuestState
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
from com.l2jmobius.util import Rnd;
SKILL_DELUXE_KEY = 2229
#Base chance for BOX to be opened
BASE_CHANCE = 100
# Percent to decrease base chance when grade of DELUXE key not match
LEVEL_DECREASE = 40
# Chance for a chest to actually be a BOX (as opposed to being a mimic).
IS_BOX = 40
class chests(JQuest) :
# init function. Add in here variables that you'd like to be inherited by subclasses (if any)
def __init__(self,id,name,descr):
# firstly, don't forget to call the parent constructor to prepare the event triggering
# mechanisms etc.
JQuest.__init__(self,id,name,descr)
self.chests = [13100,13101,13102,13103,13104,13105,13106,13107,13108,13109, \
13110,13111,13112,13113,13114,13115,13116,13117,13118,13119, \
13120,13121,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810, \
1671,1694,1717,1740,1763,1786,13213,13215,13217,13219,13221,13223, \
1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822]
for i in self.chests :
self.addSkillSeeId(i)
self.addAttackId(i)
def onSkillSee (self,npc,player,skill,targets,isPet):
if npc not in targets :
return
npcId = npc.getNpcId()
skillId = skill.getId()
skillLevel= skill.getLevel()
# check if the npc and skills used are valid for this script. Exit if invalid.
if npcId not in self.chests :
return
# if this has already been interacted, no further ai decisions are needed
# if it's the first interaction, check if this is a box or mimic
if not npc.isInteracted() :
npc.setInteracted()
if Rnd.get(100) < IS_BOX :
# if it's a box, either it will be successfully openned by a proper key, or instantly disappear
if skillId == SKILL_DELUXE_KEY :
# check the chance to open the box
keyLevelNeeded = int(npc.getLevel()/10)
levelDiff = keyLevelNeeded - skillLevel
if levelDiff < 0 :
levelDiff = levelDiff * (-1)
chance = BASE_CHANCE - levelDiff * LEVEL_DECREASE
# success, pretend-death with rewards: npc.reduceCurrentHp(99999999, player)
if Rnd.get(100) < chance :
npc.setMustRewardExpSp(False)
npc.setSpecialDrop();
npc.reduceCurrentHp(99999999, player)
return
# used a skill other than chest-key, or used a chest-key but failed to open: disappear with no rewards
npc.onDecay()
else :
attacker = player
if npc.getAttackByList().contains(player.getPet()):
attacker = player.getPet()
npc.setRunning()
npc.addDamageHate(attacker,0,999)
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker)
return
def onAttack(self,npc,player,damage,isPet) :
npcId = npc.getNpcId()
# check if the npc and skills used are valid for this script. Exit if invalid.
if npcId not in self.chests :
return
# if this was a mimic, set the target, start the skills and become agro
if not npc.isInteracted() :
npc.setInteracted()
if Rnd.get(100) < IS_BOX :
npc.onDecay()
else : # if this weren't a box, upon interaction start the mimic behaviors...
# todo: perhaps a self-buff (skill id 4245) with random chance goes here?
attacker = player
if isPet:
attacker = player.getPet()
npc.setRunning()
npc.addDamageHate(attacker,0,(damage*100)/(npc.getLevel()+7))
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker)
return
# now call the constructor (starts up the ai)
QUEST = chests(-1,"chests","ai")

View File

@@ -0,0 +1,32 @@
import sys
from com.l2jmobius.gameserver.ai import CtrlIntention
from com.l2jmobius.gameserver.datatables import SkillTable
from com.l2jmobius.gameserver.model.quest import Quest as JQuest
from com.l2jmobius.util import Rnd
class trees(JQuest) :
def __init__(self,id,name,descr):
JQuest.__init__(self,id,name,descr)
def onKill (self,npc,player,isPet):
npcId = npc.getNpcId()
if npcId in range(5185,5189) :
for x in xrange(20):
newNpc = self.addSpawn(5189,npc.getX(),npc.getY(),npc.getZ(),0,False,30000)
killer = player
if isPet :
killer = player.getPet()
newNpc.setRunning()
newNpc.addDamageHate(killer,0,999)
newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, killer)
if Rnd.get(2) :
skill = SkillTable.getInstance().getInfo(4243,1)
if skill != None and killer:
skill.getEffects(newNpc, killer)
return
QUEST = trees(-1,"fairy_trees","ai")
for i in range(5185,5189):
QUEST.addKillId(i)

View File

@@ -0,0 +1,229 @@
# Growth-capable mobs: Polymorphing upon successful feeding.
# Written by Fulminus
# # # # # # # # # # #
import sys
from com.l2jmobius.gameserver.ai import CtrlIntention
from com.l2jmobius.gameserver.datatables import NpcTable
from com.l2jmobius.gameserver.idfactory import IdFactory
from com.l2jmobius.gameserver.model.actor.instance import L2TamedBeastInstance
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
from com.l2jmobius.gameserver.network.serverpackets import CreatureSay
from com.l2jmobius.gameserver.network.serverpackets import SocialAction
from com.l2jmobius.util import Rnd;
GOLDEN_SPICE = 6643
CRYSTAL_SPICE = 6644
SKILL_GOLDEN_SPICE = 2188
SKILL_CRYSTAL_SPICE = 2189
foodSkill = {GOLDEN_SPICE:SKILL_GOLDEN_SPICE, CRYSTAL_SPICE:SKILL_CRYSTAL_SPICE}
class feedable_beasts(JQuest) :
# init function. Add in here variables that you'd like to be inherited by subclasses (if any)
def __init__(self,id,name,descr):
# firstly, don't forget to call the parent constructor to prepare the event triggering
# mechanisms etc.
JQuest.__init__(self,id,name,descr)
# DEFINE MEMBER VARIABLES FOR THIS AI
# all mobs that can eat...
self.tamedBeasts = range(12783,12789)
self.feedableBeasts = range(1451,1508)+ self.tamedBeasts
# all mobs that grow by eating
# mobId: current_growth_level, {food: [list of possible mobs[possible sublist of tamed pets]]}, chance of growth
self.growthCapableMobs = {
# Alpen Kookabura
1451: [0,{GOLDEN_SPICE:[1452,1453, 1454, 1455],CRYSTAL_SPICE:[1456,1457, 1458, 1459]},100],
1452: [1,{GOLDEN_SPICE:[1460,1462],CRYSTAL_SPICE:[]},40],
1453: [1,{GOLDEN_SPICE:[1461,1463],CRYSTAL_SPICE:[]},40],
1454: [1,{GOLDEN_SPICE:[1460,1462],CRYSTAL_SPICE:[]},40],
1455: [1,{GOLDEN_SPICE:[1461,1463],CRYSTAL_SPICE:[]},40],
1456: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1464,1466]},40],
1457: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1465,1467]},40],
1458: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1464,1466]},40],
1459: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1465,1467]},40],
1460: [2,{GOLDEN_SPICE:[[1468,1469],[12783,12784]],CRYSTAL_SPICE:[]},25],
1461: [2,{GOLDEN_SPICE:[[1468,1469],[12783,12784]],CRYSTAL_SPICE:[]},25],
1462: [2,{GOLDEN_SPICE:[[1468,1469],[12783,12784]],CRYSTAL_SPICE:[]},25],
1463: [2,{GOLDEN_SPICE:[[1468,1469],[12783,12784]],CRYSTAL_SPICE:[]},25],
1464: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1468,1469],[12783,12784]]},25],
1465: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1468,1469],[12783,12784]]},25],
1466: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1468,1469],[12783,12784]]},25],
1467: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1468,1469],[12783,12784]]},25],
# Alpen Buffalo
1470: [0,{GOLDEN_SPICE:[1471,1472, 1473, 1474],CRYSTAL_SPICE:[1475,1476, 1477, 1478]},100],
1471: [1,{GOLDEN_SPICE:[1479,1481],CRYSTAL_SPICE:[]},40],
1472: [1,{GOLDEN_SPICE:[1481,1482],CRYSTAL_SPICE:[]},40],
1473: [1,{GOLDEN_SPICE:[1479,1481],CRYSTAL_SPICE:[]},40],
1474: [1,{GOLDEN_SPICE:[1480,1482],CRYSTAL_SPICE:[]},40],
1475: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1483,1485]},40],
1476: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1484,1486]},40],
1477: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1483,1485]},40],
1478: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1484,1486]},40],
1479: [2,{GOLDEN_SPICE:[[1487,1488],[12785,12786]],CRYSTAL_SPICE:[]},25],
1480: [2,{GOLDEN_SPICE:[[1487,1488],[12785,12786]],CRYSTAL_SPICE:[]},25],
1481: [2,{GOLDEN_SPICE:[[1487,1488],[12785,12786]],CRYSTAL_SPICE:[]},25],
1482: [2,{GOLDEN_SPICE:[[1487,1488],[12785,12786]],CRYSTAL_SPICE:[]},25],
1483: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1487,1488],[12785,12786]]},25],
1484: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1487,1488],[12785,12786]]},25],
1485: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1487,1488],[12785,12786]]},25],
1486: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1487,1488],[12785,12786]]},25],
# Alpen Cougar
1489: [0,{GOLDEN_SPICE:[1490,1491, 1492, 1493],CRYSTAL_SPICE:[1494,1495, 1496, 1497]},100],
1490: [1,{GOLDEN_SPICE:[1498,1500],CRYSTAL_SPICE:[]},40],
1491: [1,{GOLDEN_SPICE:[1499,1501],CRYSTAL_SPICE:[]},40],
1492: [1,{GOLDEN_SPICE:[1498,1500],CRYSTAL_SPICE:[]},40],
1493: [1,{GOLDEN_SPICE:[1499,1501],CRYSTAL_SPICE:[]},40],
1494: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1502,1504]},40],
1495: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1503,1505]},40],
1496: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1502,1504]},40],
1497: [1,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[1503,1505]},40],
1498: [2,{GOLDEN_SPICE:[[1506,1507],[12787,12788]],CRYSTAL_SPICE:[]},25],
1499: [2,{GOLDEN_SPICE:[[1506,1507],[12787,12788]],CRYSTAL_SPICE:[]},25],
1500: [2,{GOLDEN_SPICE:[[1506,1507],[12787,12788]],CRYSTAL_SPICE:[]},25],
1501: [2,{GOLDEN_SPICE:[[1506,1507],[12787,12788]],CRYSTAL_SPICE:[]},25],
1502: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1506,1507],[12787,12788]]},25],
1503: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1506,1507],[12787,12788]]},25],
1504: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1506,1507],[12787,12788]]},25],
1505: [2,{GOLDEN_SPICE:[],CRYSTAL_SPICE:[[1506,1507],[12787,12788]]},25]
}
self.Text = [["What did you just do to me?","You want to tame me, huh?","Do not give me this. Perhaps you will be in danger.","Bah bah. What is this unpalatable thing?","My belly has been complaining. This hit the spot.","What is this? Can I eat it?","You don't need to worry about me.","Delicious food, thanks.","I am starting to like you!","Gulp"],
["I do not think you have given up on the idea of taming me.","That is just food to me. Perhaps I can eat your hand too.","Will eating this make me fat? Ha ha","Why do you always feed me?","Do not trust me. I may betray you"],
["Destroy","Look what you have done!","Strange feeling...! Evil intentions grow in my heart...!","It is happenning!","This is sad...Good is sad...!"]]
self.feedInfo = {} # : feedInfo[objectId of mob] = objectId of player feeding it
for i in self.feedableBeasts :
self.addSkillSeeId(i)
self.addKillId(i)
def spawnNext(self, npc, growthLevel,player,food) :
st = player.getQuestState("feedable_beasts")
npcId = npc.getNpcId()
nextNpcId = 0
# find the next mob to spawn, based on the current npcId, growthlevel, and food.
if growthLevel == 2:
rand = Rnd.get(2)
# if tamed, the mob that will spawn depends on the class type (fighter/mage) of the player!
if rand == 1 :
if player.getClassId().isMage() :
nextNpcId = self.growthCapableMobs[npcId][1][food][1][1]
else :
nextNpcId = self.growthCapableMobs[npcId][1][food][1][0]
# if not tamed, there is a small chance that have "mad cow" disease.
# that is a stronger-than-normal animal that attacks its feeder
else :
if Rnd.get(5) == 0 :
nextNpcId = self.growthCapableMobs[npcId][1][food][0][1]
else :
nextNpcId = self.growthCapableMobs[npcId][1][food][0][0]
# all other levels of growth are straight-forward
else :
nextNpcId = self.growthCapableMobs[npcId][1][food][Rnd.get(len(self.growthCapableMobs[npcId][1][food]))]
# remove the feedinfo of the mob that got despawned, if any
if self.feedInfo.has_key(npc.getObjectId()) :
if self.feedInfo[npc.getObjectId()] == player.getObjectId() :
self.feedInfo.pop(npc.getObjectId())
# despawn the old mob
if self.growthCapableMobs[npcId][0] == 0 :
npc.onDecay()
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 nextNpcId in self.tamedBeasts :
oldTrained = player.getTrainedBeast()
if oldTrained :
oldTrained.doDespawn()
template = NpcTable.getInstance().getTemplate(nextNpcId)
nextNpc = L2TamedBeastInstance(IdFactory.getInstance().getNextId(), template, player, foodSkill[food], npc.getX(), npc.getY(), npc.getZ())
nextNpc.setRunning()
objectId = nextNpc.getObjectId()
st = player.getQuestState("20_BringUpWithLove")
if st :
if Rnd.get(100) <= 5 and st.getQuestItemsCount(7185) == 0 :
st.giveItems(7185,1) #if player has quest 20 going, give quest item
st.set("cond","2") #it's easier to hardcode it in here than to try and repeat this stuff in the quest
# also, perform a rare random chat
rand = Rnd.get(20)
if rand > 4 : pass
elif rand == 0 : npc.broadcastPacket(CreatureSay(objectId,0,nextNpc.getName(), player.getName()+", will you show me your hideaway?"))
elif rand == 1 : npc.broadcastPacket(CreatureSay(objectId,0,nextNpc.getName(), player.getName()+", whenever I look at spice, I think about you."))
elif rand == 2 : npc.broadcastPacket(CreatureSay(objectId,0,nextNpc.getName(), player.getName()+", you do not need to return to the village. I will give you strength"))
elif rand == 3 : npc.broadcastPacket(CreatureSay(objectId,0,nextNpc.getName(), "Thanks, "+player.getName()+". I hope I can help you"))
elif rand == 4 : npc.broadcastPacket(CreatureSay(objectId,0,nextNpc.getName(), player.getName()+", what can I do to help you?"))
# 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?!)
else :
# spawn the new mob
nextNpc = self.addSpawn(nextNpcId,npc)
# register the player in the feedinfo for the mob that just spawned
self.feedInfo[nextNpc.getObjectId()] = player.getObjectId()
nextNpc.setRunning()
nextNpc.addDamageHate(player,0,99999)
nextNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player)
def onSkillSee (self,npc,player,skill,targets,isPet):
if npc not in targets :
return
# gather some values on local variables
npcId = npc.getNpcId()
skillId = skill.getId()
# check if the npc and skills used are valid for this script. Exit if invalid.
if npcId not in self.feedableBeasts : return
if skillId not in [SKILL_GOLDEN_SPICE,SKILL_CRYSTAL_SPICE] :
return
# first gather some values on local variables
objectId = npc.getObjectId()
growthLevel = 3 # if a mob is in feedableBeasts but not in growthCapableMobs, then it's at max growth (3)
if self.growthCapableMobs.has_key(npcId) :
growthLevel = self.growthCapableMobs[npcId][0]
# 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) and self.feedInfo.has_key(objectId):
return
else :
self.feedInfo[objectId] = player.getObjectId()
food = 0
if skillId == SKILL_GOLDEN_SPICE :
food = GOLDEN_SPICE
elif skillId == SKILL_CRYSTAL_SPICE :
food = CRYSTAL_SPICE
# display the social action of the beast eating the food.
npc.broadcastPacket(SocialAction(objectId,2))
# if this pet can't grow, it's all done.
if npcId in self.growthCapableMobs.keys() :
# do nothing if this mob doesn't eat the specified food (food gets consumed but has no effect).
if len(self.growthCapableMobs[npcId][1][food]) == 0 :
return
# rare random talk...
if Rnd.get(20) == 0 :
npc.broadcastPacket(CreatureSay(objectId,0,npc.getName(),self.Text[growthLevel][Rnd.get(len(self.Text[growthLevel]))]))
if growthLevel > 0 :
# 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).
if self.feedInfo[objectId] != player.getObjectId() : return
# Polymorph the mob, with a certain chance, given its current growth level
if Rnd.get(100) < self.growthCapableMobs[npcId][2] :
self.spawnNext(npc, growthLevel,player,food)
elif npcId in self.tamedBeasts :
if skillId == npc.getFoodType() :
npc.onReceiveFood()
mytext = ["Refills! Yeah!","I am such a gluttonous beast, it is embarrassing! Ha ha",
"Your cooperative feeling has been getting better and better.",
"I will help you!",
"The weather is really good. Wanna go for a picnic?",
"I really like you! This is tasty...",
"If you do not have to leave this place, then I can help you.",
"What can I help you with?",
"I am not here only for food!",
"Yam, yam, yam, yam, yam!"]
npc.broadcastPacket(CreatureSay(objectId,0,npc.getName(),mytext[Rnd.get(len(mytext))]))
return
def onKill (self,npc,player,isPet):
# remove the feedinfo of the mob that got killed, if any
if self.feedInfo.has_key(npc.getObjectId()) :
self.feedInfo.pop(npc.getObjectId())
# now call the constructor (starts up the ai)
QUEST = feedable_beasts(-1,"feedable_beasts","ai")

View File

@@ -0,0 +1,38 @@
import sys
from com.l2jmobius.gameserver.ai import CtrlIntention
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
# Angel spawns...when one of the angels in the keys dies, the other angel will spawn.
class polymorphing_angel(JQuest) :
# init function. Add in here variables that you'd like to be inherited by subclasses (if any)
def __init__(self,id,name,descr):
self.AngelSpawns ={
830:859,
1067:1068,
1062:1063,
831:860,
1070:1071
}
# finally, don't forget to call the parent constructor to prepare the event triggering
# mechanisms etc.
JQuest.__init__(self,id,name,descr)
def onKill (self,npc,player,isPet):
npcId = npc.getNpcId()
if self.AngelSpawns.has_key(npcId) :
newNpc = self.addSpawn(self.AngelSpawns[npcId],npc)
killer = player
if isPet :
killer = player.getPet()
newNpc.setRunning()
newNpc.addDamageHate(killer,0,99999)
newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, killer)
return
# now call the constructor (starts up the ai)
QUEST = polymorphing_angel(-1,"polymorphing_angel","ai")
for i in QUEST.AngelSpawns.keys() :
QUEST.addKillId(i)

View File

@@ -0,0 +1,49 @@
import sys
from com.l2jmobius.gameserver.ai import CtrlIntention
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
from com.l2jmobius.util import Rnd
class polymorphing_onAttack(JQuest) :
# init function. Add in here variables that you'd like to be inherited by subclasses (if any)
def __init__(self,id,name,descr):
self.MobSpawns ={
1258: [1259, 100, 100], #Fallen Orc Shaman -> Sharp Talon Tiger
1261: [1262, 100, 20], #Ol Mahum Transcender 1st stage
1262: [1263, 100, 10], #Ol Mahum Transcender 2st stage
1263: [1264, 100, 5], #Ol Mahum Transcender 3rd stage
1265: [1271, 100, 33], #Cave Ant Larva -> Cave Ant
1266: [1269, 100, 100], #Cave Ant Larva -> Cave Ant (always polymorphs)
1267: [1270, 100, 100], #Cave Ant Larva -> Cave Ant Soldier (always polymorphs)
1271: [1272, 66, 10], #Cave Ant -> Cave Ant Soldier
1272: [1273, 33, 5], #Cave Ant Soldier -> Cave Noble Ant
1521: [1522, 100, 30], #Claws of Splendor -> Claws of Splendor Panther
1524: [1525, 100, 30], #Blade of Splendor -> Blade of Splendor 2nd
1527: [1528, 100, 30], #Anger of Splendor -> Anger of Splendor Panther
1533: [1534, 100, 30], #Alliance of Splendor -> Alliance of Splendor Panther
1537: [1538, 100, 30] #Fang of Splendor -> Fang of Splendor Panther
}
# finally, don't forget to call the parent constructor to prepare the event triggering
# mechanisms etc.
JQuest.__init__(self,id,name,descr)
def onAttack(self,npc,player,damage,isPet) :
if npc.isVisible() and not npc.isDead() :
newId,hpRate,chance = self.MobSpawns[npc.getNpcId()]
if npc.getCurrentHp() <= (npc.getMaxHp() * hpRate/100.0) and Rnd.get(100) < chance :
# It's the only way for 1st level mob to respawn after it's deleted
npc.doDie(npc)
npc.deleteMe()
newNpc = self.addSpawn(newId,npc)
killer = player
if isPet :
killer = player.getPet()
newNpc.setRunning()
newNpc.addDamageHate(killer,0,99999)
newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, killer)
return
# now call the constructor (starts up the ai)
QUEST = polymorphing_onAttack(-1,"polymorphing_onAttack","ai")
for i in QUEST.MobSpawns.keys() :
QUEST.addAttackId(i)

View File

@@ -0,0 +1,246 @@
/*
* 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.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2CharPosition;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.model.zone.type.L2BossZone;
import com.l2jmobius.gameserver.network.serverpackets.Earthquake;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SpecialCamera;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.util.Rnd;
/**
* Antharas AI
* @author Emperorc
*/
public class Antharas extends Quest
{
private static final int ANTHARAS = 12211;
// Antharas Status Tracking :
private static final byte DORMANT = 0; // Antharas is spawned and no one has entered yet. Entry is unlocked
private static final byte WAITING = 1; // Antharas is spawned and someone has entered, triggering a 30 minute window for additional people to enter before he unleashes his attack. Entry is unlocked
private static final byte FIGHTING = 2; // Antharas is engaged in battle, annihilating his foes. Entry is locked
private static final byte DEAD = 3; // Antharas has been killed. Entry is locked
private static long _LastAction = 0;
private static L2BossZone _Zone;
// Boss: Antharas
public Antharas(int id, String name, String descr)
{
super(id, name, descr);
final int[] mob =
{
ANTHARAS
};
registerMobs(mob);
_Zone = GrandBossManager.getInstance().getZone(179700, 113800, -7709);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(ANTHARAS);
final int status = GrandBossManager.getInstance().getBossStatus(ANTHARAS);
if (status == DEAD)
{
// load the unlock date and time for antharas from DB
// if antharas is locked until a certain time, mark it so and start the unlock timer
// the unlock time has not yet expired. Mark Antharas as currently locked. Setup a timer
// to fire at the correct time (calculate the time between now and the unlock time,
// setup a timer to fire after that many msec)
final long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
if (temp > 0)
{
startQuestTimer("antharas_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Immediately spawn antharas in his cave.
// also, the status needs to be changed to DORMANT
final L2GrandBossInstance antharas = (L2GrandBossInstance) addSpawn(ANTHARAS, 185708, 114298, -8221, 32768, false, 0);
GrandBossManager.getInstance().setBossStatus(ANTHARAS, DORMANT);
antharas.broadcastPacket(new Earthquake(185708, 114298, -8221, 20, 10));
GrandBossManager.getInstance().addBoss(antharas);
}
}
else
{
final int loc_x = info.getInteger("loc_x");
final int loc_y = info.getInteger("loc_y");
final int loc_z = info.getInteger("loc_z");
final int heading = info.getInteger("heading");
final int hp = info.getInteger("currentHP");
final int mp = info.getInteger("currentMP");
final L2GrandBossInstance antharas = (L2GrandBossInstance) addSpawn(ANTHARAS, loc_x, loc_y, loc_z, heading, false, 0);
GrandBossManager.getInstance().addBoss(antharas);
antharas.setCurrentHpMp(hp, mp);
if (status == WAITING)
{
// Start timer to lock entry after 30 minutes
startQuestTimer("waiting", 1800000, antharas, null);
}
else if (status == FIGHTING)
{
_LastAction = System.currentTimeMillis();
// Start repeating timer to check for inactivity
startQuestTimer("antharas_despawn", 60000, antharas, null, true);
}
}
}
@Override
public String onAdvEvent(String event, L2NpcInstance npc, L2PcInstance player)
{
if (npc != null)
{
long temp = 0;
if (event.equalsIgnoreCase("waiting"))
{
npc.teleToLocation(185452, 114835, -8221);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(181911, 114835, -7678, 0));
startQuestTimer("antharas_has_arrived", 2000, npc, null, true);
npc.broadcastPacket(new PlaySound(1, "BS02_A", 1, npc.getObjectId(), 185452, 114835, -8221));
GrandBossManager.getInstance().setBossStatus(ANTHARAS, FIGHTING);
}
else if (event.equalsIgnoreCase("camera_1"))
{
startQuestTimer("camera_2", 3000, npc, null);
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 700, 13, -19, 0, 20000, 0, 0, 1, 0));
}
else if (event.equalsIgnoreCase("camera_2"))
{
startQuestTimer("camera_3", 10000, npc, null);
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 700, 13, 0, 6000, 20000, 0, 0, 1, 0));
}
else if (event.equalsIgnoreCase("camera_3"))
{
startQuestTimer("camera_4", 200, npc, null);
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 3700, 0, -3, 0, 10000, 0, 0, 1, 0));
}
else if (event.equalsIgnoreCase("camera_4"))
{
startQuestTimer("camera_5", 10800, npc, null);
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 1100, 0, -3, 22000, 30000, 0, 0, 1, 0));
}
else if (event.equalsIgnoreCase("camera_5"))
{
startQuestTimer("antharas_despawn", 60000, npc, null, true);
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 1100, 0, -3, 300, 7000, 0, 0, 1, 0));
npc.setIsImmobilized(false);
_LastAction = System.currentTimeMillis();
}
else if (event.equalsIgnoreCase("antharas_despawn"))
{
temp = (System.currentTimeMillis() - _LastAction);
if (temp > 1800000)
{
npc.teleToLocation(185708, 114298, -8221);
GrandBossManager.getInstance().setBossStatus(ANTHARAS, DORMANT);
npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp());
_Zone.oustAllPlayers();
cancelQuestTimer("antharas_despawn", npc, null);
}
}
else if (event.equalsIgnoreCase("antharas_has_arrived"))
{
final int dx = Math.abs(npc.getX() - 181911);
final int dy = Math.abs(npc.getY() - 114835);
if ((dx <= 50) && (dy <= 50))
{
startQuestTimer("camera_1", 2000, npc, null);
npc.getSpawn().setLocx(181911);
npc.getSpawn().setLocy(114835);
npc.getSpawn().setLocz(-7678);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
npc.setIsImmobilized(true);
cancelQuestTimer("antharas_has_arrived", npc, null);
}
else
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(181911, 114835, -7678, 0));
}
}
else if (event.equalsIgnoreCase("spawn_cubes"))
{
addSpawn(12324, 177615, 114941, -7709, 0, false, 900000);
final int radius = 1500;
for (int i = 0; i < 20; i++)
{
final int x = (int) (radius * Math.cos(i * .331)); // .331~2pi/19
final int y = (int) (radius * Math.sin(i * .331));
addSpawn(31859, 177615 + x, 114941 + y, -7709, 0, false, 900000);
}
cancelQuestTimer("antharas_despawn", npc, null);
startQuestTimer("remove_players", 900000, null, null);
}
}
else
{
if (event.equalsIgnoreCase("antharas_unlock"))
{
final L2GrandBossInstance antharas = (L2GrandBossInstance) addSpawn(ANTHARAS, 185708, 114298, -8221, 32768, false, 0);
GrandBossManager.getInstance().addBoss(antharas);
GrandBossManager.getInstance().setBossStatus(ANTHARAS, DORMANT);
antharas.broadcastPacket(new Earthquake(185708, 114298, -8221, 20, 10));
}
else if (event.equalsIgnoreCase("remove_players"))
{
_Zone.oustAllPlayers();
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
{
_LastAction = System.currentTimeMillis();
if (GrandBossManager.getInstance().getBossStatus(ANTHARAS) != FIGHTING)
{
attacker.teleToLocation(82480, 149087, -3350, true);
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
{
npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 1200, 20, -10, 0, 13000, 0, 0, 1, 0));
npc.broadcastPacket(new PlaySound(1, "BS01_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
startQuestTimer("spawn_cubes", 10000, npc, null);
GrandBossManager.getInstance().setBossStatus(ANTHARAS, DEAD);
final long respawnTime = ((192 + Rnd.get(145)) * 3600000);
startQuestTimer("antharas_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
final StatsSet info = GrandBossManager.getInstance().getStatsSet(ANTHARAS);
info.set("respawn_time", (System.currentTimeMillis() + respawnTime));
GrandBossManager.getInstance().setStatsSet(ANTHARAS, info);
return super.onKill(npc, killer, isPet);
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new Antharas(-1, "antharas", "ai");
}
}

View File

@@ -0,0 +1,697 @@
/*
* 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_FOLLOW;
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Effect;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.model.quest.QuestState;
import com.l2jmobius.gameserver.model.quest.QuestTimer;
import com.l2jmobius.gameserver.model.quest.State;
import com.l2jmobius.gameserver.model.zone.type.L2BossZone;
import com.l2jmobius.gameserver.network.serverpackets.Earthquake;
import com.l2jmobius.gameserver.network.serverpackets.MoveToPawn;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.gameserver.util.Util;
import com.l2jmobius.util.Rnd;
import javolution.util.FastList;
/**
* Baium AI Note1: if the server gets rebooted while players are still fighting Baium, there is no lock, but players also lose their ability to wake baium up. However, should another person enter the room and wake him up, the players who had stayed inside may join the raid. This can be helpful for
* players who became victims of a reboot (they only need 1 new player to enter and wake up baium) and is not too exploitable since any player wishing to exploit it would have to suffer 5 days of being parked in an empty room. Note2: Neither version of Baium should be a permanent spawn. This script
* is fully capable of spawning the statue-version when the lock expires and switching it to the mob version promptly. Additional notes ( source http://aleenaresron.blogspot.com/2006_08_01_archive.html ): * Baium only first respawns five days after his last death. And from those five days he will
* respawn within 1-8 hours of his last death. So, you have to know his last time of death. * If by some freak chance you are the only one in Baium's chamber and NO ONE comes in [ha, ha] you or someone else will have to wake Baium. There is a good chance that Baium will automatically kill whoever
* wakes him. There are some people that have been able to wake him and not die, however if you've already gone through the trouble of getting the bloody fabric and camped him out and researched his spawn time, are you willing to take that chance that you'll wake him and not be able to finish your
* quest? Doubtful. [ this powerful attack vs the player who wakes him up is NOT yet implemented here] * once someone starts attacking Baium no one else can port into the chamber where he is. Unlike with the other raid bosses, you can just show up at any time as long as you are there when they die.
* Not true with Baium. Once he gets attacked, the port to Baium closes. byebye, see you in 5 days. If nobody attacks baium for 30 minutes, he auto-despawns and unlocks the vortex
* @author Fulminus version 0.1
*/
public class Baium extends Quest
{
private L2Character _target;
private L2Skill _skill;
private static final int STONE_BAIUM = 12535;
private static final int ANGELIC_VORTEX = 12571;
private static final int LIVE_BAIUM = 12372;
private static final int ARCHANGEL = 12373;
// Baium status tracking
private static final byte ASLEEP = 0; // baium is in the stone version, waiting to be woken up. Entry is unlocked
private static final byte AWAKE = 1; // baium is awake and fighting. Entry is locked.
private static final byte DEAD = 2; // baium has been killed and has not yet spawned. Entry is locked
// fixed archangel spawnloc
private final static int ANGEL_LOCATION[][] =
{
{
114239,
17168,
10080,
63544
},
{
115780,
15564,
10080,
13620
},
{
114880,
16236,
10080,
5400
},
{
115168,
17200,
10080,
0
},
{
115792,
16608,
10080,
0
}
};
private long _LastAttackVsBaiumTime = 0;
private final List<L2NpcInstance> _Minions = new ArrayList<>(5);
private L2BossZone _Zone;
public Baium(int questId, String name, String descr)
{
super(questId, name, descr);
// set initial state
setInitialState(new State("Start", this));
final int[] mob =
{
LIVE_BAIUM
};
registerMobs(mob);
// Quest NPC starter initialization
addStartNpc(STONE_BAIUM);
addStartNpc(ANGELIC_VORTEX);
addTalkId(STONE_BAIUM);
addTalkId(ANGELIC_VORTEX);
_Zone = GrandBossManager.getInstance().getZone(113100, 14500, 10077);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(LIVE_BAIUM);
final int status = GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM);
if (status == DEAD)
{
// load the unlock date and time for baium from DB
final long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
if (temp > 0)
{
// the unlock time has not yet expired. Mark Baium as currently locked (dead). Setup a timer
// to fire at the correct time (calculate the time between now and the unlock time,
// setup a timer to fire after that many msec)
startQuestTimer("baium_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Delete the saved time and
// immediately spawn the stone-baium. Also the state need not be changed from ASLEEP
addSpawn(STONE_BAIUM, 116063, 17508, 10080, 41740, false, 0);
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, ASLEEP);
}
}
else if (status == AWAKE)
{
final int loc_x = info.getInteger("loc_x");
final int loc_y = info.getInteger("loc_y");
final int loc_z = info.getInteger("loc_z");
final int heading = info.getInteger("heading");
final int hp = info.getInteger("currentHP");
final int mp = info.getInteger("currentMP");
final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, loc_x, loc_y, loc_z, heading, false, 0);
GrandBossManager.getInstance().addBoss(baium);
final L2NpcInstance _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
{
@Override
public void run()
{
try
{
_baium.setCurrentHpMp(hp, mp);
_baium.setIsInvul(true);
_baium.setIsImmobilized(true);
_baium.setRunning();
_baium.broadcastPacket(new SocialAction(_baium.getObjectId(), 2));
startQuestTimer("baium_wakeup", 15000, _baium, null);
}
catch (final Exception e)
{
e.printStackTrace();
}
}
}, 100L);
}
else
{
addSpawn(STONE_BAIUM, 116063, 17508, 10080, 41740, false, 0);
}
}
@Override
public String onAdvEvent(String event, L2NpcInstance npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("baium_unlock"))
{
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, ASLEEP);
addSpawn(STONE_BAIUM, 116063, 17508, 10080, 41740, false, 0);
}
else if (event.equalsIgnoreCase("skill_range") && (npc != null))
{
callSkillAI(npc);
}
else if (event.equalsIgnoreCase("clean_player"))
{
_target = getRandomTarget(npc);
}
else if (event.equalsIgnoreCase("baium_wakeup") && (npc != null))
{
if (npc.getNpcId() == LIVE_BAIUM)
{
npc.broadcastPacket(new SocialAction(npc.getObjectId(), 1));
npc.broadcastPacket(new Earthquake(npc.getX(), npc.getY(), npc.getZ(), 40, 5));
// start monitoring baium's inactivity
_LastAttackVsBaiumTime = System.currentTimeMillis();
startQuestTimer("baium_despawn", 60000, npc, null, true);
startQuestTimer("skill_range", 500, npc, null, true);
final L2NpcInstance baium = npc;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
{
@Override
public void run()
{
try
{
baium.setIsInvul(false);
baium.setIsImmobilized(false);
}
catch (final Exception e)
{
e.printStackTrace();
}
}
}, 11100L);
// TODO: the person who woke baium up should be knocked across the room, onto a wall, and
// lose massive amounts of HP.
for (final int[] element : ANGEL_LOCATION)
{
final L2NpcInstance angel = addSpawn(ARCHANGEL, element[0], element[1], element[2], element[3], false, 0);
angel.setIsInvul(true);
_Minions.add(angel);
}
}
}
else if (event.equalsIgnoreCase("baium_despawn") && (npc != null))
{
// despawn the live baium after 30 minutes of inactivity
// also check if the players are cheating, having pulled Baium outside his zone...
if (npc.getNpcId() == LIVE_BAIUM)
{
// just in case the zone reference has been lost (somehow...), restore the reference
if (_Zone == null)
{
_Zone = GrandBossManager.getInstance().getZone(113100, 14500, 10077);
}
if ((_LastAttackVsBaiumTime + 1800000) < System.currentTimeMillis())
{
npc.deleteMe(); // despawn the live-baium
for (final L2NpcInstance minion : _Minions)
{
if (minion != null)
{
minion.getSpawn().stopRespawn();
minion.deleteMe();
}
}
addSpawn(STONE_BAIUM, 116063, 17508, 10080, 41740, false, 0); // spawn stone-baium
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, ASLEEP); // mark that Baium is not awake any more
_Zone.oustAllPlayers();
cancelQuestTimer("baium_despawn", npc, null);
}
else if (((_LastAttackVsBaiumTime + 300000) < System.currentTimeMillis()) && (npc.getCurrentHp() < ((npc.getMaxHp() * 3) / 4)))
{
npc.setTarget(npc);
npc.doCast(SkillTable.getInstance().getInfo(4135, 1));
}
else if (!_Zone.isInsideZone(npc))
{
npc.teleToLocation(115213, 16623, 10080);
}
}
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onTalk(L2NpcInstance npc, QuestState st)
{
final int npcId = npc.getNpcId();
if (_Zone == null)
{
_Zone = GrandBossManager.getInstance().getZone(113100, 14500, 10077);
}
if (_Zone == null)
{
return "<html><body>Angelic Vortex:<br>You may not enter while admin disabled this zone</body></html>";
}
if ((npcId == STONE_BAIUM) && (GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM) == ASLEEP))
{
if (_Zone.checkIfPlayerAllowed(st.getPlayer()))
{
// once Baium is awaken, no more people may enter until he dies, the server reboots, or
// 30 minutes pass with no attacks made against Baium.
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, AWAKE);
npc.deleteMe();
final L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, npc);
GrandBossManager.getInstance().addBoss(baium);
final L2NpcInstance _baium = baium;
ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
{
@Override
public void run()
{
try
{
_baium.setIsInvul(true);
_baium.setIsImmobilized(true);
_baium.setRunning();
_baium.broadcastPacket(new SocialAction(_baium.getObjectId(), 2));
startQuestTimer("baium_wakeup", 15000, _baium, null);
}
catch (final Exception e)
{
e.printStackTrace();
}
}
}, 100L);
}
else
{
return "Conditions are not right to wake up Baium.";
}
}
else if (npcId == ANGELIC_VORTEX)
{
if (GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM) == ASLEEP)
{
if (st.getPlayer().isFlying())
{
return "<html><body>Angelic Vortex:<br>You may not enter while flying a wyvern.</body></html>";
}
else if (st.getQuestItemsCount(4295) > 0) // bloody fabric
{
st.takeItems(4295, 1);
// allow entry for the player for the next 30 secs (more than enough time for the TP to happen)
// Note: this just means 30secs to get in, no limits on how long it takes before we get out.
_Zone.allowPlayerEntry(st.getPlayer(), 30);
st.getPlayer().teleToLocation(113100, 14500, 10077);
}
else
{
return "<html><body>Angelic Vortex:<br>You do not have enough items.</body></html>";
}
}
else
{
return "<html><body>Angelic Vortex:<br>You may not enter at this time.</body></html>";
}
}
st.exitQuest(true);
return null;
}
@Override
public String onSpellFinished(L2NpcInstance npc, L2PcInstance player, L2Skill skill)
{
if (npc.isInvul())
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
return null;
}
else if ((npc.getNpcId() == LIVE_BAIUM) && !npc.isInvul())
{
callSkillAI(npc);
}
return super.onSpellFinished(npc, player, skill);
}
@Override
public String onSpawn(L2NpcInstance npc)
{
npc.disableCoreAI(true);
return super.onSpawn(npc);
}
@Override
public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
{
if (!_Zone.isInsideZone(attacker))
{
attacker.reduceCurrentHp(attacker.getCurrentHp(), attacker, false);
return null;
}
if (npc.isInvul())
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
return null;
}
else if ((npc.getNpcId() == LIVE_BAIUM) && !npc.isInvul())
{
if (attacker.getMountType() == 1)
{
int sk_4258 = 0;
final L2Effect[] effects = attacker.getAllEffects();
if (effects.length != 0)
{
for (final L2Effect e : effects)
{
if (e.getSkill().getId() == 4258)
{
sk_4258 = 1;
}
}
}
if (sk_4258 == 0)
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4258, 1));
}
}
// update a variable with the last action against baium
_LastAttackVsBaiumTime = System.currentTimeMillis();
callSkillAI(npc);
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
{
cancelQuestTimer("baium_despawn", npc, null);
npc.broadcastPacket(new PlaySound(1, "BS01_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
// spawn the "Teleportation Cubic" for 15 minutes (to allow players to exit the lair)
addSpawn(12078, 115203, 16620, 10078, 0, false, 900000); //// should we teleport everyone out if the cubic despawns??
// "lock" baium for 5 days and 1 to 8 hours [i.e. 432,000,000 + 1*3,600,000 + random-less-than(8*3,600,000) millisecs]
final long respawnTime = ((121 + Rnd.get(8)) * 3600000);
GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, DEAD);
startQuestTimer("baium_unlock", respawnTime, null, null);
// also save the respawn time so that the info is maintained past reboots
final StatsSet info = GrandBossManager.getInstance().getStatsSet(LIVE_BAIUM);
info.set("respawn_time", (System.currentTimeMillis()) + respawnTime);
GrandBossManager.getInstance().setStatsSet(LIVE_BAIUM, info);
for (final L2NpcInstance minion : _Minions)
{
if (minion != null)
{
minion.getSpawn().stopRespawn();
minion.deleteMe();
}
}
if (getQuestTimer("skill_range", npc, null) != null)
{
getQuestTimer("skill_range", npc, null).cancel();
}
return super.onKill(npc, killer, isPet);
}
public L2Character getRandomTarget(L2NpcInstance npc)
{
final FastList<L2Character> result = new FastList<>();
final Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
{
for (final L2Object obj : objs)
{
if (obj instanceof L2Character)
{
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())) || ((L2Character) obj).isGM())
{
continue;
}
}
if ((obj instanceof L2PcInstance) || (obj instanceof L2Summon))
{
if (Util.checkIfInRange(9000, npc, obj, true) && !((L2Character) obj).isDead())
{
result.add((L2PcInstance) obj);
}
}
}
}
if (result.isEmpty())
{
for (final L2NpcInstance minion : _Minions)
{
if (minion != null)
{
result.add(minion);
}
}
}
if (result.isEmpty())
{
FastList.recycle(result);
return null;
}
final Object[] characters = result.toArray();
final QuestTimer timer = getQuestTimer("clean_player", npc, null);
if (timer != null)
{
timer.cancel();
}
startQuestTimer("clean_player", 20000, npc, null);
final L2Character target = (L2Character) characters[Rnd.get(characters.length)];
FastList.recycle(result);
return target;
}
public synchronized void callSkillAI(L2NpcInstance npc)
{
if (npc.isInvul() || npc.isCastingNow())
{
return;
}
if ((_target == null) || _target.isDead() || !(_Zone.isInsideZone(_target)))
{
_target = getRandomTarget(npc);
if (_target != null)
{
_skill = SkillTable.getInstance().getInfo(getRandomSkill(npc), 1);
}
}
final L2Character target = _target;
L2Skill skill = _skill;
if (skill == null)
{
skill = SkillTable.getInstance().getInfo(getRandomSkill(npc), 1);
}
if ((target == null) || target.isDead() || !(_Zone.isInsideZone(target)))
{
return;
}
if (Util.checkIfInRange(skill.getCastRange(), npc, target, true))
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
npc.setTarget(target);
_target = null;
_skill = null;
if (getDist(skill.getCastRange()) > 0)
{
npc.broadcastPacket(new MoveToPawn(npc, target, getDist(skill.getCastRange())));
}
try
{
Thread.sleep(1000);
npc.stopMove(null);
npc.doCast(skill);
}
catch (final Exception e)
{
}
}
else
{
npc.getAI().setIntention(AI_INTENTION_FOLLOW, target, null);
}
}
public int getRandomSkill(L2NpcInstance npc)
{
int skill;
if (npc.getCurrentHp() > ((npc.getMaxHp() * 3) / 4))
{
if (Rnd.get(100) < 10)
{
skill = 4128;
}
else if (Rnd.get(100) < 10)
{
skill = 4129;
}
else
{
skill = 4127;
}
}
else if (npc.getCurrentHp() > ((npc.getMaxHp() * 2) / 4))
{
if (Rnd.get(100) < 10)
{
skill = 4131;
}
else if (Rnd.get(100) < 10)
{
skill = 4128;
}
else if (Rnd.get(100) < 10)
{
skill = 4129;
}
else
{
skill = 4127;
}
}
else if (npc.getCurrentHp() > ((npc.getMaxHp() * 1) / 4))
{
if (Rnd.get(100) < 10)
{
skill = 4130;
}
else if (Rnd.get(100) < 10)
{
skill = 4131;
}
else if (Rnd.get(100) < 10)
{
skill = 4128;
}
else if (Rnd.get(100) < 10)
{
skill = 4129;
}
else
{
skill = 4127;
}
}
else if (Rnd.get(100) < 10)
{
skill = 4130;
}
else if (Rnd.get(100) < 10)
{
skill = 4131;
}
else if (Rnd.get(100) < 10)
{
skill = 4128;
}
else if (Rnd.get(100) < 10)
{
skill = 4129;
}
else
{
skill = 4127;
}
return skill;
}
@Override
public String onSkillSee(L2NpcInstance npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isPet)
{
if (npc.isInvul())
{
npc.getAI().setIntention(AI_INTENTION_IDLE);
return null;
}
npc.setTarget(caster);
return super.onSkillSee(npc, caster, skill, targets, isPet);
}
public int getDist(int range)
{
int dist = 0;
switch (range)
{
case -1:
break;
case 100:
dist = 85;
break;
default:
dist = range - 85;
break;
}
return dist;
}
public static void main(String[] args)
{
// Quest class and state definition
new Baium(-1, "baium", "ai");
}
}

View File

@@ -0,0 +1,222 @@
/*
* 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 com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2Attackable;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.util.Rnd;
import javolution.util.FastList;
/**
* Core AI
* @author DrLecter Revised By Emperorc
*/
public class Core extends Quest
{
private static final int CORE = 12052;
private static final int DEATH_KNIGHT = 12054;
private static final int DEATH_WRAITH = 12055;
private static final int SUSCEPTOR = 12058;
// CORE Status Tracking :
private static final byte ALIVE = 0; // Core is spawned.
private static final byte DEAD = 1; // Core has been killed.
private static boolean _FirstAttacked;
List<L2Attackable> Minions = new FastList<>();
public Core(int id, String name, String descr)
{
super(id, name, descr);
final int[] mobs =
{
CORE,
DEATH_KNIGHT,
DEATH_WRAITH,
SUSCEPTOR
};
registerMobs(mobs);
_FirstAttacked = false;
final StatsSet info = GrandBossManager.getInstance().getStatsSet(CORE);
final int status = GrandBossManager.getInstance().getBossStatus(CORE);
if (status == DEAD)
{
// load the unlock date and time for Core from DB
final long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
// if Core is locked until a certain time, mark it so and start the unlock timer
// the unlock time has not yet expired.
if (temp > 0)
{
startQuestTimer("core_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Immediately spawn Core.
final L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, 17726, 108915, -6490, 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.getInteger("loc_x");
final int loc_y = info.getInteger("loc_y");
final int loc_z = info.getInteger("loc_z");
final int heading = info.getInteger("heading");
final int hp = info.getInteger("currentHP");
final int mp = info.getInteger("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()
{
final String val = "" + _FirstAttacked;
saveGlobalQuestVar("Core_Attacked", val);
}
public void spawnBoss(L2GrandBossInstance npc)
{
GrandBossManager.getInstance().addBoss(npc);
npc.broadcastPacket(new PlaySound(1, "BS01_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
// Spawn minions
for (int i = 0; i < 5; i++)
{
final int x = 16800 + (i * 360);
Minions.add((L2Attackable) addSpawn(DEATH_KNIGHT, x, 110000, npc.getZ(), 280 + Rnd.get(40), false, 0));
Minions.add((L2Attackable) addSpawn(DEATH_KNIGHT, x, 109000, npc.getZ(), 280 + Rnd.get(40), false, 0));
final int x2 = 16800 + (i * 600);
Minions.add((L2Attackable) addSpawn(DEATH_WRAITH, x2, 109300, npc.getZ(), 280 + Rnd.get(40), false, 0));
}
for (int i = 0; i < 4; i++)
{
final int x = 16800 + (i * 450);
Minions.add((L2Attackable) addSpawn(SUSCEPTOR, x, 110300, npc.getZ(), 280 + Rnd.get(40), false, 0));
}
}
@Override
public String onAdvEvent(String event, L2NpcInstance npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("core_unlock"))
{
final L2GrandBossInstance core = (L2GrandBossInstance) addSpawn(CORE, 17726, 108915, -6490, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(CORE, ALIVE);
spawnBoss(core);
}
else if (event.equalsIgnoreCase("spawn_minion"))
{
Minions.add((L2Attackable) addSpawn(npc.getNpcId(), npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), false, 0));
}
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();
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
{
if (npc.getNpcId() == CORE)
{
if (_FirstAttacked)
{
if (Rnd.get(100) == 0)
{
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 0, npc.getName(), "Removing intruders."));
}
}
else
{
_FirstAttacked = true;
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 0, npc.getName(), "A non-permitted target has been discovered."));
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 0, npc.getName(), "Starting intruder removal system."));
}
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
{
if (npc.getNpcId() == CORE)
{
final int objId = npc.getObjectId();
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, objId, npc.getX(), npc.getY(), npc.getZ()));
npc.broadcastPacket(new CreatureSay(objId, 0, npc.getName(), "A fatal error has occurred."));
npc.broadcastPacket(new CreatureSay(objId, 0, npc.getName(), "System is being shut down..."));
npc.broadcastPacket(new CreatureSay(objId, 0, npc.getName(), "......"));
_FirstAttacked = false;
addSpawn(12053, 16502, 110165, -6394, 0, false, 900000);
addSpawn(12053, 18948, 110166, -6397, 0, false, 900000);
GrandBossManager.getInstance().setBossStatus(CORE, DEAD);
// time is 60hour +/- 23hour
final long respawnTime = (27 + Rnd.get(47)) * 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 != null) && Minions.contains(npc))
{
Minions.remove(npc);
startQuestTimer("spawn_minion", 60000, npc, null);
}
return super.onKill(npc, killer, isPet);
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new Core(-1, "core", "ai");
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.GeoData;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.model.L2CharPosition;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Summon;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.util.Util;
/**
* @author Mobius
*/
public class Elpy extends Quest
{
// NPCs
private static final int[] MOBS =
{
432, // Elpy
};
// Misc
private static final int FLEE_DISTANCE = 500;
public Elpy(int questId, String name, String descr)
{
super(questId, name, descr);
registerMobs(MOBS);
}
@Override
public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
{
npc.disableCoreAI(true);
npc.setRunning();
final L2Summon summon = isPet ? attacker.getPet() : null;
final L2Character actualAttacker = summon == null ? attacker : summon;
final double radians = Math.toRadians(Util.calculateAngleFrom(actualAttacker, 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);
final L2CharPosition charPos = new L2CharPosition(destination.getX(), destination.getY(), destination.getZ(), destination.getHeading());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, charPos);
return super.onAttack(npc, attacker, damage, isPet);
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new Elpy(-1, "eply", "ai");
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import com.l2jmobius.util.Rnd;
/**
* @by Karakan for L2JLisvus
*/
public class HoneyBear extends Quest
{
private static final int HONEY_BEAR = 5058;
public HoneyBear(int questId, String name, String descr)
{
super(questId, name, descr);
final int[] mobs =
{
HONEY_BEAR
};
registerMobs(mobs);
}
@Override
public String onSpawn(L2NpcInstance npc)
{
if ((npc.getNpcId() == HONEY_BEAR) && (Rnd.get(10) == 0))
{
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 1, npc.getName(), "What does honey of this place taste like?!"));
}
else
{
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 1, npc.getName(), "Give me some sweet, delicious golden honey!"));
}
return super.onSpawn(npc);
}
@Override
public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
{
if ((npc.getCurrentHp() / npc.getMaxHp()) > 0.99)
{
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 1, npc.getName(), "If you give me some honey, I'll at least spare your life..."));
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
{
if (npc.getNpcId() == HONEY_BEAR)
{
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 1, npc.getName(), "Only for lack of honey did I lose to the likes of you."));
}
return super.onKill(npc, killer, isPet);
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new HoneyBear(-1, "honeybear", "ai");
}
}

View File

@@ -0,0 +1,374 @@
/*
* 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 com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2Attackable;
import com.l2jmobius.gameserver.model.L2Character;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Skill;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.model.zone.type.L2BossZone;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.templates.StatsSet;
import com.l2jmobius.util.Rnd;
import javolution.util.FastList;
/**
* Orfen AI
* @author Emperorc
*/
public class Orfen extends Quest
{
private static final int[][] Pos =
{
{
43728,
17220,
-4342
},
{
55024,
17368,
-5412
},
{
53504,
21248,
-5486
},
{
53248,
24576,
-5262
}
};
private static final String[] Text =
{
"PLAYERNAME. Stop kidding yourself about your own powerlessness!",
"PLAYERNAME. I'll make you feel what true fear is!",
"You're really stupid to have challenged me. PLAYERNAME! Get ready!",
"PLAYERNAME. Do you think that's going to work?!"
};
private static final int ORFEN = 12169;
private static final int RAIKEL_LEOS = 12171;
private static final int RIBA_IREN = 12173;
private static boolean _IsTeleported;
private static List<L2Attackable> _Minions = new FastList<>();
private static L2BossZone _Zone;
private static final byte ALIVE = 0;
private static final byte DEAD = 1;
public Orfen(int id, String name, String descr)
{
super(id, name, descr);
final int[] mobs =
{
ORFEN,
RAIKEL_LEOS,
RIBA_IREN
};
registerMobs(mobs);
_IsTeleported = false;
_Zone = GrandBossManager.getInstance().getZone(Pos[0][0], Pos[0][1], Pos[0][2]);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(ORFEN);
final int status = GrandBossManager.getInstance().getBossStatus(ORFEN);
if (status == 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 = Rnd.get(10);
int x = 0;
int y = 0;
int z = 0;
if (i < 4)
{
x = Pos[1][0];
y = Pos[1][1];
z = Pos[1][2];
}
else if (i < 7)
{
x = Pos[2][0];
y = Pos[2][1];
z = Pos[2][2];
}
else
{
x = Pos[3][0];
y = Pos[3][1];
z = Pos[3][2];
}
final L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, x, y, z, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(ORFEN, ALIVE);
spawnBoss(orfen);
}
}
else
{
final int loc_x = info.getInteger("loc_x");
final int loc_y = info.getInteger("loc_y");
final int loc_z = info.getInteger("loc_z");
final int heading = info.getInteger("heading");
final int hp = info.getInteger("currentHP");
final int mp = info.getInteger("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(L2NpcInstance npc, int index)
{
((L2Attackable) npc).clearAggroList();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
final L2Spawn spawn = npc.getSpawn();
spawn.setLocx(Pos[index][0]);
spawn.setLocy(Pos[index][1]);
spawn.setLocz(Pos[index][2]);
npc.teleToLocation(Pos[index][0], Pos[index][1], Pos[index][2]);
}
public void spawnBoss(L2GrandBossInstance npc)
{
GrandBossManager.getInstance().addBoss(npc);
npc.broadcastPacket(new PlaySound(1, "BS01_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
startQuestTimer("check_orfen_pos", 10000, npc, null, true);
// Spawn minions
final int x = npc.getX();
final int y = npc.getY();
_Minions.add((L2Attackable) addSpawn(RAIKEL_LEOS, x + 100, y + 100, npc.getZ(), 0, false, 0));
_Minions.add((L2Attackable) addSpawn(RAIKEL_LEOS, x + 100, y - 100, npc.getZ(), 0, false, 0));
_Minions.add((L2Attackable) addSpawn(RAIKEL_LEOS, x - 100, y + 100, npc.getZ(), 0, false, 0));
_Minions.add((L2Attackable) addSpawn(RAIKEL_LEOS, x - 100, y - 100, npc.getZ(), 0, false, 0));
startQuestTimer("check_minion_loc", 10000, npc, null, true);
}
@Override
public String onAdvEvent(String event, L2NpcInstance npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("orfen_unlock"))
{
final int i = Rnd.get(10);
int x = 0;
int y = 0;
int z = 0;
if (i < 4)
{
x = Pos[1][0];
y = Pos[1][1];
z = Pos[1][2];
}
else if (i < 7)
{
x = Pos[2][0];
y = Pos[2][1];
z = Pos[2][2];
}
else
{
x = Pos[3][0];
y = Pos[3][1];
z = Pos[3][2];
}
final L2GrandBossInstance orfen = (L2GrandBossInstance) addSpawn(ORFEN, x, y, z, 0, 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, Rnd.get(3) + 1);
_IsTeleported = false;
}
else if (_IsTeleported && !_Zone.isInsideZone(npc))
{
setSpawnPoint(npc, 0);
}
}
else if (event.equalsIgnoreCase("check_minion_loc"))
{
for (int i = 0; i < _Minions.size(); i++)
{
final L2Attackable mob = _Minions.get(i);
if (!npc.isInsideRadius(mob, 3000, false, false))
{
mob.teleToLocation(npc.getX(), npc.getY(), npc.getZ());
((L2Attackable) npc).clearAggroList();
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
}
}
}
else if (event.equalsIgnoreCase("despawn_minions"))
{
for (int i = 0; i < _Minions.size(); i++)
{
final L2Attackable mob = _Minions.get(i);
if (mob != null)
{
mob.decayMe();
}
}
_Minions.clear();
}
else if (event.equalsIgnoreCase("spawn_minion"))
{
_Minions.add((L2Attackable) addSpawn(RAIKEL_LEOS, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0));
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSkillSee(L2NpcInstance npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isPet)
{
if (npc.getNpcId() == ORFEN)
{
final L2Character originalCaster = isPet ? caster.getPet() : caster;
if (skill.hasAggro() && (Rnd.get(5) == 0) && npc.isInsideRadius(originalCaster, 1000, false, false))
{
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 0, npc.getName(), Text[Rnd.get(4)].replace("PLAYERNAME", caster.getName().toString())));
originalCaster.teleToLocation(npc.getX(), npc.getY(), npc.getZ());
npc.setTarget(originalCaster);
npc.doCast(SkillTable.getInstance().getInfo(4064, 1));
}
}
return super.onSkillSee(npc, caster, skill, targets, isPet);
}
@Override
public String onFactionCall(L2NpcInstance npc, L2NpcInstance caller, L2PcInstance attacker, boolean isPet)
{
if ((caller == null) || (npc == null))
{
return super.onFactionCall(npc, caller, attacker, isPet);
}
final int npcId = npc.getNpcId();
final int callerId = caller.getNpcId();
if ((npcId == RAIKEL_LEOS) && (Rnd.get(20) == 0))
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4067, 4));
}
else if (npcId == RIBA_IREN)
{
int chance = 1;
if (callerId == ORFEN)
{
chance = 9;
}
if ((callerId != RIBA_IREN) && (caller.getCurrentHp() < (caller.getMaxHp() / 2)) && (Rnd.get(10) < chance))
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
npc.setTarget(caller);
npc.doCast(SkillTable.getInstance().getInfo(4516, 1));
}
}
return super.onFactionCall(npc, caller, attacker, isPet);
}
@Override
public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
{
final int npcId = npc.getNpcId();
if (npcId == ORFEN)
{
if (((npc.getCurrentHp() - damage) < (npc.getMaxHp() / 2)) && !_IsTeleported)
{
setSpawnPoint(npc, 0);
_IsTeleported = true;
}
else if (npc.isInsideRadius(attacker, 1000, false, false) && !npc.isInsideRadius(attacker, 300, false, false) && (Rnd.get(10) == 0))
{
npc.broadcastPacket(new CreatureSay(npc.getObjectId(), 0, npc.getName(), Text[Rnd.get(3)].replace("PLAYERNAME", attacker.getName().toString())));
attacker.teleToLocation(npc.getX(), npc.getY(), npc.getZ());
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4064, 1));
}
}
else if (npcId == RIBA_IREN)
{
if ((npc.getCurrentHp() - damage) < (npc.getMaxHp() / 2))
{
npc.setTarget(attacker);
npc.doCast(SkillTable.getInstance().getInfo(4516, 1));
}
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
{
if (npc.getNpcId() == ORFEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(ORFEN, DEAD);
// time is 48hour +/- 20hour
final long respawnTime = (28 + (Rnd.get(41) * 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.getNpcId() == RAIKEL_LEOS))
{
_Minions.remove(npc);
startQuestTimer("spawn_minion", 360000, npc, null);
}
return super.onKill(npc, killer, isPet);
}
public static void main(String[] args)
{
// Quest class and state definition
new Orfen(-1, "orfen", "ai");
}
}

View File

@@ -0,0 +1,289 @@
/*
* 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 com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.datatables.SkillTable;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
import com.l2jmobius.gameserver.model.L2Attackable;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.quest.Quest;
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.templates.StatsSet;
import com.l2jmobius.util.Rnd;
import javolution.util.FastList;
/**
* Queen Ant AI
* @author Emperorc
*/
public class QueenAnt extends Quest
{
private static final int QUEEN = 12001;
private static final int LARVA = 12002;
private static final int NURSE = 12003;
private static final int GUARD = 12004;
private static final int ROYAL = 12005;
// 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 List<L2Attackable> _Minions = new FastList<>();
public QueenAnt(int questId, String name, String descr)
{
super(questId, name, descr);
final int[] mobs =
{
QUEEN,
LARVA,
NURSE,
GUARD,
ROYAL
};
registerMobs(mobs);
_Zone = GrandBossManager.getInstance().getZone(-21610, 181594, -5734);
final StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
final int status = GrandBossManager.getInstance().getBossStatus(QUEEN);
if (status == DEAD)
{
// load the unlock date and time for queen ant from DB
final long temp = info.getLong("respawn_time") - System.currentTimeMillis();
// if queen ant is locked until a certain time, mark it so and start the unlock timer
// the unlock time has not yet expired.
if (temp > 0)
{
startQuestTimer("queen_unlock", temp, null, null);
}
else
{
// the time has already expired while the server was offline. Immediately spawn queen ant.
final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, -21610, 181594, -5734, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE);
spawnBoss(queen);
}
}
else
{
final int loc_x = info.getInteger("loc_x");
final int loc_y = info.getInteger("loc_y");
final int loc_z = info.getInteger("loc_z");
final int heading = info.getInteger("heading");
final int hp = info.getInteger("currentHP");
final int mp = info.getInteger("currentMP");
final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, loc_x, loc_y, loc_z, heading, false, 0);
queen.setCurrentHpMp(hp, mp);
spawnBoss(queen);
}
}
public void spawnBoss(L2GrandBossInstance npc)
{
GrandBossManager.getInstance().addBoss(npc);
if (Rnd.get(100) < 33)
{
_Zone.movePlayersTo(-19480, 187344, -5600);
}
else if (Rnd.get(100) < 50)
{
_Zone.movePlayersTo(-17928, 180912, -5520);
}
else
{
_Zone.movePlayersTo(-23808, 182368, -5600);
}
GrandBossManager.getInstance().addBoss(npc);
startQuestTimer("action", 10000, npc, null, true);
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
// Spawn minions
addSpawn(LARVA, -21600, 179482, -5846, Rnd.get(360), false, 0);
addSpawn(NURSE, -22000, 179482, -5846, 0, false, 0);
addSpawn(NURSE, -21200, 179482, -5846, 0, false, 0);
final int radius = 400;
for (int i = 0; i < 6; i++)
{
final int x = (int) (radius * Math.cos(i * 1.407)); // 1.407~2pi/6
final int y = (int) (radius * Math.sin(i * 1.407));
addSpawn(NURSE, npc.getX() + x, npc.getY() + y, npc.getZ(), 0, false, 0);
}
for (int i = 0; i < 8; i++)
{
final int x = (int) (radius * Math.cos(i * .7854)); // .7854~2pi/8
final int y = (int) (radius * Math.sin(i * .7854));
_Minions.add((L2Attackable) addSpawn(ROYAL, npc.getX() + x, npc.getY() + y, npc.getZ(), 0, false, 0));
}
startQuestTimer("check_royal__Zone", 120000, npc, null, true);
}
@Override
public String onAdvEvent(String event, L2NpcInstance npc, L2PcInstance player)
{
if (event.equalsIgnoreCase("action") && (npc != null))
{
if (Rnd.get(3) == 0)
{
if (Rnd.get(2) == 0)
{
npc.broadcastPacket(new SocialAction(npc.getObjectId(), 3));
}
else
{
npc.broadcastPacket(new SocialAction(npc.getObjectId(), 4));
}
}
}
else if (event.equalsIgnoreCase("queen_unlock"))
{
final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, -21610, 181594, -5734, 0, false, 0);
GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE);
spawnBoss(queen);
}
else if (event.equalsIgnoreCase("check_royal__Zone") && (npc != null))
{
for (int i = 0; i < _Minions.size(); i++)
{
final L2Attackable mob = _Minions.get(i);
if ((mob != null) && !_Zone.isInsideZone(mob))
{
mob.teleToLocation(npc.getX(), npc.getY(), npc.getZ());
}
}
}
else if (event.equalsIgnoreCase("despawn_royals"))
{
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_royal"))
{
_Minions.add((L2Attackable) addSpawn(ROYAL, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0));
}
else if (event.equalsIgnoreCase("spawn_nurse"))
{
addSpawn(NURSE, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onFactionCall(L2NpcInstance npc, L2NpcInstance caller, L2PcInstance attacker, boolean isPet)
{
if ((caller == null) || (npc == null))
{
return super.onFactionCall(npc, caller, attacker, isPet);
}
final int npcId = npc.getNpcId();
final int callerId = caller.getNpcId();
if (npcId == NURSE)
{
if (callerId == LARVA)
{
npc.setTarget(caller);
npc.doCast(SkillTable.getInstance().getInfo(4020, 1));
npc.doCast(SkillTable.getInstance().getInfo(4024, 1));
return null;
}
else if (callerId == QUEEN)
{
if ((npc.getTarget() != null) && (npc.getTarget() instanceof L2NpcInstance))
{
if (((L2NpcInstance) npc.getTarget()).getNpcId() == LARVA)
{
return null;
}
}
npc.setTarget(caller);
npc.doCast(SkillTable.getInstance().getInfo(4020, 1));
return null;
}
}
return super.onFactionCall(npc, caller, attacker, isPet);
}
@Override
public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
{
final int npcId = npc.getNpcId();
if (npcId == NURSE)
{
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
return null;
}
return super.onAttack(npc, attacker, damage, isPet);
}
@Override
public String onKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
{
final int npcId = npc.getNpcId();
if (npcId == QUEEN)
{
npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
GrandBossManager.getInstance().setBossStatus(QUEEN, DEAD);
// time is 36hour +/- 17hour
final long respawnTime = ((19 + Rnd.get(35)) * 3600000);
startQuestTimer("queen_unlock", respawnTime, null, null);
cancelQuestTimer("action", npc, 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);
startQuestTimer("despawn_royals", 20000, null, null);
cancelQuestTimers("spawn_minion");
}
else if (GrandBossManager.getInstance().getBossStatus(QUEEN) == ALIVE)
{
if (npcId == ROYAL)
{
_Minions.remove(npc);
startQuestTimer("spawn_royal", (280 + Rnd.get(40)) * 1000, npc, null);
}
else if (npcId == NURSE)
{
startQuestTimer("spawn_nurse", 10000, npc, null);
}
}
return super.onKill(npc, killer, isPet);
}
public static void main(String[] args)
{
// now call the constructor (starts up the ai)
new QueenAnt(-1, "queen_ant", "ai");
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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,5 @@
##############################################
### Author: Layane (andrashe@gmail.com)
##############################################
print "Hi world!"

View File

@@ -0,0 +1,12 @@
<html><body>
<table width=200>
<tr><td align="center">Echo Crystals </td></tr>
</table><br>
<a action="bypass -h Quest 3995_echo 4411">[Create an Echo Crystal - Theme of Journey]</a><br>
<a action="bypass -h Quest 3995_echo 4412">[Create an Echo Crystal - Theme of Battle]</a><br>
<a action="bypass -h Quest 3995_echo 4413">[Create an Echo Crystal - Theme of Love]</a><br>
<a action="bypass -h Quest 3995_echo 4414">[Create an Echo Crystal - Theme of Solitude]</a><br>
<a action="bypass -h Quest 3995_echo 4415">[Create an Echo Crystal - Theme of Feast]</a><br>
<a action="bypass -h Quest 3995_echo 4416">[Create an Echo Crystal - Theme of Celebration]</a><br>
<a action="bypass -h Quest 3995_echo 4417">[Create an Echo Crystal - Theme of Comedy]</a>
</body></html>

View File

@@ -0,0 +1,76 @@
### ---------------------------------------------------------------------------
### <history>
### Elektra@ElektraL2.com
### </history>
### ---------------------------------------------------------------------------
### Settings
NPC = [8042,8043]
QuestId = 3995
QuestName = "echo"
QuestDesc = "custom"
InitialHtml = "1.htm"
### Items - Format [name, giveItemId, giveItemQty, takeItem1Id, takeItem1Qty, takeItem2Id, takeItem2Qty]
Items = [
["Theme of Travel", 4411, 1, 57, 200, 4410, 1],
["Theme of Festival", 4415, 1, 57, 200, 4421, 1],
["Theme of Lonely", 4414, 1, 57, 200, 4420, 1],
["Theme of Love", 4413, 1, 57, 200, 4408, 1],
["Theme of Battle", 4412, 1, 57, 200, 4409, 1],
["Theme of Comedy", 4417, 1, 57, 200, 4419, 1],
["Theme of Celebration", 4416, 1, 57, 200, 4418, 1]
]
### ---------------------------------------------------------------------------
### DO NOT MODIFY BELOW THIS LINE
### ---------------------------------------------------------------------------
import sys
from com.l2jmobius.gameserver.model.quest import State
from com.l2jmobius.gameserver.model.quest import QuestState
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
### doRequestedEvent
def do_RequestedEvent(event, st, giveItemId, giveItemQty, takeItem1Id, takeItem1Qty, takeItem2Id, takeItem2Qty) :
if st.getQuestItemsCount(takeItem1Id) >= takeItem1Qty and st.getQuestItemsCount(takeItem2Id) >= takeItem2Qty :
st.takeItems(takeItem1Id, takeItem1Qty)
st.giveItems(giveItemId, giveItemQty)
return "Echo Crystal Created"
else :
return "You do not have enough items."
### main code
class Quest (JQuest) :
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
def onEvent (self,event,st) :
htmltext = event
if event == "0" :
return InitialHtml
for item in Items :
if event == str(item[1]):
htmltext = do_RequestedEvent(event, st, item[1], item[2], item[3], item[4], item[5], item[6])
if htmltext != event :
st.setState(COMPLETED)
st.exitQuest(1)
return htmltext
def onTalk (Self,npc,st):
htmltext = "<html><body>I have nothing to say with you</body></html>"
return InitialHtml
### Quest class and state definition
QUEST = Quest(QuestId,str(QuestId) + "_" + QuestName,QuestDesc)
CREATED = State('Start', QUEST)
COMPLETED = State('Completed', QUEST)
### Quest initialization
QUEST.setInitialState(CREATED)
for item in NPC:
### Quest NPC starter initialization
QUEST.addStartNpc(item)
### Quest NPC initialization
QUEST.addTalkId(item)

View File

@@ -0,0 +1,6 @@
<html><body>Hierarch Kadun Zu Ketra:<br>
We Ketras have come here to reclaim the land of our ancestors! We've discovered that the Varka Silenos, our loathsome enemy, defile this holy land! We will never forgive them this insult!<br>
Help us return to our homeland! May the flame of Paagrio burn within your heart eternally!<br>
But, be careful! You must remember our brothers are always watching you. <font color="LEVEL">As soon as you lay a hand on our Ketra tribe, all the promises between you and us will disappear!</font><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Hierarch Kadun Zu Ketra:<br>
Hold it, stranger! This is the sacred land of the Ketra! You defile it with your presence!<br>
We're different from the vile Orcs to the north... We'll surely reclaim this land of our ancestors! If you seriously want to help us return to our homeland, visit Messenger Wahkan!
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Ketra's Messenger Wahkan:<br>
Welcome, brave comrade!<br>
You've brought many heads of Varka Silenos! We're very impressed! A few more friends like you and we can put those Varkas down for good!<br>
Tejakar Ketra!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Ketra's Messenger Wahkan:<br>
We Ketra are the bravest of all Orc tribes! We're here to reclaim the land of our ancestors! Prepare to die, all who stand in our way!<br>
Don't take us for fools! We're well aware of the fact that in order to defeat the enemy, we must ally with outside forces! Like you! Will you be our comrade in arms? Are you ready to prove your worth alongside us on the battlefield?<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Soul Guide Asefa:<br>
Welcome, comrade of Ketra! Until the day comes when you win an honorable name on the battlefield, may the souls of our ancestors bless you and protect you!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Soul Guide Asefa:<br>
In order to receive the blessing of the ancestors, you must dedicate a<font color="LEVEL"> Buffalo horn</font> to them! Go to the battleground and return victorious, you'll receive a Buffalo horn as a reward!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Soul Guide Asefa:<br>
You, nameless foreigner! Get away from here! Don't defile the land of our ancestors!<br>
I'll bring down the curse of flames upon the enemies of Ketra!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,13 @@
<html><body>Soul Guide Asefa:<br>
Welcome, sworn friend of Ketra! I pray that the Flame of Paagrio will shed its light on your soul!<br>
The blood of the Varka Silenos you drew has been dedicated to the souls of our great ancestors in the midst of sacred flames in heaven! You'll receive the blessings of our ancestors!<br>
<a action="bypass -h Quest 6050_KetraOrcSupport 1">Blessing of Wolf (Focus): Requires 2 Buffalo Horns</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport 2">Blessing of Hawk (Death Whisper): Requires 2 Buffalo Horns</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport 3">Blessing of Bear (Might): Requires 3 Buffalo Horns</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport 4">Blessing of Spider (Acumen): Requires 3 Buffalo Horns</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport 5">Blessing of Lion (Berserker): Requires 3 Buffalo Horns</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport 6">Blessing of Coyote (Vampiric Rage): Requires 3 Buffalo Horns</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport 7">Blessing of Owl (Empower): Requires 6 Buffalo Horns</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport 8">Blessing of Wild Horse (Haste): Requires 6 Buffalo Horns</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Grocer Atan:<br>
Come on in, comrade of Ketra! I'm responsible for providing supplies to the honorable warriors of our tribe. Under special orders from the chief of our tribe, I can now offer supplies to outsiders like you!<br>
<a action="bypass -h npc_%objectId%_Buy 1814">Buy</a><br>
<a action="bypass -h npc_%objectId%_Sell">Sell</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Grocer Atan:<br>
Dear comrade of Ketra! How come what you told me and what you now show me are two different things?<br>
<a action="bypass -h npc_%objectId%_Buy 1814">Buy</a><br>
<a action="bypass -h npc_%objectId%_Sell">Sell</a><br>
<a action="bypass -h npc_%objectId%_TerritoryStatus">"Who is the lord of the manor and what is the tax rate?"</a>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Grocer Atan:<br>
I can't sell supplies to someone who is not a comrade of Ketra! Go away!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Grocer Atan:<br>
Oh... you're a wanted criminal. My man may report you to the village guards if he sees you. Escape to another place at once. I cannot sell to you now, but I trust you will be a future customer. When you are free once more, please pay our shop a visit. Don't forget us.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Warehouse Keeper Jaff:<br>
Ha! You never deposited anything here! Your memory is not as good as your reputation!
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Warehouse Keeper Jaff:<br>
Yo, comrade of Ketra! Welcome! This warehouse is where our war supplies are stored!<br>
I know you've worked hard, but I can't yet open the warehouse to a foreigner such as yourself! Keep up the good work! One day our chief will allow you to use the warehouse!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Warehouse Keeper Jaff:<br>
Have you found all you need? If there's anything else, just ask me!<br>
<a action="bypass -h npc_%objectId%_DepositP">Deposit an item.</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport Withdraw">Pick up an item.</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Warehouse Keeper Jaff:<br>
I don't care about your reputation among outsiders! You treat us Ketra fairly, we'll do the same!<br>
<a action="bypass -h npc_%objectId%_DepositP">Deposit an item.</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport Withdraw">Pick up an item.</a>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Warehouse Keeper Jaff:<br>
Come here, friend of Ketra!<br>
You've been given permission to use our warehouse by our chief! A valued warrior like you shouldn't have to carry around a heavy load! Leave anything here you don't need for combat!<br>
<a action="bypass -h npc_%objectId%_DepositP">Deposit an item.</a><br>
<a action="bypass -h Quest 6050_KetraOrcSupport Withdraw">Pick up an item.</a>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Warehouse Keeper Jaff:<br>
Go away! This warehouse is reserved for the glorious warriors of Ketra! It's not for outsiders!
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>Trader Jumara:<br>
Tejakar Ketra! Welcome, comrade! I'm a supplier of specialty items! The elder tells me that you're interested in buying something!<br>
How about this low-level booty pouch? Someday, when you're qualified to open it, you'll have the strongest armor available!<br>
Bring me a<font color="LEVEL"> Buffalo Horn</font> and I'll give you whatever you want!<br>
What would you like?<br>
<a action="bypass -h npc_%objectId%_multisell 83750001">"I'd like one of the Ketra's specialty products."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Trader Jumara:<br>
Tejakar Ketra! Welcome, dear friend!<br>
I've been ordered to supply a higher-level pouch to you, but you won't get the strongest armor yet! Try again when you've had more experiences.<br>
Bring me a<font color="LEVEL"> Buffalo Horn</font> and I'll give you whatever you want. Care to take a look?<br>
<a action="bypass -h npc_%objectId%_multisell 83750002">"I'd like one of the Ketra's specialty products."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>Trader Jumara:<br>
Tejakar Ketra! Welcome, dear friend!<br>
You're finally qualified to get the most valuable looted goods from our tribe!<br>
Now, open the box that holds the strongest armor!<br>
Bring me a<font color="LEVEL"> Buffalo Horn</font> and I'll give you anything you want!<br>
<a action="bypass -h npc_%objectId%_multisell 83750003">"I'd like one of the Ketra's specialty products."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Trader Jumara:<br>
Tejakar Ketra! Welcome, dear friend!<br>
You are not strong enough yet! Try again when you've had more experiences.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Gatekeeper Kurfa:<br>
You're a true friend of my people. My ancestors guard your every step!<br>
Stories of your valor grow everyday! Unfortunately, I can't allow you to use the gate of time and space yet. Keep up the good work!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Gatekeeper Kurfa:<br>
You, comrade of the Ketra. May the divine protection of the ancestors be with you always!<br>
Our chief has approved of your valor and will allow you to travel to a bigger battleground. So, tell me where you wish to go! I, Kurfa, will open the gate of time and space for you!<br>
<a action="bypass -h Quest 6050_KetraOrcSupport Teleport">Teleport</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Gatekeeper Kurfa:<br>
Dear sworn friend of Ketra. May the divine blessing and protection of our ancestors be with you always!<br>
Your bravery is renowned! Everybody says that when you battle, you are as hot as an exploding volcano! Our chief has given his approval for you to travel to another village! You, tell me where you wish to go! I, Kurfa will open the gate of time and space for you!<br>
<a action="bypass -h Quest 6050_KetraOrcSupport Teleport">Teleport</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>&$556;<br>
<br>
<a action="bypass -h npc_%objectId%_goto 10029" msg="811;Goddard Castle Town">Goddard Castle Town - 4900 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10030" msg="811;Rune Castle Town">Rune Castle Town - 22000 Adena</a><br1>
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>&$556;<br>
<br>
<a action="bypass -h npc_%objectId%_goto 10029" msg="811;Goddard Castle Town">Goddard Castle Town - 4900 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10030" msg="811;Rune Castle Town">Rune Castle Town - 22000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10031" msg="811;Aden Castle Town">Aden Castle Town - 21000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10032" msg="811;Wall of Argos">Wall of Argos - 7000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10033" msg="811;Hot Springs">Hot Springs - 6700 Adena</a><br1>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Gatekeeper Kurfa:<br>
I guide travelers through the gate of time and space! I don't deal with outsiders!
</body></html>

View File

@@ -0,0 +1,140 @@
# Created by Emperorc
# Finished by Kerberos_20 10/23/07
import sys
from com.l2jmobius.gameserver.model.quest import State
from com.l2jmobius.gameserver.model.quest import QuestState
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
from com.l2jmobius.gameserver.datatables import SkillTable
from com.l2jmobius.gameserver.network.serverpackets import WareHouseWithdrawalList
from com.l2jmobius.gameserver.network.serverpackets import ActionFailed
qn = "6050_KetraOrcSupport"
Kadun = 8370 #Hierarch
Wahkan= 8371 #Messenger
Asefa = 8372 #Soul Guide
Atan = 8373 #Grocer
Jaff = 8374 #Warehouse Keeper
Jumara= 8375 #Trader
Kurfa = 8376 #Gate Keeper
NPCS = range(8370,8377)
Horn = 7186
#"event number":[Buff Id,Buff Level,Cost]
BUFF={
"1":[4359,1,2],#Focus: Requires 2 Buffalo Horns
"2":[4360,1,2],#Death Whisper: Requires 2 Buffalo Horns
"3":[4345,1,3],#Might: Requires 3 Buffalo Horns
"4":[4355,1,3],#Acumen: Requires 3 Buffalo Horns
"5":[4352,1,3],#Berserker: Requires 3 Buffalo Horns
"6":[4354,1,3],#Vampiric Rage: Requires 3 Buffalo Horns
"7":[4356,1,6],#Empower: Requires 6 Buffalo Horns
"8":[4357,1,6],#Haste: Requires 6 Buffalo Horns
}
class Quest (JQuest) :
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
def onAdvEvent (self,event,npc,player) :
htmltext = "8372-2.htm"
st = player.getQuestState(qn)
if not st: return
Alevel = player.getAllianceWithVarkaKetra()
if str(event) in BUFF.keys() :
skillId,level,horns=BUFF[event]
if st.getQuestItemsCount(Horn) >= horns :
st.takeItems(Horn,horns)
npc.setTarget(player)
npc.doCast(SkillTable.getInstance().getInfo(skillId,level))
npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp())
htmltext = "8372-4.htm"
elif event == "Withdraw" :
if player.getWarehouse().getSize() == 0 :
htmltext = "8374-0.htm"
else :
player.sendPacket(ActionFailed())
player.setActiveWarehouse(player.getWarehouse())
player.sendPacket(WareHouseWithdrawalList(player, 1))
elif event == "Teleport" :
if Alevel == 4 :
htmltext = "8376-4.htm"
elif Alevel == 5 :
htmltext = "8376-5.htm"
return htmltext
def onFirstTalk (self,npc,player):
htmltext = "<html><body>You are either not carrying out your quest or don't meet the criteria.</body></html>"
st = player.getQuestState(qn)
if not st :
st = self.newQuestState(player)
npcId = npc.getNpcId()
Alevel = player.getAllianceWithVarkaKetra()
Horns = st.getQuestItemsCount(Horn)
if npcId == Kadun :
if Alevel > 0 :
htmltext = "8370-friend.htm"
else :
htmltext = "8370-no.htm"
elif npcId == Wahkan :
if Alevel > 0 :
htmltext = "8371-friend.htm"
else :
htmltext = "8371-no.htm"
elif npcId == Asefa :
st.setState(STARTED)
if Alevel < 1 :
htmltext = "8372-3.htm"
elif Alevel < 3 and Alevel > 0:
htmltext = "8372-1.htm"
elif Alevel > 2 :
htmltext = "8372-4.htm"
elif npcId == Atan :
if player.getKarma() >= 1:
htmltext = "8373-pk.htm"
elif Alevel <= 0 :
htmltext = "8373-no.htm"
elif Alevel == 1 or Alevel == 2:
htmltext = "8373-1.htm"
else:
htmltext = "8373-2.htm"
elif npcId == Jaff :
if Alevel <= 0 :
htmltext = "8374-no.htm"
elif Alevel == 1 :
htmltext = "8374-1.htm"
elif player.getWarehouse().getSize() == 0 :
htmltext = "8374-3.htm"
elif Alevel == 2 or Alevel == 3:
htmltext = "8374-2.htm"
else :
htmltext = "8374-4.htm"
elif npcId == Jumara :
if Alevel == 2 :
htmltext = "8375-1.htm"
elif Alevel == 3 or Alevel == 4 :
htmltext = "8375-2.htm"
elif Alevel == 5 :
htmltext = "8375-3.htm"
else :
htmltext = "8375-no.htm"
elif npcId == Kurfa :
if Alevel <= 0 :
htmltext = "8376-no.htm"
elif Alevel > 0 and Alevel < 4 :
htmltext = "8376-1.htm"
elif Alevel == 4 :
htmltext = "8376-2.htm"
else :
htmltext = "8376-3.htm"
return htmltext
QUEST = Quest(6050, qn, "custom")
CREATED = State('Start', QUEST)
STARTED = State('Started', QUEST)
QUEST.setInitialState(CREATED)
for i in NPCS:
QUEST.addFirstTalkId(i)
QUEST.addTalkId(Asefa)
QUEST.addTalkId(Kurfa)
QUEST.addTalkId(Jaff)

View File

@@ -0,0 +1,6 @@
<html><body>Elder Ashas Varka Durai:<br>
Welcome, my friend! I'm Ashas Varka Durai, an elder of the Varka tribe.<br>
To defend the land that was promised to us, we're at war with the arrogant Ketra Orcs. You've helped us to significantly damage them. They've proven to be much more formidable than we thought. We've reached an intractable stalemate! To bring our struggle to an end, you must make a long, hard journey. I wish you well!<br>
But, be careful. Whatever you do, you must remember our brothers are watching you. <font color="LEVEL">As soon as you lay a hand on our Varka tribe, all the promises between you and us will disappear! </font><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Elder Ashas Varka Durai:<br>
Hold it right there, stranger! Unfriendly visitors aren't welcome in this land!<br>
Traveler of the west wind! If you expect to win our trust, you must first visit <font color="LEVEL">Varka's messenger Naran Ashanuk</font>. He'll tell you what you must do.
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Ketra's Messenger Naran Ashanuk:<br>
The Silenos were a wandering tribe that followed the wind. I suppose if you've made it this far you already know that. We Varka are warriors! We're the toughest, most tenacious fighters ever! You're extremely brave!<br>
You helped us to drive those arrogant Ketra Orcs from our territory!<br>
Dear friend of the Varka, please stay and help us fight our enemy!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Varka's Messenger Naran Ashanuk:<br>
Behold the promised land of the Varka! It was given to us as a reward for spilling our blood in defense of the kingdom of Elmore! Who do those pathetic Ketra Orcs think they are? Saying that this land has belonged to them for thousands of years! Rubbish!<br>
You, traveler of the west wind! Will you help us defeat those arrogant Ketras? You'll be well-rewarded!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Soul Guide Udan Mardui:<br>
I'm Soul Guide Udan Mardui.<br>
You're a friend of Varka, aren't you? Your reputation precedes you, my friend! Unfortunately, I can't offer you any just help yet.<br>
All favors must be reciprocated with an appropriate price! When you've accumulated enough trust, come back and see me again! On behalf of our tribe, I'll give you a reward!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Soul Guide Udan Mardui:<br>
If you want to be blessed, give me the<font color="LEVEL"> seed of Nepenthes</font>! Prove yourself!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Soul Guide Udan Mardui:<br>
I'm Udan Mardui, guide of dead souls. Dear traveler of the west wind, there's nothing I can offer you.<br>
You came here looking for peace, leave the same way!<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,13 @@
<html><body>Soul Guide Udan Mardui:<br>
I am Udan Mardui, guide of dead souls.<br>
Dear friend of water, I thank you for the service you provided. May the good will and blessing of nature's goodness be with you always! I hope the reward I give you will help in your combat.<br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 1">Blessing of Wolf (Focus): Requires 2 Nepenthes Seeds</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 2">Blessing of Hawk (Death Whisper): Requires 2 Nepenthes Seeds</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 3">Blessing of Bear (Might): Requires 3 Nepenthes Seeds</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 4">Blessing of Spider (Acumen): Requires 3 Nepenthes Seeds</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 5">Blessing of Lion (Berserker): Requires 3 Nepenthes Seeds</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 6">Blessing of Coyote (Vampiric Rage): Requires 3 Nepenthes Seeds</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 7">Blessing of Owl (Empower): Requires 6 Nepenthes Seeds</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport 8">Blessing of Wild Horse (Haste): Requires 6 Nepenthes Seeds</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Grocer Diyabu:<br>
Oh! Are you the soldier I've been hearing so much about?!<br>
My name is Diyabu. As you can see, I'm a businessman. If you ever need anything, just let me know. I'll try my best to accommodate you. A hero like you deserves the best!<br>
<a action="bypass -h npc_%objectId%_Buy 1813">Buy</a><br>
<a action="bypass -h npc_%objectId%_Sell">Sell</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Grocer Diyabu:<br>
Dear Friend of Varka! You make me very sad! Friends shouldn't lie to each other! You should be more honest!<br>
<a action="bypass -h npc_%objectId%_Buy 1813">Buy</a><br>
<a action="bypass -h npc_%objectId%_Sell">Sell</a>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Grocer Diyabu:<br>
Dear traveler of the west wind. I must tell you! I deal with friends of Varka only!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Grocer Diyabu:<br>
Oh... you're a wanted criminal. My man may report you to the village guards if he sees you. Escape to another place at once. I cannot sell to you now, but I trust you will be a future customer. When you are free once more, please pay our shop a visit. Don't forget us.
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Warehouse Keeper Hagos:<br>
Ha! You never deposited anything here! Your memory is not as good as your reputation!
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Warehouse Keeper Hagos:<br>
Welcome, friend of Varka!<br>
I'm in charge of keeping the tribe's supplies. I can't help you now because I don't yet have the approval of the elder.<br>
Try a little harder! Surely he'll allow you to use the warehouse.<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Warehouse Keeper Hagos:<br>
Do they call you a criminal? I don't like labels like that... What's a criminal anyway? Someone who broke a Contract? Varkas always keep their word! So should you!<br>
<a action="bypass -h npc_%objectId%_DepositP">Deposit an item.</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport Withdraw">Pick up an item.</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Warehouse Keeper Hagos:<br>
Hello, friend of Varka! You haven't deposited any items here.<br>
<a action="bypass -h npc_%objectId%_DepositP">Deposit an item.</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport Withdraw">Pick up an item.</a>
</body></html>

View File

@@ -0,0 +1,6 @@
<html><body>Warehouse Keeper Hagos:<br>
Welcome, valiant soldier of Varka!<br>
What can I do for you?<br>
<a action="bypass -h npc_%objectId%_DepositP">Deposit an item.</a><br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport Withdraw">Pick up an item.</a>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Warehouse Keeper Hagos:<br>
Oh, traveler of the west wind! Haven't you heard? We Varka only do favors for our friends. We don't deal with strangers!
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>Trader Shikon:<br>
Greetings, friend of the Varka!<br>
Are you surprised to learn that traders such as myself exist within my warrior race? Don't you realize that rivers carry the treasures of many lands as they find their way to the sea?<br>
What I can supply to you now is this low-level booty pouch! Someday, when you can open one of our looted boxes, you'll lay your hands on the strongest armor available!<br>
Bring me a<font color="LEVEL"> Nepenthes Seed</font> and I'll give you whatever you want!<br>
<a action="bypass -h npc_%objectId%_multisell 83820001">"I want to buy one of the Varka's specialty products."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Trader Shikon:<br>
Your reputation as a valiant warrior grows everyday, along with the joy in my heart! I now hope that before long, we'll be able to settle in the promised land!<br>
I've been ordered to supply a higher-level pouch to you, but unfortunately, I can't give you the strongest armor yet! Come back when you've had more experience, and are qualified to open the box.<br>
Bring me a<font color="LEVEL"> Nepenthes Seed</font> and I'll give you whatever you want! Care to take a look?<br>
<a action="bypass -h npc_%objectId%_multisell 83820002">"I want to buy one of the Varka's specialty products."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,7 @@
<html><body>Trader Shikon:<br>
Excellent! I've never seen a fighter as strong as you!<br>
You're finally qualified to obtain the most valuable looted goods from our tribe! Now, open the box to reveal your path to the strongest armor!<br>
Bring me a<font color="LEVEL"> Nepenthes Seed</font> and I'll give you whatever you want! Care to give it a try?<br>
<a action="bypass -h npc_%objectId%_multisell 83820003">"I want to buy one of the Varka's specialty products."</a><br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Trader Shikon:<br>
Greetings, friend of the Varka!<br>
You are not strong enough yet! Try again when you've had more experiences.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Gatekeeper Teranu Mardui:<br>
Hello there, old friend!<br>
I'm dreadfully sorry, but you still are forbidden to use the gate of time and space. In the mean time, would you be willing to serve the Varka?<br>
<a action="bypass -h npc_%objectId%_Quest">Quest</a>
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Gatekeeper Teranu Mardui:<br>
We Varka have no regard for the standards of the outside world. If a person is trustworthy, he is our friend. Where do you wish to travel, friend of the Varka?<br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport Teleport">Teleport</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Gatekeeper Teranu Mardui:<br>
Welcome, friend of Varka!<br>
My elder says that I can escort you to another village. Since you're our friend, I'll gladly open the gate of time and space for you.<br>
<a action="bypass -h Quest 6051_VarkaSilenosSupport Teleport">Teleport</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>&$556;<br>
<br>
<a action="bypass -h npc_%objectId%_goto 10034" msg="811;Goddard Castle Town">Goddard Castle Town - 8000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10035" msg="811;Rune Castle Town">Rune Castle Town - 12000 Adena</a><br1>
</body></html>

View File

@@ -0,0 +1,8 @@
<html><body>&$556;<br>
<br>
<a action="bypass -h npc_%objectId%_goto 10034" msg="811;Goddard Castle Town">Goddard Castle Town - 8000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10035" msg="811;Rune Castle Town">Rune Castle Town - 12000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10036" msg="811;Aden Castle Town">Aden Castle Town - 17000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10037" msg="811;Wall of Argos">Wall of Argos - 11000 Adena</a><br1>
<a action="bypass -h npc_%objectId%_goto 10038" msg="811;Hot Springs">Hot Springs - 14000 Adena</a><br1>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Gatekeeper Teranu Mardui:<br>
I guide travelers through the gate of time and space! I don't deal with outsiders!
</body></html>

View File

@@ -0,0 +1,141 @@
# Created by Emperorc
# Finished by Kerberos_20 10/23/07
import sys
from com.l2jmobius.gameserver.model.quest import State
from com.l2jmobius.gameserver.model.quest import QuestState
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
from com.l2jmobius.gameserver.datatables import SkillTable
from com.l2jmobius.gameserver.network.serverpackets import WareHouseWithdrawalList
from com.l2jmobius.gameserver.network.serverpackets import ActionFailed
qn = "6051_VarkaSilenosSupport"
Ashas = 8377 #Hierarch
Naran = 8378 #Messenger
Udan = 8379 #Buffer
Diyabu= 8380 #Grocer
Hagos = 8381 #Warehouse Keeper
Shikon= 8382 #Trader
Teranu= 8383 #Teleporter
NPCS = range(8377,8384)
Seed = 7187
#"event number":[Buff Id,Buff Level,Cost]
BUFF={
"1":[4359,1,2],#Focus: Requires 2 Nepenthese Seeds
"2":[4360,1,2],#Death Whisper: Requires 2 Nepenthese Seeds
"3":[4345,1,3],#Might: Requires 3 Nepenthese Seeds
"4":[4355,1,3],#Acumen: Requires 3 Nepenthese Seeds
"5":[4352,1,3],#Berserker: Requires 3 Nepenthese Seeds
"6":[4354,1,3],#Vampiric Rage: Requires 3 Nepenthese Seeds
"7":[4356,1,6],#Empower: Requires 6 Nepenthese Seeds
"8":[4357,1,6],#Haste: Requires 6 Nepenthese Seeds
}
class Quest (JQuest) :
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
def onAdvEvent (self,event,npc,player) :
htmltext = "8379-2.htm"
st = player.getQuestState(qn)
if not st: return
Alevel = player.getAllianceWithVarkaKetra()
if str(event) in BUFF.keys() :
skillId,level,seeds=BUFF[event]
if st.getQuestItemsCount(Seed) >= seeds :
st.takeItems(Seed,seeds)
npc.setTarget(player)
npc.doCast(SkillTable.getInstance().getInfo(skillId,level))
npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp())
htmltext = "8379-4.htm"
elif event == "Withdraw" :
if player.getWarehouse().getSize() == 0 :
htmltext = "8381-0.htm"
else :
player.sendPacket(ActionFailed())
player.setActiveWarehouse(player.getWarehouse())
player.sendPacket(WareHouseWithdrawalList(player, 1))
elif event == "Teleport" :
if Alevel == -4 :
htmltext = "8383-4.htm"
elif Alevel == -5 :
htmltext = "8383-5.htm"
return htmltext
def onFirstTalk (self,npc,player):
htmltext = "<html><body>You are either not carrying out your quest or don't meet the criteria.</body></html>"
st = player.getQuestState(qn)
if not st :
st = self.newQuestState(player)
npcId = npc.getNpcId()
Alevel = player.getAllianceWithVarkaKetra()
Seeds = st.getQuestItemsCount(Seed)
if npcId == Ashas :
if Alevel < 0 :
htmltext = "8377-friend.htm"
else:
htmltext = "8377-no.htm"
elif npcId == Naran :
if Alevel < 0 :
htmltext = "8378-friend.htm"
else :
htmltext = "8378-no.htm"
elif npcId == Udan :
st.setState(STARTED)
if Alevel > -1 :
htmltext = "8379-3.htm"
elif Alevel > -3 and Alevel < 0:
htmltext = "8379-1.htm"
elif Alevel < -2 :
htmltext = "8379-4.htm"
elif npcId == Diyabu :
if player.getKarma() >= 1:
htmltext = "8380-pk.htm"
elif Alevel >= 0 :
htmltext = "8380-no.htm"
elif Alevel == -1 or Alevel == -2:
htmltext = "8380-1.htm"
else:
htmltext = "8380-2.htm"
elif npcId == Hagos :
if Alevel >= 0 :
htmltext = "8381-no.htm"
elif Alevel == -1 :
htmltext = "8381-1.htm"
elif player.getWarehouse().getSize() == 0 :
htmltext = "8381-3.htm"
elif Alevel == -2 or Alevel == -3:
htmltext = "8381-2.htm"
else :
htmltext = "8381-4.htm"
elif npcId == Shikon :
if Alevel == -2 :
htmltext = "8382-1.htm"
elif Alevel == -3 or Alevel == -4 :
htmltext = "8382-2.htm"
elif Alevel == -5 :
htmltext = "8382-3.htm"
else :
htmltext = "8382-no.htm"
elif npcId == Teranu :
if Alevel >= 0 :
htmltext = "8383-no.htm"
elif Alevel < 0 and Alevel > -4 :
htmltext = "8383-1.htm"
elif Alevel == -4 :
htmltext = "8383-2.htm"
else :
htmltext = "8383-3.htm"
return htmltext
QUEST = Quest(6051, qn, "custom")
CREATED = State('Start', QUEST)
STARTED = State('Started', QUEST)
QUEST.setInitialState(CREATED)
for i in NPCS:
QUEST.addFirstTalkId(i)
QUEST.addTalkId(Udan)
QUEST.addTalkId(Hagos)
QUEST.addTalkId(Teranu)

View File

@@ -0,0 +1,87 @@
# Made by DrLecter
import sys
from com.l2jmobius.gameserver.model.quest import State
from com.l2jmobius.gameserver.model.quest import QuestState
from com.l2jmobius.gameserver.model.quest.jython import QuestJython as JQuest
from com.l2jmobius.gameserver.datatables import ItemTable
MONUMENTS=[8690]+range(8769,8773)
HERO_ITEMS={
6611:["weapon_the_sword_of_hero_i00","Infinity Blade","During a critical attack, decreases one's P. Def and increases de-buff casting ability, damage shield effect, Max HP, Max MP, Max CP, and shield defense power. Also enhances damage to target during PvP.","297/137","Sword"],
6612:["weapon_the_two_handed_sword_of_hero_i00","Infinity Cleaver","Increases Max HP, Max CP, critical power and critical chance. Inflicts extra damage when a critical attack occurs and has possibility of reflecting the skill back on the player. Also enhances damage to target during PvP.","361/137","Double Handed Sword"],
6613:["weapon_the_axe_of_hero_i00","Infinity Axe","During a critical attack, it bestows one the ability to cause internal conflict to one's opponent. Damage shield function, Max HP, Max MP, Max CP as well as one's shield defense rate are increased. It also enhances damage to one's opponent during PvP.","297/137","Blunt"],
6614:["weapon_the_mace_of_hero_i00","Infinity Rod","When good magic is casted upon a target, increases MaxMP, MaxCP, Casting Spd, and MP regeneration rate. Also recovers HP 100% and enhances damage to target during PvP.","238/182","Blunt"],
6615:["weapon_the_hammer_of_hero_i00","Infinity Crusher","Increases MaxHP, MaxCP, and Atk. Spd. Stuns a target when a critical attack occurs and has possibility of reflecting the skill back on the player. Also enhances damage to target during PvP.","361/137","Blunt"],
6616:["weapon_the_staff_of_hero_i00","Infinity Scepter","When casting good magic, it can recover HP by 100% at a certain rate, increases MAX MP, MaxCP, M. Atk., lower MP Consumption, increases the Magic Critical rate, and reduce the Magic Cancel. Enhances damage to target during PvP.","290/182","Blunt"],
6617:["weapon_the_dagger_of_hero_i00","Infinity Stinger","Increases MaxMP, MaxCP, Atk. Spd., MP regen rate, and the success rate of Mortal and Deadly Blow from the back of the target. Silences the target when a critical attack occurs and has Vampiric Rage effect. Also enhances damage to target during PvP.","260/137","Dagger"],
6618:["weapon_the_fist_of_hero_i00","Infinity Fang","Increases MaxHP, MaxMP, MaxCP and evasion. Stuns a target when a critical attack occurs and has possibility of reflecting the skill back on the player at a certain probability rate. Also enhances damage to target during PvP.","361/137","Dual Fist"],
6619:["weapon_the_bow_of_hero_i00","Infinity Bow","Increases MaxMP/MaxCP and decreases re-use delay of a bow. Slows target when a critical attack occurs and has Cheap Shot effect. Also enhances damage to target during PvP.","614/137","Bow"],
6620:["weapon_the_dualsword_of_hero_i00","Infinity Wing","When a critical attack occurs, increases MaxHP, MaxMP, MaxCP and critical chance. Silences the target and has possibility of reflecting the skill back on the target. Also enhances damage to target during PvP.","361/137","Dual Sword"],
6621:["weapon_the_pole_of_hero_i00","Infinity Spear","During a critical attack, increases MaxHP, Max CP, Atk. Spd. and Accuracy. Casts dispel on a target and has possibility of reflecting the skill back on the target. Also enhances damage to target during PvP.","297/137","Pole"],
6842:["accessory_hero_cap_i00","Wings of Destiny Circlet","Hair accessory exclusively used by heroes.","0","Hair Accessory"]
}
def render_list(mode,item) :
html = "<html><body><font color=\"LEVEL\">List of Hero Items:</font><table border=0 width=300>"
if mode == "list" :
for i in HERO_ITEMS.keys() :
html += "<tr><td width=35 height=45><img src=icon."+HERO_ITEMS[i][0]+" width=32 height=32 align=left></td><td valign=top><a action=\"bypass -h Quest 7000_HeroItems "+str(i)+"\"><font color=\"FFFFFF\">"+HERO_ITEMS[i][1]+"</font></a></td></tr>"
else :
html += "<tr><td align=left><font color=\"LEVEL\">Item Information</font></td><td align=right>\
<button value=Back action=\"bypass -h Quest 7000_HeroItems buy\" width=40 height=15 back=sek.cbui94 fore=sek.cbui92>\
</td><td width=5><br></td></tr></table><table border=0 bgcolor=\"000000\" width=500 height=160><tr><td valign=top>\
<table border=0><tr><td valign=top width=35><img src=icon."+HERO_ITEMS[item][0]+" width=32 height=32 align=left></td>\
<td valign=top width=400><table border=0 width=100%><tr><td><font color=\"FFFFFF\">"+HERO_ITEMS[item][1]+"</font></td>\
</tr></table></td></tr></table><br><font color=\"LEVEL\">Item info:</font>\
<table border=0 bgcolor=\"000000\" width=290 height=220><tr><td valign=top><font color=\"B09878\">"+HERO_ITEMS[item][2]+"</font>\
</td></tr><tr><td><br>Type:"+HERO_ITEMS[item][4]+"<br><br>Patk/Matk: "+HERO_ITEMS[item][3]+"<br><br>\
<table border=0 width=300><tr><td align=center><button value=Obtain action=\"bypass -h Quest 7000_HeroItems _"+str(item)+"\" width=60 height=15 back=sek.cbui94 fore=sek.cbui92></td></tr></table></td></tr></table></td></tr>"
html += "</table></body></html>"
return html
class Quest (JQuest) :
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
def onEvent (self,event,st) :
if st.getPlayer().isHero():
if event == "buy" :
htmltext=render_list("list",0)
elif event.isdigit() and int(event) in HERO_ITEMS.keys():
htmltext=render_list("item",int(event))
elif event.startswith("_") :
item = int(event.split("_")[1])
if item == 6842:
if st.getQuestItemsCount(6842):
htmltext = "You can't have more than a circlet and a weapon."
else :
st.giveItems(item,1)
htmltext = "Enjoy your Wings of Destiny Circlet."
else :
for i in range(6611,6622):
if st.getQuestItemsCount(i):
st.exitQuest(1)
return "You already have an "+HERO_ITEMS[i][1]
st.giveItems(item,1)
htmltext = "Enjoy your "+HERO_ITEMS[item][1]
st.playSound("ItemSound.quest_fanfare_2")
st.exitQuest(1)
return htmltext
def onTalk (Self,npc,st):
htmltext = "<html><body>I have nothing to say to you.</body></html>"
if st.getPlayer().isHero():
htmltext=render_list("list",0)
else :
st.exitQuest(1)
return htmltext
QUEST = Quest(7000,"7000_HeroItems","Hero Items")
CREATED = State('Start', QUEST)
QUEST.setInitialState(CREATED)
for i in MONUMENTS:
QUEST.addStartNpc(i)

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
Our Black Anvil guild has watched you closely for a long time. We paid particular attention when you passed the cruel test of the three blacksmiths and were proclaimed an Artisan, and when you made seven Journeyman Rings and passed the guild's trial.<br>
Not long ago, we determined that you are a splendid Dwarf, with exceptional guts and acumen! I'd like to make you an official offer! One time only! Do you wish to challenge a test given to only the best Artisans? This is your chance to become a<font color="LEVEL"> Maestro</font>, the ultimate Artisan!<br>
<a action="bypass -h Quest 100_SagaOfTheMaestro 0-1">"I'll do it."</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
You've learned the truths of absolute geometry, but you still haven't learned the most sacred truths! Your pilgrimage isn't done yet!<br>
Like food, knowledge must be digested to become truth. Have more experiences and then come back!<br>
(Only a character of level 76 or above can transfer to the Maestro class. Don't abandon the quest until class transfer is complete.)
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
The Black Anvil Guild has watched you closely for a long time. We paid particular attention when you passed the cruel test of the three blacksmiths and were proclaimed an Artisan, and when you made seven Journeyman Rings and passed the guild's trial.<br>
We've determined that you're a splendid Dwarf, with exceptional guts and acumen! I'd really like to offer you the chance to become a<font color="LEVEL"> Maestro</font>, the ultimate artisan, but you don't have enough experience yet. Keep up the hard work!<br>
(This quest may only be undertaken by a Warsmith of level 76 or above.)
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Chief Golem Craftsman Telson:<br>
He's probably in<font color="LEVEL"> Goddard Castle Town</font> by now. He, like his brother, tends to show up and disappear suddenly! So, I'm not quite sure.<br>
Yesterday he came running up to me and dropped this off. He asked me to give it to you. I skimmed through it, and it seems to be a report about a spirit that protects one of the six tablets. You should read it, since you'll have to face it eventually. Now, get going! Good luck!
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Chief Golem Craftsman Telson:<br>
You should meet Master Tobald first and ask him about the pilgrimage of tablets. He's probably in<font color="LEVEL"> Goddard Castle Town</font> by now. He, like his brother, tends to show up unexpectedly and then vanish just as suddenly... So, I'm not quite sure.<br>
You must read the report I gave you! You'll need to know what's in it! Get going now! Good luck!
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
To reach the level of Maestro, you must learn the basic truths of absolute geometry. No books or scrolls exist on the subject, so your path will not be an easy one. The knowledge is far from the domain of Dwarves, in the territory of the gods. The secret is supposedly written on six ancient tablets, hidden by the gods in secluded areas and protected by formidable monsters to prevent anyone from discovering the magic they contain.<br>
Once you learn all the knowledge specified in the six tablets, you'll become a<font color="LEVEL"> Maestro</font>, with the crystal structures of metals flowing through your fingertips! A Dwarf named Master Tobald left earlier to undertake the pilgrimage of the tablets. Do you know him? His brother is the famous Master Toma! He may be careless, it must run in his family, but his abilities are undeniable! Tobald can help you with various things regarding the pilgrimage of the tablets. Go and find him!<br>
<a action="bypass -h Quest 100_SagaOfTheMaestro accept">"Where is he?"</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
Welcome back! Well, Master Tobald came by a few days ago and was talking about you! He said that you'd be coming by today, and here you are! How strange!<br>
Did you really finish the pilgrimage of tablets? You finished before Tobald! That's incredible!<br>
<a action="bypass -h Quest 100_SagaOfTheMaestro 0-2">"Now what?"</a>
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
You've learned the ultimate sacred truths of absolute geometry! My only role is to confer an appropriate title upon the person with the knowledge.<br>
On behalf of the Black Anvil Guild, I hereby grant you the title of Maestro!<br>
Congratulations! The birth of a new Maestro is a very happy occasion! I expect great things from you! Please do your best to become a model for all Dwarves!
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
You've learned the truths of absolute geometry, but you still haven't learned the most sacred truths! Your pilgrimage isn't done yet!<br>
Like food, knowledge must be digested to become truth. Have more experiences and then come back!<br>
(Only a character of level 76 or above can transfer to the Maestro class. Don't abandon the quest until class transfer is complete.)
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Chief Golem Craftsman Telson:<br>
You've learned the ultimate sacred truths of absolute geometry! My only role is to confer an appropriate title upon the person with the knowledge.<br>
On behalf of the Black Anvil guild, I hereby grant you the title of Maestro!<br>
Congratulations! The birth of a new Maestro is a very happy occasion! I expect great things from you! Please do your best to become a model for all Dwarves!
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Blueprint Seller Borodin:<br>
That's right! I've been asked to repair one of Master Tobald's inventions! What an honor! Master Toma's development of the spatial movement device was amazing, but a machine that lets you travel through time is something, isn't it?<br>
<a action="bypass -h Quest 100_SagaOfTheMaestro 1-3">"I heard that you are having a problem making the repairs."</a>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Blueprint Seller Borodin:<br>
You're really narrow-minded, aren't you? Look! I must have<font color="LEVEL"> ice crystals</font> to repair Wilma #3! You'll find them in the<font color="LEVEL"> hot springs area</font> in the north part of Goddard.<font color="LEVEL"> Chef Jeremy</font> can tell you more.
</body></html>

View File

@@ -0,0 +1,5 @@
<html><body>Blueprint Seller Borodin:<br>
Welcome back! You've brought the ice crystals that produce a temperature of absolute zero! I can fix the cooling system easily with these!<br>
I heard you killed Bumbalump! Is that true? Awesome!<br>
<a action="bypass -h Quest 100_SagaOfTheMaestro 1-4">"Here you go."</a>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Blueprint Seller Borodin:<br>
Why are you back? I fixed the cooling system of Wilma #3 and gave it to you to take to<font color="LEVEL"> Master Tobald</font>! Get going!
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Blueprint Seller Borodin:<br>
Ha! I'm embarrassed to say, but that's what happened. Honestly, I need a very powerful coolant to repair such a huge cooling system... Could you please find some<font color="LEVEL"> ice crystals</font> for me? I've heard they reach a temperature of absolute zero! You can only find them in the<font color="LEVEL"> hot springs area</font> in the northern part of Goddard.<font color="LEVEL"> Chef Jeremy</font> will tell you where to find them if you help him find some soy sauce.
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Blueprint Seller Borodin:<br>
As you can see, the problem isn't my skill, only the shortage of raw materials! I fixed it, didn't I? Take it to<font color="LEVEL"> Master Tobald</font> now. Wilma #3 is working fine!<br>
I heard you were on the pilgrimage of the tablets. I didn't realize you were so important! Good luck! May you become as great a craftsman as Master Tobald himself!
</body></html>

View File

@@ -0,0 +1,4 @@
<html><body>Tablet of Vision:<br>
You can feel the presence of the Stone of Commune near the tablet. You feel you can find out its exact location if you lay your hands on the tablet.<br>
<a action="bypass -h Quest 100_SagaOfTheMaestro 10-1">Lay hands on the tablet.</a>
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Tablet of Vision:<br>
As you are about to lay your hands on the tablet, you can feel something behind you. And a new creature that you haven't seen before appears...
</body></html>

View File

@@ -0,0 +1,3 @@
<html><body>Tablet of Vision:<br>
You need the Stone of Commune to decipher the hieroglyphs on the tablet. Speak with<font color="LEVEL"> Master Tobalt</font> about the Stone of Commune.
</body></html>

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