Esempio n. 1
0
    def turn(self, direction):
        assert direction < 4
        if self.direction == direction:
            return

        if not self.alive:  #or not self.actionLock(self.turn, direction):
            return

        self.direction = direction
        self.lastAction = time.time() + 0.15

        # Make package
        for spectator in getSpectators(self.position):
            stream = spectator.packet(0x6B)
            stream.position(self.position)
            stream.uint8(getTile(self.position).findStackpos(self))
            stream.uint16(0x63)
            stream.uint32(self.clientId())
            stream.uint8(direction)
            if spectator.version >= 953:
                stream.uint8(self.solid)
            stream.send(spectator)
Esempio n. 2
0
    def turn(self, direction):
        assert direction < 4
        if self.direction == direction:
            return

        if not self.alive: #or not self.actionLock(self.turn, direction):
            return

        self.direction = direction
        self.lastAction = time.time() + 0.15

        # Make package
        for spectator in getSpectators(self.position):
            stream = spectator.packet(0x6B)
            stream.position(self.position)
            stream.uint8(getTile(self.position).findStackpos(self))
            stream.uint16(0x63)
            stream.uint32(self.clientId())
            stream.uint8(direction)
            if spectator.version >= 953:
                stream.uint8(self.solid)
            stream.send(spectator)
Esempio n. 3
0
    def move(self,
             direction,
             spectators=None,
             level=0,
             stopIfLock=False,
             failback=None,
             push=True,
             ignorestairhop=False):
        if not self.alive:
            return -1
        elif not self.data["health"] or not self.canMove or not self.speed:
            return False

        _time = time.time()

        # Don't use actionLock (TODO: Kill?) because we might get False, which would prevent us from moving later.
        if self.lastAction > _time:
            if not stopIfLock:
                call_later(self.lastAction - _time, self.move, direction,
                           spectators, level, stopIfLock, failback, push,
                           ignorestairhop)
            return False

        # Stairhop delay.
        isPlayer = self.isPlayer()
        if not ignorestairhop and isPlayer and _time - self.lastStairHop < config.stairHopDelay and level:
            return False

        oldPosition = self.position.copy()

        # Drunk?
        if self.hasCondition(CONDITION_DRUNK):
            directions = [
                0, 1, 2, 3, 4, 5, 6, 7, direction
            ]  # Double the odds of getting the correct direction.
            directions.remove(self.reverseDirection(
            ))  # From a reality perspective, you are rarely that drunk.
            direction = random.choice(directions)

        # Recalculate position
        position = oldPosition.copy()
        if direction == 0:
            position.y -= 1
        elif direction == 1:
            position.x += 1
        elif direction == 2:
            position.y += 1
        elif direction == 3:
            position.x -= 1
        elif direction == 4:
            position.y += 1
            position.x -= 1
        elif direction == 5:
            position.y += 1
            position.x += 1
        elif direction == 6:
            position.y -= 1
            position.x -= 1
        elif direction == 7:
            position.y -= 1
            position.x += 1

        position.z += level

        # We don't walk out of the map!
        if position.x < 1 or position.y < 1 or position.x > game.map.mapInfo.width or position.y > game.map.mapInfo.height:
            return False

        # New Tile
        newTile = getTile(position)

        if not newTile:
            return False
        # oldTile
        oldTile = getTile(oldPosition)

        val = game.scriptsystem.get("move").run(creature=self)
        if val == False:
            return False

        # Deal with walkOff
        walkOffEvent = game.scriptsystem.get('walkOff')
        for item in oldTile:
            if item.isItem():
                val = walkOffEvent.run(thing=item,
                                       creature=self,
                                       position=oldPosition)
                if val == False:
                    return False

        try:
            oldStackpos = oldTile.findStackpos(self)
        except:
            return False  # Not on Tile.

        # PZ blocked?
        if (self.hasCondition(CONDITION_PZBLOCK)
                or self.getSkull() in SKULL_JUSTIFIED
            ) and newTile.getFlags() & TILEFLAGS_PROTECTIONZONE:
            self.lmessage("You are PZ blocked")
            return False

        # Block movement, even if script stop us later.
        self.lastStep = _time
        delay = self.stepDuration(
            newTile[0]) * (config.diagonalWalkCost if direction > 3 else 1)
        self.lastAction = _time + delay

        # Deal with walkOn
        walkOnEvent = game.scriptsystem.get('walkOn')
        for thing in newTile:
            if thing.solid:
                if level and not thing.isCreature():
                    continue

                # Monsters might push. This should probably be a preWalkOn event, but well. Consider this a todo for v1.1 or something.
                if push and self.isMonster() and thing.isMonster(
                ) and self.base._pushCreatures and thing.isPushable(self):
                    # Push stuff here.

                    # Clear up the creatures actions.
                    thing.stopAction()
                    thing.clearMove(direction, failback)

                    if thing.move(thing.reverseDirection(),
                                  stopIfLock=True,
                                  push=False):
                        # We "must" break here. Assume the tile is good since another creature is on it. Iterator might be invalid at this point.
                        break
                    elif self.base._hostile and thing.isAttackable(self):
                        # We can attack the creature.
                        self.target = thing
                        self.targetMode = 1

                        # Deliver final blow.
                        thing.onHit(self, -thing.data['healthmax'], PHYSICAL)
                #self.turn(direction) # Fix me?
                self.notPossible()
                return False

            if thing.isItem():
                # Script.
                r = walkOnEvent.run(thing=thing,
                                    creature=self,
                                    position=position,
                                    fromPosition=oldPosition)
                if r == False:
                    return False

                # Prevent monsters from moving on teleports.
                teledest = thing.teledest
                if teledest:
                    if not isPlayer:
                        return False
                    try:
                        self.teleport(
                            Position(teledest[0], teledest[1], teledest[2]),
                            self.position.instanceId)
                        self.magicEffect(EFFECT_TELEPORT)
                    except:
                        print(
                            "%d (%s) got a invalid teledist (%s), remove it!" %
                            (thing.itemId, thing, teledest))
                        del thing.teledest

        newStackPos = newTile.placeCreature(self)
        oldTile.removeCreature(self)

        # Clear target if we change level
        if level:
            self.cancelTarget()
            self.target = None
            self.targetMode = 0

        # Send to Player
        if isPlayer:
            # Mark for save
            self.saveData = True

            ignore = (self, )
            stream = self.packet()

            if (oldPosition.z != 7 or
                    position.z < 8):  # Only as long as it's not 7->8 or 8->7
                #stream = spectator.packet(0x6D)
                stream.uint8(0x6D)
                stream.position(oldPosition)
                stream.uint8(oldStackpos)
                stream.position(position)
            else:
                stream.removeTileItem(oldPosition, oldStackpos)

            # Levels
            if oldPosition.z > position.z:
                stream.moveUpPlayer(self, oldPosition)

            elif oldPosition.z < position.z:
                stream.moveDownPlayer(self, oldPosition)

            # Y movements
            if oldPosition.y > position.y:
                stream.uint8(0x65)
                stream.mapDescription(
                    Position(oldPosition.x - 8, position.y - 6, position.z),
                    18, 1, self)
            elif oldPosition.y < position.y:
                stream.uint8(0x67)
                stream.mapDescription(
                    Position(oldPosition.x - 8, position.y + 7, position.z),
                    18, 1, self)

            # X movements
            if oldPosition.x < position.x:
                stream.uint8(0x66)
                stream.mapDescription(
                    Position(position.x + 9, position.y - 6, position.z), 1,
                    14, self)
            elif oldPosition.x > position.x:
                stream.uint8(0x68)
                stream.mapDescription(
                    Position(position.x - 8, position.y - 6, position.z), 1,
                    14, self)

            # If we're entering protected zone, fix icons
            pzStatus = newTile.getFlags() & TILEFLAGS_PROTECTIONZONE
            pzIcon = self.extraIcons & CONDITION_PROTECTIONZONE
            if pzStatus and not pzIcon:
                self.setIcon(CONDITION_PROTECTIONZONE)
                self.refreshConditions(stream)
                if not level:
                    self.cancelTarget(stream)
                    self.target = None
                if isPlayer and self.mounted:
                    call_later(
                        0, self.changeMountStatus, False
                    )  # This should be sent after the move is completed, I believe.

            elif not pzStatus and pzIcon:
                self.removeIcon(CONDITION_PROTECTIONZONE)
                self.refreshConditions(stream)

            stream.send(self.client)

        else:
            ignore = ()

        self.position = position
        self.direction = direction % 4

        oldPosCreatures = getPlayers(oldPosition, ignore=ignore)
        newPosCreatures = getPlayers(position, ignore=ignore)
        spectators = oldPosCreatures | newPosCreatures
        invisible = self.isMonster() and self.hasCondition(CONDITION_INVISIBLE)

        if not invisible:
            for spectator in spectators:
                canSeeNew = spectator in newPosCreatures

                canSeeOld = spectator in oldPosCreatures

                stream = spectator.packet()

                if not canSeeOld and canSeeNew:
                    stream.addTileCreature(position,
                                           newStackPos,
                                           self,
                                           spectator,
                                           resend=True)

                elif canSeeOld and not canSeeNew:
                    stream.removeTileItem(oldPosition, oldStackpos)
                    """spectator.knownCreatures.remove(self)
                    self.knownBy.remove(spectator)"""

                elif canSeeOld and canSeeNew:
                    if (
                            oldPosition.z != 7 or position.z < 8
                    ) and oldStackpos < 10:  # Only as long as it's not 7->8 or 8->7

                        stream.uint8(0x6D)
                        stream.position(oldPosition)
                        stream.uint8(oldStackpos)
                        stream.position(position)

                    else:
                        stream.removeTileItem(oldPosition, oldStackpos)
                        spectator.knownCreatures.remove(self)
                        self.knownBy.remove(spectator)
                        stream.addTileCreature(position, newStackPos, self,
                                               spectator)
                stream.send(spectator.client)

        if self.scripts["onNextStep"]:
            scripts = self.scripts["onNextStep"][:]
            self.scripts["onNextStep"] = []
            for script in scripts:
                script(self)

        # Deal with appear and disappear. Ahh the power of sets :)
        disappearFrom = oldPosCreatures - newPosCreatures
        appearTo = newPosCreatures - oldPosCreatures
        disappear_event = game.scriptsystem.get('disappear')
        for creature2 in disappearFrom:
            disappear_event.run(creature=creature2, creature2=self)
            disappear_event.run(creature=self, creature2=creature2)

        appear_event = game.scriptsystem.get('appear')
        for creature2 in appearTo:
            appear_event.run(creature=creature2, creature2=self)
            appear_event.run(creature=self, creature2=creature2)

        # Stairhop delay
        if level and isPlayer:
            self.lastStairHop = _time

        if isPlayer and self.target and not self.canSee(self.target.position):
            self.cancelTarget()

        return True
Esempio n. 4
0
    def teleport(self, position, force=False):
        """if not self.actionLock(self.teleport, position):
            return False"""

        # 4 steps, remove item (creature), send new map and cords, and effects
        oldPosition = self.position.copy()
        target = self.target

        newTile = getTile(position)
        oldPosCreatures = set()
        if not newTile:
            raise game.errors.SolidTile(
                "Tile doesn't exist")  # Yea, it's fatal, even in force mode!

        if not force:
            for i in newTile.getItems():
                if i.solid:
                    raise game.errors.SolidTile()

        invisible = self.isMonster() and self.hasCondition(CONDITION_INVISIBLE)

        oldStackpos = 0
        if not invisible:
            try:
                oldStackpos = getTile(oldPosition).findStackpos(self)
                for spectator in getSpectators(oldPosition, ignore=(self, )):
                    stream = spectator.packet()
                    stream.removeTileItem(oldPosition, oldStackpos)
                    stream.magicEffect(oldPosition, 0x02)
                    stream.send(spectator)
                oldPosCreatures = getCreatures(oldPosition)
            except:
                pass  # Just append creature

        stackpos = placeCreature(self, position)
        if not stackpos:
            raise game.errors.ImpossibleMove()

        removeCreature(self, oldPosition)

        if self.creatureType == 0 and self.client:
            with self.packet() as stream:
                if oldStackpos:
                    stream.removeTileItem(oldPosition, oldStackpos)

                stream.uint8(0x64)
                stream.position(position)
                stream.mapDescription(
                    Position(position.x - 8, position.y - 6, position.z), 18,
                    14, self)

                # If we're entering protected zone, fix icons
                pzStatus = newTile.getFlags() & TILEFLAGS_PROTECTIONZONE
                pzIcon = self.extraIcons & CONDITION_PROTECTIONZONE
                if pzStatus and not pzIcon:
                    self.setIcon(CONDITION_PROTECTIONZONE)
                    self.refreshConditions(stream)
                    self.cancelTarget(stream)
                    self.target = None
                    if self.isPlayer() and self.mounted:
                        call_later(0, self.changeMountStatus, False)

                elif not pzStatus and pzIcon:
                    self.removeIcon(CONDITION_PROTECTIONZONE)
                    self.refreshConditions(stream)

                #stream.magicEffect(position, 0x02)

        self.position = position
        newPosCreatures = getCreatures(position)
        disappearFrom = oldPosCreatures - newPosCreatures
        appearTo = newPosCreatures - oldPosCreatures
        for creature2 in disappearFrom:
            game.scriptsystem.get('disappear').run(creature2=creature2,
                                                   creature=self)

        for creature2 in appearTo:
            game.scriptsystem.get('appear').run(creature2=creature2,
                                                creature=self)

        if not invisible:
            for spectator in getSpectators(position, ignore=(self, )):
                stream = spectator.packet()
                stream.addTileCreature(position, stackpos, self,
                                       spectator.player)
                stream.magicEffect(position, 0x02)
                stream.send(spectator)

        if target and not self.canSee(target.position):
            self.cancelTarget()
            self.target = None
            self.targetMode = 0

        # Stairhop delay
        if self.isPlayer():
            self.lastStairHop = time.time()
            if target and not self.canSee(target.position):
                self.cancelTarget()
Esempio n. 5
0
    def onFirstPacket(self, packet):
        packetType = packet.uint8()
        IN_TEST = False

        if packetType == 0xFF:
            # Special case for tests.
            IN_TEST = True
            
        if packetType == 0x0A and not self.ready:
            packet.pos += 2 # OS 0x00 and 0x01
            #packet.uint16() 
            version = packet.uint16() # Version int
            
            if version >= 972:
                version = packet.uint32()
                packet.uint8() # Client type.

            self.protocol = game.protocol.getProtocol(version)
            self.version = version
            print "Client protocol version %d" % version

            if not self.protocol:
                log.msg("Trying to load a invalid protocol")
                self.transport.loseConnection()
                return

            if not IN_TEST:
                if (len(packet.data) - packet.pos) == 128: # RSA 1024 is always 128
                    packet.data = otcrypto.decryptRSA(packet.getData()) # NOTICE: Should we do it in a seperate thread?
                    packet.pos = 0 # Reset position

                else:
                    log.msg("RSA, length != 128 (it's %d)" % (packet.length - packet.pos))
                    self.transport.loseConnection()
                    return

                if not packet.data or packet.uint8(): # RSA needs to decrypt just fine, so we get the data, and the first byte should be 0
                    log.msg("RSA, first char != 0")
                    self.transport.loseConnection()
                    return

                # Set the XTEA key
                k = (packet.uint32(), packet.uint32(), packet.uint32(), packet.uint32())
                sum = 0
                self.xtea = {}
                for x in xrange(32):
                    self.xtea[x] = sum + k[sum & 3] & 0xffffffff
                    sum = (sum + 0x9E3779B9) & 0xffffffff
                    self.xtea[32 + x] = sum + k[sum>>11 & 3] & 0xffffffff
                    

            ip = self.transport.getPeer().host
            
            # Ban check.
            if game.ban.ipIsBanned(ip):
                self.exitWithError("Your ip is banned.\n %s" % game.ban.banIps[ip].message())
                return 
        
            if config.gameMaxConnections <= (self.connections + len(waitingListIps)):
                if ip in waitingListIps:
                    i = waitingListIps.index(ip) + 1
                    lastChecks[ip] = time.time()
                    # Note: Everyone below this threshhold might connect. So even if your #1 on the list and there is two free slots, you can be unlucky and don't get them.
                    if i + self.connections > config.gameMaxConnections:
                        self.exitWaitingList("Too many players online. You are at place %d on the waiting list." % i, i) 
                        return
                else:
                    waitingListIps.append(ip)
                    lastChecks[ip] = time.time()
                    self.exitWaitingList("Too many players online. You are at place %d on the waiting list." % len(waitingListIps), len(waitingListIps)) 
                    return
            self.connections += 1
            try:
                waitingListIps.remove(ip)
                del lastChecks[ip]
            except:
                pass
            
            # "Gamemaster" mode?
            gamemaster = packet.uint8()

            # Check if version is correct
            if version > config.versionMax or version < config.versionMin:
                self.exitWithError(config.versionError)
                return

            # Some weird thing with 9.7.
            try:
                # Check if there is a username (and a password)
                username = packet.string()

                characterName = packet.string()

                password = packet.string()
            except:
                self.exitWithError("Try again.")
                return

            if (not username and not config.anyAccountWillDo) or not characterName:
                self.exitWithError("Could not get your account name, or character name")
                return

            packet.pos += 6 # I don't know what this is

            # Our funny way of doing async SQL
            account = yield sql.conn.runQuery("SELECT `id`,`language` FROM `accounts` WHERE `name` = %s AND `password` = SHA1(CONCAT(`salt`, %s))", (username, password))

            if not account:
                account = game.scriptsystem.get("loginAccountFailed").runSync(None, client=self, username=username, password=password)
                if not account or account == True:
                    self.exitWithError("Invalid username or password")
                    return

            account = account[0]
            
            # Ban check.
            if game.ban.accountIsBanned(account['id']):
                self.exitWithError("Your account is banned.\n %s" % game.ban.banAccounts[account['id']].message())
                return 
            
            if not len(account) >= 2 or not account['language']:
                language = config.defaultLanguage
            else:
                language = account['language']
                
            character = yield sql.conn.runQuery("SELECT p.`id`,p.`name`,p.`world_id`,p.`group_id`,p.`account_id`,p.`vocation`,p.`health`,p.`mana`,p.`soul`,p.`manaspent`,p.`experience`,p.`posx`,p.`posy`,p.`posz`,p.`instanceId`,p.`sex`,p.`looktype`,p.`lookhead`,p.`lookbody`,p.`looklegs`,p.`lookfeet`,p.`lookaddons`,p.`lookmount`,p.`town_id`,p.`skull`,p.`stamina`, p.`storage`, p.`inventory`, p.`depot`, p.`conditions`, s.`fist`,s.`fist_tries`,s.`sword`,s.`sword_tries`,s.`club`,s.`club_tries`,s.`axe`,s.`axe_tries`,s.`distance`,s.`distance_tries`,s.`shield`,s.`shield_tries`,s.`fishing`, s.`fishing_tries`, g.`guild_id`, g.`guild_rank`, p.`balance` FROM `players` AS `p` LEFT JOIN player_skills AS `s` ON p.`id` = s.`player_id` LEFT JOIN player_guild AS `g` ON p.`id` = g.`player_id` WHERE p.account_id = %s AND p.`name` = %s AND p.`world_id` = %s", (account['id'], characterName, config.worldId))

            if not character:
                character = game.scriptsystem.get("loginCharacterFailed").runSync(None, client=self, account=account, name=characterName)
                if not character or character == True:
                    self.exitWithError("Character can't be loaded")
                    return
                
            character = character[0]
            if gamemaster and character['group_id'] < 3:
                self.exitWithError("You are not gamemaster! Turn off gamemaster mode in your IP changer.")
                return

            # Ban check.
            if isinstance(character, game.player.Player):
                if game.ban.playerIsBanned(character):
                    self.exitWithError("Your player is banned.\n %s" % game.ban.banAccounts[character.data["id"]].message())
                    return 
            elif game.ban.playerIsBanned(character['id']):
                self.exitWithError("Your player is banned.\n %s" % game.ban.banAccounts[character['id']].message())
                return 
            
            # If we "made" a new character in a script, character = the player.
            player = None
            if isinstance(character, game.player.Player):
                player = character
                game.player.allPlayers[player.name()] = player
            elif character['name'] in game.player.allPlayers:
                player = game.player.allPlayers[character['name']]
                if player.client:
                    self.exitWithError("This character is already logged in!")
                    return
                sql.runOperation("UPDATE `players` SET `lastlogin` = %s, `online` = 1 WHERE `id` = %s", (int(time.time()), character['id']))
            if player:    
                self.player = player
                if self.player.data["health"] <= 0:
                    self.player.onSpawn()
                self.player.client = self
                tile = getTile(self.player.position)
                tile.placeCreature(self.player)
                # Send update tile to refresh all players. We use refresh because it fixes the order of things as well.
                updateTile(self.player.position, tile)
                
            else:
                # Bulld the dict since we disabled automaticly doing this. Here we cast Decimal objects to int aswell (no longer automaticly either)
                yield deathlist.loadDeathList(character['id'])
                character["language"] = language
                game.player.allPlayers[character['name']] = game.player.Player(self, character)
                self.player = game.player.allPlayers[character['name']]
                if self.player.data["health"] <= 0:
                    self.player.onSpawn()

                try:
                    tile = getTile(self.player.position)
                    tile.placeCreature(self.player)
                    # Send update tile to refresh all players. We use refresh because it fixes the order of things as well.
                    updateTile(self.player.position, tile)
                        
                except AttributeError:
                    self.player.position = Position(*game.map.mapInfo.towns[1][1])
                    tile = getTile(self.player.position)
                    tile.placeCreature(self.player)
                    # Send update tile to refresh all players. We use refresh because it fixes the order of things as well.
                    updateTile(self.player.position, tile)
                        
                # Update last login
                sql.runOperation("UPDATE `players` SET `lastlogin` = %s WHERE `id` = %s", (int(time.time()), character['id']))

            self.packet = self.player.packet
            self.player.sendFirstPacket()
            self.ready = True # We can now accept other packages

            # Call the login script
            game.scriptsystem.get("login").runSync(self.player)
            
            # If we got a waiting list, now is a good time to verify the list
            if lastChecks:
                checkTime = time.time()
                for entry in lastChecks:
                    if checkTime - lastChecks[entry] > 3600:
                        waitingListIps.remove(entry)
                        del lastChecks[entry]
                        
        elif packetType == 0x00 and self.transport.getPeer().host in config.executeProtocolIps:
            self.gotFirst = False
            t = TibiaPacket()
            if not config.executeProtocolAuthKeys:
                self.ready = 2
            try:
                while True:
                    op = packet.string()
                    print op
                    if op == "CALL" and self.ready == 2:
                        print "do this"
                        result = yield game.functions.executeCode(packet.string())
                        
                        t.string(result)
                    elif op == "AUTH":
                        print "auth"
                        result = packet.string() in config.executeProtocolAuthKeys
                        if result:
                            t.string("True")
                            self.ready = 2
                        else:
                            t.string("False")
            except struct.error:
                pass # End of the line
            t.send(self)
Esempio n. 6
0
    def onFirstPacket(self, packet):
        packetType = packet.uint8()
        IN_TEST = False

        if packetType == 0xFF:
            # Special case for tests.
            IN_TEST = True

        if packetType == 0x0A and not self.ready:
            packet.pos += 2  # OS 0x00 and 0x01
            #packet.uint16()
            version = packet.uint16()  # Version int

            if version >= 972:
                version = packet.uint32()
                packet.uint8()  # Client type.

            self.protocol = game.protocol.getProtocol(version)
            self.version = version
            print "Client protocol version %d" % version

            if not self.protocol:
                log.msg("Trying to load a invalid protocol")
                self.transport.loseConnection()
                return

            if not IN_TEST:
                if (len(packet.data) -
                        packet.pos) == 128:  # RSA 1024 is always 128
                    packet.data = otcrypto.decryptRSA(packet.getData(
                    ))  # NOTICE: Should we do it in a seperate thread?
                    packet.pos = 0  # Reset position

                else:
                    log.msg("RSA, length != 128 (it's %d)" %
                            (packet.length - packet.pos))
                    self.transport.loseConnection()
                    return

                if not packet.data or packet.uint8(
                ):  # RSA needs to decrypt just fine, so we get the data, and the first byte should be 0
                    log.msg("RSA, first char != 0")
                    self.transport.loseConnection()
                    return

                # Set the XTEA key
                k = (packet.uint32(), packet.uint32(), packet.uint32(),
                     packet.uint32())
                sum = 0
                self.xtea = {}
                for x in xrange(32):
                    self.xtea[x] = sum + k[sum & 3] & 0xffffffff
                    sum = (sum + 0x9E3779B9) & 0xffffffff
                    self.xtea[32 + x] = sum + k[sum >> 11 & 3] & 0xffffffff

            ip = self.transport.getPeer().host

            # Ban check.
            if game.ban.ipIsBanned(ip):
                self.exitWithError("Your ip is banned.\n %s" %
                                   game.ban.banIps[ip].message())
                return

            if config.gameMaxConnections <= (self.connections +
                                             len(waitingListIps)):
                if ip in waitingListIps:
                    i = waitingListIps.index(ip) + 1
                    lastChecks[ip] = time.time()
                    # Note: Everyone below this threshhold might connect. So even if your #1 on the list and there is two free slots, you can be unlucky and don't get them.
                    if i + self.connections > config.gameMaxConnections:
                        self.exitWaitingList(
                            "Too many players online. You are at place %d on the waiting list."
                            % i, i)
                        return
                else:
                    waitingListIps.append(ip)
                    lastChecks[ip] = time.time()
                    self.exitWaitingList(
                        "Too many players online. You are at place %d on the waiting list."
                        % len(waitingListIps), len(waitingListIps))
                    return
            self.connections += 1
            try:
                waitingListIps.remove(ip)
                del lastChecks[ip]
            except:
                pass

            # "Gamemaster" mode?
            gamemaster = packet.uint8()

            # Check if version is correct
            if version > config.versionMax or version < config.versionMin:
                self.exitWithError(config.versionError)
                return

            # Some weird thing with 9.7.
            try:
                # Check if there is a username (and a password)
                username = packet.string()

                characterName = packet.string()

                password = packet.string()
            except:
                self.exitWithError("Try again.")
                return

            if (not username
                    and not config.anyAccountWillDo) or not characterName:
                self.exitWithError(
                    "Could not get your account name, or character name")
                return

            packet.pos += 6  # I don't know what this is

            # Our funny way of doing async SQL
            account = yield sql.conn.runQuery(
                "SELECT `id`,`language` FROM `accounts` WHERE `name` = %s AND `password` = SHA1(CONCAT(`salt`, %s))",
                (username, password))

            if not account:
                account = game.scriptsystem.get("loginAccountFailed").runSync(
                    None, client=self, username=username, password=password)
                if not account or account == True:
                    self.exitWithError("Invalid username or password")
                    return

            account = account[0]

            # Ban check.
            if game.ban.accountIsBanned(account['id']):
                self.exitWithError(
                    "Your account is banned.\n %s" %
                    game.ban.banAccounts[account['id']].message())
                return

            if not len(account) >= 2 or not account['language']:
                language = config.defaultLanguage
            else:
                language = account['language']

            character = yield sql.conn.runQuery(
                "SELECT p.`id`,p.`name`,p.`world_id`,p.`group_id`,p.`account_id`,p.`vocation`,p.`health`,p.`mana`,p.`soul`,p.`manaspent`,p.`experience`,p.`posx`,p.`posy`,p.`posz`,p.`instanceId`,p.`sex`,p.`looktype`,p.`lookhead`,p.`lookbody`,p.`looklegs`,p.`lookfeet`,p.`lookaddons`,p.`lookmount`,p.`town_id`,p.`skull`,p.`stamina`, p.`storage`, p.`inventory`, p.`depot`, p.`conditions`, s.`fist`,s.`fist_tries`,s.`sword`,s.`sword_tries`,s.`club`,s.`club_tries`,s.`axe`,s.`axe_tries`,s.`distance`,s.`distance_tries`,s.`shield`,s.`shield_tries`,s.`fishing`, s.`fishing_tries`, g.`guild_id`, g.`guild_rank`, p.`balance` FROM `players` AS `p` LEFT JOIN player_skills AS `s` ON p.`id` = s.`player_id` LEFT JOIN player_guild AS `g` ON p.`id` = g.`player_id` WHERE p.account_id = %s AND p.`name` = %s AND p.`world_id` = %s",
                (account['id'], characterName, config.worldId))

            if not character:
                character = game.scriptsystem.get(
                    "loginCharacterFailed").runSync(None,
                                                    client=self,
                                                    account=account,
                                                    name=characterName)
                if not character or character == True:
                    self.exitWithError("Character can't be loaded")
                    return

            character = character[0]
            if gamemaster and character['group_id'] < 3:
                self.exitWithError(
                    "You are not gamemaster! Turn off gamemaster mode in your IP changer."
                )
                return

            # Ban check.
            if isinstance(character, game.player.Player):
                if game.ban.playerIsBanned(character):
                    self.exitWithError(
                        "Your player is banned.\n %s" %
                        game.ban.banAccounts[character.data["id"]].message())
                    return
            elif game.ban.playerIsBanned(character['id']):
                self.exitWithError(
                    "Your player is banned.\n %s" %
                    game.ban.banAccounts[character['id']].message())
                return

            # If we "made" a new character in a script, character = the player.
            player = None
            if isinstance(character, game.player.Player):
                player = character
                game.player.allPlayers[player.name()] = player
            elif character['name'] in game.player.allPlayers:
                player = game.player.allPlayers[character['name']]
                if player.client:
                    self.exitWithError("This character is already logged in!")
                    return
                sql.runOperation(
                    "UPDATE `players` SET `lastlogin` = %s, `online` = 1 WHERE `id` = %s",
                    (int(time.time()), character['id']))
            if player:
                self.player = player
                if self.player.data["health"] <= 0:
                    self.player.onSpawn()
                self.player.client = self
                tile = getTile(self.player.position)
                tile.placeCreature(self.player)
                # Send update tile to refresh all players. We use refresh because it fixes the order of things as well.
                updateTile(self.player.position, tile)

            else:
                # Bulld the dict since we disabled automaticly doing this. Here we cast Decimal objects to int aswell (no longer automaticly either)
                yield deathlist.loadDeathList(character['id'])
                character["language"] = language
                game.player.allPlayers[character['name']] = game.player.Player(
                    self, character)
                self.player = game.player.allPlayers[character['name']]
                if self.player.data["health"] <= 0:
                    self.player.onSpawn()

                try:
                    tile = getTile(self.player.position)
                    tile.placeCreature(self.player)
                    # Send update tile to refresh all players. We use refresh because it fixes the order of things as well.
                    updateTile(self.player.position, tile)

                except AttributeError:
                    self.player.position = Position(
                        *game.map.mapInfo.towns[1][1])
                    tile = getTile(self.player.position)
                    tile.placeCreature(self.player)
                    # Send update tile to refresh all players. We use refresh because it fixes the order of things as well.
                    updateTile(self.player.position, tile)

                # Update last login
                sql.runOperation(
                    "UPDATE `players` SET `lastlogin` = %s WHERE `id` = %s",
                    (int(time.time()), character['id']))

            self.packet = self.player.packet
            self.player.sendFirstPacket()
            self.ready = True  # We can now accept other packages

            # Call the login script
            game.scriptsystem.get("login").runSync(self.player)

            # If we got a waiting list, now is a good time to verify the list
            if lastChecks:
                checkTime = time.time()
                for entry in lastChecks:
                    if checkTime - lastChecks[entry] > 3600:
                        waitingListIps.remove(entry)
                        del lastChecks[entry]

        elif packetType == 0x00 and self.transport.getPeer(
        ).host in config.executeProtocolIps:
            self.gotFirst = False
            t = TibiaPacket()
            if not config.executeProtocolAuthKeys:
                self.ready = 2
            try:
                while True:
                    op = packet.string()
                    print op
                    if op == "CALL" and self.ready == 2:
                        print "do this"
                        result = yield game.functions.executeCode(
                            packet.string())

                        t.string(result)
                    elif op == "AUTH":
                        print "auth"
                        result = packet.string(
                        ) in config.executeProtocolAuthKeys
                        if result:
                            t.string("True")
                            self.ready = 2
                        else:
                            t.string("False")
            except struct.error:
                pass  # End of the line
            t.send(self)
Esempio n. 7
0
    def move(self, direction, spectators=None, level=0, stopIfLock=False, callback=None, failback=None, push=True):
        if not self.alive or not self.actionLock(self.move, direction, spectators, level, stopIfLock, callback, failback, push):
            return

        if not self.data["health"] or not self.canMove or not self.speed:
            return False

        oldPosition = self.position.copy()

        # Drunk?
        if self.hasCondition(CONDITION_DRUNK):
            directions = [0,1,2,3,4,5,6,7,direction] # Double the odds of getting the correct direction.
            directions.remove(self.reverseDirection()) # From a reality perspective, you are rarely that drunk.
            direction = random.choice([0,1,2,3,4,5,6,7,direction])

        # Recalculate position
        position = oldPosition.copy()
        if direction == 0:
            position.y -= 1
        elif direction == 1:
            position.x += 1
        elif direction == 2:
            position.y += 1
        elif direction == 3:
            position.x -= 1
        elif direction == 4:
            position.y += 1
            position.x -= 1
        elif direction == 5:
            position.y += 1
            position.x += 1
        elif direction == 6:
            position.y -= 1
            position.x -= 1
        elif direction == 7:
            position.y -= 1
            position.x += 1

        position.z += level
            
        # We don't walk out of the map!
        if position.x < 1 or position.y < 1 or position.x > game.map.mapInfo.width or position.y > game.map.mapInfo.height:
            self.cancelWalk()
            return

        # New Tile
        newTile = getTile(position)
        
        if not newTile:
            return self.clearMove(direction, failback)
        
        # oldTile
        oldTile = getTile(oldPosition)
        if not oldTile:
            # This always raise
            raise Exception("(old)Tile not found (%s). This shouldn't happend!" % oldPosition)

        val = game.scriptsystem.get("move").runSync(self)
        if val == False:
            return self.clearMove(direction, failback)

        try:
            oldStackpos = oldTile.findStackpos(self)
        except:
            return self.clearMove(direction, failback)

        # Deal with walkOff
        for item in oldTile.getItems():
            game.scriptsystem.get('walkOff').runSync(item, self, None, position=oldPosition)

        # Deal with preWalkOn
        for item in newTile.getItems():
            r = game.scriptsystem.get('preWalkOn').runSync(item, self, None, oldTile=oldTile, newTile=newTile, position=position)
            if r == False:
                return self.clearMove(direction, failback)

        # PZ blocked?
        if (self.hasCondition(CONDITION_PZBLOCK) or self.getSkull() in SKULL_JUSTIFIED) and newTile.getFlags() & TILEFLAGS_PROTECTIONZONE:
            self.lmessage("You are PZ blocked")
            return self.clearMove(direction, failback)
            
        if newTile.ground.solid:
            self.notPossible()
            return self.clearMove(direction, failback)

        if newTile.things:
            for thing in newTile.things:
                if not self.isPlayer() and isinstance(thing, Item) and thing.teleport:
                    return self.clearMove(direction, failback)

                if thing.solid:
                    if level and isinstance(thing, Creature):
                        continue

                    # Monsters might push. This should probably be a preWalkOn event, but well. Consider this a todo for v1.1 or something.
                    if push and isinstance(thing, Monster) and self.isMonster() and self.base.pushCreatures and thing.base.pushable:
                        # Push stuff here.

                        # Clear up the creatures actions.
                        thing.stopAction()
                        thing.clearMove(direction, failback)

                        if thing.move(thing.reverseDirection(), stopIfLock=True, push=False):
                            # We "must" break here. Assume the tile is good since another creature is on it. Iterator might be invalid at this point.
                            break
                        elif self.base.hostile and thing.isAttackable(self):
                            # We can attack the creature.
                            self.target = thing
                            self.targetMode = 1

                            # Deliver final blow.
                            thing.onHit(self, -thing.data['healthmax'], PHYSICAL)

                    #self.turn(direction) # Fix me?
                    self.notPossible()
                    return self.clearMove(direction, failback)

        _time = time.time()
        self.lastStep = _time
        delay = self.stepDuration(newTile.ground) * (config.diagonalWalkCost if direction > 3 else 1)
        self.lastAction = _time + delay

        newStackPos = newTile.placeCreature(self)
        oldTile.removeCreature(self)

        # Weird #112 issue. Hack fix.
        if self in oldTile.things:
            while True:
                if self not in oldTile.things: break
                oldTile.removeCreature(self)

        # Clear target if we change level
        if level:
            self.cancelTarget()
            self.target = None
            self.targetMode = 0


        # Send to Player
        if self.isPlayer():
            # Mark for save
            self.saveData = True

            ignore = (self,)
            stream = self.packet()

            if (oldPosition.z != 7 or position.z < 8): # Only as long as it's not 7->8 or 8->7
                #stream = spectator.packet(0x6D)
                stream.uint8(0x6D)
                stream.position(oldPosition)
                stream.uint8(oldStackpos)
                stream.position(position)
            else:
                stream.removeTileItem(oldPosition, oldStackpos)

            # Levels
            if oldPosition.z > position.z:
                stream.moveUpPlayer(self, oldPosition)

            elif oldPosition.z < position.z:
                stream.moveDownPlayer(self, oldPosition)

            # Y movements
            if oldPosition.y > position.y:
                stream.uint8(0x65)
                stream.mapDescription(Position(oldPosition.x - 8, position.y - 6, position.z), 18, 1, self)
            elif oldPosition.y < position.y:
                stream.uint8(0x67)
                stream.mapDescription(Position(oldPosition.x - 8, position.y + 7, position.z), 18, 1, self)

            # X movements
            if oldPosition.x < position.x:
                stream.uint8(0x66)
                stream.mapDescription(Position(position.x + 9, position.y - 6, position.z), 1, 14, self)
            elif oldPosition.x > position.x:
                stream.uint8(0x68)
                stream.mapDescription(Position(position.x - 8, position.y - 6, position.z), 1, 14, self)

            # If we're entering protected zone, fix icons
            pzStatus = newTile.getFlags() & TILEFLAGS_PROTECTIONZONE
            pzIcon = self.extraIcons & CONDITION_PROTECTIONZONE
            if pzStatus and not pzIcon:
                self.setIcon(CONDITION_PROTECTIONZONE)
                self.refreshConditions(stream)
                if not level:
                    self.cancelTarget(stream)
                    self.target = None
                if self.isPlayer() and self.mounted:
                    callLater(0, self.changeMountStatus, False) # This should be sent after the move is completed, I believe.

            elif not pzStatus and pzIcon:
                self.removeIcon(CONDITION_PROTECTIONZONE)
                self.refreshConditions(stream)


            stream.send(self.client)
            
        else:
            ignore = ()
            
        self.position = position
        self.direction = direction % 4
        
        oldPosCreatures = getPlayers(oldPosition, ignore=ignore)
        newPosCreatures = getPlayers(position, ignore=ignore)
        spectators = oldPosCreatures|newPosCreatures
        invisible = self.isMonster() and self.hasCondition(CONDITION_INVISIBLE)

        for spectator in spectators:
            # Make packet
            if not spectator.client or invisible:
                continue

            canSeeNew = spectator in newPosCreatures
            if canSeeNew:
                assert spectator.canSee(position)
            canSeeOld = spectator in oldPosCreatures
            if canSeeOld:
                assert spectator.canSee(oldPosition)
            stream = spectator.packet()

            if not canSeeOld and canSeeNew:
                stream.addTileCreature(position, newStackPos, self, spectator, resend=True)

            elif canSeeOld and not canSeeNew:
                stream.removeTileItem(oldPosition, oldStackpos)
                """spectator.knownCreatures.remove(self)
                self.knownBy.remove(spectator)"""

            elif canSeeOld and canSeeNew:
                if (oldPosition.z != 7 or position.z < 8) and oldStackpos < 10: # Only as long as it's not 7->8 or 8->7

                    stream.uint8(0x6D)
                    stream.position(oldPosition)
                    stream.uint8(oldStackpos)
                    stream.position(position)

                else:
                    stream.removeTileItem(oldPosition, oldStackpos)
                    spectator.knownCreatures.remove(self)
                    self.knownBy.remove(spectator)
                    stream.addTileCreature(position, newStackPos, self, spectator)
            stream.send(spectator.client)

        if self.scripts["onNextStep"]:
            scripts = self.scripts["onNextStep"][:]
            self.scripts["onNextStep"] = []
            for script in scripts:
                script(self)

        # Deal with walkOn
        for item in newTile.getItems(): # Scripts
            game.scriptsystem.get('walkOn').runDeferNoReturn(item, self, None, position=position, fromPosition=oldPosition)
            if item.teledest:
                try:
                    self.teleport(Position(item.teledest[0], item.teledest[1], item.teledest[2]), self.position.instanceId)
                    self.magicEffect(EFFECT_TELEPORT)
                except:
                    log.msg("%d (%s) got a invalid teledist (%s), remove it!" % (item.itemId, item, item.teledest))
                    del item.teledest

        # Deal with appear and disappear. Ahh the power of sets :)
        disappearFrom = oldPosCreatures - newPosCreatures
        appearTo = newPosCreatures - oldPosCreatures
        for creature2 in disappearFrom:
            game.scriptsystem.get('disappear').runDeferNoReturn(creature2, self)
            game.scriptsystem.get('disappear').runDeferNoReturn(self, creature2)

        for creature2 in appearTo:
            game.scriptsystem.get('appear').runDeferNoReturn(creature2, self)
            game.scriptsystem.get('appear').runDeferNoReturn(self, creature2)

        # Stairhop delay
        if level and self.isPlayer():
            self.lastStairHop = time.time()

        if self.isPlayer() and self.target and not self.canSee(self.target.position):
            self.cancelTarget()
           
        if callback: reactor.callLater(0, callback)
        return True
Esempio n. 8
0
    def teleport(self, position, force=False):
        """if not self.actionLock(self.teleport, position):
            return False"""

        
        # 4 steps, remove item (creature), send new map and cords, and effects
        oldPosition = self.position.copy()

        newTile = getTile(position)
        oldPosCreatures = set()
        if not newTile:
            raise game.errors.SolidTile("Tile doesn't exist") # Yea, it's fatal, even in force mode!
        
        if not force:
            for i in newTile.getItems():
                if i.solid:
                    raise game.errors.SolidTile()

        invisible = self.isMonster() and self.hasCondition(CONDITION_INVISIBLE)

        oldStackpos = 0
        if not invisible:
            try:
                oldStackpos = getTile(oldPosition).findStackpos(self)
                for spectator in getSpectators(oldPosition, ignore=(self,)):
                    stream = spectator.packet()
                    stream.removeTileItem(oldPosition, oldStackpos)
                    stream.magicEffect(oldPosition, 0x02)
                    stream.send(spectator)
                oldPosCreatures = getCreatures(oldPosition)
            except:
                pass # Just append creature
        
        stackpos = placeCreature(self, position)
        if not stackpos:
            raise game.errors.ImpossibleMove()
        
        removeCreature(self, oldPosition)
        
        if self.creatureType == 0 and self.client:
            print "Good"
            with self.packet() as stream:
                if oldStackpos: 
                   stream.removeTileItem(oldPosition, oldStackpos)
                
                stream.uint8(0x64)
                stream.position(position)
                stream.mapDescription(Position(position.x - 8, position.y - 6, position.z), 18, 14, self)

                # If we're entering protected zone, fix icons
                pzStatus = newTile.getFlags() & TILEFLAGS_PROTECTIONZONE
                pzIcon = self.extraIcons & CONDITION_PROTECTIONZONE
                if pzStatus and not pzIcon:
                    self.setIcon(CONDITION_PROTECTIONZONE)
                    self.refreshConditions(stream)
                    self.cancelTarget(stream)
                    self.target = None
                    if self.isPlayer() and self.mounted:
                        callLater(0, self.changeMountStatus, False)

                elif not pzStatus and pzIcon:
                    self.removeIcon(CONDITION_PROTECTIONZONE)
                    self.refreshConditions(stream)

                #stream.magicEffect(position, 0x02)

        self.position = position        
        newPosCreatures = getCreatures(position)
        disappearFrom = oldPosCreatures - newPosCreatures
        appearTo = newPosCreatures - oldPosCreatures
        for creature2 in disappearFrom:
            game.scriptsystem.get('disappear').runSync(creature2, self)

        for creature2 in appearTo:
            game.scriptsystem.get('appear').runSync(creature2, self)


        if not invisible:
            for spectator in getSpectators(position, ignore=(self,)):
                stream = spectator.packet()
                stream.addTileCreature(position, stackpos, self, spectator.player)
                stream.magicEffect(position, 0x02)
                stream.send(spectator)

        if self.target and not self.canSee(self.target.position):
            self.cancelTarget()
            self.target = None
            self.targetMode = 0
            
        # Stairhop delay
        if self.isPlayer():
            self.lastStairHop = time.time()
            if self.target and not self.canSee(self.target.position):
                self.cancelTarget()