123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- Quest scripts define the complete or near-complete flow of events that take place from the
- start to the end of a quest. This includes, but is not limitted to, starting and accepting
- the quest, following complex dialogs, attacking or killing mobs, finding quest items, spawning
- quest mobs, completing a quest, and getting rewards.
- In order for quest scripts to function properly, at least 3 classes must be imported from Java:
- from net.sf.l2j.gameserver.model.quest import State
- from net.sf.l2j.gameserver.model.quest import QuestState
- from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
- In addition, the jython library "sys" is generally imported for convinience. More classes can
- be imported as needed, in order to access other components of the core and enhance the abilities
- of the script.
- Jython quest scripts essentially inherit from the Java class net.sf.l2j.gameserver.model.quest.Quest
- Developers who are comfortable with Java may read the source code for this class, as provided by the
- l2jserver project (www.l2jserver.com) for full details and available functions. Alternatively, one
- may read forward in this documentation.
- AVAILABLE TRIGGER FUNCTIONS:
- There exist a set of functions that are predefined for quests and are triggered from various actions.
- These functions, their triggers, and the parameters passed into the script are defined below:
- 1) onAdvEvent(self, event, npc, player)
- This function is called whenever a player clicks on a link in a quest dialog and whenever
- a timer fires. Also, should other functions (see below - onTalk, onKill, etc) are not
- implemented, this function will be called in their place.
- The parameter "npc" contains a reference to the instance of NPC associated with this event.
- This may be the NPC registered in a timer, or the NPC with whom a player is speaking, etc.
- This parameter may be NULL in certain circumstances.
- The parameter "player" contains a reference to the player participating in this function. It
- may be the player speaking to the NPC, or the player who caused a timer to start (and owns
- that timer).
- This parameter may be NULL in certain circumstances.
- The parameter "event" contains a string identifier for the event. Generally, this string
- is passed directly via the link. For example:
- <a action="bypass -h Quest 626_ADarkTwilight 31517-1.htm">hello</a>
- The above link sets the event variable to "31517-1.htm" for the quest 626_ADarkTwilight
- In the case of timers, this will be the name of the timer. This parameter serves as a
- sort of identifier.
- The parameter "self" is a reference to the quest itself. You may use self.XXXX where XXXX is
- any function defined in the parent class of your quest.
- 2) onEvent(self, event, st)
- This function is called in place of onAdvEvent if the former is not implemented. If a script
- contains BOTH onAdvEvent AND onEvent, then onEvent will never be called unless the script's
- onAdvEvent explicitely calls onEvent within.
- The parameter "st" contains a reference to the QuestState of the player who used the link or
- started the timer.
- The parameters "event" and "self" are same as in onAdvEvent.
- 3) onAttack(self, npc, player, damage, isPet)
- This function is called whenever a player attacks an NPC that is registered for the quest
- The parameter "npc" contains a reference to the exact instance of the NPC that got attacked
- The parameter "player" contains a reference to the exact instance of the player who attacked.
- The parameter "damage" is a number, representing the total damage that this attack has inflicted to the NPC.
- The parameter "isPet" is a boolean. When false it denotes that the attacker was indeed the player.
- If true it specifies that the damage was actually dealt by the player's pet.
- The parameter "self" works the same as in onEvent.
- 4) onKill(self, npc, player, isPet)
- This function is called whenever a player kills an NPC that is registered for the quest
- All parameters are the same as in onAttack, lacking the damage parameter, of course.
- 5) onSkillSee(self, npc, caster, skill, targets, isPet)
- This function is called whenever a player casts a skill near a registered NPC (1000 distance)
- The "npc" and "isPet" parameters are same as with onAttack.
- the "caster" parameter references the actual instance of the player who cast the spell.
- The "skill" parameter is a referece to the actual skill that was used (from which info about the id and level
- of the skill can be obtained).
- The "targets" parameter is an array of all objects (can be any type of object, including mobs and players) that
- are affected by the skill.
- NOTE: if a skill does damage, BOTH onSkillSee AND onAttack will be triggered for the damaged NPC! However,
- only onSkillSee will be triggered if the skill does no damage, or if it damages an NPC who has no onAttack
- registration while near another NPC who has an onSkillSee registration.
- 6) onTalk(self,npc, player)
- This function is called whenever a player clicks to the "Quest" link of an NPC that is registered
- for the quest.
- All parameters are the same as in onAttack
- 7) onFirstTalk(self,npc, player)
- This function is called whenever a player talks to an NPC that is registered for the quest. That is,
- it is triggered from the very first click on the NPC, not via another dialog.
- NOTE 1: Each NPC can be registered to at most one quest for triggering this function. In other words,
- the same one NPC cannot respond to an "onFirstTalk" request from two different quests.
- Attempting to register an NPC in two different quests for this function will result in one of the
- two registration being ignored.
- NOTE 2: Since a Quest link isn't clicked in order to reach this, a quest state can be invalid within this
- function. The coder of the script may need to create a new quest state (if necessary), by using:
- st = self.newQuestState(player)
- NOTE 3: the returned value of onFirstTalk replaces the default html that would have otherwise been loaded
- from a subfolder of .../gameserver/data/html/...
- If you wish to show the default html, within onFirstTalk do npc.showChatWindow(player) and then return ""
- All parameters are the same as in onAttack.
- 8) onDeath (self, npc, character, st)
- This function is called whenever an exact INSTANCE of a character who was previously registered for this
- event dies. The registration for onDeath events is NOT done via the quest itself, but it is instead handled
- by the QuestState of a particular player.
- The parameter "npc" contains a reference to the exact instance of the NPC that KILLED the character.
- The parameter "character" contains a reference to the exact instance of the character that got killed.
- The parameter "st" contains a reference to the QuestState of whomever was interested (waiting) for this kill
- The parameter "self" works the same as in onEvent.
- 9) onSpawn (self, npc)
- Currently the only function that has no reference to a player. It is triggered whenever an NPC spawns or
- respawns and passes a reference to the newly (re)spawned NPC. It is useful for initializations, starting
- quest timers, displaying chat (NpcSay), and more.
- The parameter "npc" contains a reference to the exact instance of the NPC who just (re)spawned.
- 10) onFactionCall(self, npc, caller, attacker, isPet)
- Triggered when an npc is called by another npc in the same faction.
- The parameter "npc" contains a reference to the exact instance of the NPC who is being asked for help
- The parameter "caller" contains a reference to the exact instance of the NPC who is asking for help
- The parameter "attacker" contains a reference to the exact instance of the player who attacked the caller
- The "isPet" parameters works same as with onAttack.
- 11) onAggroRangeEnter(self, npc, player, isPet)
- This is currently here only as a place-holder. This function is NOT yet called from any part of the code.
- The idea is it will be called whenever a player or pet come near an aggro mob (enter its aggro range).
- The parameters "npc", "player", and "isPet" work similar to onAttack.
-
- 12) REGISTRATION FUNCTIONS:
- The functions described below have a single purpose: To register an NPC for event triggers. Simply put,
- an NPC must be registered in a quest for a particular event in order for the NPC to respond to the occurence
- of thatevent.
- Registration Functions are NOT called automatically. Instead, they should be added at the bottom of your
- quest script.
- Descriptions of all registration functions follow:
- a) addStartNpc(npcId)
- Registers an NPC for onTalk events. These NPCs are considered start NPCs. Therefore, the player
- does NOT need to have started the quest in order to access the onTalk section of the quest.
- Instead, when a player talks to NPCs registered by addStartNpc, then the players automatically get
- a CREATED state for this quest.
- The parameter "npcId" contains the id of the template for this NPC.
- b) addTalkId(npcId)
- Registers an NPC for onTalk events. These NPCs are not considered start NPCs (unless they are also
- registered with addStartNpc). NPCs registered using addTalkId will only respond to the player's
- click of a "Quest" link if and only if the player has alredy started the quest.
- The parameter "npcId" contains the id of the template for this NPC.
- c) addAttackId(npcId)
- Registers an NPC for onAttack events. The players do NOT need to be registered for the quest in order
- to trigger a response to an attack against this NPC.
- The parameter "npcId" contains the id of the template for this NPC.
- d) addKillId(npcId)
- Registers an NPC for onKill events. The players do NOT need to be registered for the quest in order
- to trigger a response to this NPC getting killed.
- The parameter "npcId" contains the id of the template for this NPC.
- e) addFirstTalkId(npc)
- Registers an NPC for onFirstTalk events.
- f) addSpawnId(npc)
- Registers an NPC for onSpawn events.
- g) addSkillSeeId(npc)
- Registers an NPC for onSkillSee events.
- f) addFactionCallId(npc)
- Registers an NPC for onFactionCall events.
- h) addAggroRangeEnterId(npc)
- Registers an NPC for onAggroRangeEnter events (remember, those events aren't yet supported and will not be
- triggered by core yet).
-
- 13) OVERRIDABLE QUEST FUNCTIONS:
- There exist a few functions which are automatically called by the core (and optionally manually called within
- your script) which meant to be overriden by your quest script for special needs.
- a) saveGlobalData()
- Optional function. If a quest (or ai) needs to keep track of variables that are persistant beyond a reboot
- but are not tied to any particular character (for example, count how many players have finished a quest in
- order to do some special action when the count reaches 1000), then you can override this function and add
- code for saving your special variabls. This function will automatically be called when the server is shutting
- down as well as when you attempt to reload the quest using GM commands. The actual functions used to save
- those variables are described in section 11, below.
- b) init_LoadGlobalData()
- Optional function. If a quest has saved global data, you will also need to implement a way to load the data
- back. Here, you can define everything from which variables to look for and load to the structure in which
- you wish to store the data (for example, you may want to format things as an array, or a dictionary, or some
- other structure). The actual functions used to load those variables are described in section 11, below.
- 14) OTHER QUEST FUNCTIONS:
- In addition to the trigger functions (which are called automatically by the core when certain actions take place)
- there also exist a variety of functions that belong to the Quest class and can be accessed within each script.
- To call those functions one needs to prefix the call with "self." and provide the appropriate parameters. For
- example, if the Quest class had a function named "foo" and it expected an integer parameter, you could call this
- function from anywhere within the "class Quest" segment of your script, using the code
- self.foo(5)
- The full listing of available functions can be seen in the class net.sf.l2j.gameserver.model.quest.Quest, which
- is located at net/sf/l2j/gameserver/model/quest/Quest.java from the l2jserver project. However, a few of the
- more common functions are summarized here:
- a) startQuestTimer(name, time, npc, player, repeating)
- Starts a timer. The timer will call onAdvEvent(name, npc, player) each time that it fires.
- The parameter name is a string which serves as the name of the timer (or "event").
- time refers to the number of milliseconds that the timer will wait before it fires.
- npc is the actual instance of an NPC or Mob assosiated with the timer. If this timer is not tied to
- any particular instance, you should pass None as the parameter.
- player is the actual instance of a player assosiated with the timer. If this timer is not tied to
- any particular instance, you should pass None as the parameter.
- repeating is a boolean (True or False) variable. If this is False, the timer will only fire once. If
- this is True, the timer will keep firing at equal periods (equal to the "time" parameter) for ever,
- unless you explicitely cancel the timer, reboot the server, or reload the quest (assuming that your
- script doesn't automatically start the timer again when it loads).
- b) getQuestTimer(name, npc, player)
- Allows you to grab an instance of the timer. This is primarily used behind the scenes (from core) and
- you would rarely really need it, but I am describing as it is somewhat important in understanding timers.
- The parameter name refers to the name with which a timer was added. It is the first and most important
- key in identifying the timer. Two timers with different name are always considered unrelated to each
- other. If the name is the same, the timers are further identified by the npc and player associated.
- npc is the second key for identifying timers. A null (None) npc acts as a wildcard! That is, if you call
- this function with a null npc parameter, it will consider as matches any timers with the correct
- name and player, regardless of which NPC was used. On the other hand, if you use a non-null npc, this
- function will consider as matches any timers with the same name, npc, and player as well as timers
- with the same name and player but null NPC.
- player is the last key for identifying timers. A null (None) player acts as a wildcard! That is, if you call
- this function with a null player parameter, it will consider as matches any timers with the correct
- name and npc, regardless of which player was used. On the other hand, if you use a non-null player, this
- function will consider as matches any timers with the same name, npc, and player as well as timers
- with the same name and npc but null player.
- Naturally, if both player and npc are null, matches are identified based solely on the name.
- c) cancelQuestTimer(name, npc, player)
- Cancels a timer. See getQuestTimer for details on how this call will match and discover which timer to
- cancel. If multiple timers match the parameters, only the first timer that the code discovers will be cancelled.
- d) saveGlobalQuestVar(var, value)
- This permanently (until explicit deletion) saves a variable that is global for this quest. Here, global
- refers to the fact that it is not tied to any particular player! It does not mean global for all quest.
- var is a string denoting the variable name.
- value is a string denoting the value of the variable "var".
- For storing complex structures, your script must provide code which properly breaks down the data into
- var/value pairs and saves it in a way that can be read back.
- e) loadGlobalQuestVar(var)
- This loads a permanently saved variable that is global for all players within this quest. It then
- returns the result as a string. It returns an empty string if the specified variable does not exist
- for this quest.
- var is the name of the variable you wish to load
- f) deleteGlobalQuestVar(var)
- Deletes a global quest variable for this quest (same definition of "global" as in #d).
- var is the name of the variable you wish to delete
- g) deleteAllGlobalQuestVars()
- Deletes ALL global quest variables for this quest (same definition of "global" as in #d).
- h) getRandomPartyMember(player)
- Returns a random player who is in the same party as the referenced parameter. If the referenced
- parameter is a player who is not in a party, it returns the player reference itself automatically.
- If the reference is null, it returns null.
- player is a reference to a player instance.
- i) getRandomPartyMember(player, var, value)
- Similar to #h but only returns a result among those players who have the specified var and value pair
- among their QuestState variables (see QuestState description below). If no party member matches these
- conditions, a null (None) is returned.
- The reference player may also be among the possible results if it also matches the conditions.
- Similarly to #h, if the reference player is not in a party, then only the var/value pairs are checked.
- In that case, if the player matches the conditions, the same player is returned, else null is returned.
- player: The reference player whose party will be checked
- var: The variable name necessary for a match. If this is null (None), then a completely random
- party member is returned regardless of the value (same as in #h).
- value: the required value of the "var" before a party member is considered for the random poll.
- Example usage:
- self.getRandomPartyMemberState(player, "cond","5")
- This will return a random party member among those members who have cond=5.
- j) getRandomPartyMemberState(player, state)
- Similar to #h but only returns a result among those players whose QuestState has a state matching the
- passed "state" variable (see QuestState description below). If no party member matches the state
- condition a null (None) is returned.
- If the reference player is not in a party, either the reference is return if it matches the state
- condition, or a null (None) is returned if the reference player doesn't match the state condition.
- For example,
- self.getRandomPartyMemberState(player, State.COMPLETED)
- will return a random party member among those members who have completed the quest.
- Quest:
- After writing your script, in order to initialize your quest and register it with the game server, near the
- bottom of your script, you must use:
- QUEST = Quest(id,"12345_QuestName","Description")
- For example:
- QUEST = Quest(626,"626_ADarkTwilight","A Dark Twilight")
- It is often useful to define the quest name in a variable at the top of the script (typically called "qn").
- In that case, you may register your quest using:
- QUEST = Quest(626,qn,"A Dark Twilight")
- In addition, you can register quest items with this quest. All registered items will be DELETED from the
- player's inventory, as soon as the quest is aborted or completed. Many quests reward items that are not
- meant to be deleted upon quest completion, even if the items appear in the quest inventory (example: star of destiny).
- Such items should NOT be registered as questItems. To register items with a quest, you need to modify the __init__
- function of the quest. For a simple quest with no registrations, the __init__ function will look something like :
- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
- For a quest with registered items, this should be:
- def __init__(self,id,name,descr):
- JQuest.__init__(self,id,name,descr)
- self.questItemIds = [1234,5678]
- In this example, the items with id 1234 and 5678 are registered.
- QuestState:
- A QuestState is not part of the quest definition itself, but it contains the information that tracks the
- progress of a particular player for this quest. Given a player instance, the quest-state of that player for
- this quest can be found using:
- st = player.getQuestState("12345_questname")
- If the player does NOT have a quest-state for this quest (i.e. the player is not currently doing this quest), then
- st will be null.
- In addition, the queststate of a random party member who has a particular variable and value stored for this quest,
- can be discovered using:
- partyMember = self.getRandomPartyMember(player,"variable","value")
- st = partyMember.getQuestState("12345_questname")
- Similarly, the queststate of a random party member who has reached a particular STATE for this quest,
- can be discovered using:
- partyMember = self.getRandomPartyMemberState(player,STATE)
- st = partyMember.getQuestState("12345_questname")
- For example, instead of "variable" and "value" in the first sample, one may use "cond" and "1". Instead of STATE in
- the second sample, one may use State.STARTED
- While a QuestState can be discovered from a player, it can also access the player instance back when needed, using
- st.getPlayer()
- All other public methods of implementation of QuestState are accessible from jython. Similarly, objects
- reachable from st can be further used in order to reach deeper. For example, one may do something like:
- st.getPlayer().getClan().getLeader().getPlayerInstance().getPet()
- (this example may not be fully accurate or may get deprecated in the future...it is only meant as a
- little demonstation of how one may reach deeper into a chain of objects that are accessible. In this
- case, from the QuestState, we get the player whose QuestState this is, then get that player's clan,
- the clan's leader, the leader's actual player instance, and from there, we find the leader's summonned pet!)
-
- State:
- States are used to track segments of the quest for players. States are not a property of any particular quest and
- States Types cannot be added or removed dynamically. They are a mere enumeration used universally by all quests.
- Each QuestState carries a State value which can be compared to the available (global) state types in order to check
- the progress that the given character has with regards to the given QuestState (see QuestState info above).
- The available state types are:
- CREATED
- STARTED
- COMPLETED
- For example, given an instance of a QuestState (st) for a given player doing some quest, one can check if the
- player has completed the quest by doing the comparison:
- st.getState() == State.COMPLETED
|