Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Periachronicles

Junior Spellweaver
Joined
Nov 23, 2008
Messages
146
Reaction score
11
Re: Peria chronicles

I used decompile3, pycharm professionnal edition with a python 3.8 venv

I am actually decompiling everything i can, gonna take a while, i'll post everything later

Edit :
Found something interesting in the engineUpdater.pyc, there is a link to the engine sources svn.
I believe it is down at the moment we speak, but we might find some links working to the sources without having to decompile everything
 
Junior Spellweaver
Joined
Nov 23, 2008
Messages
146
Reaction score
11
Re: Peria chronicles

If anyone wants it, there is the compiled app.py



Deleted this part of the code :

Code:
if currentLocale != 'cp949':
                 if self.Renderer.NativeWindowHandle:
                     text = 'Unsupported system locale : {}'.format(currentLocale)
                     text += '\n\nTo execute the client, change system locale to cp949 (Korean)'
                     self.showWindowsMessageBox(text)
                     self.nxlog = None
                     self.quit(0)
                     return
 
Joined
Aug 14, 2009
Messages
2,304
Reaction score
1,189
Re: Peria chronicles

Okay deleting this check works however the client will not work on non-korean language systems XD

18:18:19.278:natuum:WARNING:Build error [CB1_QSR1034@Quest] - ValueError: '완료 가능' is not a valid MarkerTypes
18:18:19.278:natuum.builder:INFO: D:/Jenkins/workspace/NT_Live_CI/code/python/lib/enum.py:574 in _missing_() -
18:18:19.278:natuum.builder:INFO: D:/Jenkins/workspace/NT_Live_CI/code/python/lib/enum.py:545 in __new__() -
18:18:19.278:natuum.builder:INFO: D:/Jenkins/workspace/NT_Live_CI/code/python/lib/enum.py:561 in __new__() -
18:18:19.382:natuum.client.resource:INFO:preloading data [CB1_QSR1034@Quest] failed : '완료 가능' is not a valid MarkerTypes

I am actually decompiling everything i can, gonna take a while, i'll post everything later

You happened to have the quest.py?
 
Junior Spellweaver
Joined
Nov 23, 2008
Messages
146
Reaction score
11
Re: Peria chronicles

Hello,

There is the quest.py

Code:
import abc, collections, enum, numbers, os, re, math, thing, natuum.util, natuum.cutscene, natuum.relationship, natuum.gameClass
from natuum.gameClass.common import CarveResultEnum
logQuest = os.environ.get('NT_QUEST_LOG', '0') != '0'
if logQuest:
    if not __final__:
        LOG_DEBUG = natuum.getLogger('quest').debug
        LOG_INFO = natuum.getLogger('quest').info
else:

    def LOG_DEBUG(*args):
        return True


QUEST_STATE_KEY_STATE = 'state'
QUEST_STATE_KEY_PENDING_NEXT_STATE = 'pendingNextState'
QUEST_STATE_KEY_RESULT_STATE = 'resultState'
QUEST_STATE_KEY_INSTANCE_ID = 'instanceID'
QUEST_STATE_KEY_VARIABLES = 'variables'
QUEST_STATE_KEY_TOKEN_ID = 'tokenID'
QUEST_STATE_KEY_PATTERN_QUEST_KEY = 'patternQuestKey'
QUEST_STATE_KEY_QUEST_GIVER_UID = 'questGiverUID'
QUEST_STATE_KEY_FORWARD_REVERTIBLE = 'forwardRevertible'
QUEST_STATE_KEY_BACKWARD_REVERTIBLE = 'backwardRevertible'
QUEST_STATE_KEY_TRIGGERED_FORWARD_INDEX = 'triggeredForwardIndex'
QUEST_STATE_KEY_PLAYED_COMPLETE_CUTSCENE = 'playedCompleteCutscene'
QUEST_STATE_KEY_REWARD_APPLIED = 'rewardApplied'
QUEST_STATE_CHANGE_TIMESTAMP = 'changedTime'
QUEST_STATE_KEY_SELECTED = 'selected'
QUEST_VAR_ELAPSED_TIME = 'elapsedTime'
QUEST_VAR_FINISH_TIME = 'finishTime'
QUEST_VAR_KEY_COUNT = 'count'
QUEST_VAR_KEY_TARGET_CLASS_ID = 'targetClassID'
QUEST_VAR_KEY_TARGET_COUNT = 'targetCount'
SYSTEM_MESSAGE_ID_ITEM_TURNED_IN = 'Quest_msg_item_turned_in'
_STRING_TRIGGER_TYPE_CONVERSATION = 'conversation'
_STRING_TRIGGER_TYPE_PROXIMITY_ENTER = 'enter'
_STRING_TRIGGER_TYPE_KILL_COUNT = 'killCount'
_STRING_TRIGGER_TYPE_ITEM_COUNT = 'itemCount'
_STRING_TRIGGER_TYPE_RANDOM_KILL_COUNT = 'randomKillCount'
_STRING_TRIGGER_TYPE_RANDOM_ITEM_COUNT = 'randomItemCount'
_STRING_TRIGGER_TYPE_TIMER = 'timer'
_STRING_TRIGGER_TYPE_SELECTION = 'selection'
_STRING_TRIGGER_TYPE_GUARDIAN_CHANGED = 'guardianChanged'
_STRING_TRIGGER_TYPE_PROPERTY = 'property'
_STRING_TRIGGER_TYPE_GUARDIAN_PROPERTY = 'guardianProperty'
_STRING_TRIGGER_TYPE_CONTRACT = 'contract'
_STRING_TRIGGER_TYPE_HAND = 'hand'
_STRING_TRIGGER_TYPE_DECK = 'deck'
_STRING_TRIGGER_TYPE_ACTION = 'action'
_STRING_TRIGGER_TYPE_RELATIONSHIP = 'relationship'
_STRING_TRIGGER_TYPE_DINE = 'dine'
TutorialQuestsForStats = {v:i + 2000 for i, v in enumerate(('QDtutorial', 'QDtutorial2',
                                                            'QDtutorial3', 'QDtutorial3_1',
                                                            'QDtutorial4', 'QDtutorial4_1',
                                                            'QDtutorial4_2', 'QDtutorial5',
                                                            'QDtutorial5_1', 'QDtutorial6',
                                                            'QDtutorial7'))}
MainQuestsForStats = {v:i + 3000 for i, v in enumerate(('CB1_QMR1000', 'CB1_QMR1001',
                                                        'CB1_QMR1002', 'CB1_QMR1004',
                                                        'CB1_QMR1003', 'CB1_QMR1005',
                                                        'CB1_QMR1006', 'CB1_QMR1007',
                                                        'CB1_QMR1008', 'CB1_QMR1009',
                                                        'CB1_QMR1042', 'CB1_QMR1010',
                                                        'CB1_QMR1011', 'CB1_QMR1066',
                                                        'CB1_QMR1067', 'CB1_QMR1068',
                                                        'CB1_QMR1012', 'CB1_QMR1013',
                                                        'CB1_QMR1014', 'CB1_QMR1015',
                                                        'CB1_QMR1017', 'CB1_QMR1016',
                                                        'CB1_QMR1018', 'CB1_QMR1019',
                                                        'CB1_QMR1020', 'CB1_QMR1021',
                                                        'CB1_QMR1022', 'CB1_QMR1023',
                                                        'CB1_QMR1043', 'CB1_QMR1024',
                                                        'CB1_QMR1025', 'CB1_QMR1060',
                                                        'CB1_QMR1061', 'CB1_QMR1062',
                                                        'CB1_QMR1026', 'CB1_QMR1027',
                                                        'CB1_QMR1028', 'CB1_QMR1029',
                                                        'CB1_QMR1031', 'CB1_QMR1030',
                                                        'CB1_QMR1032', 'CB1_QMR1033',
                                                        'CB1_QMR1034', 'CB1_QMR1035',
                                                        'CB1_QMR1036', 'CB1_QMR1037',
                                                        'CB1_QMR1044', 'CB1_QMR1038',
                                                        'CB1_QMR1039', 'CB1_QMR1063',
                                                        'CB1_QMR1064', 'CB1_QMR1065',
                                                        'CB1_QMR1040', 'CB1_QMR1041',
                                                        'CB1_QS1121', 'CB1_QS1122',
                                                        'CB1_QS1123', 'CB1_QS1204',
                                                        'CB1_QS1207', 'CB1_QS1208',
                                                        'CB1_QS1213', 'CB1_QS1137',
                                                        'CB1_QS1138', 'CB1_QS1139',
                                                        'CB1_QS1205', 'CB1_QS1209',
                                                        'CB1_QS1210', 'CB1_QS1215',
                                                        'CB1_QS1140', 'CB1_QS1141',
                                                        'CB1_QS1142', 'CB1_QS1206',
                                                        'CB1_QS1211', 'CB1_QS1212',
                                                        'CB1_QS1217'))}
MainQuestsForStats.update(TutorialQuestsForStats)

class ReportTargetType(enum.IntEnum):
    All = 0
    QuestGiver = 1

    @staticmethod
    def convert(value: 'str or None') -> 'ReportTargetType':
        if value is None or (value == natuum.quest.ReportTargetType.All.name):
            return natuum.quest.ReportTargetType.All
        return natuum.quest.ReportTargetType.QuestGiver


class QuestType(enum.IntEnum):
    MainQuest = 0
    SubQuest = 1
    DailyQuest = 2
    GroupQuest = 3

    @staticmethod
    def convert(questType: 'str or None') -> 'QuestType':
        if questType is None or (questType == natuum.quest.QuestType.MainQuest.name):
            return natuum.quest.QuestType.MainQuest
        if questType == natuum.quest.QuestType.SubQuest.name:
            return natuum.quest.QuestType.SubQuest
        if questType == natuum.quest.QuestType.DailyQuest.name:
            return natuum.quest.QuestType.DailyQuest
        return natuum.quest.QuestType.GroupQuest


class CountTypes(enum.Enum):
    LessThan = 'lessThan'
    GreaterThanOrEqualTo = 'greaterThanOrEqualTo'

    @staticmethod
    def convert(countType: 'None or str') -> 'CountTypes':
        if countType is None:
            return CountTypes.GreaterThanOrEqualTo
        return CountTypes(countType)


class ComparisonTypes(enum.Enum):
    EQUAL = '=='
    NOT_EQUAL = '!='
    GREATER_THAN = '>'
    GREATER_THAN_OR_EQUAL_TO = '>='
    LESS_THAN = '<'
    LESS_THAN_OR_EQUAL_TO = '<='
    CONTAINS = 'contains'
    IN = 'in'
    RANGE = 'range'

          [USER=437263]clas[/USER]smethod
    def compare(cls, compType: 'ComparisonTypes', value: 'var', target: 'var'):
        if cls.CONTAINS == compType:
            return target in value
        if cls.IN == compType:
            return value in target
        if cls.RANGE == compType:
            return target[0] <= value and target[1] > value
        if cls.EQUAL == compType:
            return value == target
        if cls.NOT_EQUAL == compType:
            return value != target
        if cls.GREATER_THAN == compType:
            return value > target
        if cls.GREATER_THAN_OR_EQUAL_TO == compType:
            return value >= target
        if cls.LESS_THAN == compType:
            return value < target
        if cls.LESS_THAN_OR_EQUAL_TO == compType:
            return value <= target
        raise ValueError('invalid comparison type : {}'.format(compType))


class QuantifierTypes(enum.Enum):
    FOR_ALL = 'forAll'
    THERE_EXSITS = 'thereExists'


class ActionRoleTypes(enum.Enum):
    SUBJECT = 'subject'
    OBJECT = 'object'
    INDIRECT_OBJECT = 'indirectObject'


class MarkerTypes(enum.Enum):
    EMPHASIS = '강조 환상'
    MOVE = '이동'
    STARTABLE = '시작 가능'
    UNSTARTABLE = '시작 불가능'
    ACTIVE = '진행 중'
    COMPLETE = '완료 가능'
    REQUEST_SELECTION = '선택 요청 환상'

    @staticmethod
    def isQuestStateMarker(markerType: 'MarkerTypes'):
        return MarkerTypes.STARTABLE == markerType or MarkerTypes.UNSTARTABLE == markerType or MarkerTypes.ACTIVE == markerType or MarkerTypes.COMPLETE == markerType


class UIStates(enum.Enum):
    DEFAULT = 'Default'
    ACTIVE_COMPLETED = 'ActiveCompleted'
    ACTIVE_FAILED = 'ActiveFailed'
    INACTIVE_FINISHED = 'InactiveFinished'
    INACTIVE_NOT_STARTED = 'InactiveNotStarted'

          [USER=437263]clas[/USER]smethod
    def isActiveQuestState(cls, uiStates: 'UIStates') -> 'bool':
        return cls.DEFAULT == uiStates or cls.ACTIVE_COMPLETED == uiStates or cls.ACTIVE_FAILED == uiStates

          [USER=437263]clas[/USER]smethod
    def isDetailedActiveQuestState(cls, uiStates: 'UIStates') -> 'bool':
        return cls.ACTIVE_COMPLETED == uiStates or cls.ACTIVE_FAILED == uiStates

          [USER=437263]clas[/USER]smethod
    def iterateActiveStates(cls) -> 'generator of UIStates':
        for state in cls:
            if cls.isActiveQuestState(state):
                yield state

          [USER=437263]clas[/USER]smethod
    def convertToUIStateMap(cls, stateMap: 'collections.Mapping', finished: 'collections.Sequence') -> 'collections.Mapping':
        uiStateMap = dict()
        for questID, subMap in stateMap.items():
            uiState = cls.getUIState(subMap)
            if uiState is None:
                continue
            else:
                uiStateMap[questID] = uiState

        for questID in finished:
            uiStateMap[questID] = cls.INACTIVE_FINISHED

        return uiStateMap

          [USER=437263]clas[/USER]smethod
    def toDescString(cls, value: 'UIStates') -> 'str':
        if cls.DEFAULT == value:
            return '기본'
        if cls.ACTIVE_COMPLETED == value:
            return '진행(조건 만족 상태)'
        if cls.ACTIVE_FAILED == value:
            return '진행(실패 상태)'
        if cls.INACTIVE_FINISHED == value:
            return '완료'
        if cls.INACTIVE_NOT_STARTED == value:
            return '시작 전'
        return ''

          [USER=437263]clas[/USER]smethod
    def getUIState(cls, subMap: 'collections.Mapping') -> 'None or UIStates':
        try:
            state = subMap[QUEST_STATE_KEY_STATE]
        except KeyError:
            return
        else:
            uiState = cls._translate(QuestStates(state))
            return uiState

          [USER=437263]clas[/USER]smethod
    def _translate(cls, state: 'QuestStates') -> 'None or UIStates':
        if QuestStates.COMPLETED == state or (QuestStates.FINISHED_CUTSCENE == state or QuestStates.FINISHED == state):
            return cls.ACTIVE_COMPLETED
        if QuestStates.ACCEPTED == state or (QuestStates.WATCH == state):
            return cls.DEFAULT
        if QuestStates.FAILED == state:
            return cls.ACTIVE_FAILED


class MarkerStates(enum.Enum):
    ALL = 'All'
    ACCEPTED = 'Accepted'
    COMPLETED = 'Completed'
    FAILED = 'Failed'

          [USER=437263]clas[/USER]smethod
    def _translate(cls, state: 'MarkerStates') -> 'None or UIStates':
        if cls.ACCEPTED == state:
            return UIStates.DEFAULT
        if cls.COMPLETED == state:
            return UIStates.ACTIVE_COMPLETED
        if cls.FAILED == state:
            return UIStates.ACTIVE_FAILED


class UIStateBoundInfo:

    def __init__(self, rawMap: 'collections.Mapping'):
        self._UIStateBoundInfo__infoMap = dict()
        for key, value in rawMap.items():
            self._UIStateBoundInfo__infoMap[UIStates(key)] = value

    def getValue(self, uiState: 'UIStates') -> 'None or var':
        if uiState in self._UIStateBoundInfo__infoMap:
            return self._UIStateBoundInfo__infoMap[uiState]
        return self._UIStateBoundInfo__infoMap.get(UIStates.DEFAULT)

    def ensureType(self, expectedType: 'var'):
        for value in self._UIStateBoundInfo__infoMap.values():
            if not isinstance(value, expectedType):
                msg = 'invalid value : {}, expected type : {}'
                raise ValueError(msg.format(value, expectedType))

    def ensureStates(self, checkActive: 'bool'=False, isNotDetailed: 'bool'=False):
        if checkActive:
            for state in self._UIStateBoundInfo__infoMap.keys():
                if not UIStates.isActiveQuestState(state):
                    msg = 'invalid state : {}, expected active ui state'
                    raise ValueError(msg.format(state))

        if isNotDetailed:
            for state in self._UIStateBoundInfo__infoMap.keys():
                if UIStates.isDetailedActiveQuestState(state):
                    msg = 'invalid state : {}, unexpected ui state'
                    raise ValueError(msg.format(state))

    _UIStateBoundInfo__infoMap = None


class UIInfo:
    StateInfo = collections.namedtuple('StateInfo', ('Title', 'Description', 'SimpleDescription'))
    MarkerInfo = collections.namedtuple('MarkerInfo', ('Target', 'MarkerType', 'Tooltip',
                                                       'QuestType', 'Repeatable'))
    _UIInfo__FINISHED_TRIGGER_FORMAT = '<del>{}</del>'

    def __init__(self, questType: 'natuum.quest.QuestType', repeatable: 'bool', title: 'str', rawMarkerInfos: 'None or collections.Mapping', rawGuideTarget: 'None or collections.Mapping', rewardDesc: 'str', rawUIDesc: 'None or col
lections.Mapping', rawUIDescPreq: 'None or collections.Mapping', rawUIDescTrigger: 'None or collections.Mapping'):
        self._UIInfo__title = title
        if rawMarkerInfos:
            stateMap = dict()
            markerMap = dict()
            for state, value in rawMarkerInfos.items():
                markerState = MarkerStates(state)
                stateMap[markerState] = self.StateInfo(title, '', value['questMarkerText'])
                infoList = list()
                for marker in value['markers']:
                    infoList.append(self.MarkerInfo(marker['markerTarget'], natuum.quest.MarkerTypes(marker['markerType']), marker.get('tooltip'), questType, repeatable))

                markerMap[markerState] = infoList

            self._UIInfo__stringInfo = self._UIInfo__translateInfoMap(stateMap)
            self._UIInfo__markerInfo = self._UIInfo__translateInfoMap(markerMap)
        if rawGuideTarget:
            guideTarget = dict()
            for key, subMap in rawGuideTarget.items():
                guideTarget[key] = AuxInfo.GuideTarget(subMap)

            self._UIInfo__guideTarget = UIStateBoundInfo(guideTarget)
            self._UIInfo__guideTarget.ensureType(AuxInfo.GuideTarget)
        self._UIInfo__rewardDesc = rewardDesc
        if rawUIDesc:
            self._UIInfo__uiDesc = UIStateBoundInfo(rawUIDesc)
            self._UIInfo__uiDesc.ensureType((str, type(None)))
            self._UIInfo__uiDesc.ensureStates(isNotDetailed=True)
        if rawUIDescPreq:
            self._UIInfo__uiDescPreq = UIStateBoundInfo(rawUIDescPreq)
            self._UIInfo__uiDescPreq.ensureType((str, type(None)))
            self._UIInfo__uiDescPreq.ensureStates(isNotDetailed=True)
        if rawUIDescTrigger:
            self._UIInfo__uiDescTrigger = UIStateBoundInfo(rawUIDescTrigger)
            self._UIInfo__uiDescTrigger.ensureType((str, type(None)))

          [USER=1333341624]Property[/USER]
    def Title(self) -> 'str':
        return self._UIInfo__title

          [USER=1333341624]Property[/USER]
    def RewardDesc(self) -> 'str':
        return self._UIInfo__rewardDesc

          [USER=1333341624]Property[/USER]
    def HasGuideTarget(self) -> 'bool':
        return self._UIInfo__guideTarget is not None

    def getInfo(self, uiState: 'UIStates') -> 'None or .StateInfo':
        if self._UIInfo__stringInfo is not None:
            return self._UIInfo__stringInfo.getValue(uiState)

    def getMarkerInfo(self, uiState: 'UIStates') -> 'None or sequence of .MarkerInfo':
        if self._UIInfo__markerInfo is not None:
            return self._UIInfo__markerInfo.getValue(uiState)

    def getGuideTarget(self, uiState: 'UIStates') -> 'None or AuxInfo.GuideTarget':
        if self._UIInfo__guideTarget is not None:
            return self._UIInfo__guideTarget.getValue(uiState)

    def getDesc(self, uiState: 'UIStates') -> 'None or str':
        if self._UIInfo__uiDesc is not None:
            return self._UIInfo__uiDesc.getValue(uiState)

    def getPrerequisiteDesc(self, uiState: 'UIStates') -> 'None or str':
        if self._UIInfo__uiDescPreq is not None:
            return self._UIInfo__uiDescPreq.getValue(uiState)

    def getRawTriggerDesc(self, uiState: 'UIStates') -> 'None or str':
        if self._UIInfo__uiDescTrigger is not None:
            return self._UIInfo__uiDescTrigger.getValue(uiState)

    def getTriggerDesc(self, uiState: 'UIStates', descTriggerAux: 'None or str') -> 'None or str':
        raw = self.getRawTriggerDesc(uiState)
        if UIStates.DEFAULT == uiState:
            textList = list()
            if raw:
                textList.append(raw)
            if descTriggerAux:
                textList.append(descTriggerAux)
            text = '\n'.join(textList)
        elif UIStates.ACTIVE_COMPLETED == uiState:
            textList = list()
            defaultText = self.getRawTriggerDesc(UIStates.DEFAULT)
            if defaultText:
                textList.append(self._UIInfo__FINISHED_TRIGGER_FORMAT.format(defaultText))
            if descTriggerAux:
                textList.append(self._UIInfo__FINISHED_TRIGGER_FORMAT.format(descTriggerAux))
            if raw:
                if defaultText != raw:
                    textList.append(raw)
            text = '\n'.join(textList)
        else:
            text = raw
        if text:
            return text

    @staticmethod
    def __translateInfoMap(infoMap: 'collections.Mapping') -> 'UIStateBoundInfo':
        translated = dict()
        for markerState, info in infoMap.items():
            key = MarkerStates._translate(markerState)
            if key is not None:
                translated[key] = info

        defaultInfo = infoMap.get(MarkerStates.ALL)
        if defaultInfo is None:
            defaultInfo = infoMap.get(MarkerStates.ACCEPTED)
        if defaultInfo is not None:
            translated[UIStates.DEFAULT] = defaultInfo
        return UIStateBoundInfo(translated)

    _UIInfo__title = None
    _UIInfo__stringInfo = None
    _UIInfo__markerInfo = None
    _UIInfo__guideTarget = None
    _UIInfo__rewardDesc = None
    _UIInfo__uiDesc = None
    _UIInfo__uiDescPreq = None
    _UIInfo__uiDescTrigger = None


class AuxInfo:
    _AuxInfo__AUX_KEY_GUIDED_QUEST_ID = 'guidedQuestID'

    class GuideTarget:

        class Types(enum.Enum):
            PERSON_NAME = 'PersonName'
            PERSON_UID = 'PersonUID'
            QUEST_ROLE = 'QuestRole'
            ITEM_NAME = 'ItemName'
            SIGNPOST = 'Signpost'

        Target = thing.accessor.ri(None, doc='str')
        TargetType = thing.accessor.ri(None, doc='.Types')
        TargetName = thing.accessor.ri(None, doc='str')
        ZoneName = thing.accessor.ri(None, doc='str')

        def __init__(self, subMap: 'collections.Mapping'):
            target = subMap['target']
            if not isinstance(target, str):
                raise ValueError('invalid guide target : {}'.format(target))
            self.Target = target
            self.TargetType = self.Types(subMap['targetType'])
            self.TargetName = subMap.get('targetName')
            self.ZoneName = subMap.get('zoneName')

          [USER=437263]clas[/USER]smethod
    def getGuidedQuestID(cls, auxInfo: 'collections.Mapping') -> 'None or str':
        guidedQuestID = auxInfo.get(cls._AuxInfo__AUX_KEY_GUIDED_QUEST_ID)
        return guidedQuestID

          [USER=437263]clas[/USER]smethod
    def setGuidedQuestID(cls, auxInfo: 'collections.Mapping', questID: 'None or str') -> 'collections.Mapping':
        if questID is None:
            auxInfo.pop(cls._AuxInfo__AUX_KEY_GUIDED_QUEST_ID, None)
        else:
            auxInfo[cls._AuxInfo__AUX_KEY_GUIDED_QUEST_ID] = questID
        return auxInfo


class QuestStates(enum.IntEnum):
    INIT = 0
    SELECT = 1
    ACCEPTED = 2
    REJECTED = 3
    WATCH = 4
    COMPLETED = 5
    FAILED = 6
    FINISHED_CUTSCENE = 7
    CANCELED_CUTSCENE = 8
    CANCELED = 9
    FINISHED = 10

    @staticmethod
    def isActive(state: 'QuestStates', isRejectable: 'bool') -> 'bool':
        if isRejectable:
            return state >= QuestStates.WATCH
        return True

          [USER=437263]clas[/USER]smethod
    def toString(cls, value: 'QuestStates') -> 'str':
        if cls.INIT == value:
            return '시작'
        if cls.SELECT == value:
            return '선택'
        if cls.ACCEPTED == value:
            return '수락'
        if cls.REJECTED == value:
            return '거절'
        if cls.WATCH == value:
            return '감시'
        if cls.COMPLETED == value:
            return '조건 만족'
        if cls.FAILED == value:
            return '실패'
        if cls.FINISHED_CUTSCENE == value:
            return '완료 컷신'
        if cls.CANCELED_CUTSCENE == value:
            return '취소 컷신'
        if cls.CANCELED == value:
            return '취소'
        if cls.FINISHED == value:
            return '완료'
        return '알 수 없는 상태'

          [USER=437263]clas[/USER]smethod
    def convertToStringMap(cls, stateMap: 'collections.Mapping', finished: 'collections.Sequence') -> 'collections.Mapping':
        textMap = dict()
        for questID, subMap in stateMap.items():
            state = subMap.get(QUEST_STATE_KEY_STATE)
            if state is not None:
                textMap[questID] = cls.toString(state)

        for questID in finished:
            textMap[questID] = cls.toString(cls.FINISHED)

        return textMap

          [USER=437263]clas[/USER]smethod
    def isCompletable(cls, subMap: 'collections.Mapping') -> 'bool':
        return cls.COMPLETED == subMap.get(QUEST_STATE_KEY_STATE)


class ResultStates(enum.IntEnum):
    SUCCEEDED = 0
    FAILED = 1
    FAILED_INVALID_ITEM_INFO = 2
    FAILED_ENTER_LIMIT = 3
    FAILED_CARVE_TARGET_NOT_FOUND = 4
    FAILED_CARVE_INVALID_KIRANA = 5
    FAILED_CARVE_INVALID_ITEM = 6
    FAILED_CARVE_ALREADY_CARVED = 7
    FAILED_CARVE_RESERVED_KIRANA = 8

          [USER=437263]clas[/USER]smethod
    def convertFromCarveResult(cls, value: 'int') -> 'ResultStates':
        if CarveResultEnum.SUCCEEDED == value:
            return cls.SUCCEEDED
        if CarveResultEnum.FAILED_ALREADY_CARVED == value:
            return cls.FAILED_CARVE_ALREADY_CARVED
        if CarveResultEnum.FAILED_INVALID_ITEM == value:
            return cls.FAILED_CARVE_INVALID_ITEM
        if CarveResultEnum.FAILED_INVALID_KIRANA == value:
            return cls.FAILED_CARVE_INVALID_KIRANA
        if CarveResultEnum.FAILED_RESERVED_KIRANA == value:
            return cls.FAILED_CARVE_RESERVED_KIRANA
        return cls.FAILED_ENTER_LIMIT

          [USER=437263]clas[/USER]smethod
    def convertToFailedMessageID(cls, value: 'int') -> 'None or str':
        if cls.FAILED == value:
            return 'Quest_msg_result_failed_default'
        if cls.FAILED_INVALID_ITEM_INFO == value:
            return 'Quest_msg_result_failed_invalid_item_info'
        if cls.FAILED_ENTER_LIMIT == value:
            return 'Quest_msg_result_failed_enter_limit'
        if cls.FAILED_CARVE_TARGET_NOT_FOUND == value:
            return 'Quest_msg_result_failed_carve_target_not_found'
        if cls.FAILED_CARVE_INVALID_KIRANA == value:
            return 'Quest_msg_result_failed_carve_invalid_kirana'
        if cls.FAILED_CARVE_INVALID_ITEM == value:
            return 'Quest_msg_result_failed_carve_invalid_item'
        if cls.FAILED_CARVE_ALREADY_CARVED == value:
            return 'Quest_msg_result_failed_carve_already_carved'
        if cls.FAILED_CARVE_RESERVED_KIRANA == value:
            return 'Quest_msg_result_failed_carve_reserved_kirana'


class TriggerTypes(enum.IntEnum):
    CONVERSATION = 0
    PROXIMITY_ENTER = 1
    ITEM_COUNT = 2
    KILL_COUNT = 3
    RANDOM_ITEM_COUNT = 4
    RANDOM_KILL_COUNT = 5
    ACTION = 6
    SELECTION = 7
    TIMER = 8
    GUARDIAN_CHANGED = 9
    PROPERTY = 10
    GUARDIAN_PROPERTY = 11
    SELECT_STATE = 12
    CONTRACT = 13
    DECK = 14
    HAND = 15
    RELATIONSHIP = 16
    DINE = 17

    @staticmethod
    def isRevertible(triggerType: 'TriggerTypes') -> 'bool':
        return TriggerTypes.RANDOM_ITEM_COUNT == triggerType or TriggerTypes.PROPERTY == triggerType or TriggerTypes.GUARDIAN_PROPERTY == triggerType or TriggerTypes.ITEM_COUNT == triggerType or TriggerTypes.DECK == triggerType or
 TriggerTypes.HAND == triggerType

    @staticmethod
    def isInstant(triggerType: 'TriggerTypes') -> 'bool':
        return TriggerTypes.SELECTION == triggerType or TriggerTypes.SELECT_STATE == triggerType

    @staticmethod
    def _convert(value: 'str'):
        if value == _STRING_TRIGGER_TYPE_CONVERSATION:
            return TriggerTypes.CONVERSATION
        if value == _STRING_TRIGGER_TYPE_PROXIMITY_ENTER:
            return TriggerTypes.PROXIMITY_ENTER
        if value == _STRING_TRIGGER_TYPE_ITEM_COUNT:
            return TriggerTypes.ITEM_COUNT
        if value == _STRING_TRIGGER_TYPE_KILL_COUNT:
            return TriggerTypes.KILL_COUNT
        if value == _STRING_TRIGGER_TYPE_RANDOM_ITEM_COUNT:
            return TriggerTypes.RANDOM_ITEM_COUNT
        if value == _STRING_TRIGGER_TYPE_RANDOM_KILL_COUNT:
            return TriggerTypes.RANDOM_KILL_COUNT
        if value == _STRING_TRIGGER_TYPE_TIMER:
            return TriggerTypes.TIMER
        if value == _STRING_TRIGGER_TYPE_SELECTION:
            return TriggerTypes.SELECTION
        if value == _STRING_TRIGGER_TYPE_GUARDIAN_CHANGED:
            return TriggerTypes.GUARDIAN_CHANGED
        if value == _STRING_TRIGGER_TYPE_PROPERTY:
            return TriggerTypes.PROPERTY
        if value == _STRING_TRIGGER_TYPE_GUARDIAN_PROPERTY:
            return TriggerTypes.GUARDIAN_PROPERTY
        if value == _STRING_TRIGGER_TYPE_CONTRACT:
            return TriggerTypes.CONTRACT
        if value == _STRING_TRIGGER_TYPE_DECK:
            return TriggerTypes.DECK
        if value == _STRING_TRIGGER_TYPE_HAND:
            return TriggerTypes.HAND
        if value == _STRING_TRIGGER_TYPE_ACTION:
            return TriggerTypes.ACTION
        if value == _STRING_TRIGGER_TYPE_RELATIONSHIP:
            return TriggerTypes.RELATIONSHIP
        if value == _STRING_TRIGGER_TYPE_DINE:
            return TriggerTypes.DINE
        raise ValueError('invalid trigger type : {}'.format(value))


class TriggerUsageTypes(enum.IntEnum):
    START = 0
    UPDATE = 1


class DescDelims(enum.Enum):
    DungeonDesc = '<D>'
    EpicKiranaClassIDs = '<E>'
    TownDesc = '<T>'


class DungeonDescDelims(enum.Enum):
    KiranaClassIDs = '<DA>'
    DungeonRecordKey = '<DB>'


class ConversationTriggerInfo:
    QuestID = thing.accessor.ri(None, doc='str')
    UsageType = thing.accessor.ri(None, doc='TriggerUsageTypes')
    ListenerQuestRole = thing.accessor.ri(None, doc='str')
    SelectionText = thing.accessor.ri(None, doc='str')
    ConfirmText = thing.accessor.ri(None, doc='None or str')

    def __init__(self, listenerQuestRole: 'str', selectionText: 'str', confirmText: 'None or str', questID: 'str', usageType: 'TriggerUsageTypes'):
        self.QuestID = questID
        self.ListenerQuestRole = listenerQuestRole
        self.SelectionText = selectionText
        self.ConfirmText = confirmText
        self.UsageType = usageType


class ContractInfo:
    TargetClassID = thing.accessor.ri(None, doc='thing.system.uuid')

    def __init__(self, targetClassID: 'str'):
        self.TargetClassID = natuum.util.convertToUUID(targetClassID)


class DeckInfo:
    ClassIDCounts = thing.accessor.ri(None, doc='list')

    def __init__(self, classIDs: 'collections.Sequence'):
        countMap = dict()
        for classIDStr in classIDs:
            classID = natuum.util.convertToUUID(classIDStr)
            if classID not in countMap:
                countMap[classID] = 0
            else:
                countMap[classID] += 1

        self.ClassIDCounts = list()
        for classID, count in countMap.items():
            self.ClassIDCounts.append((classID, count))


class HandInfo:

    class HandCondition:
        Quantifier = thing.accessor.ri(None, doc='None or QuantifierTypes')
        ClassIDs = thing.accessor.ri(None, doc='None or collections.Sequence')
        PropertyCondition = thing.accessor.ri(None, doc='None or PropertyCondition')

        def initialize(self, raw: 'None or collections.Mapping') -> 'bool':
            if raw is not None:
                self.Quantifier = QuantifierTypes(raw['quantifier'])
                classIDs = raw.get('classIDs')
                if classIDs:
                    self.ClassIDs = list()
                    for classID in classIDs:
                        self.ClassIDs.append(natuum.util.convertToUUID(classID))

                property = raw.get('property')
                if property:
                    self.PropertyCondition = PropertyCondition(property)
            return self.Quantifier and (self.ClassIDs or self.PropertyCondition)

    AverageLevel = thing.accessor.ri(None, doc='float')
    Count = thing.accessor.ri(None, doc='int')
    Condition = thing.accessor.ri(None, doc='None or HandInfo.HandCondition')

    def __init__(self, raw: 'collections.Mapping'):
        self.AverageLevel = raw.get('minAverageLevel', 0.0)
        self.Count = int(raw['minCount'])
        condition = self.HandCondition()
        if condition.initialize(raw.get('condition')):
            self.Condition = condition


class ActionInfo:
    ActionID = thing.accessor.ri(None, doc='str')
    HostRole = thing.accessor.ri(None, doc='str')

    def __init__(self, actionID: 'str', hostRole: 'str'):
        if not isinstance(actionID, str):
            raise ValueError('invalid actionID : {}'.format(actionID))
        self.ActionID = actionID
        self.HostRole = ActionRoleTypes(hostRole)


class CountTriggerInfo:
    TargetClassID = thing.accessor.ri(None, doc='thing.system.uuid')
    TargetCount = thing.accessor.ri(None, doc='int')
    Type = thing.accessor.ri(None, doc='CountTypes')
    PropertyCondition = thing.accessor.ri(None, doc='None or PropertyCondition')
    TargetQuestRole = thing.accessor.ri(None, doc='None or str')
    UIName = thing.accessor.ri(None, doc='None or str')

    def __init__(self, targetClassID: 'str', targetCount: 'int', countType: 'str'=None, propertyCondition: 'PropertyCondition'=None, questRole: 'str'=None, uiName: 'str'=None):
        self.TargetClassID = natuum.util.convertToUUID(targetClassID)
        try:
            natuum.gameClass.getClassByID(self.TargetClassID)
        except Exception:
            raise ValueError('unknown classID : {}'.format(targetClassID))

        self.TargetCount = targetCount
        self.Type = CountTypes.convert(countType)
        self.PropertyCondition = propertyCondition
        self.TargetQuestRole = questRole
        self.UIName = uiName


class RandomCountTriggerInfo:
    TargetClassIDCandidates = thing.accessor.ri(None, doc='list')
    TargetCountRangeMax = thing.accessor.ri(None, doc='int')
    TargetCountRangeMin = thing.accessor.ri(None, doc='int')
    Type = thing.accessor.ri(None, doc='CountTypes')

    def __init__(self, candidates: 'collections.Sequence', maxCount: 'int', minCount: 'int', countType: 'str'=None):
        if not candidates:
            raise ValueError('random trigger should have at least one candidate')
        if maxCount < minCount or (maxCount < 1 or minCount < 1):
            msg = 'invalid range : [ {}, {} ]'
            raise ValueError(msg.format(minCount, maxCount))
        self.TargetClassIDCandidates = list()
        for value in candidates:
            classID = natuum.util.convertToUUID(value)
            try:
                natuum.gameClass.getClassByID(classID)
            except Exception:
                raise ValueError('unknown classID : {}'.format(value))

            self.TargetClassIDCandidates.append(classID)

        self.TargetCountRangeMax = maxCount
        self.TargetCountRangeMin = minCount
        self.Type = CountTypes.convert(countType)


class EnterTriggerInfo:

    class TargetTypes(enum.IntEnum):
        QuestRole = 0
        Name = 1
        Signpost = 2

        @staticmethod
        def convert(value: 'str') -> 'EnterTriggerInfo.TargetTypes':
            if value == EnterTriggerInfo.TargetTypes.QuestRole.name:
                return EnterTriggerInfo.TargetTypes.QuestRole
            if value == EnterTriggerInfo.TargetTypes.Name.name:
                return EnterTriggerInfo.TargetTypes.Name
            if value == EnterTriggerInfo.TargetTypes.Signpost.name:
                return EnterTriggerInfo.TargetTypes.Signpost
            msg = 'invalid enter trigger target type : {}'
            raise ValueError(msg.format(value))

    Target = thing.accessor.ri(None, doc='str')
    Range = thing.accessor.ri(None, doc='float')
    Type = thing.accessor.ri(None, doc='EnterTriggerInfo.TargetTypes')

    def __init__(self, target: 'str', targetType: 'str', range: 'float'):
        self.Target = target
        self.Type = EnterTriggerInfo.TargetTypes.convert(targetType)
        self.Range = range


class AcceptTriggerInfo:

    def __init__(self, acceptText: 'None or str', rejectText: 'None or str'):
        self._AcceptTriggerInfo__selectionMap = dict()
        self._AcceptTriggerInfo__keys = list()
        if acceptText is not None:
            self._AcceptTriggerInfo__selectionMap[acceptText] = QuestStates.ACCEPTED
            self._AcceptTriggerInfo__keys.append(acceptText)
        if rejectText is not None:
            self._AcceptTriggerInfo__selectionMap[rejectText] = QuestStates.REJECTED
            self._AcceptTriggerInfo__keys.append(rejectText)
            self._AcceptTriggerInfo__isRejectable = True
        else:
            self._AcceptTriggerInfo__isRejectable = False

          [USER=1333341624]Property[/USER]
    def Keys(self) -> 'collections.Sequence':
        return self._AcceptTriggerInfo__keys

          [USER=1333341624]Property[/USER]
    def IsRejectable(self) -> 'bool':
        return self._AcceptTriggerInfo__isRejectable

    def getValue(self, key: 'str') -> 'None or str':
        return self._AcceptTriggerInfo__selectionMap.get(key)

    _AcceptTriggerInfo__selectionMap = None
    _AcceptTriggerInfo__keys = None
    _AcceptTriggerInfo__isRejectable = None


class SelectionTriggerInfo:
    Results = collections.namedtuple('Results', ('NextQuestIDs', ))

    def __init__(self, selectionMap: 'collecctions.Mapping'):
        self._SelectionTriggerInfo__selectionMap = collections.OrderedDict()
        self._SelectionTriggerInfo__keys = list()
        for selectionText, nextQuestIDs in selectionMap.items():
            if nextQuestIDs:
                if isinstance(nextQuestIDs, collections.Sequence):
                    self._SelectionTriggerInfo__selectionMap[selectionText] = self.Results(nextQuestIDs)
            self._SelectionTriggerInfo__keys.append(selectionText)

          [USER=1333341624]Property[/USER]
    def Keys(self) -> 'collections.Sequence':
        return self._SelectionTriggerInfo__keys

    def getResults(self, key: 'str') -> 'None or .Results':
        return self._SelectionTriggerInfo__selectionMap.get(key)

    _SelectionTriggerInfo__selectionMap = None
    _SelectionTriggerInfo__keys = None


class GuardianChangedTriggerInfo:
    FromClassID = thing.accessor.ri(None, doc='None or thing.system.uuid')
    ToClassID = thing.accessor.ri(None, doc='None or thing.system.uuid')
    UsageType = thing.accessor.ri(None, doc='TriggerUsageTypes')

    def __init__(self, fromClassID: 'None or thing.system.uuid', classID: 'None or thing.system.uuid', usageType: 'TriggerUsageTypes'):
        if fromClassID is not None:
            self.FromClassID = natuum.util.convertToUUID(fromClassID)
        else:
            self.FromClassID = None
        if classID is not None:
            self.ToClassID = natuum.util.convertToUUID(classID)
        else:
            self.ToClassID = None
        self.UsageType = usageType


class PropertyTriggerInfo:
    Condition = thing.accessor.ri(None, doc='PropertyCondition')

    def __init__(self, condition: 'collections.Mapping'):
        self.Condition = PropertyCondition(condition)


class TriggerInfo:

    def __init__(self, triggerType: 'TriggerTypes', triggerName: 'str', auxArg: 'var'):
        self._TriggerInfo__triggerType = triggerType
        self._TriggerInfo__triggerName = triggerName
        self._TriggerInfo__auxArg = auxArg

          [USER=1333341624]Property[/USER]
    def TriggerType(self) -> 'TriggerTypes':
        return self._TriggerInfo__triggerType

          [USER=1333341624]Property[/USER]
    def TriggerName(self) -> 'str':
        return self._TriggerInfo__triggerName

          [USER=1333341624]Property[/USER]
    def AuxArg(self) -> 'var':
        return self._TriggerInfo__auxArg

    _TriggerInfo__triggerType = None
    _TriggerInfo__triggerName = None
    _TriggerInfo__auxArg = None


class TriggerInfoList:

    def __init__(self, infoList: 'collections.Sequence', isInstant: 'bool'):
        if not infoList:
            raise ValueError('invalid info list : {}'.format(infoList))
        for subList in infoList:
            if not subList:
                raise ValueError('invalid sub info list : {}'.format(subList))

        self._TriggerInfoList__infoList = infoList
        self._TriggerInfoList__isInstant = isInstant

          [USER=1333341624]Property[/USER]
    def IsInstant(self):
        return self._TriggerInfoList__isInstant

    def iterate(self) -> 'generator of list of TriggerInfo':
        for subList in self._TriggerInfoList__infoList:
            yield subList

    def getSubListByIndex(self, index: 'int') -> 'None or list of TriggerInfo':
        try:
            return self._TriggerInfoList__infoList[index]
        except IndexError:
            return

    def iterateWithIndex(self) -> 'generator of ( int, list of TriggerInfo )':
        for index, subList in enumerate(self._TriggerInfoList__infoList):
            yield (
             index, subList)

    _TriggerInfoList__infoList = None
    _TriggerInfoList__isInstant = None


class InverseTriggerInfoList(TriggerInfoList):
    ModifierTargets = thing.accessor.ri(None, doc='None or dict')

    def __init__(self, infoMap):
        super().__init__(list(infoMap.values()), False)
        self.ModifierTargets = self._InverseTriggerInfoList__getModifierTargets()
        self._InverseTriggerInfoList__infoMap = infoMap

    def getSubListByIndex(self, index: 'int') -> 'None or list of TriggerInfo':
        return self._InverseTriggerInfoList__infoMap.get(index)

    def iterateWithIndex(self) -> 'generator of ( int, list of TriggerInfo )':
        for index, subList in self._InverseTriggerInfoList__infoMap.items():
            yield (
             index, subList)

    @staticmethod
    def create(triggerList: 'TriggerInfoList') -> 'None or InverseTriggerInfoList':
        revertible = dict()
        for index, subList in triggerList.iterateWithIndex():
            subRevertible = list()
            for info in subList:
                if TriggerTypes.isRevertible(info.TriggerType):
                    subRevertible.append(info)

            if subRevertible:
                revertible[index] = subRevertible

        if revertible:
            return InverseTriggerInfoList(revertible)

    def __getModifierTargets(self) -> 'None or collections.Mapping':
        targetMap = dict()
        for subList in self.iterate():
            for info in subList:
                if not TriggerTypes.isRevertible(info.TriggerType):
                    continue
                else:
                    if info.TriggerType not in targetMap:
                        targetMap[info.TriggerType] = set()
                    subSet = targetMap[info.TriggerType]
                if TriggerTypes.ITEM_COUNT == info.TriggerType:
                    subSet.add((info.AuxArg.TargetClassID,
                     info.AuxArg.PropertyCondition))
                else:
                    if TriggerTypes.RANDOM_ITEM_COUNT == info.TriggerType:
                        subSet.add(info)
                    else:
                        if TriggerTypes.PROPERTY == info.TriggerType:
                            subSet.add(info.AuxArg.Condition.PropertyName)
                        else:
                            if TriggerTypes.GUARDIAN_PROPERTY == info.TriggerType:
                                subSet.add(info.AuxArg.Condition.PropertyName)
                            else:
                                if TriggerTypes.DECK == info.TriggerType:
                                    continue
                if TriggerTypes.HAND == info.TriggerType:
                    continue

        if targetMap:
            return targetMap

    _InverseTriggerInfoList__infoMap = None


class CutsceneInfo:
    ScriptData = thing.accessor.ri(None, doc='natuum.cutscene.ScriptData')
    RoleNameMap = thing.accessor.ri(None, doc='dict')
    CaptionPositionMap = thing.accessor.ri(None, doc='dict')
    IsStaged = thing.accessor.ri(None, doc='bool')
    StageFlag = thing.accessor.ri(None, doc='None or int')

    def __init__(self, scriptData: 'natuum.cutscene.ScriptData', roleNameMap: 'collections.Mapping', captionPositionMap: 'collections.Mapping', isStaged: 'int or bool'):
        self.ScriptData = scriptData
        self.RoleNameMap = roleNameMap
        self.CaptionPositionMap = captionPositionMap
        self.IsStaged = bool(isStaged)
        self.StageFlag = natuum.cutscene.QuestStagedFlag if isStaged else None


class RelationshipTarget(natuum.relationship.RelationshipTarget):
    STR_QUEST_GIVER = 'QUEST_GIVER'

          [USER=1333341624]Property[/USER]
    def TargetQuestGiver(self):
        return self.Target == self.STR_QUEST_GIVER


class RelationshipCondition:
    RelationshipTarget = thing.accessor.ri(None, doc='RelationshipTarget')
    Value = thing.accessor.ri(None, doc='Value')
    CountType = thing.accessor.ri(None, doc='CountTypes')

    def __init__(self, info: 'collections.Mapping'):
        self.RelationshipTarget = RelationshipTarget(info['target'])
        self.CountType = CountTypes.convert(info['countType'])
        value = info['value']
        if not isinstance(value, int):
            msg = 'invalid relationship value : {}'.format(value)
            raise ValueError(msg)
        self.Value = value

    def check(self, level: 'int') -> 'bool':
        if CountTypes.LessThan == self.CountType:
            return level < self.Value
        return level >= self.Value


class RelationshipConditionList:

    class IGetter(metaclass=abc.ABCMeta):

              [USER=2000283886]abc[/USER].abstractmethod
        def getRelationship(self, target: 'str', group: 'natuum.relationship.RelationshipGroup') -> 'int':
            pass

    def __init__(self, value: 'collections.Sequence'):
        self._RelationshipConditionList__giverRelationship = list()
        self._RelationshipConditionList__targetedRelationship = list()
        for info in value:
            cond = RelationshipCondition(info)
            if cond.RelationshipTarget.TargetQuestGiver:
                self._RelationshipConditionList__giverRelationship.append(cond)
            else:
                self._RelationshipConditionList__targetedRelationship.append(cond)

    def checkGiver(self, getter: '.IGetter', giverUID: 'str') -> 'bool':
        for cond in self._RelationshipConditionList__giverRelationship:
            relTarget = cond.RelationshipTarget
            level = getter.getRelationship(giverUID, relTarget.Group)
            if not cond.check(level):
                return False

        return True

    def checkTargeted(self, getter: '.IGetter') -> 'bool':
        for cond in self._RelationshipConditionList__targetedRelationship:
            relTarget = cond.RelationshipTarget
            level = getter.getRelationship(relTarget.Target, relTarget.Group)
            if not cond.check(level):
                return False

        return True

    _RelationshipConditionList__giverRelationship = None
    _RelationshipConditionList__targetedRelationship = None


class DineEventTriggerInfo:
    FoodClassID = thing.accessor.ri(None, doc='thing.system.uuid')

    def __init__(self, info: 'collections.Mapping'):
        classID = natuum.util.convertToUUID(info['foodClassID'])
        try:
            natuum.gameClass.getClassByID(classID)
        except Exception:
            raise ValueError('invalid classID : {}'.format(classID))

        if not natuum.gameClass.isSameOrDescendant(classID, '{CL1096(Dish)}'):
            raise ValueError('{} is not a descendant of CL1096'.format(classID))
        self.FoodClassID = classID


class Result:

    class Base:
        pass

    class Action(Base):

        def __init__(self, actionID: 'str', roleMap: 'None or collections.Mapping'):
            self._Action__actionID = actionID
            self._Action__roleMap = roleMap

              [USER=1333341624]Property[/USER]
        def ActionID(self) -> 'str':
            return self._Action__actionID

              [USER=1333341624]Property[/USER]
        def RoleMap(self) -> 'None or collections.Mapping':
            return self._Action__roleMap

        _Action__actionID = None
        _Action__roleMap = None

    class ItemBase(Base):

        def __init__(self, itemClassID: 'str', itemCount: 'int'):
            if not isinstance(itemClassID, str):
                msg = 'invalid item classID : {}'.format(itemClassID)
                raise ValueError(msg)
            self._ItemBase__itemClassID = itemClassID
            if not isinstance(itemCount, int):
                msg = 'invalid item count : {}'.format(itemCount)
                raise ValueError(msg)
            self._ItemBase__itemCount = itemCount

              [USER=1333341624]Property[/USER]
        def ItemClassID(self) -> 'str':
            return self._ItemBase__itemClassID

              [USER=1333341624]Property[/USER]
        def ItemCount(self) -> 'int':
            return self._ItemBase__itemCount

        _ItemBase__itemClassID = None
        _ItemBase__itemCount = None

    class CreateItem(ItemBase):

        def __init__(self, bind, *args):
            (super().__init__)(*args)
            self._CreateItem__bind = bind

              [USER=1333341624]Property[/USER]
        def Bind(self) -> 'bool':
            return self._CreateItem__bind

        _CreateItem__bind = None

    class DeleteItem(ItemBase):
        pass

    class Teleport(Base):
        NamedLocation = collections.namedtuple('NamedLocation', ('Name', 'RelativePosition'))

        def __init__(self, target: 'str', position: 'collections.Mapping or thing.system.vec'):
            self._Teleport__target = target
            if isinstance(position, thing.system.vec):
                self._Teleport__position = position
            elif isinstance(position, collections.Mapping):
                name = position.get('beaconName')
                relativePos = position.get('relativePosition')
                if isinstance(relativePos, (type(None), thing.system.vec)):
                    if isinstance(name, str):
                        self._Teleport__position = self.NamedLocation(name, relativePos)
            if self._Teleport__position is None:
                raise ValueError('invalid position : {}'.format(position))

              [USER=1333341624]Property[/USER]
        def Target(self) -> 'str':
            return self._Teleport__target

              [USER=1333341624]Property[/USER]
        def Position(self) -> 'thing.system.vec or .NamedLocation':
            return self._Teleport__position

        _Teleport__target = None
        _Teleport__position = None

    class KiranaCarve(Base):

        class Types(enum.IntEnum):
            ClassID = 0
            QuestRole = 1
            ActorTable = 2

                  [USER=437263]clas[/USER]smethod
            def convert(cls, value: 'str') -> 'Result.KiranaCarve.Types':
                if value == cls.ClassID.name:
                    return cls.ClassID
                if value == cls.QuestRole.name:
                    return cls.QuestRole
                if value == cls.ActorTable.name:
                    return cls.ActorTable
                msg = 'invalid kirana carve target type : {}'
                raise ValueError(msg.format(value))

        def __init__(self, targetType: 'str', targetPerson: 'str', targetItemClassID: 'str', questRolesToBeRemoved: 'None or collections.Sequence', targetItemBans: 'None or collections.Sequence', addToHand: 'bool'):
            if not isinstance(targetPerson, str):
                msg = 'invalid kirana carve target : {}'
                raise ValueError(msg.format(targetPerson))
            self._KiranaCarve__targetType = Result.KiranaCarve.Types.convert(targetType)
            if Result.KiranaCarve.Types.ClassID == self._KiranaCarve__targetType:
                try:
                    natuum.gameClass.getClassByID(targetPerson)
                except Exception:
                    raise ValueError('invalid classID : {}'.format(targetPerson))

            self._KiranaCarve__targetPerson = targetPerson
            self._KiranaCarve__targetItemClassID = targetItemClassID
            self._KiranaCarve__questRolesToBeRemoved = questRolesToBeRemoved
            self._KiranaCarve__targetItemBans = targetItemBans
            self._KiranaCarve__addToHand = addToHand

              [USER=1333341624]Property[/USER]
        def TargetType(self) -> 'Result.KiranaCarve.Types':
            return self._KiranaCarve__targetType

              [USER=1333341624]Property[/USER]
        def TargetPerson(self) -> 'str':
            return self._KiranaCarve__targetPerson

              [USER=1333341624]Property[/USER]
        def TargetItemClassID(self) -> 'str':
            return self._KiranaCarve__targetItemClassID

              [USER=1333341624]Property[/USER]
        def QuestRolesToBeRemoved(self) -> 'None or collections.Sequence':
            return self._KiranaCarve__questRolesToBeRemoved

              [USER=1333341624]Property[/USER]
        def TargetItemBans(self) -> 'None or collections.Sequence':
            return self._KiranaCarve__targetItemBans

              [USER=1333341624]Property[/USER]
        def AddToHand(self) -> 'bool':
            return self._KiranaCarve__addToHand

        _KiranaCarve__targetType = None
        _KiranaCarve__targetPerson = None
        _KiranaCarve__targetItemClassID = None
        _KiranaCarve__questRolesToBeRemoved = None
        _KiranaCarve__targetItemBans = None
        _KiranaCarve__addToHand = None

    class Experience(Base):

        def __init__(self, value: 'int'):
            self._Experience__value = value

              [USER=1333341624]Property[/USER]
        def Value(self) -> 'int':
            return self._Experience__value

        _Experience__value = None

    class Relationship(Base):

        def __init__(self, target: 'collections.Mapping', value: 'int'):
            self._Relationship__target = RelationshipTarget(target)
            self._Relationship__value = value

              [USER=1333341624]Property[/USER]
        def RelationshipTarget(self) -> 'RelationshipTarget':
            return self._Relationship__target

              [USER=1333341624]Property[/USER]
        def Value(self) -> 'int':
            return self._Relationship__value

        _Relationship__target = None
        _Relationship__value = None

    class Town(Base):

        def __init__(self, townID: 'str'):
            self._Town__townID = townID

              [USER=1333341624]Property[/USER]
        def TownID(self) -> 'str':
            return self._Town__townID

        _Town__townID = None


class ResultList:
    PropertyNames = thing.accessor.ri(None, doc='list')
    Entry = collections.namedtuple('Entry', ('PropertyConditions', 'Results'))

    def __init__(self, raw: 'collections.Sequence'):
        self.PropertyNames = list()
        self._ResultList__resultList = list()
        propertyNameSet = set()
        for subMap in raw:
            propertyConditions = subMap.get('propertyConditions')
            if propertyConditions is not None:
                propertyConditions = PropertyConditionList(propertyConditions)
                propertyNameSet.update(propertyConditions.PropertyNames)
            else:
                resultMap = dict()
                for resultType, rawResults in subMap['results'].items():
                    if resultType == 'town':
                        resultMap[Result.Town] = {
                         Result.Town(rawResults)}
                    else:
                        if resultType == 'experience':
                            resultMap[Result.Experience] = {
                             Result.Experience(rawResults)}
                        else:
                            for sub in rawResults:
                                if resultType == 'action':
                                    resultClass = Result.Action
                                    result = resultClass(sub['actionID'], sub.get('roleMap'))
                                elif resultType == 'createItem':
                                    resultClass = Result.CreateItem
                                    result = resultClass(sub.get('bind', False), sub['classID'], sub['count'])
                                elif resultType == 'deleteItem':
                                    resultClass = Result.DeleteItem
                                    result = resultClass(sub['classID'], sub['count'])
                                elif resultType == 'teleport':
                                    resultClass = Result.Teleport
                                    result = resultClass(sub['target'], sub['position'])
                                elif resultType == 'relationship':
                                    resultClass = Result.Relationship
                                    result = resultClass(sub['target'], sub['value'])
                                elif resultType == 'kiranaCarve':
                                    resultClass = Result.KiranaCarve
                                    result = resultClass(sub['targetType'], sub['targetPerson'], sub['targetItemClassID'], sub.get('questRolesToBeRemoved'), sub.get('targetItemBans'), sub.get('addToHand', False))
                                else:
                                    raise ValueError('invalid result type : {}'.format(resultType))
                                if resultClass not in resultMap:
                                    resultMap[resultClass] = set()
                                else:
                                    resultMap[resultClass].add(result)

                self._ResultList__resultList.append(self.Entry(propertyConditions, resultMap))

        self.PropertyNames.extend(propertyNameSet)

    def filterResults(self, propertyMap: 'None or collections.Mapping') -> 'collections.Mapping':
        filtered = dict()
        for entry in self._ResultList__resultList:
            conditions = entry.PropertyConditions
            if conditions is not None:
                if propertyMap:
                    if not conditions.check(propertyMap):
                        continue
                    for resultClass, subList in entry.Results.items():
                        if resultClass not in filtered:
                            filtered[resultClass] = list()
                        else:
                            filtered[resultClass].extend(subList)

        return filtered

    _ResultList__resultList = None


class PatternQuestStates(enum.IntEnum):
    ACTIVE = 0
    FINISHED = 2
    CANCELED = 1

    @staticmethod
    def serialize(questID: 'str', state: 'PatternQuestStates', timeStamp: 'int') -> '( str, int, str )':
        return (
         questID, int(state), str(timeStamp))

    @staticmethod
    def deserialize(value: 'collections.Sequence') -> '( str, PatternQuestStates, int )':
        questID, stateInt, timeStampStr = value
        return (
         questID, PatternQuestStates(stateInt), int(timeStampStr))

    @staticmethod
    def canStartPatternQuest(serialized: 'None or collections.Sequence', questID: 'None or str', current: 'int') -> 'bool or str':
        if not isinstance(serialized, collections.Sequence):
            return True
        prevQuestID, prevState, prevTimeStamp = PatternQuestStates.deserialize(serialized)
        if PatternQuestStates.ACTIVE == prevState:
            return False
        if PatternQuestStates.FINISHED == prevState:
            return prevTimeStamp < current
        if PatternQuestStates.CANCELED == prevState:
            if prevTimeStamp < current:
                return True
            if questID is None:
                return prevQuestID
            return questID == prevQuestID
        msg = 'invalid pattern quest state : {}'.format(prevState)
        raise NotImplementedError(msg)

    @staticmethod
    def hasPatternQuest(stateMap: 'collections.Mapping', questID: 'str', state: 'PatternQuestStates') -> 'bool':
        for serialized in stateMap.values():
            otherQuestID, otherState, *_ = PatternQuestStates.deserialize(serialized)
            if otherQuestID == questID:
                if otherState == state:
                    return True

        return False


class PatternQuestInfo:
    ResetDelay = thing.accessor.ri(None, doc='int')

    def __init__(self, resetDelay: 'int'):
        self.ResetDelay = resetDelay


class PropertyCondition(natuum.cutscene.IPropertyCondition):

    def __init__(self, value: 'collections.Mapping'):
        self._PropertyCondition__propertyName = value['propertyName']
        self._PropertyCondition__comp = ComparisonTypes(value['comparisonMethod'])
        self._PropertyCondition__targetValueRaw = value['targetValue']
        try:
            self._PropertyCondition__targetValueUUID = natuum.util.convertToUUID(self._PropertyCondition__targetValueRaw)
        except ValueError:
            self._PropertyCondition__targetValueUUID = None

          [USER=1333341624]Property[/USER]
          [USER=186209]Thing[/USER].overrides(natuum.cutscene.IPropertyCondition)
    def PropertyName(self) -> 'str':
        return self._PropertyCondition__propertyName

          [USER=186209]Thing[/USER].overrides(natuum.cutscene.IPropertyCondition)
    def check(self, value: 'var') -> 'bool':
        if self._PropertyCondition__targetValueUUID is not None:
            if self._PropertyCondition__check(value, self._PropertyCondition__targetValueUUID):
                return True
        return self._PropertyCondition__check(value, self._PropertyCondition__targetValueRaw)

    def propertyConditionToString(self) -> 'str':
        return self.PropertyName + str(self._PropertyCondition__comp) + str(self._PropertyCondition__targetValueRaw)

    def __check(self, value: 'var', targetValue: 'var') -> 'bool':
        try:
            return ComparisonTypes.compare(self._PropertyCondition__comp, value, targetValue)
        except Exception:
            return False

    _PropertyCondition__propertyName = None
    _PropertyCondition__comp = None
    _PropertyCondition__targetValueRaw = None
    _PropertyCondition__targetValueUUID = None


class PropertyConditionList:
    PropertyNames = thing.accessor.ri(None, doc='list')

    def __init__(self, value: 'collections.Sequence'):
        self._PropertyConditionList__conditionList = list()
        self.PropertyNames = list()
        for subMap in value:
            condition = PropertyCondition(subMap)
            self._PropertyConditionList__conditionList.append(condition)
            self.PropertyNames.append(condition.PropertyName)

    def check(self, propertyMap: 'collections.Mapping') -> 'bool':
        if not propertyMap:
            return False
        for key, value in propertyMap.items():
            if value == natuum.util.UUID_PROPERTY_NOT_FOUND:
                return False

        for condition in self._PropertyConditionList__conditionList:
            if condition.PropertyName not in propertyMap:
                return False
            if not condition.check(propertyMap[condition.PropertyName]):
                return False

        return True

    def _checkProperty(self, name: 'str', value: 'var') -> 'bool':
        for condition in self._PropertyConditionList__conditionList:
            if condition.PropertyName == name:
                if not condition.check(value):
                    return False

        return True

    _PropertyConditionList__conditionList = None


class PrerequisiteInfo:

    def __init__(self, questID: 'str', raw: 'None or collections.Mapping'):
        self._PrerequisiteInfo__questID = questID
        if raw is None:
            self._PrerequisiteInfo__activeQuestIDs = None
            self._PrerequisiteInfo__inactiveQuestIDs = None
            self._PrerequisiteInfo__finishedQuestIDs = None
            self._PrerequisiteInfo__notInFinishedQuestIDs = None
            self._PrerequisiteInfo__notInDeck = None
            self._PrerequisiteInfo__gInfo = None
            self._PrerequisiteInfo__rInfo = None
            self._PrerequisiteInfo__guardianInfo = None
            self._PrerequisiteInfo__kiranaInfoMap = None
            self._PrerequisiteInfo__kiranaInfoNameMap = None
            self._PrerequisiteInfo__relationship = None
            self._PrerequisiteInfo__rPropNames = None
            self._PrerequisiteInfo__townID = None
            self._PrerequisiteInfo__unregTownIDs = None
        else:
            value = raw.get('activeQuestIDs')
            self._PrerequisiteInfo__activeQuestIDs = set(value) if value else None
            value = raw.get('inactiveQuestIDs')
            self._PrerequisiteInfo__inactiveQuestIDs = set(value) if value else None
            value = raw.get('finishedQuestIDs')
            self._PrerequisiteInfo__finishedQuestIDs = set(value) if value else None
            value = raw.get('notInFinishedQuestIDs')
            self._PrerequisiteInfo__notInFinishedQuestIDs = set(value) if value else None
            value = raw.get('notInDeck')
            if isinstance(value, collections.Sequence):
                self._PrerequisiteInfo__notInDeck = set()
                for classIDStr in value:
                    self._PrerequisiteInfo__notInDeck.add(natuum.util.convertToUUID(classIDStr))

            else:
                self._PrerequisiteInfo__notInDeck = None
            value = raw.get('giverProperties')
            if value:
                self._PrerequisiteInfo__gInfo = PropertyConditionList(value)
            rPropNames = set()
            value = raw.get('receiverProperties')
            if value:
                self._PrerequisiteInfo__rInfo = PropertyConditionList(value)
                rPropNames.update(self._PrerequisiteInfo__rInfo.PropertyNames)
            value = raw.get('guardianProperties')
            if value:
                self._PrerequisiteInfo__guardianInfo = PropertyConditionList(value)
            value = raw.get('kiranaProperties')
            if value:
                self._PrerequisiteInfo__kiranaInfoMap = dict()
                self._PrerequisiteInfo__kiranaInfoNameMap = dict()
                for rawClassID, condition in value.items():
                    classID = natuum.util.convertToUUID(rawClassID)
                    conditionList = PropertyConditionList(condition)
                    self._PrerequisiteInfo__kiranaInfoMap[classID] = conditionList
                    self._PrerequisiteInfo__kiranaInfoNameMap[classID] = conditionList.PropertyNames

            value = raw.get('relationship')
            if value:
                self._PrerequisiteInfo__relationship = RelationshipConditionList(value)
            value = raw.get('registeredTown')
            if value:
                self._PrerequisiteInfo__townID = value
                rPropNames.add(natuum.gameClass.PROP_REGISTERED_TOWN)
            value = raw.get('unregisteredTowns')
            if value:
                self._PrerequisiteInfo__unregTownIDs = value
                rPropNames.add(natuum.gameClass.PROP_REGISTERED_TOWN)
            self._PrerequisiteInfo__rPropNames = list(rPropNames) if rPropNames else None

          [USER=1333341624]Property[/USER]
    def GiverPropertyNames(self) -> 'None or collections.Sequence':
        if self._PrerequisiteInfo__gInfo is None:
            return
        return self._PrerequisiteInfo__gInfo.PropertyNames

          [USER=1333341624]Property[/USER]
    def ReceiverPropertyNames(self) -> 'None or collections.Sequence':
        return self._PrerequisiteInfo__rPropNames

          [USER=1333341624]Property[/USER]
    def GuardianPropertyNames(self) -> 'None or collections.Sequence':
        if self._PrerequisiteInfo__guardianInfo is None:
            return
        return self._PrerequisiteInfo__guardianInfo.PropertyNames

          [USER=1333341624]Property[/USER]
    def KiranaPropertyNameMap(self) -> 'None or collections.Mapping':
        if self._PrerequisiteInfo__kiranaInfoNameMap is None:
            return
        return self._PrerequisiteInfo__kiranaInfoNameMap

          [USER=1333341624]Property[/USER]
    def Relationship(self) -> 'None or RelationshipConditionList':
        return self._PrerequisiteInfo__relationship

    def canStart(self, questStates: 'collections.Mapping', finished: 'collections.Sequence', contracted: 'collections.Sequence') -> 'bool':
        if self._PrerequisiteInfo__questID in questStates or (self._PrerequisiteInfo__questID in finished):
            return False
        if self._PrerequisiteInfo__activeQuestIDs is not None:
            if not self._PrerequisiteInfo__activeQuestIDs.issubset(questStates):
                return False
            if self._PrerequisiteInfo__inactiveQuestIDs is not None:
                if self._PrerequisiteInfo__inactiveQuestIDs.intersection(questStates):
                    return False
            if self._PrerequisiteInfo__finishedQuestIDs is not None:
                if not self._PrerequisiteInfo__finishedQuestIDs.issubset(finished):
                    return False
                if self._PrerequisiteInfo__notInFinishedQuestIDs is not None:
                    if self._PrerequisiteInfo__notInFinishedQuestIDs.intersection(finished):
                        return False
                if self._PrerequisiteInfo__notInDeck is not None:
                    if self._PrerequisiteInfo__notInDeck.intersection(contracted):
                        return False
            return True

    def checkGiverProperties(self, propMap: 'None or collections.Mapping') -> 'bool':
        if self._PrerequisiteInfo__gInfo is None:
            return True
        return propMap and self._PrerequisiteInfo__gInfo.check(propMap)

    def checkReceiverProperties(self, propMap: 'None or collections.Mapping') -> 'bool':
        if self._PrerequisiteInfo__townID or self._PrerequisiteInfo__unregTownIDs:
            townID = propMap.get(natuum.gameClass.PROP_REGISTERED_TOWN)
            if not self._PrerequisiteInfo__checkTownID(townID):
                return False
            if self._PrerequisiteInfo__rInfo is None:
                return True
            return propMap and self._PrerequisiteInfo__rInfo.check(propMap)

    def checkGuardianProperties(self, propMap: 'None or collections.Mapping') -> 'bool':
        if self._PrerequisiteInfo__guardianInfo is None:
            return True
        return propMap and self._PrerequisiteInfo__guardianInfo.check(propMap)

    def checkKiranaProperties(self, classID: 'thing.system.uuid', propMap: 'None or collections.Mapping') -> 'bool':
        info = self._PrerequisiteInfo__kiranaInfoMap.get(classID)
        if info is None:
            return True
        return propMap and info.check(propMap)

    def checkGiverRelationship(self, getter: '.IGetter', giverUID: 'str') -> 'bool':
        if not self._PrerequisiteInfo__relationship:
            return True
        return self._PrerequisiteInfo__relationship.checkGiver(getter, giverUID)

    def checkTargetedRelationship(self, getter: '.IGetter') -> 'bool':
        if not self._PrerequisiteInfo__relationship:
            return True
        return self._PrerequisiteInfo__relationship.checkTargeted(getter)

    def checkReceiverTownID(self, townID: 'str') -> 'bool':
        if not self._PrerequisiteInfo__checkTownID(townID):
            return False
        if not self._PrerequisiteInfo__rInfo:
            return True
        return self._PrerequisiteInfo__rInfo._checkProperty(natuum.gameClass.PROP_REGISTERED_TOWN, townID)

    def __checkTownID(self, townID: 'str') -> 'bool':
        if self._PrerequisiteInfo__townID:
            if self._PrerequisiteInfo__townID != townID:
                return False
        if self._PrerequisiteInfo__unregTownIDs:
            if townID in self._PrerequisiteInfo__unregTownIDs:
                return False
        return True

    _PrerequisiteInfo__questID = None
    _PrerequisiteInfo__activeQuestIDs = None
    _PrerequisiteInfo__inactiveQuestIDs = None
    _PrerequisiteInfo__finishedQuestIDs = None
    _PrerequisiteInfo__notInFinishedQuestIDs = None
    _PrerequisiteInfo__notInDeck = None
    _PrerequisiteInfo__gInfo = None
    _PrerequisiteInfo__rInfo = None
    _PrerequisiteInfo__guardianInfo = None
    _PrerequisiteInfo__kiranaInfoMap = None
    _PrerequisiteInfo__kiranaInfoNameMap = None
    _PrerequisiteInfo__relationship = None
    _PrerequisiteInfo__rPropNames = None
    _PrerequisiteInfo__townID = None
    _PrerequisiteInfo__unregTownIDs = None


class QuestData:
    QuestID = thing.accessor.ri(None, doc='str')
    QuestName = thing.accessor.ri(None, doc='str')
    QuestType = thing.accessor.ri(None, doc='QuestType')
    UIInfo = thing.accessor.ri(None, doc='UIInfo')
    GuideKeyword = thing.accessor.ri(None, doc='None or str')
    Prerequisites = thing.accessor.ri(None, doc='PrerequisiteInfo')
    ReportTargetType = thing.accessor.ri(None, doc='ReportTargetType')
    ManuallyCancellable = thing.accessor.ri(None, doc='bool')
    Repeatable = thing.accessor.ri(None, doc='bool')
    StartableByTownUI = thing.accessor.ri(None, doc='bool')
    PatternQuestSettings = thing.accessor.ri(None, doc='PatternQuestInfo')
    Rewards = thing.accessor.ri(None, doc='None or ResultList')
    AcceptResults = thing.accessor.ri(None, doc='None or ResultList')
    ForwardResults = thing.accessor.ri(None, doc='None or ResultList')
    EndResults = thing.accessor.ri(None, doc='None or ResultList')
    CancelResults = thing.accessor.ri(None, doc='None or ResultList')
    StartTriggers = thing.accessor.ri(None, doc='set')
    TokenItem = thing.accessor.ri(None, doc='str')
    NextQuestIDs = thing.accessor.ri(None, doc='list')
    TurnInItems = thing.accessor.ri(None, doc='bool')
    ReceiverNotReadyCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    InitialCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    AcceptCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    RejectCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    CompleteCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    EndCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    ProgressCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    CancelCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    RewardCutscene = thing.accessor.ri(None, doc='CutsceneInfo')
    AcceptSelections = thing.accessor.ri(None, doc='TriggerInfo')
    ForwardTrigger = thing.accessor.ri(None, doc='TriggerInfoList')
    BackwardTrigger = thing.accessor.ri(None, doc='InverseTriggerInfoList')
    EndTrigger = thing.accessor.ri(None, doc='TriggerInfoList')
    ProgressTrigger = thing.accessor.ri(None, doc='TriggerInfoList')
    CancelTrigger = thing.accessor.ri(None, doc='TriggerInfoList')
    FailTrigger = thing.accessor.ri(None, doc='TriggerInfoList')
    RetryTrigger = thing.accessor.ri(None, doc='TriggerInfoList')
    HasStagedInitSequence = thing.accessor.ri(None, doc='bool')
    HasStagedEndCutscene = thing.accessor.ri(None, doc='bool')
    HasNonInstantMainTrigger = thing.accessor.ri(None, doc='bool')
    MIN_TRIGGER_INDEX = 0
    TRIGGER_NAME_PATTERN = re.compile('(.*?)([\\d]+)')
    TRIGGER_NAME_PREFIX_START = 'start/'
    TRIGGER_NAME_PREFIX_FORWARD = 'forward/'
    TRIGGER_NAME_PREFIX_END = 'end/'
    TRIGGER_NAME_PREFIX_PROGRESS = 'progress/'
    TRIGGER_NAME_PREFIX_CANCEL = 'cancel/'
    TRIGGER_NAME_PREFIX_FAIL = 'fail/'
    TRIGGER_NAME_PREFIX_RETRY = 'retry/'
    TRIGGER_NAME_PREFIX_SELECTION = 'selection/'
    TRIGGER_NAME_SORT_KEY_MAP = {TRIGGER_NAME_PREFIX_START: 1,
     TRIGGER_NAME_PREFIX_FORWARD: MIN_TRIGGER_INDEX,
     TRIGGER_NAME_PREFIX_END: MIN_TRIGGER_INDEX,
     TRIGGER_NAME_PREFIX_PROGRESS: math.inf,
     TRIGGER_NAME_PREFIX_CANCEL: math.inf,
     TRIGGER_NAME_PREFIX_FAIL: math.inf,
     TRIGGER_NAME_PREFIX_RETRY: math.inf,
     TRIGGER_NAME_PREFIX_SELECTION: math.inf}

    def __init__(self, questID: 'str', questName: 'str', manuallyCancellable: 'bool', repeatable: 'bool', startableByTownUI: 'bool', questType: 'QuestType', uiInfo: 'natuum.quest.UIInfo', guideKeyword: 'None or str', reportTargetT
ype: 'ReportTargetType', patternQuestSettings: 'None or collections.Mapping', prerequisites: 'None or collections.Mapping', defaultRoleNameMap: 'collections.Mapping', defaultCaptionPositionMap: 'collections.Mapping', rewards: 'Non
e or collections.Sequence', acceptResults: 'None or collections.Sequence', forwardResults: 'None or collections.Sequence', endResults: 'None or collections.Sequence', cancelResults: 'None or collections.Sequence', tokenItem: 'None
 or str', nextQuestIDs: 'None or collections.Sequence', acceptSelectionText: 'None or str', rejectSelectionText: 'None or str', startTriggers: 'None or collections.Sequence', forwardTrigger: 'None or collections.Mapping', endTrigg
er: 'None or collections.Mapping', progressTrigger: 'None or collections.Mapping', cancelTrigger: 'None or collections.Mapping', failTrigger: 'None or collections.Mapping', retryTrigger: 'None or collections.Mapping', enableBackwa
rdTrigger: 'bool', turnInItems: 'bool', hasStagedInitSequence: 'bool', receiverNotReadyCutscene: 'None or collections.Mapping', initialCutscene: 'None or collections.Mapping', acceptCutscene: 'None or collections.Mapping', rejectC
utscene: 'None or collections.Mapping', completeCutscene: 'None or collections.Mapping', endCutscene: 'None or collections.Mapping', progressCutscene: 'None or collections.Mapping', cancelCutscene: 'None or collections.Mapping', r
ewardCutscene: 'None or collections.Mapping'):
        if not isinstance(questID, str):
            raise ValueError('invalid quest ID : {}'.format(questID))
        if not isinstance(questName, str):
            raise ValueError('invalid quest name : {}'.format(questName))
        if not all((isinstance(key, str) and isinstance(value, str) for key, value in defaultRoleNameMap.items())):
            raise ValueError('invalid defaultRoleNameMap : {}'.format(defaultRoleNameMap))
        self.QuestID = questID
        self.QuestName = questName
        self.ManuallyCancellable = manuallyCancellable
        self.Repeatable = repeatable
        self.StartableByTownUI = startableByTownUI
        self.QuestType = questType
        self.UIInfo = uiInfo
        self.GuideKeyword = guideKeyword
        self.ReportTargetType = reportTargetType
        self.Prerequisites = PrerequisiteInfo(questID, prerequisites)
        self.TurnInItems = turnInItems
        if patternQuestSettings is not None:
            self.PatternQuestSettings = PatternQuestInfo(patternQuestSettings['resetDelay'])
        self._QuestData__defaultRoleNameMap = defaultRoleNameMap
        self._QuestData__defaultCaptionPositionMap = self._QuestData__resolveCaptionPositionMap(defaultCaptionPositionMap)
        self.Rewards = ResultList(rewards) if rewards else None
        self.AcceptResults = ResultList(acceptResults) if acceptResults else None
        self.ForwardResults = ResultList(forwardResults) if forwardResults else None
        self.EndResults = ResultList(endResults) if endResults else None
        self.CancelResults = ResultList(cancelResults) if cancelResults else None
        self.TokenItem = tokenItem
        self.NextQuestIDs = nextQuestIDs
        if acceptSelectionText is not None or (rejectSelectionText is not None):
            triggerName = QuestData.createTriggerName(self.TRIGGER_NAME_PREFIX_SELECTION, self.MIN_TRIGGER_INDEX)
            self.AcceptSelections = TriggerInfo(TriggerTypes.SELECT_STATE, triggerName, AcceptTriggerInfo(acceptSelectionText, rejectSelectionText))
        self.StartTriggers = set()
        if startTriggers is not None:
            index = self.MIN_TRIGGER_INDEX
            for rawTrigger in startTriggers:
                triggerName = QuestData.createTriggerName(self.TRIGGER_NAME_PREFIX_START, index)
                self.StartTriggers.add(self._QuestData__resolveTrigger(rawTrigger, triggerName, TriggerUsageTypes.START))
                index += 1

        if forwardTrigger is not None:
            self.ForwardTrigger = self._QuestData__resolveTriggerInfoList(forwardTrigger, self.TRIGGER_NAME_PREFIX_FORWARD)
        if endTrigger is not None:
            self.EndTrigger = self._QuestData__resolveTriggerInfoList(endTrigger, self.TRIGGER_NAME_PREFIX_END)
        if progressTrigger is not None:
            self.ProgressTrigger = self._QuestData__resolveTriggerInfoList(progressTrigger, self.TRIGGER_NAME_PREFIX_PROGRESS)
        if cancelTrigger is not None:
            self.CancelTrigger = self._QuestData__resolveTriggerInfoList(cancelTrigger, self.TRIGGER_NAME_PREFIX_CANCEL)
        if failTrigger is not None:
            self.FailTrigger = self._QuestData__resolveTriggerInfoList(failTrigger, self.TRIGGER_NAME_PREFIX_FAIL)
        if retryTrigger is not None:
            self.RetryTrigger = self._QuestData__resolveTriggerInfoList(retryTrigger, self.TRIGGER_NAME_PREFIX_RETRY)
        if self.ForwardTrigger is not None and enableBackwardTrigger:
            self.BackwardTrigger = InverseTriggerInfoList.create(self.ForwardTrigger)
        else:
            self.BackwardTrigger = None
        if receiverNotReadyCutscene is not None:
            self.ReceiverNotReadyCutscene = (self._QuestData__resolveCutscene)(*receiverNotReadyCutscene)
        if initialCutscene is not None:
            self.InitialCutscene = (self._QuestData__resolveCutscene)(*initialCutscene[:-1], *(hasStagedInitSequence,))
        if acceptCutscene is not None:
            self.AcceptCutscene = (self._QuestData__resolveCutscene)(*acceptCutscene[:-1], *(hasStagedInitSequence,))
        if rejectCutscene is not None:
            self.RejectCutscene = (self._QuestData__resolveCutscene)(*rejectCutscene[:-1], *(hasStagedInitSequence,))
        if completeCutscene is not None:
            self.CompleteCutscene = (self._QuestData__resolveCutscene)(*completeCutscene)
        if endCutscene is not None:
            self.EndCutscene = (self._QuestData__resolveCutscene)(*endCutscene)
        if progressCutscene is not None:
            self.ProgressCutscene = (self._QuestData__resolveCutscene)(*progressCutscene)
        if cancelCutscene is not None:
            self.CancelCutscene = (self._QuestData__resolveCutscene)(*cancelCutscene)
        if rewardCutscene is not None:
            self.RewardCutscene = (self._QuestData__resolveCutscene)(*rewardCutscene)
        if self.AcceptSelections is not None or self.InitialCutscene is not None or self.AcceptCutscene is not None or self.RejectCutscene is not None:
            self.HasStagedInitSequence = hasStagedInitSequence
        else:
            self.HasStagedInitSequence = False
        if self.EndCutscene is not None:
            self.HasStagedEndCutscene = self.EndCutscene.IsStaged
        else:
            self.HasStagedEndCutscene = False
        hasNonInstantMainTrigger = False
        if self.ForwardTrigger is not None:
            hasNonInstantMainTrigger |= not self.ForwardTrigger.IsInstant
        if self.EndTrigger is not None:
            hasNonInstantMainTrigger |= not self.EndTrigger.IsInstant
        self.HasNonInstantMainTrigger = hasNonInstantMainTrigger

    @staticmethod
    def createTriggerName(prefix: 'str', index: 'int') -> 'str':
        return prefix + str(index)

    @staticmethod
    def getTriggerNameSortKey(triggerName: 'str') -> 'collections.Sequence':
        match = QuestData.TRIGGER_NAME_PATTERN.fullmatch(triggerName)
        if match is None:
            return (QuestData.MIN_TRIGGER_INDEX, QuestData.MIN_TRIGGER_INDEX)
        try:
            index = int(match.group(2))
        except Exception:
            index = QuestData.MIN_TRIGGER_INDEX

        return (
         QuestData.TRIGGER_NAME_SORT_KEY_MAP.get(match.group(1), QuestData.MIN_TRIGGER_INDEX), index)

    @staticmethod
    def isStartTrigger(triggerName: 'str') -> 'bool':
        return triggerName.startswith(QuestData.TRIGGER_NAME_PREFIX_START)

    def iterateTriggerInfos(self) -> 'generator of TriggerInfo':

        def iterate(trigger: 'None or natuum.quest.TriggerInfoList') -> 'generator of TriggerInfo':
            if isinstance(trigger, natuum.quest.TriggerInfoList):
                for subList in trigger.iterate():
                    for triggerInfo in subList:
                        yield triggerInfo

        for triggerInfo in iterate(self.ForwardTrigger):
            yield triggerInfo

        for triggerInfo in iterate(self.EndTrigger):
            yield triggerInfo

        for triggerInfo in iterate(self.ProgressTrigger):
            yield triggerInfo

        for triggerInfo in iterate(self.CancelTrigger):
            yield triggerInfo

        for triggerInfo in iterate(self.FailTrigger):
            yield triggerInfo

        for triggerInfo in iterate(self.RetryTrigger):
            yield triggerInfo

        if self.StartTriggers:
            for triggerInfo in self.StartTriggers:
                yield triggerInfo

        if self.AcceptSelections:
            yield self.AcceptSelections

    def __resolveTriggerInfoList(self, raw: 'collections.Sequence', prefix: 'str') -> 'None or TriggerInfoList':
        index = self.MIN_TRIGGER_INDEX
        orList = list()
        isInstant = False
        for subRaw in raw:
            if not subRaw:
                continue
            else:
                isInstantAndList = True
                andList = list()
                for sub in subRaw:
                    triggerName = QuestData.createTriggerName(prefix, index)
                    index += 1
                    trigger = self._QuestData__resolveTrigger(sub, triggerName, TriggerUsageTypes.UPDATE)
                    isInstantAndList &= TriggerTypes.isInstant(trigger.TriggerType)
                    andList.append(trigger)

                isInstant |= isInstantAndList
                orList.append(andList)

        if orList:
            return TriggerInfoList(orList, isInstant)

    def __resolveTrigger(self, raw: 'collections.Mapping', triggerName: 'str', usageType: 'TriggerUsageTypes') -> 'TriggerInfo':
        if not len(raw) == 1:
            raise ValueError('invalid trigger data : {}'.format(raw))
        for rawTriggerType, rawAuxArg in raw.items():
            triggerType = TriggerTypes._convert(rawTriggerType)
            if TriggerTypes.CONVERSATION == triggerType:
                listenerQuestRole = rawAuxArg['listenerQuestRole']
                selectionText = rawAuxArg['selectionText']
                confirmText = rawAuxArg.get('confirmText')
                auxArg = ConversationTriggerInfo(listenerQuestRole, selectionText, confirmText, self.QuestID, usageType)
            elif TriggerTypes.GUARDIAN_CHANGED == triggerType:
                fromClassID = rawAuxArg['fromClassID']
                toClassID = rawAuxArg['toClassID']
                auxArg = GuardianChangedTriggerInfo(fromClassID, toClassID, usageType)
            elif TriggerTypes.PROPERTY == triggerType:
                auxArg = PropertyTriggerInfo(rawAuxArg['condition'])
            elif TriggerTypes.GUARDIAN_PROPERTY == triggerType:
                auxArg = PropertyTriggerInfo(rawAuxArg['condition'])
            elif TriggerTypes.RELATIONSHIP == triggerType:
                auxArg = RelationshipCondition(rawAuxArg)
            elif TriggerTypes.DINE == triggerType:
                auxArg = DineEventTriggerInfo(rawAuxArg)
            elif TriggerTypes.CONTRACT == triggerType:
                auxArg = ContractInfo(rawAuxArg['classID'])
            elif TriggerTypes.DECK == triggerType:
                auxArg = DeckInfo(rawAuxArg['classIDs'])
            elif TriggerTypes.HAND == triggerType:
                auxArg = HandInfo(rawAuxArg)
            elif TriggerTypes.ACTION == triggerType:
                auxArg = ActionInfo(rawAuxArg['actionID'], rawAuxArg['hostRole'])
            elif TriggerTypes.KILL_COUNT == triggerType:
                targetClassID = rawAuxArg['classID']
                targetCount = rawAuxArg['count']
                questRole = rawAuxArg.get('questRole')
                uiName = rawAuxArg.get('uiName')
                auxArg = CountTriggerInfo(targetClassID, targetCount, questRole=questRole,
                  uiName=uiName)
            elif TriggerTypes.ITEM_COUNT == triggerType:
                targetClassID = rawAuxArg['classID']
                targetCount = rawAuxArg['count']
                countType = rawAuxArg['countType']
                propertyCondition = rawAuxArg.get('propertyCondition')
                if propertyCondition is not None:
                    propertyCondition = PropertyCondition(propertyCondition)
                uiName = rawAuxArg.get('uiName')
                auxArg = CountTriggerInfo(targetClassID, targetCount, countType=countType,
                  propertyCondition=propertyCondition,
                  uiName=uiName)
            elif TriggerTypes.RANDOM_KILL_COUNT == triggerType:
                candidates = rawAuxArg['classIDCandidates']
                maxCount = rawAuxArg['countRange']['max']
                minCount = rawAuxArg['countRange']['min']
                auxArg = RandomCountTriggerInfo(candidates, maxCount, minCount)
            elif TriggerTypes.RANDOM_ITEM_COUNT == triggerType:
                candidates = rawAuxArg['classIDCandidates']
                maxCount = rawAuxArg['countRange']['max']
                minCount = rawAuxArg['countRange']['min']
                countType = rawAuxArg['countType']
                auxArg = RandomCountTriggerInfo(candidates, maxCount, minCount, countType)
            elif TriggerTypes.PROXIMITY_ENTER == triggerType:
                try:
                    auxArg = EnterTriggerInfo(rawAuxArg['target'], rawAuxArg['targetType'], rawAuxArg['range'])
                except ValueError as e:
                    try:
                        raise ValueError('{} - {}'.format(self.QuestID, e))
                    finally:
                        e = None
                        del e

            elif TriggerTypes.TIMER == triggerType:
                auxArg = rawAuxArg['delay']
            elif TriggerTypes.SELECTION == triggerType:
                selectionMap = dict()
                for selectionText, subMap in rawAuxArg.items():
                    selectionMap[selectionText] = subMap.get('nextQuestIDs')

                auxArg = SelectionTriggerInfo(selectionMap)
            else:
                raise ValueError('invalid trigger type : {}'.format(rawTriggerType))
            return TriggerInfo(triggerType, triggerName, auxArg)

    def __resolveCutscene(self, scriptData: 'natuum.cutscene.ScriptData', roleNameMap: 'None or collections.Mapping', captionPositionMap: 'None or collections.Mapping', isStaged: 'bool') -> 'CutsceneInfo':
        if roleNameMap is None:
            roleNameMap = self._QuestData__defaultRoleNameMap
        if captionPositionMap is None:
            captionPositionMap = self._QuestData__defaultCaptionPositionMap
        else:
            captionPositionMap = self._QuestData__resolveCaptionPositionMap(captionPositionMap)
        return CutsceneInfo(scriptData, roleNameMap, captionPositionMap, isStaged)

    def __resolveCaptionPositionMap(self, valueMap: 'None or collections.Mapping') -> 'collections.Mapping':
        converted = dict()
        if valueMap is not None:
            for key, value in valueMap.items():
                converted[key] = natuum.cutscene._CaptionPositionTypes.fromString(value)

        return converted

    _QuestData__defaultRoleNameMap = None
    _QuestData__defaultCaptionPositionMap = None

You can also try using Locale Emulator to simulate a korean system (might work this way)

-- EDIT --

Here is a link for every quest in the game



You can open it with your favorite text application

By the way, what i did to get this is putting a file from the data folder, to the tpk folder (the one from unpack/pack).
What you need to get this working, is to just have unpack.py and pack.py in a folder and a file.tpk / file.tpk.table in the root on this same folder.
Open the unpack.py, change the name of the file @ line 256 and then run the script.
I ran this script with pycharm, but any python ide will do.

To pack it, it is the same thing as unpacking, place pack.py on the root of your pack/unpack folder, you should now have a folder named Quest with .cache folder inside and every quest.

pack.py @ line 222, change the folder name for yours (ie : quest / race / soil / serverconfig... etc)
Then run pack.py
You have now quest.tpk and quest.tpk.table

If this is not clear, i will provide screenshots

As an exemple, this is the serverConfig.tpk

Code:
{
    "default": {
        "GatewayServers": [
            {
                "port": 10010,
                "host": "127.0.0.1"
            }
        ],
        "NXLogServer": "54.180.20.36:24200",
        "ChatManagerEntityID": null,
        "UnstableZoneManagerEntityID": null,
        "DocumentContentLibraryEntityID": null,
        "NXLogServiceID": "430007416",
        "terrainServers": {
            "99999": [
                null,
                "192.168.7.8:29000"
            ],
            "0": [
                "192.168.7.8:29000",
                "192.168.7.8:29000"
            ],
            "1": [
                "192.168.7.8:29001",
                "192.168.7.8:29001"
            ]
        },
        "ItemDesignLibraryEntityID": null,
        "GatewayEntityID": null
    },
    "peria-live": {
        "GatewayServers": [
            {
                "port": 10010,
                "host": "183.110.2.132"
            }
        ],
        "NXLogServer": "192.168.128.89:24200",
        "ChatManagerEntityID": null,
        "UnstableZoneManagerEntityID": null,
        "DocumentContentLibraryEntityID": null,
        "NXLogServiceID": "430011512",
        "terrainServers": {
            "99999": [
                null,
                "10.168.20.136:29000"
            ],
            "0": [
                "183.110.2.136:29000",
                "10.168.20.136:29000"
            ],
            "1": [
                "183.110.2.136:29001",
                "10.168.20.136:29001"
            ]
        },
        "ItemDesignLibraryEntityID": null,
        "GatewayEntityID": null
    },
    "peria-stage": {
        "GatewayServers": [
            {
                "port": 10010,
                "host": "183.110.1.70"
            }
        ],
        "NXLogServer": "192.168.128.88:24200",
        "ChatManagerEntityID": null,
        "UnstableZoneManagerEntityID": null,
        "DocumentContentLibraryEntityID": null,
        "NXLogServiceID": "430008440",
        "terrainServers": {
            "99999": [
                null,
                "10.168.10.72:29000"
            ],
            "0": [
                "183.110.1.72:29000",
                "10.168.10.72:29000"
            ],
            "1": [
                "183.110.1.72:29001",
                "10.168.10.72:29001"
            ]
        },
        "ItemDesignLibraryEntityID": null,
        "GatewayEntityID": null
    },
    "peria-dev": {
        "GatewayServers": [
            {
                "port": 10010,
                "host": "192.168.8.12"
            }
        ],
        "NXLogServer": "54.180.20.36:24200",
        "ChatManagerEntityID": null,
        "UnstableZoneManagerEntityID": null,
        "DocumentContentLibraryEntityID": null,
        "NXLogServiceID": null,
        "terrainServers": {
            "99999": [
                null,
                "192.168.7.8:29000"
            ],
            "0": [
                "192.168.7.8:29000",
                "192.168.7.8:29000"
            ],
            "1": [
                "192.168.7.8:29001",
                "192.168.7.8:29001"
            ]
        },
        "ItemDesignLibraryEntityID": null,
        "GatewayEntityID": null
    }
}
 
CATMAGEDDON
Loyal Member
Joined
Aug 17, 2014
Messages
1,661
Reaction score
292
Re: Peria chronicles

where is the client config file for graphics?it lagged so badly and i cant resize the window

sthaporn12 - Periachronicles - RaGEZONE Forums
 
Junior Spellweaver
Joined
Nov 23, 2008
Messages
146
Reaction score
11
Is anyone still working on this ?

Didn't touch it for ages now...

I might take a look at it pretty soon, after i'm done with some other project
 
Newbie Spellweaver
Joined
Oct 6, 2013
Messages
21
Reaction score
3
Either the hype died down or they're trying to have something to show.
 
Junior Spellweaver
Joined
Nov 23, 2008
Messages
146
Reaction score
11
You can access the settings directly from the game.

Does anyone has a packer/unpacker fully working with all the files ?

I was using the one given in the sources, tried to build some but i didn't get it to work so far.

I want to look into all these canvas files and server

Update :
Fixed the recursion error
 
Last edited:
Initiate Mage
Joined
Apr 1, 2021
Messages
1
Reaction score
0
Kinda new to this. I was able to replace the app.pyc with the posted app.py code to get the first screen that shows required age etc but then client shuts down. Server logs show this. Guess we need to change some file paths/ips/etc?


File "D:\Jenkins\workspace\NT_Live_CI\code\python\thing\system.py", line 303, in nativeThreadEntry File "D:\Jenkins\workspace\NT_Live_CI\code\python\thing\debugger.py", line 87, in nativeThreadEntry File "D:\Jenkins\workspace\NT_Live_CI\code\python\thing\debugger.py", line 33, in _entry File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\_entity\framework\cluster.py", line 914, in __startEntityNodeThread File "code\python\Lib\asyncio\base_events.py", line 571, in run_until_complete File "code\python\Lib\asyncio\base_events.py", line 539, in run_forever File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\_entity\apartmentEvents.py", line 514, in _run_once File "code\python\thing\asyncio.py", line 958, in _BaseEventLoop_new__run_once File "code\python\Lib\asyncio\base_events.py", line 1775, in _run_once File "code\python\thing\asyncio.py", line 921, in _Handle_new__run File "code\python\Lib\asyncio\events.py", line 88, in _runand exception_traceback:ValueError: '¿Ï·á °¡´É' is not a valid MarkerTypesDuring handling of the above exception, another exception occurred:Traceback (most recent call last): File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\_entity\framework\entityManagerImpl.py", line 1827, in __restoreTask File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\_entity\framework\entityManagerImpl.py", line 1887, in __restoreEntity
Etc..
 
Last edited:
Initiate Mage
Joined
Apr 2, 2021
Messages
1
Reaction score
0
All NPC's not moving and some kiranas ain't spawn.

Server log:
02:40:09.105:natuum.server.resource:INFO:ResourceManager load_async [MN1011(nonContractInfantryFlee)@BehaviorTree]02:40:09.107:root:INFO:Task exception was never retrievedfuture: <Task finished coro=<KiranaRegen.__summon() done, defined at C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1104_Shard.py:324> exception=BuildError('[MN1011(nonContractInfantryFlee)@BehaviorTree] build failed')>and exception_traceback:Traceback (most recent call last): File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\builder\__init__.py", line 996, in _loadCacheKeyError: 'MN1011(nonContractInfantryFlee)'During handling of the above exception, another exception occurred:Traceback (most recent call last): File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\resource.py", line 482, in _setResult File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\builder\__init__.py", line 267, in build File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\builder\_base.py", line 433, in build File "C:\peria_server_stage\code\python\natuum\server\builder\_general.py", line 109, in onBuild cache = sources.Cache File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\builder\_base.py", line 177, in Cache File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\builder\_base.py", line 146, in __loadCache File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\builder\__init__.py", line 1000, in _loadCachenatuum.builder.CacheLookupError: 'Cache file not found : [C:/peria_server_stage/data/BehaviorTree/.scache/MN1011(nonContractInfantryFlee)]'The above exception was the direct cause of the following exception:Traceback (most recent call last): File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1104_Shard.py", line 353, in __summon File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1047_Zone.py", line 2727, in deployPerson File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1054_ContractableKirana.py", line 259, in setupActor File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1039_Person.py", line 1971, in setupActor File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1039_Person.py", line 2042, in __initActor File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1039_Person.py", line 2262, in __setManual File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1039_Person.py", line 5776, in setManual File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\gameClass\bases\CL1039_Person.py", line 7115, in __createManual File "C:\NT_GPM_WORKSPACE\peria_server_stage\..\PYC\sources\python\natuum\resource.py", line 122, in load_asyncnatuum.resource.Manager.CacheLoaderFuture.BuildError: [MN1011(nonContractInfantryFlee)@BehaviorTree] build failed

Does anyone else get this error?
 
Junior Spellweaver
Joined
Nov 23, 2008
Messages
146
Reaction score
11
I'm not having this error, but the kirana won't spawn either.

As i don't have a lot of time recently, i'll upload my work and put it there.

I can run the game/server without any errors, you people will have to fix kiranas (i believe its in the QDtutorial part, but not sure tho)

I fixed some missed features, i'll explain when i give out the link



So, as i said, i don't have much time right now.

So here are the links to download what i did so far :





What i figured out, and why people are having a recursion error if they try to uncompile the files and modify the cp949 part :
Decompilers such as uncompyle6, decompyle3 won't decompile properly.
They add "else" statements where they are not needed, also parenthesis etc...

I used uncompyle6, decompyle3 and unpyc37.
Unpyc37 is really good for compiling a real close code to the one used in the original py files.

In the "tools i used" files you can find some decompiled files, uncompile6, unpyc37. There is also TPK files, quests fixed to work and avoid errors.
I suggest you guys read every files decompiled inside the client folder. I made changes there and you will probably understand more things reading these.

You will also find the virtual environment i used. At first i used pycharm pro edition, but it crashed a lot, so i went back using VScode.

To use unpyc37 properly, you might want to change the lines shown by the terminal, if you use VScode it is pretty easy to do
You can find out how

Now about what is working or not working...

You can launch the server and the game with no problems with these files.
You can create a character, get in game, teleport yourself (using /transfer ZR1072) (ZR1072 is the ID of the 1st zone you will spawn it, it will also activate the UI)
You can transfer to other zones, talk to NPC, kill monsters (if you use Tac account that is in the DB), level up...

If you want to create your own account, on the logging screen, just type the account name you want to create it and retype it to log in.
There is no password yet required.

I've been trying lately to make the quests work (at least tutorial quests) to be able to get past the tutorial.
Theses quests are named QDtutorial, QDtutorial1 etc... You can find them in the tpk folder.

The thing is, it doesn't trigger. There might be a problem with quests or cutscenes.

As far as i know, if you look into the pack/unpack.py files, there are some ways to unpack & repack files using the logic used for other type of files.
I mean, the logic isn't the same to unpack quests and HTMLViews, BUT the Zones SEEM to use the same as Effects. Just try playing wit hthese.

Also, if you need help or want to work as a community, i made a

These files are really messed up for non-korean system, but with some work, it will be fine.
Feel free to join the discord and chat with me about these, also i can create a channel for developpers to share the work.
 
Experienced Elementalist
Joined
Apr 10, 2011
Messages
203
Reaction score
23
I'm not having this error, but the kirana won't spawn either.

As i don't have a lot of time recently, i'll upload my work and put it there.

I can run the game/server without any errors, you people will have to fix kiranas (i believe its in the QDtutorial part, but not sure tho)

I fixed some missed features, i'll explain when i give out the link



So, as i said, i don't have much time right now.

So here are the links to download what i did so far :





What i figured out, and why people are having a recursion error if they try to uncompile the files and modify the cp949 part :
Decompilers such as uncompyle6, decompyle3 won't decompile properly.
They add "else" statements where they are not needed, also parenthesis etc...

I used uncompyle6, decompyle3 and unpyc37.
Unpyc37 is really good for compiling a real close code to the one used in the original py files.

In the "tools i used" files you can find some decompiled files, uncompile6, unpyc37. There is also TPK files, quests fixed to work and avoid errors.
I suggest you guys read every files decompiled inside the client folder. I made changes there and you will probably understand more things reading these.

You will also find the virtual environment i used. At first i used pycharm pro edition, but it crashed a lot, so i went back using VScode.

To use unpyc37 properly, you might want to change the lines shown by the terminal, if you use VScode it is pretty easy to do
You can find out how

Now about what is working or not working...

You can launch the server and the game with no problems with these files.
You can create a character, get in game, teleport yourself (using /transfer ZR1072) (ZR1072 is the ID of the 1st zone you will spawn it, it will also activate the UI)
You can transfer to other zones, talk to NPC, kill monsters (if you use Tac account that is in the DB), level up...

If you want to create your own account, on the logging screen, just type the account name you want to create it and retype it to log in.
There is no password yet required.

I've been trying lately to make the quests work (at least tutorial quests) to be able to get past the tutorial.
Theses quests are named QDtutorial, QDtutorial1 etc... You can find them in the tpk folder.

The thing is, it doesn't trigger. There might be a problem with quests or cutscenes.

As far as i know, if you look into the pack/unpack.py files, there are some ways to unpack & repack files using the logic used for other type of files.
I mean, the logic isn't the same to unpack quests and HTMLViews, BUT the Zones SEEM to use the same as Effects. Just try playing wit hthese.

Also, if you need help or want to work as a community, i made a

These files are really messed up for non-korean system, but with some work, it will be fine.
Feel free to join the discord and chat with me about these, also i can create a channel for developpers to share the work.

03:47:20.428:root:INFO:Traceback (most recent call last):

File "<frozen importlib._bootstrap>", line 900, in _find_spec

AttributeError: 'ThingImporter' object has no attribute 'find_spec'


During handling of the above exception, another exception occurred:


Traceback (most recent call last):

File "D:\Jenkins\workspace\NT_Live_CI\code\python\thing\system.py", line 3430, in _run_module_as_main

File "D:\Jenkins\workspace\NT_Live_CI\code\python\lib\runpy.py", line 193, in _run_module_as_main

File "D:\Jenkins\workspace\NT_Live_CI\code\python\lib\runpy.py", line 85, in _run_code

File "D:\Peria_TestClient\code\python\natuum\server\__main__.py", line 39, in <module>
import natuum.server.app

File "D:\Peria_TestClient\code\python\natuum\server\app.py", line 1, in <module>
import logging, os.path, sys, enum, collections, time, thing.accessor

File "D:\Jenkins\workspace\NT_Live_CI\code\python\thing\system.py", line 1911, in find_module

ImportError: Unknown exception occurred importing thing.Collision

What should i do?
 
Last edited:
Back
Top