• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Solved] Desync Problem

Status
Not open for further replies.
Level 11
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 :
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.
 

Attachments

  • QuestSystem.w3x
    96.5 KB · Views: 28
Level 11
Joined
Dec 19, 2012
Messages
411
Thanks for your response, I've also thinking the same thing that if it is really only pure visibility problem then it shouldn't causing any desync. I'm not sure if internally war3 does syncing any thing regarding item's visibility. Anywhere, the solution you gave don't seem to appear in the native list, else I would be using it as the replacement of SetItemVisible()
 
Level 39
Joined
Feb 27, 2007
Messages
5,019
Probably have to use a unit and trigger the interaction, then. You could just give the unit ghost (permanent invisibility), make it for the player you want to be able to interact with it, and pause it upon creation. When a hero is ordered to "smart" it and comes within range then that's the equivalent of picking it up.
 
Level 11
Joined
Dec 19, 2012
Messages
411
Not a bad idea. Just 2 parts :
"You could just give the unit ghost (permanent invisibility), make it for the player you want to be able to interact with it" need to consider if unit have item type that could detect invisibility?
"When a hero is ordered to "smart" it and comes within range then that's the equivalent of picking it up." which need to consider how if the player "intended" not to pick it up and just pass by?


Actually I've already came up alternative solution before posting this thread (to see if someone could solve it) before i change my system mechanism.


The similar part to your idea is, still using unit as replacement of item, but instead of giving ghost (permanent invisibility), i will set the transparency of the unit locally to "hide" it. Pause is not needed as the unit belongs to a computer. When player select the unit within range then it would be equivalent of picking an item.


Looks like i still have to change the mechanism in the end. Thanks for anyone helping me :)
 
Level 13
Joined
Mar 24, 2013
Messages
1,105
Well you can pretty easily deny someone who shouldn't be picking up an item.

I'm not sure its really necessary to hide the item for people who shouldn't be able to pick it up.

However, it seems like it might make more sense if you could add the newly recieved item to a player/units "bag" or some type of extended inventory. That way when they recieved the item it could go right into that and then there would never be any question of being able to pick it up or see it. You could also make it if its in this "bag" the items bonuses are not given.

although saying all this is bascially to say you either need to write an inventory system or require one. Which might not be something desirable.
 
Level 11
Joined
Dec 19, 2012
Messages
411
Well you can pretty easily deny someone who shouldn't be picking up an item.
Unfortunately its not an option for me, I don't want the other players could seen the item as it would cause confusion.

Even though I could just drop the item immediately once the other player picked it up, but the item's position would changed and could get abused easily (trolling people)

However, it seems like it might make more sense if you could add the newly recieved item to a player/units "bag" or some type of extended inventory. That way when they recieved the item it could go right into that and then there would never be any question of being able to pick it up or see it. You could also make it if its in this "bag" the items bonuses are not given.

although saying all this is bascially to say you either need to write an inventory system or require one. Which might not be something desirable.
Since system is meant to publish publicly, so adding an extra inventory system is definitely not an option. It would have chance to causes conflict toward user's self made/implemented system. User might not want an extra inventory appear in game though.
 
Level 13
Joined
Nov 7, 2014
Messages
571
Maybe try this:

JASS:
// interacting_unit is the unit that can see and pickup the item
local player interacting_player = GetOwningPlayer(interacting_unit)
call SetItemPlayer(my_item, interacting_player, /*change-color:*/false)
call SetItemVisible(my_item, GetLocalPlayer() == interacting_player)

...

private function set_dropped_item_player_15 takes nothing returns nothing
    call SetItemPlayer(GetManipulatedItem(), Player(15), false)
endfunction
private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DROP_ITEM)
    call TriggerAddAction(t, function set_dropped_item_player_15)
endfunction
 
Level 13
Joined
Nov 7, 2014
Messages
571
followed your script, desync still occurring though

Yeah, you are right it does desync...

One more try:

JASS:
// interacting_unit is the unit that can see and pickup the item
local player interacting_player = GetOwningPlayer(interacting_unit)
call SetItemPlayer(my_item, interacting_player, /*change-color:*/false)
call SetItemVisible(my_item, GetLocalPlayer() == interacting_player)

...

private function on_item_pickup takes nothing returns nothing
    local item it = GetManipulatedItem()
    call SetItemPlayer(it, Player(15), /*change-color:*/false)
    call SetItemVisible(it, true)
    set it = null
endfunction
private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_PICKUP_ITEM)
    call TriggerAddAction(t, function on_item_pickup)
endfunction
 
Last edited:
Status
Not open for further replies.
Top