Пример #1
0
    def login(self, username, password, serverNumber=0):
        """
        Perform a KoL login given a username and password. A server number may also be specified
        to ensure that the user logs in using that particular server. This can be helpful
        if the user continues to be redirected to a server that is down.
        """

        self.userName = username
        self.userPasswordHash = hashlib.md5(password).hexdigest()

        # Grab the KoL homepage.
        homepageRequest = HomepageRequest(self, serverNumber=serverNumber)
        homepageResponse = homepageRequest.doRequest()
        self.serverURL = homepageResponse["serverURL"]

        # Perform the login.
        loginRequest = LoginRequest(self, homepageResponse["loginChallenge"])
        loginRequest.doRequest()

        # Load the charpane once to make StatusRequest report the rollover time
        charpaneRequest = CharpaneRequest(self)
        charpaneRequest.doRequest()

        # Get pwd, user ID, and the user's name.
        request = StatusRequest(self)
        response = request.doRequest()
        self.pwd = response["pwd"]
        self.userName = response["name"]
        self.userId = int(response["playerid"])
        self.rollover = int(response["rollover"])
Пример #2
0
    def login(self, username, password, serverNumber=0):
        """
        Perform a KoL login given a username and password. A server number may also be specified
        to ensure that the user logs in using that particular server. This can be helpful
        if the user continues to be redirected to a server that is down.
        """

        self.userName = username
        self.userPasswordHash = hashlib.md5(password).hexdigest()

        # Grab the KoL homepage.
        homepageRequest = HomepageRequest(self, serverNumber=serverNumber)
        homepageResponse = homepageRequest.doRequest()
        self.serverURL = homepageResponse["serverURL"]

        # Perform the login.
        loginRequest = LoginRequest(self, homepageResponse["loginChallenge"])
        loginRequest.doRequest()

        # Load the charpane once to make StatusRequest report the rollover time
        charpaneRequest = CharpaneRequest(self)
        charpaneRequest.doRequest()

        # Get pwd, user ID, and the user's name.
        request = StatusRequest(self)
        response = request.doRequest()
        self.pwd = response["pwd"]
        self.userName = response["name"]
        self.userId = int(response["playerid"])
        self.rollover = int(response["rollover"])
Пример #3
0
    def _buff(self, uid, buff):
        n = buff['casts']
        cost = buff['mp_cost']
        mpRequired = n * cost
        r2 = StatusRequest(self.session)
        d2 = self.tryRequest(r2)
        mpBefore = int(d2['mp'])
        self.log("Preparing to cast buff {} (requires {} mp)"
                 .format(buff['description'], mpRequired))
        if mpBefore < mpRequired:
            try:
                self.debugLog("Requesting healing from module {}"
                              .format(self._healer))
                replies = self._raiseEvent("heal", self._healer, 
                                           {'type': 'mp', 
                                            'points': mpRequired,
                                            'percent': self._mpMax})
                healResult = replies[-1].data
                mpBefore = healResult['mp']
            except IndexError:
                raise FatalError("Invalid healer {}".format(self._healer))

        self.log("Casting skill {} x{}".format(buff['id'], n))
        r1 = UseSkillRequest(self.session, str(buff['id']), n, uid)
        _d1 = self.tryRequest(r1, numTries=1)
        r2 = StatusRequest(self.session)
        d2 = self.tryRequest(r2)
        mpAfter = int(d2['mp'])
        self.log("Used {} mp. (Now at {}/{})"
                 .format(mpBefore - mpAfter, mpAfter, d2['maxmp']))
        return mpBefore - mpAfter 
Пример #4
0
 def initialize(self, lastKnownState, initData): 
     super(PeriodicAnnouncementModule, self).initialize(lastKnownState, 
                                                        initData) 
     for k,v in lastKnownState['messages'].items(): 
         if v['order'] is None:
             v['order'] = []
         if k in self._messages and v['hard']: 
             messageEntry = self._messages[k]
             messageEntry['last'] = int(v['last'])
             if v['mode'] != messageEntry['mode']: 
                 messageEntry.update({'order': [], 'index': 0}) 
             else: 
                 order = v['order']
                 if order:
                     for k2 in messageEntry['messages'].keys(): 
                         if k2 not in order: 
                             order.append(k2) 
                 messageEntry.update(
                     {'order': order, 
                      'index': min(v['index'], len(order))}) 
         elif not v['hard']:
             self._messages[k] = v
     self._initializationValid = True
     r2 = StatusRequest(self.session) 
     d2 = self.tryRequest(r2) 
     self._rolloverTime = int(d2['rollover'])
     self._run.set() 
Пример #5
0
 def hpMpStatus(self):
     rStat = StatusRequest(self.session)
     dStat = (self.tryRequest(rStat))
     return {
         'hp': int(dStat['hp']),
         'mp': int(dStat['mp']),
         'maxhp': int(dStat['maxhp']),
         'maxmp': int(dStat['maxmp'])
     }
Пример #6
0
 def _checkStock(self):
     with InventoryLock.lock:
         self._invMan.refreshInventory()
         inv = self._invMan.completeInventory()
         r = StatusRequest(self._s)
         d = tryRequest(r, numTries=6, initialDelay=3, scaleFactor=1.25)
         meat = int(d['meat'])
         itemsOwed = {}
         meatOwed = 0
         
         con = self._db.getDbConnection()
         c = con.cursor()
         c.execute("SELECT * FROM {}".format(self._name))
         msg = c.fetchone()
         while msg is not None:
             if msg['state'] in [self.OUTBOX_SENDING,
                                 self.OUTBOX_DEFERRED]:
                 message = decode(msg['data'])
                 itemsOwed = _itemsToDict(message.get('items', []), 
                                          itemsOwed)
                 meatOwed += message.get('meat', 0)
             msg = c.fetchone()
         difference = dict((iid, inv.get(iid, 0) - qty)
                           for iid,qty in itemsOwed.items())
         deficit = dict((iid, -diff) for iid,diff in difference.items()
                        if diff < 0)
         if deficit:
             # get items in display case
             r2 = GetDisplayCaseRequest(self._s)
             d2 = tryRequest(r2)
             display = _itemsToDict(d2['items'])
             difference = dict(
                 (iid, inv.get(iid, 0) + display.get(iid, 0) - qty)
                 for iid,qty in itemsOwed.items())
             deficit = dict((iid, -diff) for iid,diff in difference.items()
                            if diff < 0)
         if deficit or meatOwed > meat:
             # notify admins of item deficit!
             warningText = ("Warning: {} has an item deficit of: \n"
                            .format(self._props.userName))
             for iid, d in deficit.items():
                 warningText += ("\n{}: {}"
                                 .format(
                                     d, getItemFromId(iid).get(
                                         'name', "item ID {}".format(iid))))
             if meatOwed > meat:
                 warningText += "\n{} meat".format(meatOwed-meat)
             with con:
                 c2 = con.cursor()
                 for adminUid in self._props.getAdmins("mail_fail"):
                     # notify admins of deficit
                     
                     newMsg = {'userId': adminUid, 'meat': 0,
                               'text': warningText, 'items': []}
                     self._insertSplitKmail(c2, self.OUTBOX_SENDING, 
                                            newMsg, reserveItems=False)
Пример #7
0
 def heal(self, hint, args, status):
     if args.get('__lucifer__', False):
         self.parent.log("Skipping Lucifer (no recursive Lucifer allowed)")
         return
     with InventoryLock.lock:
         invMan = self.parent.inventoryManager
         invMan.refreshInventory()
         inv = invMan.inventory()
         if inv.get(571, 0) == 0:
             qty = 0
             if self.buyFromMall:
                 try:
                     qty = buyFromMall(self.parent.session,
                                       571,
                                       logFunc=self.parent.log)
                 except kol.Error.Error:
                     pass
             if qty == 0:
                 self.parent.log("Out of Lucifers.")
                 return
         r1 = StatusRequest(self.parent.session)
         d1 = tryRequest(r1)
         if self.maxFull is not None and int(d1['full']) >= self.maxFull:
             self.parent.log("Reached reserve fullness.")
             return
         mpToHeal = status['maxmp'] - status['mp']
         hpNeeded = min(1 + (mpToHeal / 9 + 1), status['maxhp'])
         self.parent.log("Lucifer: requires {} hp, have {} hp.".format(
             hpNeeded, status['hp']))
         if hpNeeded > status['hp']:
             curHp = None
             self.parent.log("Healing for Lucifer...")
             if self.extHealer is None:
                 reply = self.parent._heal({
                     'type': 'hp',
                     'points': hpNeeded,
                     '__lucifer__': True
                 })
                 curHp = reply['hp']
             else:
                 replies = self.parent._raiseEvent(
                     "heal", "__" + self.extHealer + "__", {
                         'type': 'hp',
                         'points': hpNeeded,
                         '__lucifer__': True
                     })
                 curHp = replies[-1]['hp']
             if curHp < hpNeeded:
                 self.parent.log("Failed to heal for Lucifer.")
                 return
             self.parent.log("Healed for Lucifer!")
         r2 = EatFoodRequest(self.parent.session, 571)
         try:
             tryRequest(r2, numTries=1)
         except kol.Error.Error as e:
             self.parent.log("Lucifer error: {}".format(e[0]))
Пример #8
0
 def _online(self):
     now = time.time()
     if now - self._lastOnlineCheck <= 2:
         return True
     try:
         tryRequest(StatusRequest(self._s), nothrow=False, numTries=6,
                    initialDelay=10, scaleFactor=1)
         self._lastOnlineCheck = now
         return True
     except (kol.Error.Error, urllib2.HTTPError):
         pass
     return False
Пример #9
0
 def canReceiveItems(self):
     now = time.time()
     if now - self._lastCanReceiveItemsCheck <= 3600:
         return self._lastCanReceiveItems
     self._lastCanReceiveItemsCheck = now
     r = StatusRequest(self._s)
     d = tryRequest(r, numTries=6, initialDelay=3, scaleFactor=1.25)
     canReceive = ((int(d.get('hardcore',"1")) == 0 and
                   int(d.get('roninleft',"1")) == 0) 
                   or
                   int(d.get('casual',"0")) == 1 
                   or
                   int(d.get('freedralph',"0")) == 1)
     self._lastCanReceiveItems = canReceive
     return canReceive
Пример #10
0
def buyFromMall(session, itemId, quantity=1, maxPrice=0, logFunc=None):
    if logFunc is None:
        logFunc = _empty
    s = tryRequest(StatusRequest(session))
    canBuy = ((int(s.get('hardcore', "1")) == 0
               and int(s.get('roninleft', "1")) == 0)
              or int(s.get('casual', "0")) == 1
              or int(s.get('freedralph', "0")) == 1)
    if not canBuy:
        raise kol.Error.Error("Can't buy from mall in Ronin/Hardcore",
                              kol.Error.USER_IN_HARDCORE_RONIN)

    with InventoryLock.lock:
        item = getItemFromId(itemId)
        itemName = item.get('name', str(itemId))
        numTries = 0
        numBought = 0
        numResults = 10
        logFunc("Trying to buy {}x {} from mall...".format(quantity, itemName))
        while numTries < 10:
            r1 = MallItemSearchRequest(session,
                                       itemName,
                                       maxPrice=maxPrice,
                                       numResults=numResults)
            d1 = tryRequest(r1, numTries=1)
            itemList = [
                item for item in d1['results'] if item.get('id', -1) == itemId
            ]
            listFull = (len(itemList) == numResults)
            availableList = [
                item for item in itemList if not item.get('hitLimit', False)
            ]
            if not itemList:
                return numBought
            if not availableList and listFull:
                numResults *= 2
            while availableList and numBought < quantity:
                item = availableList[0]
                limitedMode = False
                qty = min(quantity, item['quantity'])
                if 'limit' in item:
                    qty = 1
                    limitedMode = True
                price = item['price']
                storeId = item['storeId']

                logFunc("Buying {}x {} @ {} meat from store {}".format(
                    qty, itemName, price, storeId))
                r2 = MallItemPurchaseRequest(session, storeId, itemId, price,
                                             qty)
                try:
                    d2 = tryRequest(r2, numTries=1)
                    numBought += d2['items'][0]['quantity']
                    logFunc("Spent {} meat and got {}x {}.".format(
                        d2['meatSpent'], d2['items'][0]['quantity'], itemName))
                    if not limitedMode:
                        availableList.pop(0)
                except kol.Error.Error as e:
                    if e.code == kol.Error.ITEM_NOT_FOUND:
                        logFunc("Could not buy item. Refreshing...")
                        # refresh search
                        availableList = []
                        continue
                    else:
                        logFunc("Error buying from this store. Moving on...")
                        availableList.pop(0)
                        continue
            numTries += 1
            if numBought >= quantity:
                break
        return numBought
Пример #11
0
    def __init__(self, s, c, props, inv, configFile, db, exitEvent):
        """ Initialize the BotSystem """

        self._exitEvent = exitEvent

        self._initialized = False

        # trigger to stop heartbeat subsystem
        self._hbStop = threading.Event()

        # start subsystems
        try:
            oldTxt = None
            hbSys = HeartbeatSubsystem(numThreads=6,
                                       period=5,
                                       stopEvent=self._hbStop)
            evSys = EventSubsystem()

            # initialize subsystems
            super(BotSystem, self).__init__(name="sys.system",
                                            identity="system",
                                            evSys=evSys,
                                            hbSys=hbSys)

            if exitEvent.is_set():
                sys.exit()

            # copy arguments
            self._s = s
            self._c = c
            self._props = props
            self._inv = inv
            self._db = db
            self._log = logging.getLogger()

            # initialize some RunProperties data now that we are logged on
            self._log.debug("Getting my userId...")
            r1 = StatusRequest(self._s)
            d1 = tryRequest(r1)
            self._props.userId = int(d1['playerid'])
            self._log.info("Getting my clan...")
            r2 = UserProfileRequest(self._s, self._props.userId)
            d2 = tryRequest(r2)
            self._props.clan = d2.get('clanId', -1)
            self._log.info("I am a member of clan #{} [{}]!".format(
                self._props.clan, d2.get('clanName', "Not in any clan")))

            # config file stuff
            self._config = None
            self._overWriteConfig = False
            oldTxt = self._loadConfig(configFile)

            # listen to channels
            self._initializeChatChannels(self._config)
            c.getNewChatMessages()  # discard old PM's and whatnot

            # initialize directors
            self._dir = None
            iData = InitData(s, c, props, inv, db)
            self._log.info("Starting communication system...")
            self._dir = CommunicationDirector(self, iData,
                                              self._config['director'])
            self._lastCheckedChat = 0
            self._initialized = True
        except:
            self._hbStop.set()
            raise
        finally:
            # rewrite config file (values may be modified by modules/managers)
            if oldTxt is not None:
                self._saveConfig(configFile, oldTxt)
Пример #12
0
 def _finishInitialization(self):
     r2 = StatusRequest(self.session)
     d2 = self.tryRequest(r2)
     self._rolloverTime = int(d2['rollover'])
Пример #13
0
def getUniqueDateString(session):
    r = StatusRequest(session)
    d = tryRequest(r)
    s = str(d['rollover'])
    return s
Пример #14
0
    def _finishInitialization(self):
        # get list of clan members (both in whitelist and roster)
        self.log("Initializing ranks...")
        r1 = ClanWhitelistRequest(self.session)
        d1 = self.tryRequest(r1)
        self._ranks = {
            _rankTransform(rank['rankName']): rank
            for rank in d1['ranks']
        }
        r2 = StatusRequest(self.session)
        d2 = self.tryRequest(r2)
        self._rolloverTime = int(d2['rollover'])

        # load promotion rules
        self._promotionRules = {}
        for rankname, rule in self._ruleConfig.items():
            key = _rankTransform(rankname)
            nextRankName = toTypeOrNone(rule['next_rank'])
            nextkey = _rankTransform(nextRankName) if nextRankName else None
            nextRankId = self._ranks.get(nextkey, {}).get('rankId')

            if key not in self._ranks:
                raise FatalError(
                    "Invalid clan rank: {} (available ranks: {})".format(
                        key, ", ".join(self._ranks.keys())))
            if nextkey is not None and nextkey not in self._ranks:
                raise FatalError(
                    "Invalid clan rank: {} (available ranks: {})".format(
                        nextkey, ", ".join(self._ranks.keys())))

            try:
                self._promotionRules[self._ranks[key]['rankId']] = ({
                    'demotionAllowed':
                    stringToBool(rule['demotion_allowed']),
                    'minKarma':
                    int(rule['min_karma']),
                    'minDaysBeforePromotion':
                    int(rule['min_days_until_next_promotion']),
                    'minDaysInClan':
                    int(rule['min_days_in_clan']),
                    'nextRankId':
                    nextRankId,
                    'rankName':
                    rankname
                })
            except ValueError:
                raise "ClanRankModule: error parsing rank {}".format(rankname)

        # pick a random time to run today
        assumedExecTime = 7200
        latestPossibleExecTime = self._rolloverTime - assumedExecTime
        if time.time() < self._lastRun:
            self.log("Already performed ranking today.")
        elif time.time() > latestPossibleExecTime:
            self.log("Too late to run rankings today.")
        else:
            if self._immediate:
                self._execTime = int(time.time()) + 15
            else:
                self._execTime = random.randint(int(time.time()),
                                                latestPossibleExecTime)
            self.log("Running rankings in {} minutes.".format(
                int((self._execTime - time.time()) / 60)))
Пример #15
0
    def _processCommand(self, message, cmd, args):
        if cmd == "die":
            args = args.strip()
            if args == "":
                args = "0"
            try:
                t = int(args)
                e = kol.Error.Error("Manual crash")
                e.timeToWait = t * 60 + 1
                self.chat("Coming online in {} minutes.".format(t))
                raise e
            except kol.Error.Error:
                raise
            except:
                pass
            return "Invalid argument to !die '{}'".format(args)
        elif cmd == "simulate":
            self.parent.director._processChat([{
                'text': args,
                'userName': "******",
                'userId': -2,
                'channel': "hobopolis",
                'type': "normal",
                'simulate': True
            }])
            return "Simulated message: {}".format(args)
        elif cmd == "spam":
            return "\n".join(["SPAM"] * 15)
        elif cmd == "restart":
            self._raiseEvent("RESTART", "__system__")
        elif cmd == "raise_event":
            r = self._raiseEvent(args)
            return "Reply to event '{}': {}".format(args, r)
        elif cmd == "kmail_test":
            n = 1000
            try:
                n = int(args)
            except Exception:
                pass

            text = ""
            count = 0
            startChar = "A"
            while n >= 100:
                count += 100
                n -= 100
                newText = "A" * 100 + "{}".format(count)
                newText = startChar + newText[-99:]
                text += newText
                startChar = " "
            k = Kmail(message['userId'], text)
            self.sendKmail(k)
        elif cmd == "bot_status":
            r = StatusRequest(self.session)
            d = self.tryRequest(r)
            return "\n".join("{}: {}".format(k, v) for k, v in d.items()
                             if k not in ["pwd", "eleronkey"])
        elif cmd == "inclan":
            tf = self.parent.checkClan(int(args))
            return str(tf)
        elif cmd == "plist":
            return str(self.properties.getPermissions(int(args)))
        elif cmd == "say":
            txtMatch = re.search(r"^\s*(?:/(\w+))?\s*(.*)", args)
            if txtMatch:
                self.chat(txtMatch.group(2), channel=txtMatch.group(1))
                return None
            return "Error matching text"
        return None