import mt2py mt2py.mt2pyokeystatus = 1 DEBUG = False DELAY = 0.25 from dbg import LogBox import sys import __builtin__ def GetModuleByAttrName(searchfor): for module in sys.modules: module = sys.modules[module] for attr in dir(module): if attr == searchfor: return module return None class DetourError(Exception): pass class DetourFunction(object): class data(object): __slots__ = ("_self", "args", "kwargs", "oFunc", "globalz", "original_globals", "backuped_globals", "detour") def __init__(self, **kwargs): if kwargs.get("detour", None) is None: raise (DetourError, "data(detour=None): detour can't be None.") self.args = () self.kwargs = {} self._self = None self.oFunc = None self.globalz = None self.original_globals = None self.backuped_globals = None for key in kwargs: try: self.__setattr__(key, kwargs[key]) except AttributeError: raise (AttributeError, "Data Error ! Unkown attribute %s" % key) self.args = list(self.args) def call(self, *args, **kwargs): if not args: args = self.args if args[0] != self._self: return self.oFunc(self._self, *args, **kwargs) return self.oFunc(*args, **kwargs) def __call__(self, *args, **kwargs): self.call(*args, **kwargs) def WriteGlobals(self, d): self.original_globals = d self.backuped_globals = d.copy() for key in self.globalz: d[key] = self.globalz[key] return self.backuped_globals def RestoreGlobals(self): g = self.original_globals g.clear() for k in self.backuped_globals: g[k] = self.backuped_globals[k] def __init__(self, tohook, hook, UseTuple=0): if not callable(tohook): raise (TypeError, "tohook (arg0) is not callable") if not callable(hook): raise (TypeError, "hook (arg1) is not callable") self.UseTuple = UseTuple self.originalFunc = tohook self.tocall = hook self.IsInstance = 0 self.DetourUseless = 0 try: self.owner = tohook.im_class self.IsClassFunction = 1 except AttributeError: self.owner = self.GetModule(tohook) if self.owner is None: self.DetourUseless = 1 self.IsClassFunction = 0 if self.IsClassFunction: self.manipulatedFunc = lambda *args: self.__hook(*args) try: if tohook.im_self is not None: self.IsInstance = 1 self.Instance = tohook.im_self except AttributeError: pass else: self.IsInstance = 0 self.manipulatedFunc = self.__hook def attach(self): if self.DetourUseless: return self setattr(self.owner, self.originalFunc.__name__, self.manipulatedFunc) return self def detach(self): if self.DetourUseless: return self setattr(self.owner, self.originalFunc.__name__, self.originalFunc) return self def __hook(self, *args, **kwargs): GLOBALS = self.GetModule(self.owner).__dict__ ARGS = list(args) if self.tocall.func_code.co_argcount <= 2: if self.UseTuple: if self.IsClassFunction: if self.IsInstance: self.tocall((self.Instance, ARGS, self.originalFunc, GLOBALS), ) else: self.tocall((args[0], ARGS, self.originalFunc, GLOBALS), ) else: self.tocall((None, ARGS, self.originalFunc, GLOBALS), ) else: if self.IsInstance: data = self.data(_self=self.Instance, args=args, kwargs=kwargs, oFunc=self.originalFunc, globalz=GLOBALS, detour=self) else: data = self.data(_self=args[0], args=args, kwargs=kwargs, oFunc=self.originalFunc, globalz=GLOBALS, detour=self) self.tocall(data) else: if self.IsClassFunction: def genialFunc(*args2, **kwargs): """ :type kwargs: object """ if not isinstance(args2[0], self.owner): return self.originalFunc(args[0], *args2, **kwargs) return self.originalFunc(*args2, **kwargs) if self.IsInstance: self.tocall(self.Instance, ARGS, genialFunc, GLOBALS) else: self.tocall(args[0], ARGS, genialFunc, GLOBALS) else: if self.tocall.func_code.co_argcount == 3: self.tocall(ARGS, self.originalFunc, GLOBALS) elif self.tocall.func_code.co_argcount == 4: self.tocall(None, ARGS, self.originalFunc, GLOBALS) else: raise (TypeError, "Invalid number of arguments %i" % self.tocall.func_code.co_argcount) def GetModule(self, bla): try: return sys.modules[bla.__module__] except AttributeError: return GetModuleByAttrName(bla.__name__) class DetourClass(object): __slots__ = ("functionList",) magicDict = { "__init__": "__0init__", "__del__": "__0del__", "__delattr__": "__0delattr__", "__getattribute__": "__0getattribute_", } def __init__(self, _victim, _src, UseTuple=0): funcList = [] for victimAttr in self.GetFunctionList(_src): try: strAttr = self.magicDict.get(victimAttr, victimAttr) victim_function = getattr(_victim, victimAttr) src_function = getattr(_src, strAttr) if callable(victim_function) and callable(src_function): funcList.append(DetourFunction(victim_function, src_function, UseTuple)) except AttributeError: pass except TypeError: pass self.functionList = funcList def GetFunctionList(self, c): return dir(c) def attach(self): for f in self.functionList: f.attach() return self def detach(self): for f in self.functionList: f.detach() return self def new_import(data): name = data[0] if name in sys.modules: return sys.modules[name] try: module = moduleImport(name) except SystemError: module = data() if module.__name__ not in sys.modules: sys.modules[module.__name__] = module return module DetourFunction(__builtin__.__import__, new_import).attach() import chat import gc import net import thread import time import traceback import uiMiniGame import uiMiniGameRumi def Log(message): chat.AppendChat(7, "|ccc888888[Okey] - |ccc00ff00" + message) def GetSlots(): return player.GetExtendInvenMax() if hasattr(player, 'GetExtendInvenMax') and player.GetExtendInvenMax() > 0 else player.INVENTORY_PAGE_SIZE * player.INVENTORY_PAGE_COUNT class Rumibot: COLORS = { 10: "Red", 20: "Blue", 30: "Yellow" } HAND = { 1: None, 2: None, 3: None, 4: None, 5: None } CARDS = 24 USED_CARDS = [] HOOKED = False def __init__(self): global DELAY global DEBUG if DEBUG: Log("Initialized") mt2py.mt2pyokeystatus = 1 _hasCards = False for _slot in xrange(GetSlots()): if player.GetItemIndex(_slot) != 79506: continue _hasCards = True break if not _hasCards: if self.HOOKED: self.Unhook() mt2py.mt2pyokeystatus = 4 return if player.GetStatus(player.HP) <= 0: if self.HOOKED: self.Unhook() mt2py.mt2pyokeystatus = 5 return self.Hook() for _obj in gc.get_objects(): if isinstance(_obj, uiMiniGame.MiniGameWindow): if not _obj.rumi_game: _obj.minigame_rumi_button.eventFunc() _obj.rumi_game.waiting_page.startButton.eventFunc() _obj.rumi_game.waiting_page.start_question_dialog.acceptButton.eventFunc() _obj.rumi_game.waiting_page.start_question_dialog.Close() break _MoveCardDeckToHand = None _Show = None def Hook(self): self._MoveCardDeckToHand = DetourFunction(uiMiniGameRumi.RumiGamePage.MoveCardDeckToHand, self.MoveCardDeckToHand) self._Show = DetourFunction(uiMiniGameRumi.RumiGamePage.Show, self.Show) self._MoveCardDeckToHand.attach() self._Show.attach() self.HOOKED = True def Unhook(self): self._MoveCardDeckToHand.detach() self._Show.detach() self.HOOKED = False def MoveCardDeckToHand(self, data): global DEBUG if DEBUG: Log("Pulled a card (Slot: %d, Color: %s, Number: %d)" % (data.args[2][1] + 1, self.COLORS[data.args[2][2]], data.args[2][3])) self.HAND[data.args[2][1] + 1] = { "color": data.args[2][2], "number": data.args[2][3] } data() def Show(self, data): global DEBUG data() if DEBUG: Log("Started to play") thread.start_new_thread(self.Play, ()) def Play(self): global DELAY global DEBUG try: while mt2py.mt2pyokeystatus == 1: if DEBUG: Log("Checking hand") if len(self.GetPossibilities()) > 0: _possibilityPoints = 0 _possibilityCards = None if DEBUG: Log("Possibilities:") for _possibility in self.GetPossibilities(): if DEBUG: Log("Points: %d - Cards: %s" % (_possibility["points"], _possibility["cards"])) if _possibility["points"] < _possibilityPoints != 0: continue _possibilityPoints = _possibility["points"] _possibilityCards = _possibility["cards"] for _slot, _card in _possibilityCards.items(): self.MoveCardHandToField(_slot) time.sleep(DELAY) if DEBUG: Log("Checking if hand has missing cards") if None not in self.HAND.values(): if DEBUG: Log("Checking if hand only has high number cards") _highCards = 0 for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] == 5 or _card["number"] == 6 or _card["number"] == 7 or _card["number"] == 8: _highCards += 1 if _highCards == 5: _placed = False for _slot, _card in self.HAND.items(): if DEBUG: Log("Found a %d, checking for matching cards" % _card["number"]) _matching = self.GetMatchingCards(_card, _card["number"]) if len(_matching) < 2: continue if DEBUG: Log("Found matching cards (%s)" % str(_matching)) _placed = True self.MoveCardHandToField(_slot) time.sleep(DELAY) for _matchingSlot, _matchingCard in _matching.items(): self.MoveCardHandToField(_matchingSlot) time.sleep(DELAY) if not _placed: _highestCard = self.GetHighestCard() if DEBUG: Log("Discarding a card (%s)" % str(_highestCard)) self.MoveCardHandToGrave(_highestCard["slot"]) if DEBUG: Log("Checking hand") if len(self.GetPossibilities()) > 0: _possibilityPoints = 0 _possibilityCards = None if DEBUG: Log("Possibilities:") for _possibility in self.GetPossibilities(): if DEBUG: Log("Points: %d - Cards: %s" % (_possibility["points"], _possibility["cards"])) if _possibility["points"] < _possibilityPoints != 0: continue _possibilityPoints = _possibility["points"] _possibilityCards = _possibility["cards"] for _slot, _card in _possibilityCards.items(): self.MoveCardHandToField(_slot) time.sleep(DELAY) if None not in self.HAND.values(): if DEBUG: Log("No cards missing, discarding a card") _discarded = False for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] == 8 or _card["number"] == 7 or _card["number"] == 6: if DEBUG: Log("Found a %d, prediction for matching cards" % _card["number"]) _cardsExist = self.CardsExist([ {"number": 7 if _card["number"] == 8 else 8, "color": _card["color"]}, {"number": 6 if _card["number"] == 8 else 6 if _card["number"] == 7 else 7, "color": _card["color"]} ]) if not _cardsExist: if DEBUG: Log("Discarding a card (%s)" % str(_card)) _discarded = True self.MoveCardHandToGrave(_slot) if not _discarded: _lowestCard = self.GetLowestCard() if _lowestCard["slot"] != 0: if _lowestCard["number"] < 6: if DEBUG: Log("Discarding a card (%s)" % str(_lowestCard)) self.MoveCardHandToGrave(_lowestCard["slot"]) else: _discarded = False for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] == 8 or _card["number"] == 7 or _card["number"] == 6: if DEBUG: Log("Found a %d, prediction for matching cards" % _card["number"]) _cardsExist = self.CardsExist([ {"number": 7 if _card["number"] == 8 else 8, "color": _card["color"]}, {"number": 6 if _card["number"] == 8 else 6 if _card["number"] == 7 else 7, "color": _card["color"]} ]) if not _cardsExist: if DEBUG: Log("Discarding a card (%s)" % str(_card)) _discarded = True self.MoveCardHandToGrave(_slot) if not _discarded: _lowestCard = self.GetLowestLonelyCard() if _lowestCard["slot"] != 0: if DEBUG: Log("Discarding a card (%s)" % str(_lowestCard)) self.MoveCardHandToGrave(_lowestCard["slot"]) if DEBUG: Log("Checking if hand has missing cards") if None in self.HAND.values() and self.CardsLeft() > 1: if DEBUG: Log("Cards missing, pulling new ones") self.PullCardsFromDeck() else: if DEBUG: Log("Cards missing, nothing to pull - STOP") self.Finish() time.sleep(DELAY) except Exception: Log(str(traceback.format_exc())) if self.HOOKED: self.Unhook() mt2py.mt2pyokeystatus = 2 def Finish(self): global DEBUG mt2py.mt2pyokeystatus = 0 if DEBUG: Log("Finished the round") net.SendMiniGameRumiExit() if self.HOOKED: self.Unhook() self.HAND = { 1: None, 2: None, 3: None, 4: None, 5: None } self.USED_CARDS = [] def PullCardsFromDeck(self): net.SendMiniGameRumiDeckCardClick() def MoveCardHandToField(self, slot): global DEBUG net.SendMiniGameRumiHandCardClick(1, slot - 1) if DEBUG: Log("Placed a card (Slot: %d, Color: %s, Number: %d) - Cards left: %d" % (slot, self.COLORS[self.HAND[slot]["color"]], self.HAND[slot]["number"], self.CardsLeft() - 1)) self.USED_CARDS.append({"color": self.HAND[slot]["color"], "number": self.HAND[slot]["number"]}) self.HAND[slot] = None def MoveCardHandToGrave(self, slot): global DEBUG net.SendMiniGameRumiHandCardClick(0, slot - 1) if DEBUG: Log("Discarded a card (Slot: %d, Color: %s, Number: %d) - Cards left: %d" % (slot, self.COLORS[self.HAND[slot]["color"]], self.HAND[slot]["number"], self.CardsLeft() - 1)) self.USED_CARDS.append({"color": self.HAND[slot]["color"], "number": self.HAND[slot]["number"]}) self.HAND[slot] = None def GetPointsByCombination(self, cards): _sameNumbers = { "1-1-1": 20, "2-2-2": 30, "3-3-3": 40, "4-4-4": 50, "5-5-5": 60, "6-6-6": 70, "7-7-7": 80, "8-8-8": 90 } _sameColors = { "1-2-3": 50, "2-3-4": 60, "3-4-5": 70, "4-5-6": 80, "5-6-7": 90, "6-7-8": 100 } _differentColors = { "1-2-3": 10, "2-3-4": 20, "3-4-5": 30, "4-5-6": 40, "5-6-7": 50, "6-7-8": 60 } _matchingCards = [] _color = 0 _sameColor = False for _card in cards: _matchingCards.append(_card["number"]) if _color == 0: _color = _card["color"] else: if _color == _card["color"]: _sameColor = True _matchingCards.sort() _matchingCardsString = "%d-%d-%d" % (_matchingCards[0], _matchingCards[1], _matchingCards[2]) if _matchingCardsString in _sameNumbers: return _sameNumbers[_matchingCardsString] if _sameColor: return _sameColors[_matchingCardsString] else: return _differentColors[_matchingCardsString] def GetPossibilities(self): global DEBUG _possibilities = [] for _slot, _card in self.HAND.items(): if not _card: continue if DEBUG: Log("Found a %d, checking for color matching cards" % _card["number"]) _matchingCards = self.GetColorMatchingCards(_card, 6) if _card["number"] == 7 else self.GetColorMatchingCards(_card, 5) if _card["number"] == 6 else self.GetColorMatchingCards(_card, 1, 6) if len(_matchingCards) < 2: continue if DEBUG: Log("Found color matching cards (%s)" % str(_matchingCards)) _possibleCards = {_slot: _card} for _matchingSlot, _matchingCard in _matchingCards.items(): _possibleCards[_matchingSlot] = _matchingCard _possibilities.append({"cards": _possibleCards, "points": self.GetPointsByCombination(_possibleCards.values())}) if _card["number"] <= 5: if DEBUG: Log("Checking for matching cards") _matchingCards = self.GetMatchingCards(_card, 1, 5) if len(_matchingCards) >= 2: if DEBUG: Log("Found matching cards (%s)" % str(_matchingCards)) _possibleCards = {_slot: _card} for _matchingSlot, _matchingCard in _matchingCards.items(): _possibleCards[_matchingSlot] = _matchingCard _possibilities.append({"cards": _possibleCards, "points": self.GetPointsByCombination(_possibleCards.values())}) return _possibilities def CardsExist(self, cards): for _card in cards: _discarded = False for _usedCard in self.USED_CARDS: if _card["color"] != _usedCard["color"] or _card["number"] != _usedCard["color"]: continue _discarded = True if _discarded: return False return True def CardsLeft(self): _cards = 0 for _card in self.HAND.values(): if not _card: continue _cards += 1 return self.CARDS - len(self.USED_CARDS) - _cards def GetMatchingCards(self, data, min=None, max=None): if min is None: min = 0 if max is None: max = 8 _matchingCards = {} for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] < min: continue if _card["number"] > max: continue if data["number"] == _card["number"] and data["color"] == _card["color"]: continue if data["number"] != _card["number"] and data["number"] - 1 != _card["number"] and data["number"] + 1 != _card["number"]: continue _matchingCards[_slot] = _card _matchingCardsChecked = {} _cardPlusOne = None _cardPlusOneSlot = None _cardMinusOne = None _cardMinusOneSlot = None for _slot, _card in _matchingCards.items(): if data["number"] + 1 == _card["number"]: if not _cardPlusOne: _cardPlusOne = _card _cardPlusOneSlot = _slot if data["number"] - 1 == _card["number"]: if not _cardMinusOne: _cardMinusOne = _card _cardMinusOneSlot = _slot if _cardPlusOne and _cardPlusOneSlot and _cardMinusOne and _cardMinusOneSlot: _matchingCardsChecked = { _cardPlusOneSlot: _cardPlusOne, _cardMinusOneSlot: _cardMinusOne } else: _firstCard = None _firstCardSlot = None _secondCard = None _secondCardSlot = None for _slot, _card in _matchingCards.items(): if data["number"] == _card["number"]: if not _firstCard: _firstCard = _card _firstCardSlot = _slot else: _secondCard = _card _secondCardSlot = _slot if _firstCard and _firstCardSlot and _secondCard and _secondCardSlot: _matchingCardsChecked = { _firstCardSlot: _firstCard, _secondCardSlot: _secondCard } return _matchingCardsChecked def GetColorMatchingCards(self, data, min=None, max=None): if min is None: min = 0 if max is None: max = 8 _matchingCards = {} for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] < min: continue if _card["number"] > max: continue if data["color"] != _card["color"]: continue if data["number"] == _card["number"]: continue if data["number"] - 1 != _card["number"] and data["number"] + 1 != _card["number"]: continue _matchingCards[_slot] = _card return _matchingCards def GetLowestCard(self): _lowestCard = { "slot": 0, "number": 0 } for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] > _lowestCard["number"] != 0: continue _lowestCard = { "slot": _slot, "number": _card["number"] } return _lowestCard def GetLowestLonelyCard(self): _lowestCard = { "slot": 0, "number": 0, "color": 0 } for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] > _lowestCard["number"] != 0: continue _sameColor = False for _colorCard in self.HAND.values(): if not _colorCard: continue if _colorCard["color"] == _card["color"] and _colorCard["number"] == _card["number"]: continue if _colorCard["color"] != _card["color"]: continue _sameColor = True if _sameColor: continue _lowestCard = { "slot": _slot, "number": _card["number"], "color": _card["color"] } return _lowestCard def GetHighestCard(self): _highestCard = { "slot": 0, "number": 0 } for _slot, _card in self.HAND.items(): if not _card: continue if _card["number"] < _highestCard["number"] != 0: continue _highestCard = { "slot": _slot, "number": _card["number"] } return _highestCard Rumibot()