- Joined
- Dec 19, 2012
- Messages
- 411
So, when i developing my Quest System, i'm facing a pretty strange desync problem.
What i did is this :
It strangely could cause desync randomly, the situations i met when desync occurs :
Hopefully someone could clarify me if i did something wrong.
In case you all need the trigger (be warned that it is pretty complicated) :
Test map is attached if someone need to test in map.
What i did is this :
JASS:
if GetLocalPlayer() != itemOwner then
call SetItemVisible(someItem, false)
endif
It strangely could cause desync randomly, the situations i met when desync occurs :
- when I picked up 1st item it would desync
- when I picked up 2nd item it would desync (not 1st item)
- when other player picked up item it would desync
- when I select the the unit (for returning quest and not pass item to the unit) it would desync
Hopefully someone could clarify me if i did something wrong.
In case you all need the trigger (be warned that it is pretty complicated) :
JASS:
library QuestSystem /* version 0.1.5
*====================================Quest System by DD_LegionTN====================================*
*
* System Description :
* A fully customized quest system that using game text as main display for quests
*
*===================================================================================================*
*
* Version
* v0.1.
*===================================================================================================*
*
* Features :
* - Enable to create a quest just in a minute
*
*===================================================================================================*
*
* Requirement :
* */requires /*
*
* */Table /*
* - As lots of data need to be stored and retrieved, a table is nessasary for
* data manangement
*
* */TableArray /*
* - Extension of Table to enable multi-array to be used so that a more clean and clear code
* could be coded
*
* */optional ErrorMessage /*
* - For clear and precise debug result (temporary not using, might use in future)
*
*===================================================================================================*/
//! novjass
API :
//used by PICK_UP requirement
struct RectSet extends array
static method create takes nothing returns thistype
// -create a new rect set
method addRect takes rect r returns nothing
// -add a rect to the rect set
endstruct
struct Quest extends array
static method create takes nothing returns thistype
// -create a new quest instance
method operator title= takes string s returns nothing
// -assign quest title
method operator difficulty= takes string s returns nothing
// -assign quest difficulty
// -default contains 3 difficulties (you may add your own at configurable globals block):
// *QUEST_DIFFICULTY[0] = "normal"
// *QUEST_DIFFICULTY[1] = "moderate"
// *QUEST_DIFFICULTY[2] = "hard"
method operator description= takes string s returns nothing
// -assign quest description
method operator descriptionLines= takes integer lines returns nothing
// -assign quest description's line used
// -only need to assign if description used more then 2 lines or improper text position may occurs
method setEffectPathReceive takes string s, string attachPoint returns nothing
// -assign receive effect path
method setEffectPathReturn takes string s, string attachPoint returns nothing
// -assign return effect path
method operator questEventList takes integer whichList returns nothing
// -set the specific list for the event (for randomize quest)
method operator questConditionList takes integer whichList returns nothing
// -set the specific list for the condition (for randomize quest)
method operator questContentList takes integer whichList returns nothing
// -set the specific list for the content (for randomize quest)
method operator questRewardList takes integer whichList returns nothing
// -set the specific list for the reward (for randomize quest)
endstruct
/*******************************************************************************************/
struct QuestEvent extends array
static method create takes Quest q returns thistype
// -create a new quest receive event instance
// -a quest can have 2 or more receive event (for quest randomization)
method operator registerReceiveEvent= takes integer i returns nothing
// -assign quest receive event type
// -currently have 1 quest event type :
// * QUEST_EVENT_SELECT
method operator registerReturnEvent= takes integer i returns nothing
// -assign quest return event type
// -currently have 1 quest event type :
// * QUEST_EVENT_SELECT
method operator receiveFrom= takes unit u returns nothing
// -assign quest to a target unit (receive quest from unit u)
method operator returnTo= takes unit u returns nothing
// -assign quest to a target unit (return quest to unit u)
method operator questAbilityId= takes integer i returns nothing
// -assign quest ability (icon for player to click to receive/return quest)
// -must contains 2 levels
endstruct
/*******************************************************************************************/
struct QuestCondition extends array
static method create takes Quest q returns thistype
// -create a new quest conditon instance
// -a quest can have 2 or more condition event (for quest randomization)
method operator addLevel= takes integer levelRequired returns nothing
// -assign lv condition
method operator addQuest= takes Quest q returns nothing
// -assign quest condition (so quest1 needed to be completed before quest2 could be received)
endstruct
/*******************************************************************************************/
struct QuestContent extends array
static method create takes Quest q returns thistype
// -create a new quest content instance
// -a quest can have 2 or more content (for quest randomization)
method registerKillUnit takes integer uId, integer noToKill returns nothing
// -assign killing requirement
// -uId : unit-type id
// -noToKill : number to kill
method registerTalk takes unit u, integer aId, string extraDescription, string extraDescription2, string effectPath returns nothing
// -assign talk requirement
// -u : unit to talk
// -aId : ability id (so that player can click the ability and complete requirement, only 1 lv is needed)
// -extraDescription : Will display at quest details at quest requirement : "Talk to XXX (extraDescription goes here)"
// -extraDescription2 : Will display at player's screen after player clicked the ability
// -effectPath : the effect path indicates talkable unit
method registerPickUp takes RectSet rs, integer iId, integer noToPick, string extraDescription returns nothing
// -assign pick up requirement
// -rs : RectSet which defined a set of rect
// -iId : item-type id
// -noToPick : number of item to pick
// -extraDescription : Will dispaly at quest details at quest requirement : "Pick up XXX (extraDescription goes here)"
endstruct
/*******************************************************************************************/
struct QuestReward extends array
static method create takes Quest q returns thistype
// -create a new quest reward instance
// -a quest can have 2 or more reward instance (for quest randomization)
method operator gold= takes integer amount returns nothing
// -setting the reward gold
method operator lumber= takes integer amount returns nothing
// -setting the reward lumber
method operator experience= takes integer amount returns nothing
// -setting the reward experience
endstruct
//! endnovjass
/**************************************************************************************************/
/*****************************************CONFIGURABLE*********************************************/
/**************************************************************************************************/
globals
//Dummy unit id (selectable unit)
private constant integer DUMMY_ID = 'h000'
//Dummy hero id for fast viewing quest info
private constant integer QUEST_INFO_ID = 'H001'
//Maximum number of quests that allowed to be taken by player
private constant integer MAX_QUEST_PER_PLAYER = 7
//Maximum range for the player to near the NPC before he could be able to talk to NPC and accept the quest(s)
private constant real MAX_RANGE = 200.
/*
color list for enhancing your visual when viewing the quest info, modify the color to suit your own needs if needed
A text picture for layout for easier understand which text will get which type of color :
QUEST_NAME_STRING quest name
QUEST_DIFFICULTY_STRING QUEST_DIFFICULTY_XXXX
-----------QUEST_BASIC DESRIPCTION HERE-----------------
-----------QUEST_BASIC DESRIPCTION HERE-----------------
QUEST_REQUIREMENT_STRING
- QUEST_BASIC CONTAIN GOES HERE
- QUEST_BASIC CONTAIN GOES HERE
Example output (based on default) :
Quest Name : Your quest
Quest Difficulty : Normal
You quest description locates here
Quest Requirement :
- Kill 2 unit type (0/2)
- Kill 2 unit type 2 (0/2)
So, here is the list that describe which text will get which color :
quest name - white color (user may specific color by adding color code)
QUEST_NAME_STRING, QUEST_DIFFICULTY_STRING, QUEST_REQUIREMENT_STRING - QUEST_COLOR_GENERAL
QUEST_DIFFICULTY[x] - QUEST_COLOR_DIFFICULTY[x] where x = 1, 2, 3... depend on the number of difficulty user defining
QUEST_BASIC DESRIPCTION HERE - QUEST_COLOR_DESCRIPTION
QUEST_BASIC CONTAIN GOES HERE - 2 type of colors : For incomplete quest requirement - QUEST_COLOR_INCOMPLETE
For coplete quest requirement - QUEST_COLOR_COMPLETE
*/
constant string QUEST_COLOR_GENERAL = "|cff4da6ff" //moderate blue (77, 166, 255)
constant string QUEST_COLOR_DESCRIPTION = "|cff48d1cc" //medium turquoise (72, 209, 204)
constant string QUEST_COLOR_INCOMPLETE = "|cffff6666" //moderate red (255, 102, 102)
constant string QUEST_COLOR_COMPLETE = "|cff66ff99" //light green (102, 255, 153)
//color code for highlight dialog's hotkey
constant string DIALOG_HOTKEY_HIGHLIGHT = "|cffffff00"
//string array used by QUEST_BASIC for quest difficulty (configure it in Init() )
string array QUEST_DIFFICULTY
//string array used for color effect for QUEST_DIFFICULTY (configure it in Init() )
string array QUEST_COLOR_DIFFICULTY
//integer array used as hotkey for the dialog, input an ASCII character (or integer if you know what to do)
integer array DIALOG_HOTKEY
endglobals
//Init function for user to configure
private function Init takes nothing returns nothing
//Configure your own difficulty here, you may have more than 3, defaultly is set to 3
set QUEST_DIFFICULTY[0] = "normal"
set QUEST_DIFFICULTY[1] = "moderate"
set QUEST_DIFFICULTY[2] = "hard"
//Configure your own difficulty color here, it is dependent on the index of difficulty (index 0 matches with index 0)
set QUEST_COLOR_DIFFICULTY[0] = "|cffffffb3" //pale yellow (255, 255, 179)
set QUEST_COLOR_DIFFICULTY[1] = "|cffb3ffb3" //pale green (179, 255, 179)
set QUEST_COLOR_DIFFICULTY[2] = "|cffff66b3" //pink (255, 102, 179)
//Configure your own dialog button hotkey here (index starts with 0 and end with MAX_QUEST_PER_PLAYER)
set DIALOG_HOTKEY[0] = '1'
set DIALOG_HOTKEY[1] = '2'
set DIALOG_HOTKEY[2] = '3'
set DIALOG_HOTKEY[3] = '4'
set DIALOG_HOTKEY[4] = '5'
set DIALOG_HOTKEY[5] = '6'
set DIALOG_HOTKEY[6] = '7'
set DIALOG_HOTKEY[7] = 512 //ESC hotkey
endfunction
//A function that adjusts text display's position of y, leave it if you unsure what it is
private function getTextDisplayY takes real NoOfLines returns real
return 0.54 - NoOfLines*0.04
endfunction
//A function that adjusts text display's position of x, leave it if you unsure what it is
private constant function getTextDisplayX takes nothing returns real
return 0.25
endfunction
/**************************************************************************************************/
/********************************BELOW ARE NON-CONFIGURABLE****************************************/
/**************************************************************************************************/
//globals init for player usable constants when using QuestSystem
globals
//constants used by QUEST_EVENT for quest registeration type
constant integer QUEST_EVENT_SELECT = 1
endglobals
//globals init private CONSTANT or ARRAY_CONSTANT which use internally by QuestSystem only
globals
//constants used by table for distinguish which part of quest is writing/retrieving
private constant integer QUEST_BASIC = 0
private constant integer QUEST_EVENT = 1
private constant integer QUEST_CONDITION = 2
private constant integer QUEST_CONTENT = 3
private constant integer QUEST_REWARD = 4
//constants used by QUEST_EVENT for table index
private constant integer RECEIVE_EVENT = 0
private constant integer RETURN_EVENT = 1
private constant integer QUEST_ABILITY_ID = 1
//constants used by QUEST_CONDITION for content's types
private constant integer LEVEL = 1
private constant integer QUEST = 2
//constants used by QUEST_CONTENT for content's types
private constant integer KILL = 1
private constant integer TALK = 2
private constant integer PICK_UP = 3
//constants used by QUEST_REWARD for reward's types
private constant integer GOLD = 1
private constant integer LUMBER = 2
private constant integer EXPERIENCE = 3
//constants used by pTable for setting player's quest progress type
private constant integer QUEST_NOT_TAKING = 0 //haven't take the quest
private constant integer QUEST_IN_PROGRESS = 1 //quest in progress
private constant integer QUEST_COMPLETE = 2 //complete requirement
private constant integer QUEST_COMPLETED = 3 //received reward, quest fully completed
//constants used for checking quest completion for possible pregression to next quest(s)
private constant integer QUEST_COMPLETED_CHECK = 1
private constant integer LEVEL_UP_CHECK = 2
//constant used by table for defining array slot is not in use
private constant integer NOT_IN_USE = 0
//constant used by setting quest ability level : 2 = quest ready to be completed
private constant integer COMPLETE = 2
//constant used by defining TableArray size for counting how many parts does quest have (array slot 0 is NOT included)
//(EVENT, CONDITION, CONTENT, REWARD)
private constant integer MAXIMUM_QUEST_PART = 5
//constants used for starting index of RETURN_EVENT for easier looping
// starting index for RECEIVE_EVENT is 1
//A unit is impossible to have 10k quests assigned to it, so it is a safe value
private constant integer MAX_QUEST_PER_UNIT = 10000
/*
A list of string constants used by dispaly quest info
*/
private constant string QUEST_NAME_STRING = "Quest Name : "
private constant string QUEST_DIFFICULTY_STRING = "Quest Difficulty : "
private constant string QUEST_REQUIREMENT_STRING = "Quest Requirement :"
//index used by table
private integer array TABLE_INDEX
//Player's hero (self configure and init it)
unit array HERO
//Player's quest dummy hero (will auto create at map init)
unit array QUEST_INFO
endglobals
//globals init for non-constant variables
globals
//main table for storing quest data
private HashTable5D table
//sub table for storing quest instance
//(instance for each quest of QUEST_EVENT, QUEST_CONDITION_, QUEST_CONTENT, QUEST_REWARD)
private TableArray iTable
//sub table for storing quest instance to a unit
private HashTable uTable
//sub table for storing quest id (use as retrieve quest id from ability id)
private Table qTable
//sub table for storing player quest data
private HashTable4D pTable
//sub table for storing quest id (use as retrieve quest id from item id)
private Table eTable
//sub catalog table for storing connection between quests
private HashTable3D cTable
//sub catalog table for storing QUEST_CONTENT of type talk data
private Table tTable
//sub catalog table for storing rect's data
private HashTable rTable
//not related to table : a unit for filtration of units for QuestProcess.onSelect and QuestProcess.onEnter()
private unit filterUnit
endglobals
/**************************************************************************************************/
private function ClearTextMessagesForPlayer takes player p returns nothing
if GetLocalPlayer() == p then
call ClearTextMessages()
endif
endfunction
private function DistanceBetweenCoordinates takes real x, real y, real x2, real y2 returns real
local real dx = x2 - x
local real dy = y2 - y
return SquareRoot(dx * dx + dy * dy)
endfunction
//A function that filter out unwanted units where trigger will run when selecting a unit
private function OnSelectFilter takes nothing returns boolean
local integer pId
set filterUnit = GetFilterUnit()
set pId = GetPlayerId(GetOwningPlayer(filterUnit))
return GetUnitTypeId(filterUnit) != DUMMY_ID and filterUnit != HERO[pId]
endfunction
private function OnEnterFilter takes nothing returns boolean
set filterUnit = GetFilterUnit()
return GetUnitTypeId(filterUnit) != QUEST_INFO_ID and GetPlayerSlotState(GetOwningPlayer(filterUnit)) == PLAYER_SLOT_STATE_PLAYING
endfunction
//A function that return the array index of dialogButton
//Formula : player Id * MAX_QUEST_PER_PLAYER + i
private function getButtonIndex takes integer pId, integer i returns integer
return pId*MAX_QUEST_PER_PLAYER + i
endfunction
/**************************************************************************************************/
/**/private module Initialize
/**/ private static method onInit takes nothing returns nothing
/**/ set table = HashTable.create()
/**/ set iTable = TableArray[MAXIMUM_QUEST_PART]
/**/ set uTable = HashTable.create()
/**/ set qTable = Table.create()
/**/ set pTable = HashTable.create()
/**/ set eTable = Table.create()
/**/ set cTable = HashTable.create()
/**/ set tTable = Table.create()
/**/ set rTable = HashTable.create()
/**/
/**/ set TABLE_INDEX[0] = 1 //TITLE
/**/ set TABLE_INDEX[1] = 2 //DIFFICULTY
/**/ set TABLE_INDEX[2] = 3 //DESCRIPTION
/**/ set TABLE_INDEX[3] = 4 //DESCRIPTION_LINE
/**/ set TABLE_INDEX[4] = 5 //QUEST_AVAIABLE_EFFECT_PATH
/**/ set TABLE_INDEX[5] = 6 //TABLE_INDEX[4] ATTACH_POINT
/**/ set TABLE_INDEX[6] = 7 //QUEST_COMPLETE_EFFECT_PATH
/**/ set TABLE_INDEX[7] = 8 //TABLE_INDEX[6] ATTACH_POINT
/**/ set TABLE_INDEX[8] = 9 //QUEST_EVENT_LIST
/**/ set TABLE_INDEX[9] = 10 //QUEST_CONDITION_LIST
/**/ set TABLE_INDEX[10] = 11//QUEST_CONTENT_LIST
/**/ set TABLE_INDEX[11] = 12//QUEST_REWARD_LIST
/**/
/**/ call Init()
/**/ endmethod
/**/endmodule
/**/
/**/
/**/private struct S extends array
/**/ implement Initialize
/**/endstruct
/**/
/**/
/**/private keyword QuestProcess
/**************************************************************************************************/
/**************************************************************************************************/
/**/struct RectSet extends array
/**/ private static thistype instanceCount = 0
/**/ private integer subset
/**/
/**/ static method create takes nothing returns thistype
/**/ local thistype this = instanceCount + 1
/**/ set instanceCount = this
/**/
/**/ set subset = 0
/**/
/**/ return this
/**/ endmethod
/**/
/**/ method addRect takes rect r returns nothing
/**/ set subset = subset + 1
/**/ set rTable[this].rect[subset] = r
/**/ endmethod
/**/
/**/ //private access by PlayerData.initPickItem
/**/ method readRect takes integer subset returns rect
/**/ return rTable[this].rect[subset]
/**/ endmethod
/**/
/**/ //private access by PlayerData.initPickItem
/**/ method operator rectCount takes nothing returns integer
/**/ return subset
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
/**/struct Quest extends array
/**/ private static thistype questInstance = 0
/**/
/**/ //method only for internal use
/**/ static method getQuestCount takes nothing returns integer
/**/ return questInstance
/**/ endmethod
/**/
/**/ //Create a new quest instance
/**/ static method create takes nothing returns thistype
/**/ local thistype this = questInstance + 1
/**/ set questInstance = this
/**/
/**/ //Default initialization
/**/ set this.questEventList = 1 //nessasary component
/**/ set this.questConditionList = 0 //optional component (will auto init if user defined condition)
/**/ set this.questContentList = 1 //nesssasry component
/**/ set this.questRewardList = 0 //optional component (will auto init if user defined reward)
/**/
/**/ return this
/**/ endmethod
/**/
/**/ //Quest Title
/**/ method operator title= takes string s returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[0]] = s
/**/ endmethod
/**/
/**/ //Quest difficulty
/**/ method operator difficulty= takes string s returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[1]] = s
/**/ endmethod
/**/
/**/ //Quest description
/**/ method operator description= takes string s returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[2]] = s
/**/ endmethod
/**/
/**/ //Quest description's lines
/**/ method operator descriptionLines= takes integer lines returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[3]] = lines
/**/ endmethod
/**/
/**/ //Quest receiving effect's path
/**/ method setEffectPathReceive takes string s, string attachPoint returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[4]] = s
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[5]] = attachPoint
/**/ endmethod
/**/
/**/ //Quest returning effect's path
/**/ method setEffectPathReturn takes string s, string attachPoint returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[6]] = s
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[7]] = attachPoint
/**/ endmethod
/**/
/**/ method operator questEventList= takes integer whichList returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[8]] = whichList
/**/ endmethod
/**/
/**/ method operator questConditionList= takes integer whichList returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[9]] = whichList
/**/ endmethod
/**/
/**/ method operator questContentList= takes integer whichList returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[10]] = whichList
/**/ endmethod
/**/
/**/ method operator questRewardList= takes integer whichList returns nothing
/**/ set table[this][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[11]] = whichList
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
/**/struct QuestEvent extends array
/**/ private static Quest temp
/*================================================================================================*/
/**/ //Creates a new QuestEvent instance
/**/ static method create takes Quest q returns thistype
/**/ local thistype this = iTable[QUEST_EVENT].integer[q] + 1
/**/ set iTable[QUEST_EVENT].integer[q] = this
/**/
/**/ //Assign temporary quest instance for later use
/**/ set temp = q
/**/
/**/ return this
/**/ endmethod
/*================================================================================================*/
/**/ //Assign quest registeration type, currently only have QUEST_EVENT_SELECT
/**/ method operator registerReceiveEvent= takes integer i returns nothing
/**/ set table[temp][QUEST_EVENT][this][NOT_IN_USE].integer[RECEIVE_EVENT] = i
/**/ endmethod
/**/
/**/ //Assign quest returning type, currently only have QUEST_EVENT_SELECT
/**/ method operator registerReturnEvent= takes integer i returns nothing
/**/ set table[temp][QUEST_EVENT][this][NOT_IN_USE].integer[RETURN_EVENT] = i
/**/ endmethod
/**/
/**/ //assign this quest to unit u so that player can retrieve/return quest from unit u
/**/ //
/**/ //uTable[id].integer[0] equaivalent to "Retrieving registered quest instance from a unit"
/**/ // as a unit can have 2 or more quest registered to it
/**/
/**/ //Assign quest to unit u for receiving(starting a quest) from unit u
/**/ method operator receiveFrom= takes unit u returns nothing
/**/ local integer id = GetHandleId(u)
/**/ local integer i = uTable[id].integer[RECEIVE_EVENT] + 1
/**/ set uTable[id].integer[RECEIVE_EVENT] = i
/**/ set uTable[id].integer[i+1] = temp
/**/
/**/ set table[temp][QUEST_EVENT][this][RECEIVE_EVENT].unit[0] = u
/**/ endmethod
/**/
/**/ //Assign quest to unit u for returning(complete a quest) to unit u
/**/ method operator returnTo= takes unit u returns nothing
/**/ local integer id = GetHandleId(u)
/**/ local integer i = uTable[id].integer[RETURN_EVENT] + 1
/**/ set uTable[id].integer[RETURN_EVENT] = i
/**/ set uTable[id].integer[MAX_QUEST_PER_UNIT+i] = temp
/**/
/**/ set table[temp][QUEST_EVENT][this][RETURN_EVENT].unit[0] = u
/**/ endmethod
/**/
/**/ //Add ability id (quest), needed to be assigned when using QUEST_EVENT_SELECT
/**/ method operator questAbilityId= takes integer i returns nothing
/**/ set qTable.integer[i] = temp
/**/ set table[temp][QUEST_EVENT][this][QUEST_ABILITY_ID].integer[0] = i
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
/**/struct QuestCondition extends array
/**/ private static Quest temp
/**/
/**/ static method create takes Quest q returns thistype
/**/ local thistype this = iTable[QUEST_CONDITION].integer[q] + 1
/**/ set iTable[QUEST_CONDITION].integer[q] = this
/**/
/**/ if this == 1 then
/**/ set q.questConditionList = this
/**/ endif
/**/
/**/ //Assign temporary quest instance for later use
/**/ set temp = q
/**/
/**/ return this
/**/ endmethod
/**/
/**/ method operator addLevel= takes integer levelRequired returns nothing
/**/ local integer i = cTable[LEVEL][levelRequired].integer[0] + 1
/**/ set cTable[LEVEL][levelRequired].integer[0] = i
/**/
/**/ set table[temp][QUEST_CONDITION][this][LEVEL].integer[0] = levelRequired
/**/ set cTable[LEVEL][levelRequired].integer[i] = temp
/**/ endmethod
/**/
/**/ method operator addQuest= takes Quest q returns nothing
/**/ local integer i = cTable[QUEST][q].integer[0] + 1
/**/ set cTable[QUEST][q].integer[0] = i
/**/ set cTable[QUEST][q].integer[i] = temp
/**/
/**/ set i = table[temp][QUEST_CONDITION][this][QUEST].integer[0] + 1
/**/ set table[temp][QUEST_CONDITION][this][QUEST].integer[0] = i
/**/ set table[temp][QUEST_CONDITION][this][QUEST].integer[i] = q
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
/**/struct QuestContent extends array
/**/ private static Quest temp
/**/ private integer subset
/**/
/**/ static method create takes Quest q returns thistype
/**/ local thistype this = iTable[QUEST_CONTENT].integer[q] + 1
/**/ set iTable[QUEST_CONTENT].integer[q] = this
/**/
/**/ //Assign temporary quest instance for later use
/**/ set temp = q
/**/
/**/ set subset = 0
/**/
/**/ return this
/**/ endmethod
/**/
/**/ method registerKillUnit takes integer uId, integer noToKill returns nothing
/**/ set subset = subset + 1
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[0] = KILL
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[1] = uId
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[2] = noToKill
/**/ endmethod
/**/
/**/ method registerTalk takes unit u, integer aId, string extraDescription, string extraDescription2, string effectPath returns nothing
/**/ set subset = subset + 1
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[0] = TALK
/**/ set table[temp][QUEST_CONTENT][this][subset].unit[1] = u
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[2] = aId
/**/ set table[temp][QUEST_CONTENT][this][subset].string[3] = extraDescription
/**/ set table[temp][QUEST_CONTENT][this][subset].string[4] = extraDescription2
/**/ set table[temp][QUEST_CONTENT][this][subset].string[5] = effectPath
/**/
/**/ set tTable.integer[aId] = temp
/**/ endmethod
/**/
/**/ method registerPickUp takes RectSet rs, integer iId, integer noToPick, string extraDescription returns nothing
/**/ set subset = subset + 1
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[0] = PICK_UP
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[1] = rs
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[2] = iId
/**/ set table[temp][QUEST_CONTENT][this][subset].integer[3] = noToPick
/**/
/**/ set eTable.integer[iId] = temp
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
/**/struct QuestReward extends array
/**/ private static Quest temp
/**/
/**/ static method create takes Quest q returns thistype
/**/ local thistype this = iTable[QUEST_REWARD].integer[q] + 1
/**/ set iTable[QUEST_REWARD].integer[q] = this
/**/
/**/ if this == 1 then
/**/ set q.questRewardList = this
/**/ endif
/**/
/**/ //Assign temporary quest instance for later use
/**/ set temp = q
/**/
/**/ return this
/**/ endmethod
/**/
/**/ method operator gold= takes integer amount returns nothing
/**/ set table[temp][QUEST_REWARD][this][GOLD].integer[0] = amount
/**/ endmethod
/**/
/**/ method operator lumber= takes integer amount returns nothing
/**/ set table[temp][QUEST_REWARD][this][LUMBER].integer[0] = amount
/**/ endmethod
/**/
/**/ method operator experience= takes integer amount returns nothing
/**/ set table[temp][QUEST_REWARD][this][EXPERIENCE].integer[0] = amount
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
globals
//Globas used by QuestData.isQuestInPlayerQuestList()
private integer li //loop index
private integer mi //max index
//Globals for storing number of quest player has taken
//and which quest is taken by each player respectively
private integer array playerQuest
private integer array playerQuestCount
//Globals for dialog and button creations
private dialog array playerDialog
private button array dialogButton
//Globals for QuestProcess.onClick()
private trigger dialogTrigger = CreateTrigger()
//Globals used by QuestProcess.onSelect()
private trigger selectTrigger = CreateTrigger()
//Global used by QuestProcess.onSelect() and PlayerData.isQuestAvailable()
private integer playerQuestStatus
//Globals used by QuestProcess.onAccept()
private trigger acceptTrigger = CreateTrigger()
private player oAp //onAccept player
private integer oAi //onAccept loop integer
private integer oAi2 //onAccept loop integer 2
private integer oApi //onAccept player id
private integer oAq //onAccept quest id
private string oAs //onAccept string
//Globals used by QuestProcess.onDeselect()
private trigger deselectTrigger = CreateTrigger()
private unit deselectUnit
//Globals used by QuestProcess.onDeath()
private trigger deathTrigger = CreateTrigger()
//Globals used by QuestProcess.onPick()
private trigger pickTrigger = CreateTrigger()
//Globals used by QuestProcess.onDrop()
private trigger dropTrigger = CreateTrigger()
private timer dropTimer = CreateTimer()
private item onDropItem
private player onDropPlayer
//Globals used by QuestProcess.onLevel()
private trigger levelTrigger = CreateTrigger()
//Globals used by QuestProcess.onEnter()
private trigger enterTrigger = CreateTrigger()
endglobals
private keyword QuestData
private keyword PlayerData
/**************************************************************************************************/
/**************************************************************************************************/
/**/private struct QuestData extends array
/**/ readonly static integer qId = 0
/**/ private static integer array list
/**/
/*================================================================================================*/
/**/ //Uncategorised methods are placed here
/**/
/**/ //Method for obtaining ablity id in QUEST_EVENT (affected by QuestData.init)
/**/ static method getQuestAbilityId takes nothing returns integer
/**/ return table[qId][QUEST_EVENT][list[QUEST_EVENT]][QUEST_ABILITY_ID].integer[0]
/**/ endmethod
/**/
/**/ //return difficulty with color
/**/ static method getQuestDifficultyEx takes nothing returns string
/**/ local integer i = 0
/**/ local string s = thistype.getQuestDifficulty()
/**/
/**/ loop
/**/ exitwhen QUEST_DIFFICULTY[i] == s
/**/ set i = i + 1
/**/ endloop
/**/
/**/ return QUEST_COLOR_DIFFICULTY[i] + s
/**/ endmethod
/*================================================================================================*/
/**/ //Method for obtaining quest Id from a unit's handle id or from ability id
/**/ static method getQuestIdFromAbility takes integer aId returns integer
/**/ return qTable.integer[aId]
/**/ endmethod
/*================================================================================================*/
/**/ //Methods for init quest Id which is used by QUEST_BASIC and QUEST_EVENT
/**/
/**/ private static method initList takes nothing returns nothing
/**/ set list[QUEST_EVENT] = QuestData.getQuestEventList()
/**/ set list[QUEST_CONDITION] = QuestData.getQuestConditionList()
/**/ set list[QUEST_CONTENT] = QuestData.getQuestContentList()
/**/ set list[QUEST_REWARD] = QuestData.getQuestRewardList()
/**/ endmethod
/**/
/**/ static method init takes integer id, integer i returns nothing
/**/ set qId = uTable[id].integer[i]
/**/ call thistype.initList()
/**/ endmethod
/**/
/**/ static method initEx takes integer q returns nothing
/**/ set qId = q
/**/ call thistype.initList()
/**/ endmethod
/*================================================================================================*/
/**/ //Methods for obtaining data from QUEST_BASIC
/**/ static method getQuestId takes nothing returns integer
/**/ return qId
/**/ endmethod
/**/
/**/ static method getQuestName takes nothing returns string
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[0]]
/**/ endmethod
/**/
/**/ //Returns difficulty without color
/**/ static method getQuestDifficulty takes nothing returns string
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[1]]
/**/ endmethod
/**/
/**/ static method getQuestDescription takes nothing returns string
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[2]]
/**/ endmethod
/**/
/**/ static method getQuestDescriptionLines takes nothing returns integer
/**/ local integer i = table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[3]]
/**/
/**/ //If user doesn't specific description line (i == 0), return 1
/**/ if i == 0 then
/**/ return 1
/**/ else
/**/ return i
/**/ endif
/**/ endmethod
/**/
/**/ static method getQuestEffectPathAvailable takes nothing returns string
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[4]]
/**/ endmethod
/**/
/**/ static method getQuestAttachPointAvailable takes nothing returns string
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[5]]
/**/ endmethod
/**/
/**/ static method getQuestEffectPathComplete takes nothing returns string
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[6]]
/**/ endmethod
/**/
/**/ static method getQuestAttachPointComplete takes nothing returns string
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].string[TABLE_INDEX[7]]
/**/ endmethod
/**/
/**/ static method getQuestEventList takes nothing returns integer
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[8]]
/**/ endmethod
/**/
/**/ static method getQuestConditionList takes nothing returns integer
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[9]]
/**/ endmethod
/**/
/**/ static method getQuestContentList takes nothing returns integer
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[10]]
/**/ endmethod
/**/
/**/ static method getQuestRewardList takes nothing returns integer
/**/ return table[qId][QUEST_BASIC][NOT_IN_USE][NOT_IN_USE].integer[TABLE_INDEX[11]]
/**/ endmethod
/*================================================================================================*/
/**/ //Methods used for retrieveing receiving/returning unit from QUEST_EVENT
/**/
/**/ //Return the quest receiving unit's
/**/ static method getQuestReceiveUnit takes nothing returns unit
/**/ return table[qId][QUEST_EVENT][list[QUEST_EVENT]][RECEIVE_EVENT].unit[0]
/**/ endmethod
/**/
/**/ //Return the quest returning's unit
/**/ static method getQuestReturnUnit takes nothing returns unit
/**/ return table[qId][QUEST_EVENT][list[QUEST_EVENT]][RETURN_EVENT].unit[0]
/**/ endmethod
/*================================================================================================*/
/**/ //Methods used for retriving condition data in QUEST_CONDITION
/**/
/**/ //Obtaining the maximum check loop for looping through all connected quest's conditions
/**/ static method getQuestCheckMaxLoop takes integer checkingType, integer i returns integer
/**/ return cTable[checkingType][i].integer[0]
/**/ endmethod
/**/
/**/ //Obtaining the related quest's id for checking if all conditions fullfilled and would unlock the quest if it is
/**/ static method getQuestCheckId takes integer checkingType, integer i, integer loopInt returns integer
/**/ return cTable[checkingType][i].integer[loopInt]
/**/ endmethod
/**/
/**/ //Obtaining the maximum loop for a quest's condition
/**/ static method getConditionMaxLoop takes integer qId returns integer
/**/ return table[qId][QUEST_CONDITION][list[QUEST_CONDITION]][QUEST].integer[0]
/**/ endmethod
/**/
/**/ //Obtaining the quest id from a given quest id that required to check
/**/ //(qId required to complete before the quest could be proceed)
/**/ static method getConditionQuestId takes integer qId, integer loopInt returns integer
/**/ return table[qId][QUEST_CONDITION][list[QUEST_CONDITION]][QUEST].integer[loopInt]
/**/ endmethod
/**/
/**/ //Method for counting the amount of quest condition
/**/ static method getQuestConditionCount takes integer q returns integer
/**/ return iTable[QUEST_CONDITION].integer[q]
/**/ endmethod
/**/
/**/ //Method for obtaining the quest level requirement
/**/ static method getQuestLevelRequirement takes nothing returns integer
/**/ return table[qId][QUEST_CONDITION][list[QUEST_CONDITION]][LEVEL].integer[0]
/**/ endmethod
/*================================================================================================*/
/**/ //Main Methods that get used throughout the QUEST_CONTENT
/**/
/**/ //obtaining QUEST_CONTENT type
/**/ static method getQuestContentType takes integer q, integer ss returns integer
/**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].integer[0]
/**/ endmethod
/**/
/**/ //obtaining overall QUEST_CONTENT and convert them into strings (included player progress)
/**/ static method getQuestRequirements takes integer q, integer pId returns string
/**/ local string s = "|r- "
/**/ local string s2 //for storing quest complete/incomeplete color
/**/ local integer contentType = 0
/**/ local integer subset = 0
/**/ local integer uId
/**/ local integer i
/**/ local integer i2
/**/
/**/ loop
/**/ set subset = subset + 1
/**/ set contentType = thistype.getQuestContentType(q, subset)
/**/ exitwhen contentType == 0
/**/
/**/ if subset > 1 then
/**/ set s = s + "\n|r- "
/**/ endif
/**/
/**/ if contentType == KILL then
/**/ set uId = thistype.getKillUnitId(q, subset)
/**/ set i = thistype.getRequireKillAmountEx(q, uId, subset) //amount required to kill
/**/ set i2 = PlayerData.getKillAmount(q, uId, pId) //amount player need to kill
/**/
/**/ if i2 >= i then
/**/ set s2 = QUEST_COLOR_COMPLETE
/**/ else
/**/ set s2 = QUEST_COLOR_INCOMPLETE
/**/ endif
/**/
/**/ set s = s + s2 + "Kill " + I2S(i) + " |r" + GetObjectName(uId) + s2 + " (" + I2S(i2) + "/" + I2S(i) + ")"
/**/ elseif contentType == TALK then
/**/
/**/ if PlayerData.isUnitTalked(q, pId, QuestData.getTalkAbilityId(q, subset)) then
/**/ set s2 = QUEST_COLOR_COMPLETE
/**/ else
/**/ set s2 = QUEST_COLOR_INCOMPLETE
/**/ endif
/**/
/**/ set s = s + s2 + "Talk to " + GetUnitName(QuestData.getTalkUnit(q, subset)) + QuestData.getTalkExtraDescription(q, subset)
/**/ elseif contentType == PICK_UP then
/**/ set i = thistype.getPickUpRequireAmount(q, subset)
/**/ set i2 = PlayerData.getPickUpAmount(q, pId, thistype.getPickUpItemId(q, subset), QuestData.getPickUpRectSet(q, subset))
/**/
/**/ if i2 >= i then
/**/ set s2 = QUEST_COLOR_COMPLETE
/**/ else
/**/ set s2 = QUEST_COLOR_INCOMPLETE
/**/ endif
/**/
/**/ set s = s + s2 + "Pick up " + I2S(i) + " " + GetObjectName(thistype.getPickUpItemId(q, subset)) + s2 + QuestData.getPickUpExtraDescription(q, subset) + " (" + I2S(i2) + "/" + I2S(i) + ")"
/**/ endif
/**/ endloop
/**/
/**/ return s
/**/ endmethod
/**/ //------------------------------------------------------------------------------------------
/**/ /**///Method used for obtaining QUEST_CONTENT data with type of KILL
/**/ /**/static method getKillUnitId takes integer q, integer ss returns integer
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].integer[1]
/**/ /**/endmethod
/**/ /**/
/**/ /**///ss = subset, subset is given, so no need to search for it
/**/ /**/static method getRequireKillAmountEx takes integer q, integer uId, integer ss returns integer
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].integer[2]
/**/ /**/endmethod
/**/ /**/
/**/ /**///subset is not given, needed to be search
/**/ /**/static method getRequireKillAmount takes integer q, integer uId returns integer
/**/ /**/ local integer subset = 0
/**/ /**/ local integer contentType
/**/ /**/
/**/ /**/ loop
/**/ /**/ set subset = subset + 1
/**/ /**/ set contentType = thistype.getQuestContentType(q, subset)
/**/ /**/ exitwhen contentType == 0
/**/ /**/
/**/ /**/ if contentType == KILL and thistype.getKillUnitId(q, subset) == uId then
/**/ /**/ return thistype.getRequireKillAmountEx(q, uId, subset)
/**/ /**/ endif
/**/ /**/ endloop
/**/ /**/
/**/ /**/ return 0
/**/ /**/endmethod
/**/ //------------------------------------------------------------------------------------------
/**/ /**///Methods used for obtaining QUEST_CONTENT data with type of TALK
/**/ /**/static method getTalkUnit takes integer q, integer ss returns unit
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].unit[1]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getTalkAbilityId takes integer q, integer ss returns integer
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].integer[2]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getTalkExtraDescription takes integer q, integer ss returns string
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].string[3]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getTalkExtraDescription2 takes integer q, integer aId returns string
/**/ /**/ local integer ss = 0
/**/ /**/ local integer contentType
/**/ /**/
/**/ /**/ loop
/**/ /**/ set ss = ss + 1
/**/ /**/ set contentType = QuestData.getQuestContentType(q, ss)
/**/ /**/ exitwhen contentType == 0
/**/ /**/
/**/ /**/ if thistype.getTalkAbilityId(q, ss) == aId then
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].string[4]
/**/ /**/ endif
/**/ /**/ endloop
/**/ /**/
/**/ /**/ return ""
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getTalkEffectPath takes integer q, integer ss returns string
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].string[5]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getTalkQuestId takes integer aId returns integer
/**/ /**/ return tTable.integer[aId]
/**/ /**/endmethod
/**/ //------------------------------------------------------------------------------------------
/**/ /**///Methods used for obtaining QUEST_CONTENT data with type of PICK_UP
/**/ /**/
/**/ /**/static method getPickUpRectSet takes integer q, integer ss returns RectSet
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].integer[1]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getPickUpItemId takes integer q, integer ss returns integer
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].integer[2]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getPickUpRequireAmount takes integer q, integer ss returns integer
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].integer[3]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getPickUpExtraDescription takes integer q, integer ss returns string
/**/ /**/ return table[q][QUEST_CONTENT][list[QUEST_CONTENT]][ss].string[4]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getPickUpQuestId takes integer iId returns integer
/**/ /**/ return eTable.integer[iId]
/**/ /**/endmethod
/**/ //------------------------------------------------------------------------------------------
/*================================================================================================*/
/**/ //Methods for obtaining rewards (gold, lumber, exp) amount
/**/ static method getGoldReward takes nothing returns integer
/**/ return table[qId][QUEST_REWARD][1][GOLD].integer[0]
/**/ endmethod
/**/
/**/ static method getLumberReward takes nothing returns integer
/**/ return table[qId][QUEST_REWARD][1][LUMBER].integer[0]
/**/ endmethod
/**/
/**/ static method getExperienceReward takes nothing returns integer
/**/ return table[qId][QUEST_REWARD][1][EXPERIENCE].integer[0]
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
/**/private struct PlayerData extends array
/*================================================================================================*/
/**/ //Misc methods
/**/
/**/ static method removeQuestItem takes integer q, integer pId returns nothing
/**/ local integer ss = 0
/**/ local integer slot = 0
/**/ local integer iId
/**/ local integer array itId
/**/ local integer contentType
/**/ local item it
/**/
/**/ call QuestData.initEx(q)
/**/
/**/ loop
/**/ set itId[slot] = GetItemTypeId(UnitItemInSlot(HERO[pId], slot))
/**/ set slot = slot + 1
/**/ exitwhen slot == bj_MAX_INVENTORY
/**/ endloop
/**/
/**/ loop
/**/ set ss = ss + 1
/**/ set contentType = QuestData.getQuestContentType(q, ss)
/**/ exitwhen contentType == 0
/**/
/**/ if contentType == PICK_UP then
/**/ set iId = QuestData.getPickUpItemId(q, ss)
/**/ set slot = 0
/**/
/**/ loop
/**/ if itId[slot] == iId then
/**/ set it = UnitItemInSlot(HERO[pId], slot)
/**/ call thistype.setPickUpItemOwner(GetHandleId(it), null)
/**/ call RemoveItem(it)
/**/ endif
/**/
/**/ set slot = slot + 1
/**/ exitwhen slot == bj_MAX_INVENTORY
/**/ endloop
/**/ endif
/**/ endloop
/**/ endmethod
/*================================================================================================*/
/**/ //Methods for obtaining quest start index for a player
/**/ static method getPlayerQuestStartIndex takes integer pId returns integer
/**/ return pId*MAX_QUEST_PER_PLAYER
/**/ endmethod
/**/
/**/ //Methods for obtaining a new quest start index (newly registered quest)
/**/ static method getQuestNewIndex takes integer pId returns integer
/**/ return thistype.getPlayerQuestStartIndex(pId) + playerQuestCount[pId]
/**/ endmethod
/*================================================================================================*/
/**/ //Methods for setting/obtaining player's quest status, there are 4 types :
/**/ //QUEST_NOT_TAKING, QUEST_IN_PROGRESS, QUEST_COMPLETE, QUEST_COMPLETED
/**/
/**/ static method getPlayerQuestStatus takes Quest q, integer pId returns integer
/**/ return pTable[pId][q][NOT_IN_USE].integer[NOT_IN_USE]
/**/ endmethod
/**/
/**/ static method setPlayerQuestStatus takes Quest q, integer pId, integer progressType returns nothing
/**/ set pTable[pId][q][NOT_IN_USE].integer[NOT_IN_USE] = progressType
/**/ endmethod
/*================================================================================================*/
/**/ //Methods used for updating players quests's contents
/**/
/**/ //------------------------------------------------------------------------------------------
/**/ /**///Methods used for updating player kill quest
/**/ /**/
/**/ /**/static method getKillAmount takes integer q, integer uId, integer pId returns integer
/**/ /**/ return pTable[pId][q][uId].integer[NOT_IN_USE]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method updateKillQuest takes integer q, integer uId, integer pId returns nothing
/**/ /**/ set pTable[pId][q][uId].integer[NOT_IN_USE] = thistype.getKillAmount(q, uId, pId) + 1
/**/ /**/endmethod
/**/ //------------------------------------------------------------------------------------------
/**/ /**///Methods used for updating player talk quest
/**/ /**/
/**/ /**/static method setUnitTalked takes integer q, integer pId, integer aId returns nothing
/**/ /**/ set pTable[pId][q][aId].boolean[NOT_IN_USE] = true
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method isUnitTalked takes integer q, integer pId, integer aId returns boolean
/**/ /**/ return pTable[pId][q][aId].boolean[NOT_IN_USE]
/**/ /**/endmethod
/**/ /**/
/**/ /**///Methods used for applying talk effect on unit to notify player there is talkable quest in progress
/**/ /**/
/**/ /**/static method applyTalkEffect takes integer q, integer pId, unit u, integer aId, string s returns nothing
/**/ /**/ set pTable[pId][q][aId].effect[NOT_IN_USE] = AddSpecialEffectTarget(s, u, "overhead")
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method removeTalkEffect takes integer q, integer pId, integer aId returns nothing
/**/ /**/ call DestroyEffect(pTable[pId][q][aId].effect[0])
/**/ /**/ set pTable[pId][q][aId].effect[NOT_IN_USE] = null
/**/ /**/endmethod
/**/ //------------------------------------------------------------------------------------------
/**/ /**///Methods used for updating and init player pick up quest
/**/ /**/
/**/ /**/static method getPickUpItemOwner takes integer itemHandle returns player
/**/ /**/ return pTable[itemHandle][NOT_IN_USE][NOT_IN_USE].player[NOT_IN_USE]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method setPickUpItemOwner takes integer itemHandle, player p returns nothing
/**/ /**/ set pTable[itemHandle][NOT_IN_USE][NOT_IN_USE].player[NOT_IN_USE] = p
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getRectSetInstance takes integer q, integer pId, integer iId returns RectSet
/**/ /**/ return pTable[pId][q][iId].integer[NOT_IN_USE]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method getPickUpAmount takes integer q, integer pId, integer iId, RectSet rs returns integer
/**/ /**/ return pTable[pId][q][iId].integer[rs]
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method updatePickUpAmount takes integer q, integer pId, integer iId returns nothing
/**/ /**/ local RectSet rs = thistype.getRectSetInstance(q, pId, iId)
/**/ /**/ set pTable[pId][q][iId].integer[rs] = thistype.getPickUpAmount(q, pId, iId, rs) + 1
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method decreasePickUpAmount takes integer q, integer pId, integer iId returns nothing
/**/ /**/ local RectSet rs = thistype.getRectSetInstance(q, pId, iId)
/**/ /**/ set pTable[pId][q][iId].integer[rs] = thistype.getPickUpAmount(q, pId, iId, rs) - 1
/**/ /**/endmethod
/**/ /**/
/**/ /**/static method initPickItem takes RectSet rs, integer iId, integer maxSpawn, integer q, integer pId returns nothing
/**/ /**/ local integer spawn = 0
/**/ /**/ local integer rectMax = rs.rectCount
/**/ /**/ local integer random
/**/ /**/ local integer array rectSubset
/**/ /**/ local rect r
/**/ /**/
/**/ /**/ set pTable[pId][q][iId].integer[NOT_IN_USE] = rs
/**/ /**/
/**/ /**/ loop
/**/ /**/ set rectSubset[rectMax] = rectMax
/**/ /**/ set rectMax = rectMax - 1
/**/ /**/ exitwhen rectMax == 0
/**/ /**/ endloop
/**/ /**/
/**/ /**/ set rectMax = rs.rectCount
/**/ /**/
/**/ /**/ loop
/**/ /**/ set random = GetRandomInt(1, rectMax)
/**/ /**/ set r = rs.readRect(rectSubset[random])
/**/ /**/ set bj_lastCreatedItem = CreateItem(iId, GetRandomReal(GetRectMinX(r), GetRectMaxX(r)), GetRandomReal(GetRectMinY(r), GetRectMaxY(r)))
/**/ /**/
/**/ /**/ if GetLocalPlayer() != Player(pId) then
/**/ /**/ call SetItemVisible(bj_lastCreatedItem, false)
/**/ /**/ endif
/**/ /**/
/**/ /**/ call thistype.setPickUpItemOwner(GetHandleId(bj_lastCreatedItem), Player(pId))
/**/ /**/ set rectSubset[random] = rectSubset[rectMax]
/**/ /**/ set rectMax = rectMax - 1
/**/ /**/
/**/ /**/
/**/ /**/ set spawn = spawn + 1
/**/ /**/ exitwhen spawn == maxSpawn
/**/ /**/ endloop
/**/ /**/
/**/ /**/ set r = null
/**/ /**/endmethod
/*================================================================================================*/
/**/ //Methods used for applying talk effect on unit to notify player there is available quest(s)
/**/
/**/ //remove quest effect for single player
/**/ static method removeQuestEffect takes integer q, integer pId returns nothing
/**/ call DestroyEffect(pTable[pId][q][NOT_IN_USE].effect[1])
/**/ set pTable[pId][q][NOT_IN_USE].effect[1] = null
/**/ endmethod
/**/
/**/ //apply quest effect for single player
/**/ //new : a new quest/complete quest (receive from unit/return to unit)
/**/ static method applyQuestEffectSingle takes integer q, integer pId, boolean new returns nothing
/**/ local string s
/**/ local string attachPoint
/**/ local unit u
/**/
/**/ call QuestData.initEx(q)
/**/
/**/ if new then
/**/ set s = QuestData.getQuestEffectPathAvailable()
/**/ set attachPoint = QuestData.getQuestAttachPointAvailable()
/**/ else
/**/ set s = QuestData.getQuestEffectPathComplete()
/**/ set attachPoint = QuestData.getQuestAttachPointComplete()
/**/ endif
/**/
/**/ if GetLocalPlayer() != Player(pId) then
/**/ set s = ""
/**/ endif
/**/
/**/ if attachPoint == "" then
/**/ //TEMPORARY AS HAAVEN'T IMPLEMENTED
/**/ set pTable[pId][q][NOT_IN_USE].effect[1] = AddSpecialEffect(s, 0, 0)
/**/ else
/**/ if new then
/**/ set u = QuestData.getQuestReceiveUnit()
/**/ else
/**/ set u = QuestData.getQuestReturnUnit()
/**/ endif
/**/
/**/ set pTable[pId][q][NOT_IN_USE].effect[1] = AddSpecialEffectTarget(s, u, attachPoint)
/**/
/**/ set u = null
/**/ endif
/**/ endmethod
/**/
/**/ //apply quest effect to all player (currently not in use, might be used/removed in future)
/**/ static method applyQuestEffectAll takes integer q returns nothing
/**/ local integer pId = 0
/**/ local string effectPath
/**/ local string s
/**/ local string attachPoint
/**/ local unit receiveUnit
/**/
/**/ call QuestData.initEx(q)
/**/
/**/ set effectPath = QuestData.getQuestEffectPathAvailable()
/**/ set attachPoint = QuestData.getQuestAttachPointAvailable()
/**/
/**/ if attachPoint != "" then
/**/ set receiveUnit = QuestData.getQuestReceiveUnit()
/**/ loop
/**/ set s = effectPath
/**/
/**/ if GetLocalPlayer() != Player(pId) then
/**/ set s = ""
/**/ endif
/**/
/**/ set pTable[pId][q][NOT_IN_USE].effect[1] = AddSpecialEffectTarget(s, receiveUnit, attachPoint)
/**/
/**/ set pId = pId + 1
/**/ exitwhen pId == bj_MAX_PLAYERS
/**/ endloop
/**/ set receiveUnit = null
/**/ else
/**/ loop
/**/ set s = effectPath
/**/
/**/ if GetLocalPlayer() != Player(pId) then
/**/ set s = ""
/**/ endif
/**/
/**/ //TEMPORARY AS HAVEN'T IMPLEMENTED
/**/ set pTable[pId][q][NOT_IN_USE].effect[1] = AddSpecialEffect(s, 0, 0)
/**/
/**/ set pId = pId + 1
/**/ exitwhen pId == bj_MAX_PLAYERS
/**/ endloop
/**/ endif
/**/ endmethod
/*================================================================================================*/
/**/ //Methods to check player's quest status
/**/
/**/ //check if q is receive-able if within the q's condition list's required quest are completed
/**/ static method isRequiredQuestCompleted takes integer q, integer pId returns boolean
/**/ local integer loopInt = 0
/**/ local integer maxLoop = QuestData.getConditionMaxLoop(q)
/**/
/**/ if maxLoop == 0 then
/**/ return true
/**/ endif
/**/
/**/ loop
/**/ set loopInt = loopInt + 1
/**/
/**/ if thistype.getPlayerQuestStatus(QuestData.getConditionQuestId(q, loopInt), pId) != QUEST_COMPLETED then
/**/ return false
/**/ endif
/**/
/**/ exitwhen maxLoop == loopInt
/**/ endloop
/**/
/**/ return true
/**/ endmethod
/**/
/**/ //check if q's contents are completed
/**/ static method isQuestComplete takes integer q, integer pId returns boolean
/**/ local integer subset = 1
/**/ local integer contentType
/**/ local integer i
/**/ local RectSet rs
/**/
/**/ call QuestData.initEx(q)
/**/
/**/ loop
/**/ set contentType = QuestData.getQuestContentType(q, subset)
/**/ exitwhen contentType == 0
/**/
/**/ if contentType == KILL then
/**/ set i = QuestData.getKillUnitId(q, subset) //uId
/**/
/**/ if thistype.getKillAmount(q, i, pId) < QuestData.getRequireKillAmountEx(q, i, subset) then
/**/ return false
/**/ endif
/**/ elseif contentType == TALK then
/**/ if not thistype.isUnitTalked(q, pId, QuestData.getTalkAbilityId(q, subset)) then
/**/ return false
/**/ endif
/**/ elseif contentType == PICK_UP then
/**/ set rs = QuestData.getPickUpRectSet(q, subset)
/**/ set i = QuestData.getPickUpItemId(q, subset)
/**/
/**/ if thistype.getPickUpAmount(q, pId, i, rs) < QuestData.getPickUpRequireAmount(q, subset) then
/**/ return false
/**/ endif
/**/ endif
/**/
/**/ set subset = subset + 1
/**/ endloop
/**/
/**/ return true
/**/ endmethod
/**/
/**/ //check if player's quest status equal to quest complete
/**/ static method isQuestCompleteEx takes integer playerStatus returns boolean
/**/ return playerStatus == QUEST_COMPLETE
/**/ endmethod
/**/
/**/ static method isQuestAvailableEx takes integer q, integer pId returns boolean
/**/ call QuestData.initEx(q)
/**/ return thistype.getPlayerQuestStatus(q, pId) == QUEST_NOT_TAKING and /*
*/GetHeroLevel(HERO[pId]) >= QuestData.getQuestLevelRequirement() and /*
*/thistype.isRequiredQuestCompleted(q, pId)
endmethod
/*================================================================================================*/
/**/ //Methods for checking available quests
/**/
/**/ //Check if specific quest qId is available for player pId to receive
/**/ static method isQuestAvailable takes integer qId, integer playerQuestStatus, integer lv, integer pId returns boolean
/**/ //First check if qId != 0
/**/ return qId != 0 and /*
If second check fail, next check ensure that the player hvn't received the quest
*/playerQuestStatus == QUEST_NOT_TAKING and /*
Third check level condition
*/GetHeroLevel(HERO[pId]) >= lv and /*
Fourth check quest condition
*/thistype.isRequiredQuestCompleted(qId, pId)
/**/ endmethod
/**/
/**/ //Once a quest is completed, it will check any linked quest's conditions for unlocking any possible quests
/**/ static method checkAvailableQuest takes integer i, integer pId, integer checkingType returns nothing
/**/ local integer loopInt = 0
/**/ local Quest q
/**/ local integer maxLoop
/**/ local integer checkType
/**/
/**/ if checkingType == QUEST_COMPLETED_CHECK then
/**/ //i = completed quest id
/**/ set checkType = QUEST
/**/ elseif checkingType == LEVEL_UP_CHECK then
/**/ //i = hero level
/**/ set checkType = LEVEL
/**/ endif
/**/
/**/ set maxLoop = QuestData.getQuestCheckMaxLoop(checkType, i)
/**/
/**/ if maxLoop != 0 then
/**/ loop
/**/ set loopInt = loopInt + 1
/**/ set q = QuestData.getQuestCheckId(checkType, i, loopInt)
/**/
/**/ if PlayerData.isQuestAvailableEx(q, pId) then
/**/ call thistype.applyQuestEffectSingle(q, pId, true)
/**/ endif
/**/
/**/ exitwhen loopInt == maxLoop
/**/ endloop
/**/ endif
/**/ endmethod
/**/
/**/
/**/endstruct
/**************************************************************************************************/
/**************************************************************************************************/
/**/private struct QuestProcess extends array
/*================================================================================================*/
/**/ //Methods for main quest procressing when player select a unit, a unit died etc
/**/
/**/ //Display quest info for a player once dialog button clicked
/**/ private static method onClick takes nothing returns boolean
/**/ local string s
/**/ local button clickedButton = GetClickedButton()
/**/ local player p = GetTriggerPlayer()
/**/ local integer pId = GetPlayerId(p)
/**/ local integer i = PlayerData.getPlayerQuestStartIndex(pId)
/**/ local integer dialogIndex = getButtonIndex(pId, 0)
/**/
/**/ //obtaining quest's dialog index number
/**/ loop
/**/ if clickedButton == dialogButton[dialogIndex] then
/**/ exitwhen true
/**/ endif
/**/
/**/ set dialogIndex = dialogIndex + 1
/**/ set i = i + 1
/**/ endloop
/**/
/**/
/**/ //init quest data
/**/ call QuestData.initEx(playerQuest[i])
/**/
/**/ //Start of setting quest info:
/**/ //Quest Name : YourQuestTitle
/**/ set s = QUEST_COLOR_GENERAL + "Quest Name : |r" + QuestData.getQuestName() + "\n"
/**/
/**/ //Quest Difficulty : YourQuestDifficulty
/**/ set s = s + QUEST_COLOR_GENERAL + "Quest Difficulty : " + QuestData.getQuestDifficultyEx() + "\n"
/**/
/**/ //YourQuestDescription
/**/ set s = s + QUEST_COLOR_DESCRIPTION + QuestData.getQuestDescription() + "\n\n"
/**/
/**/ //Quest Requirement :
/**/ //- YourQuestRequirement
/**/ set s = s + QUEST_COLOR_GENERAL + "Quest Requirement :\n" + QuestData.getQuestRequirements(playerQuest[i], pId)
/**/
/**/ //Set the number of lines that the quest have so that quest can display at proper place
/**/ //Default number of line (assuming description and requirement take 1 line only) : 5
/**/ call DisplayTextToPlayer(p, getTextDisplayX(), getTextDisplayY(5+QuestData.getQuestDescriptionLines()), s)
/**/
/**/ set p = null
/**/ set clickedButton = null
/**/ return false
/**/ endmethod
/**/
/**/ //Display quest titles for a player
/**/ private static method displayQuestTitle takes player p, integer pId returns nothing
/**/ local string s
/**/ local integer i = 0
/**/ local integer i2
/**/
/**/ call ClearTextMessagesForPlayer(p)
/**/
/**/ if playerQuestCount[pId] == 0 then
/**/ //Display no quest in progress as player doesn't accept any quest
/**/ call DisplayTextToPlayer(p, 0, 0, QUEST_COLOR_GENERAL + "Currently you don't have any registered quest inside your list")
/**/ else
/**/ //Display quest list for player to check the current in progress quest(s)
/**/ call DialogClear(playerDialog[pId])
/**/ call DialogSetMessage(playerDialog[pId], "Quest List")
/**/ set i2 = PlayerData.getPlayerQuestStartIndex(pId)
/**/
/**/ loop
/**/ exitwhen playerQuest[i2] == 0
/**/
/**/ //init quest data
/**/ call QuestData.initEx(playerQuest[i2])
/**/ set s = DIALOG_HOTKEY_HIGHLIGHT + I2S(i+1) + " |r" + QuestData.getQuestName()
/**/
/**/ if PlayerData.isQuestComplete(playerQuest[i2], pId) then
/**/ set s = s + " (Completed)|r"
/**/ endif
/**/
/**/ set dialogButton[getButtonIndex(pId, i)] = DialogAddButton(playerDialog[pId], s, DIALOG_HOTKEY[i])
/**/
/**/ set i = i + 1
/**/ set i2 = i2 + 1
/**/ endloop
/**/
/**/ call DialogAddButton(playerDialog[pId], "Cancel", DIALOG_HOTKEY[MAX_QUEST_PER_PLAYER])
/**/ call DialogDisplay(p, playerDialog[pId], true)
/**/ endif
/**/ endmethod
/**/
/**/ //Init quest contents
/**/ private static method initQuestContent takes integer q, integer pId returns nothing
/**/ local integer ss = 0
/**/ local integer contentType
/**/
/**/ loop
/**/ set ss = ss + 1
/**/ set contentType = QuestData.getQuestContentType(q, ss)
/**/ exitwhen contentType == 0
/**/
/**/ if contentType == TALK then
/**/ //Init talk effect when player accepted quest that contains "talk" as quest content
/**/ call PlayerData.applyTalkEffect(q, pId, QuestData.getTalkUnit(q, ss), QuestData.getTalkAbilityId(q, ss), QuestData.getTalkEffectPath(q, ss))
/**/ elseif contentType == PICK_UP then
/**/ //Init pick up type requirement when player accepted quest that contains "pick up" as quest content
/**/ call PlayerData.initPickItem(QuestData.getPickUpRectSet(q, ss), QuestData.getPickUpItemId(q, ss), QuestData.getPickUpRequireAmount(q, ss), q, pId)
/**/ endif
/**/ endloop
/**/ endmethod
/**/
/**/ private static method onSelect takes nothing returns boolean
/**/ local integer ss
/**/ local integer questId
/**/ local integer contentType
/**/ local integer aIdStart
/**/ local integer aIdEnd
/**/ local integer unitHandle
/**/ local integer i //loop integer
/**/ local integer i2 //loop end integer (for RECEIVE_EVENT)
/**/ local integer i3 //loop end integer (for RETURN_EVENT)
/**/ local integer playerQuestStatusStart
/**/ local integer playerQuestStatusEnd
/**/ local unit selectUnit = GetTriggerUnit()
/**/ local player p = GetTriggerPlayer()
/**/ local integer pId = GetPlayerId(p)
/**/ local integer lv
/**/ local real x = GetUnitX(selectUnit) //x position of NPC
/**/ local real y = GetUnitY(selectUnit) //y position of NPC
/**/ local boolean first = true
/**/ local boolean new
/**/
/**/ if selectUnit == QUEST_INFO[pId] then
/**/ call SetUnitX(selectUnit, GetUnitX(HERO[pId]))
/**/ call SetUnitY(selectUnit, GetUnitY(HERO[pId]))
/**/ call SelectUnitForPlayerSingle(HERO[pId], p)
/**/ call thistype.displayQuestTitle(p, pId)
/**/
/**/ elseif DistanceBetweenCoordinates(GetUnitX(HERO[pId]), GetUnitY(HERO[pId]), x, y) <= MAX_RANGE then
/**/ set lv = GetHeroLevel(HERO[pId])
/**/
/**/ set unitHandle = GetHandleId(selectUnit)
/**/ set i2 = uTable[unitHandle].integer[RECEIVE_EVENT] + 1 //number of quests that able to receive from this unit
/**/ set i3 = uTable[unitHandle].integer[RETURN_EVENT] //number of quests that able to return to this unit
/**/
/**/ set i = 2
/**/
/**/ loop
/**/ //First init quest data for unit selectUnit
/**/ //i : integer that determine which quest are checking, 2 for checking 1st quest, 3 for checking 2nd quest etc...
/**/
/**/ //Init data for RECEIVE_EVENT
/**/ call QuestData.init(unitHandle, i)
/**/ set questId = QuestData.getQuestId()
/**/ set playerQuestStatusStart = PlayerData.getPlayerQuestStatus(questId, pId)
/**/ set aIdStart = QuestData.getQuestAbilityId()
/**/ //check if (current receive int < i2) and (selectUnit == receive unit) and (isQuestAvailable for player)
/**/ set new = i <= i2 and selectUnit == QuestData.getQuestReceiveUnit() and PlayerData.isQuestAvailable(questId, playerQuestStatusStart, lv, pId)
/**/
/**/ //Init data for RETURN_EVENT
/**/ call QuestData.init(unitHandle, MAX_QUEST_PER_UNIT+i-1)
/**/ set playerQuestStatusEnd = PlayerData.getPlayerQuestStatus(QuestData.getQuestId(), pId)
/**/ set aIdEnd = QuestData.getQuestAbilityId()
/**/
/**/ if new or /*
*/ (MAX_QUEST_PER_UNIT+i-1 <= MAX_QUEST_PER_UNIT+i3 and PlayerData.isQuestCompleteEx(playerQuestStatusEnd)) then
/**/ if first then
/**/ set first = false
/**/
/**/ //Create a dummy unit for displaying quest
/**/ set bj_lastCreatedUnit = CreateUnit(p, DUMMY_ID, x, y, 0.)
/**/
/**/ //Select dummy for the player
/**/ call SelectUnitForPlayerSingle(bj_lastCreatedUnit, p)
/**/ endif
/**/
/**/ //Add quest ability to dummy unit
/**/ if new then
/**/ call UnitAddAbility(bj_lastCreatedUnit, aIdStart)
/**/ else
/**/ call UnitAddAbility(bj_lastCreatedUnit, aIdEnd)
/**/ call SetUnitAbilityLevel(bj_lastCreatedUnit, aIdEnd, COMPLETE)
/**/ endif
/**/ endif
/**/
/**/ set i = i + 1
/**/ exitwhen (i > i2) and (MAX_QUEST_PER_UNIT+i-1 > MAX_QUEST_PER_UNIT+i3)
/**/ endloop
/**/
/**/ //Check if present available talk quest
/**/ set i = PlayerData.getPlayerQuestStartIndex(pId)
/**/ set i2 = i + playerQuestCount[pId]
/**/ loop
/**/ set questId = playerQuest[i]
/**/ call QuestData.initEx(questId)
/**/ set ss = 0
/**/
/**/ loop
/**/ set ss = ss + 1
/**/ set contentType = QuestData.getQuestContentType(questId, ss)
/**/ exitwhen contentType == 0
/**/
/**/ if contentType == TALK and QuestData.getTalkUnit(questId, ss) == selectUnit and /*
*/ not PlayerData.isUnitTalked(questId, pId, QuestData.getTalkAbilityId(questId, ss)) then
/**/ if first then
/**/ set first = false
/**/
/**/ //Create a dummy unit for displaying quest
/**/ set bj_lastCreatedUnit = CreateUnit(p, DUMMY_ID, x, y, 0.)
/**/
/**/ //Select dummy for the player
/**/ call SelectUnitForPlayerSingle(bj_lastCreatedUnit, p)
/**/ endif
/**/
/**/ call UnitAddAbility(bj_lastCreatedUnit, QuestData.getTalkAbilityId(questId, ss))
/**/ endif
/**/ endloop
/**/
/**/ set i = i + 1
/**/ exitwhen playerQuest[i] == 0 or i > i2
/**/ endloop
/**/
/**/ set first = true
/**/ endif
/**/
/**/ set p = null
/**/ set selectUnit = null
/**/
/**/ return false
/**/ endmethod
/**/
/**/ private static method onAccept takes nothing returns boolean
/**/ local unit u = GetTriggerUnit()
/**/ set oAp = GetTriggerPlayer()
/**/ set oApi = GetPlayerId(oAp)
/**/
/**/ if GetUnitTypeId(u) == DUMMY_ID then
/**/ set oAi = GetSpellAbilityId()
/**/ set oAq = QuestData.getQuestIdFromAbility(oAi)
/**/ //Select back player's hero
/**/ call SelectUnitForPlayerSingle(HERO[oApi], oAp)
/**/
/**/ call ClearTextMessagesForPlayer(oAp)
/**/
/**/ if oAq == 0 then
/**/ //means it is talk ability
/**/ set oAq = QuestData.getTalkQuestId(oAi)
/**/
/**/ call DisplayTextToPlayer(oAp, 0, 0.2, QuestData.getTalkExtraDescription2(oAq, oAi) + "\n")
/**/
/**/ call PlayerData.setUnitTalked(oAq, oApi, oAi)
/**/ call PlayerData.removeTalkEffect(oAq, oApi, oAi)
/**/
/**/ if PlayerData.isQuestComplete(oAq, oApi) then
/**/ call PlayerData.setPlayerQuestStatus(oAq, oApi, QUEST_COMPLETE)
/**/ //Apply complete quest effect
/**/ call PlayerData.applyQuestEffectSingle(oAq, oApi, false)
/**/ //init quest data
/**/ call QuestData.initEx(oAq)
/**/
/**/ call DisplayTextToPlayer(oAp, 0, 0, QUEST_COLOR_GENERAL + "Quest - |r" + QuestData.getQuestName() + QUEST_COLOR_GENERAL + " has been completed")
/**/ endif
/**/ else
/**/ //Destroy quest effect
/**/ call PlayerData.removeQuestEffect(oAq, oApi)
/**/
/**/ if GetUnitAbilityLevel(u, oAi) == COMPLETE then
/**/ //init quest data
/**/ call QuestData.initEx(oAq)
/**/
/**/ set oAs = QUEST_COLOR_GENERAL + "Quest - |r" + QuestData.getQuestName() + QUEST_COLOR_GENERAL + " has been fully completed."
/**/ set oAs = oAs + "\n\nRewards :"
/**/
/**/ //Check if gold reward is not 0
/**/ set oAi = QuestData.getGoldReward()
/**/ if oAi != 0 then
/**/ //Reward gold
/**/ call SetPlayerState(oAp, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(oAp, PLAYER_STATE_RESOURCE_GOLD) + oAi)
/**/ set oAs = oAs + "\n- " + I2S(oAi) + " Gold"
/**/ endif
/**/
/**/ //Check if lumber reward is not 0
/**/ set oAi = QuestData.getLumberReward()
/**/ if oAi != 0 then
/**/ //Reward lumber
/**/ call SetPlayerState(oAp, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(oAp, PLAYER_STATE_RESOURCE_LUMBER) + oAi)
/**/ set oAs = oAs + "\n- " + I2S(oAi) + " Lumber"
/**/ endif
/**/
/**/ //Check if experience reward is not 0
/**/ set oAi = QuestData.getExperienceReward()
/**/ if oAi != 0 then
/**/ //Reward experience
/**/ call AddHeroXP(HERO[oApi], oAi, true)
/**/ set oAs = oAs + "\n- " + I2S(oAi) + " Experience"
/**/ endif
/**/
/**/ set oAi = PlayerData.getPlayerQuestStartIndex(oApi)
/**/ set oAi2 = oAi + playerQuestCount[oApi]
/**/ //rearrange player's quest list (Example : 1, 2, 3, 4, 0, 0, 0) 2 completed, so will become (1, 3, 4, 0, 0, 0, 0)
/**/ loop
/**/ if playerQuest[oAi] == oAq then
/**/ loop
/**/ set playerQuest[oAi] = playerQuest[oAi+1]
/**/ set oAi = oAi + 1
/**/ exitwhen oAi == oAi2
/**/ endloop
/**/
/**/ set playerQuest[oAi] = 0
/**/ exitwhen true
/**/ endif
/**/
/**/ set oAi = oAi + 1
/**/ endloop
/**/
/**/ set playerQuestCount[oApi] = playerQuestCount[oApi] - 1
/**/ call PlayerData.setPlayerQuestStatus(oAq, GetPlayerId(oAp), QUEST_COMPLETED)
/**/ //remove quest item from unit (if present)
/**/ call PlayerData.removeQuestItem(oAq, oApi)
/**/ //Check for available quest(s)
/**/ call PlayerData.checkAvailableQuest(oAq, oApi, QUEST_COMPLETED_CHECK)
/**/
/**/ call DisplayTextToPlayer(oAp, 0, 0, oAs)
/**/ else
/**/ //Register quest into player's quest list
/**/ set playerQuest[PlayerData.getQuestNewIndex(oApi)] = oAq
/**/ //Increase player quest count by one
/**/ set playerQuestCount[oApi] = playerQuestCount[oApi] + 1
/**/ //Set player quest progress type to : QUEST_IN_PROGRESS
/**/ call PlayerData.setPlayerQuestStatus(oAq, oApi, QUEST_IN_PROGRESS)
/**/ //Init quest data
/**/ call QuestData.initEx(oAq)
/**/ //Init quest content
/**/ call thistype.initQuestContent(oAq, oApi)
/**/
/**/ call DisplayTextToPlayer(oAp, 0, 0, QUEST_COLOR_GENERAL + "Quest - |r" + QuestData.getQuestName() + QUEST_COLOR_GENERAL + " has been registered into your quest list.")
/**/ endif
/**/ endif
/**/ endif
/**/ return false
/**/ endmethod
/**/
/**/ private static method onDeselect takes nothing returns boolean
/**/ set deselectUnit = GetTriggerUnit()
/**/ if GetUnitTypeId(deselectUnit) == DUMMY_ID then
/**/ call RemoveUnit(deselectUnit)
/**/ endif
/**/ return false
/**/ endmethod
/**/
/**/ private static method onDeath takes nothing returns boolean
/**/ local unit diedUnit = GetTriggerUnit()
/**/ local unit killUnit = GetKillingUnit()
/**/ local integer uId = GetUnitTypeId(diedUnit)
/**/ local player p = GetOwningPlayer(killUnit)
/**/ local integer pId = GetPlayerId(p)
/**/ local integer i = PlayerData.getPlayerQuestStartIndex(pId) - 1
/**/ local integer i2 = i + MAX_QUEST_PER_PLAYER
/**/ local integer killAmount
/**/ local integer requireKillAmount
/**/ local string s
/**/ local Quest q
/**/
/**/ loop
/**/ set i = i + 1
/**/ set q = playerQuest[i]
/**/ exitwhen q == 0 or playerQuest[i] == 0 or i == i2
/**/
/**/ set killAmount = PlayerData.getKillAmount(q, uId, pId)
/**/ set requireKillAmount = QuestData.getRequireKillAmount(q, uId)
/**/
/**/ if requireKillAmount != 0 and killAmount < requireKillAmount then
/**/ set s = GetUnitName(diedUnit)
/**/ set killAmount = killAmount + 1
/**/
/**/ if killAmount == requireKillAmount then
/**/ set s = s + QUEST_COLOR_COMPLETE
/**/ else
/**/ set s = s + QUEST_COLOR_INCOMPLETE
/**/ endif
/**/
/**/ call ClearTextMessagesForPlayer(p)
/**/
/**/ call DisplayTextToPlayer(p, 0, 0, s + " (" + I2S(killAmount) + "/" + I2S(requireKillAmount) + ")")
/**/
/**/ call PlayerData.updateKillQuest(q, uId, pId)
/**/
/**/ if PlayerData.isQuestComplete(q, pId) then
/**/ call PlayerData.setPlayerQuestStatus(q, pId, QUEST_COMPLETE)
/**/ //Apply complete quest effect
/**/ call PlayerData.applyQuestEffectSingle(q, pId, false)
/**/ //init quest data
/**/ call QuestData.initEx(q)
/**/
/**/ call DisplayTextToPlayer(p, 0, 0, QUEST_COLOR_GENERAL + "Quest - |r" + QuestData.getQuestName() + QUEST_COLOR_GENERAL + " has been completed")
/**/ endif
/**/ endif
/**/ endloop
/**/
/**/ return false
/**/ endmethod
/**/
/**/ private static method onPick takes nothing returns boolean
/**/ local integer q
/**/ local player p = GetOwningPlayer(GetTriggerUnit())
/**/ local player itemOwner
/**/ local integer pId = GetPlayerId(p)
/**/ local item it = GetManipulatedItem()
/**/ local integer iId = GetItemTypeId(it)
/**/ local integer amountPicked
/**/ local integer requirePickAmount
/**/ local string s
/**/ local integer i = 1
/**/
/**/ set q = QuestData.getPickUpQuestId(iId)
/**/
/**/ if q != 0 then
/**/ set itemOwner = PlayerData.getPickUpItemOwner(GetHandleId(it))
/**/ if itemOwner == p then
/**/ call QuestData.initEx(q)
/**/
/**/ loop
/**/ if QuestData.getPickUpItemId(q, i) == iId then
/**/ exitwhen true
/**/ endif
/**/ set i = i + 1
/**/ endloop
/**/
/**/ set requirePickAmount = QuestData.getPickUpRequireAmount(q, i)
/**/ set amountPicked = PlayerData.getPickUpAmount(q, pId, iId, PlayerData.getRectSetInstance(q, pId, iId))
/**/
/**/ if requirePickAmount != 0 and amountPicked < requirePickAmount then
/**/ set s = GetItemName(it)
/**/ set amountPicked = amountPicked + 1
/**/ call PlayerData.updatePickUpAmount(q, GetPlayerId(GetOwningPlayer(GetTriggerUnit())), iId)
/**/
/**/ if amountPicked == requirePickAmount then
/**/ set s = s + QUEST_COLOR_COMPLETE
/**/ else
/**/ set s = s + QUEST_COLOR_INCOMPLETE
/**/ endif
/**/
/**/ call ClearTextMessagesForPlayer(p)
/**/
/**/ call DisplayTextToPlayer(p, 0, 0, s + " (" + I2S(amountPicked) + "/" + I2S(requirePickAmount) + ")")
/**/
/**/ if PlayerData.isQuestComplete(q, pId) then
/**/ call PlayerData.setPlayerQuestStatus(q, pId, QUEST_COMPLETE)
/**/ call PlayerData.applyQuestEffectSingle(q, pId, false)
/**/
/**/ call DisplayTextToPlayer(p, 0, 0, QUEST_COLOR_GENERAL + "Quest - |r" + QuestData.getQuestName() + QUEST_COLOR_GENERAL + " has been completed")
/**/ endif
/**/ endif
/**/ else
/**/ set bj_lastCreatedItem = CreateItem(iId, GetUnitX(HERO[pId]), GetUnitY(HERO[pId]))
/**/ call PlayerData.setPickUpItemOwner(GetHandleId(bj_lastCreatedItem), itemOwner)
/**/ call PlayerData.setPickUpItemOwner(GetHandleId(it), null)
/**/
/**/ if GetLocalPlayer() != itemOwner then
/**/ call SetItemVisible(bj_lastCreatedItem, false)
/**/ endif
/**/
/**/ call RemoveItem(it)
/**/ endif
/**/ endif
/**/
/**/ set p = null
/**/ set it = null
/**/ set itemOwner = null
/**/ return false
/**/ endmethod
/**/
/**/ private static method onDrop2 takes nothing returns nothing
/**/ local integer iId = GetItemTypeId(onDropItem)
/**/ local integer q = QuestData.getPickUpQuestId(iId)
/**/ local integer pId = GetPlayerId(onDropPlayer)
/**/
/**/ if GetLocalPlayer() != onDropPlayer then
/**/ call SetItemVisible(onDropItem, false)
/**/ endif
/**/
/**/ if PlayerData.isQuestComplete(q, pId) then
/**/ call PlayerData.setPlayerQuestStatus(q, pId, QUEST_IN_PROGRESS)
/**/ call PlayerData.removeQuestEffect(q, pId)
/**/ endif
/**/
/**/ call PlayerData.decreasePickUpAmount(q, pId, iId)
/**/ endmethod
/**/
/**/ private static method onDrop takes nothing returns boolean
/**/ local integer q
/**/ local integer iId
/**/ set onDropPlayer = GetOwningPlayer(GetTriggerUnit())
/**/ set onDropItem = GetManipulatedItem()
/**/ set iId = GetItemTypeId(onDropItem)
/**/ set q = QuestData.getPickUpQuestId(iId)
/**/
/**/ if q != 0 then
/**/ call TimerStart(dropTimer, 0., false, function thistype.onDrop2)
/**/ endif
/**/
/**/ return false
/**/ endmethod
/**/
/**/ private static method onLevel takes nothing returns boolean
/**/ local unit u = GetTriggerUnit()
/**/ local integer pId = GetPlayerId(GetOwningPlayer(u))
/**/
/**/ if u == HERO[pId] then
/**/ call PlayerData.checkAvailableQuest(GetHeroLevel(u), pId, LEVEL_UP_CHECK)
/**/ endif
/**/
/**/ set u = null
/**/ return false
/**/ endmethod
/*================================================================================================*/
/**/ //Methods mainly for init quests
/**/
/**/ private static method effectInit takes integer pId returns boolean
/**/ local integer q = 0
/**/ local integer max = Quest.getQuestCount()
/**/
/**/ loop
/**/ set q = q + 1
/**/ exitwhen q > max
/**/
/**/ //If no condition present for the quest
/**/ if QuestData.getQuestConditionCount(q) == 0 then
/**/ call PlayerData.applyQuestEffectSingle(q, pId, true)
/**/ endif
/**/ endloop
/**/
/**/ return false
/**/ endmethod
/**/
/**/ private static method onEnter takes nothing returns boolean
/**/ local unit u = GetTriggerUnit()
/**/ local integer pId = GetPlayerId(GetOwningPlayer(u))
/**/
/**/ if QUEST_INFO[pId] == null and u == HERO[pId] then
/**/ set QUEST_INFO[pId] = CreateUnit(Player(pId), QUEST_INFO_ID, GetUnitX(HERO[pId]), GetUnitY(HERO[pId]), 0)
/**/ call thistype.effectInit(pId)
/**/ endif
/**/
/**/ set u = null
/**/ return false
/**/ endmethod
/**/
/**/ private static method onInit takes nothing returns nothing
/**/ local integer i = 0
/**/ local player p
/**/ local region r = CreateRegion()
/**/
/**/ call RegionAddRect(r, bj_mapInitialPlayableArea)
/**/ call TriggerRegisterEnterRegion(enterTrigger, r, Filter(function OnEnterFilter))
/**/
/**/ loop
/**/ set p = Player(i)
/**/
/**/ call TriggerRegisterPlayerUnitEvent(selectTrigger, p, EVENT_PLAYER_UNIT_SELECTED, Filter(function OnSelectFilter))
/**/ call TriggerRegisterPlayerUnitEvent(acceptTrigger, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
/**/ call TriggerRegisterPlayerUnitEvent(deselectTrigger, p, EVENT_PLAYER_UNIT_DESELECTED, null)
/**/ call TriggerRegisterPlayerUnitEvent(deathTrigger, p, EVENT_PLAYER_UNIT_DEATH, null)
/**/ call TriggerRegisterPlayerUnitEvent(pickTrigger, p, EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
/**/ call TriggerRegisterPlayerUnitEvent(dropTrigger, p, EVENT_PLAYER_UNIT_DROP_ITEM, null)
/**/ call TriggerRegisterPlayerUnitEvent(levelTrigger, p, EVENT_PLAYER_HERO_LEVEL, null)
/**/
/**/ //Init array value
/**/ set playerQuestCount[i] = 0
/**/
/**/ //Init dialog value
/**/ set playerDialog[i] = DialogCreate()
/**/ call TriggerRegisterDialogEvent(dialogTrigger, playerDialog[i])
/**/
/**/ set i = i + 1
/**/ exitwhen i == bj_MAX_PLAYERS
/**/ endloop
/**/
/**/ loop
/**/ set p = Player(i)
/**/
/**/ call TriggerRegisterPlayerUnitEvent(deathTrigger, p, EVENT_PLAYER_UNIT_DEATH, null)
/**/
/**/ set i = i + 1
/**/ exitwhen i == bj_MAX_PLAYER_SLOTS
/**/ endloop
/**/
/**/ call TriggerAddCondition(selectTrigger, Condition(function thistype.onSelect))
/**/ call TriggerAddCondition(acceptTrigger, Condition(function thistype.onAccept))
/**/ call TriggerAddCondition(deselectTrigger, Condition(function thistype.onDeselect))
/**/ call TriggerAddCondition(deathTrigger, Condition(function thistype.onDeath))
/**/ call TriggerAddCondition(pickTrigger, Condition(function thistype.onPick))
/**/ call TriggerAddCondition(dropTrigger, Condition(function thistype.onDrop))
/**/ call TriggerAddCondition(levelTrigger, Condition(function thistype.onLevel))
/**/ call TriggerAddCondition(enterTrigger, Condition(function thistype.onEnter))
/**/ call TriggerAddCondition(dialogTrigger, Condition(function thistype.onClick))
/**/
/**/ set p = null
/**/ set r = null
/**/ endmethod
/**/endstruct
/**************************************************************************************************/
endlibrary
Test map is attached if someone need to test in map.