def promotion(self, npc, player): npc.sayTo(player, "Do you want me to promote you?") word = yield word = word.title() if word in accept: if player.data["vocation"] < 4 and player.data["level"] > 20: if player.removeMoney(20000): sql.runOperation( "UPDATE `players` SET `vocation` = %s WHERE `id` = %s", (player.data["vocation"] + 4, player.data["id"])) player.data["vocation"] += 4 npc.sayTo(player, "Congratulations! You are now promoted.") else: npc.sayTo(player, "You do not have enough money!") elif player.data["level"] < 20: npc.sayTo( player, "I am sorry, but I can only promote you once you have reached level" ) else: npc.sayTo(player, "You are already promoted!")
def firstPacketLoginChar(self, packet): characterName = packet.string() if (not self.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.runQuery("SELECT `id`,`language` FROM `accounts` WHERE `name` = %s AND `password` = SHA1(CONCAT(`salt`, %s))", self.username, self.password) if not account: account = game.scriptsystem.get("loginAccountFailed").run(client=self, username=username, password=self.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.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").run(client=self, account=account, name=characterName) if not character or character == True: self.exitWithError("Character can't be loaded") return character = character[0] # 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 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: # Load deathlist. 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").run(creature=self.player)
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)
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)
def saveAll(force=False): """ Save everything, players, houses, global storage etc. """ commited = False t = time.time() for player in game.player.allPlayers.values(): result = player._saveQuery(force) if result: sql.runOperation(*result) commited = True # Global storage if saveGlobalStorage or force: for field in globalStorage: type = "" if field in jsonFields: data = otjson.dumps(globalStorage[field]) type = "json" elif field in pickleFields: data = fastPickler(globalStorage[field]) type = "pickle" else: data = globalStorage[field] sql.runOperation( "INSERT INTO `globals` (`key`, `data`, `type`) VALUES(%s, %s, %s) ON DUPLICATE KEY UPDATE `data` = %s", (field, data, type, data)) commited = True # Houses if game.map.houseTiles: for houseId, house in game.house.houseData.iteritems(): # House is loaded? if houseId in game.map.houseTiles: try: items = house.data["items"].copy() except: log.msg("House id %d have broken items!" % houseId) items = {} # Broken items for tile in game.map.houseTiles[houseId]: _items = [] lastItem = None for item in tile.bottomItems(): ic = item.count if not item.fromMap and (ic == None or ic > 0): if lastItem and lastItem.itemId == item.itemId and lastItem.stackable and lastItem.count < 100: # Stack. lCount = lastItem.count lastItem.count = min(100, lCount + ic) ic -= lastItem.count - lCount item.count = ic if ic or ic == None: _items.append(item) lastItem = item _items.reverse() items[tile.position] = _items if items != house.data["items"]: house.data["items"] = items house.save = True # Force save if house.save: log.msg("Saving house ", houseId) sql.runOperation( "UPDATE `houses` SET `owner` = %s,`guild` = %s,`paid` = %s, `data` = %s WHERE `id` = %s", (house.owner, house.guild, house.paid, fastPickler(house.data) if house.data else '', houseId)) house.save = False commited = True else: log.msg("Not saving house", houseId) if force: log.msg("Full (forced) save took: %f" % (time.time() - t)) elif commited: log.msg("Full save took: %f" % (time.time() - t))
def saveAll(force=False): """ Save everything, players, houses, global storage etc. """ commited = False t = time.time() for player in game.player.allPlayers.values(): result = player._saveQuery(force) if result: sql.runOperation(*result) commited = True # Global storage if saveGlobalStorage or force: for field in globalStorage: type = "" if field in jsonFields: data = otjson.dumps(globalStorage[field]) type = "json" elif field in pickleFields: data = fastPickler(globalStorage[field]) type = "pickle" else: data = globalStorage[field] sql.runOperation("INSERT INTO `globals` (`key`, `data`, `type`) VALUES(%s, %s, %s) ON DUPLICATE KEY UPDATE `data` = %s", (field, data, type, data)) commited = True # Houses if game.map.houseTiles: for houseId, house in game.house.houseData.iteritems(): # House is loaded? if houseId in game.map.houseTiles: try: items = house.data["items"].copy() except: log.msg("House id %d have broken items!" % houseId) items = {} # Broken items for tile in game.map.houseTiles[houseId]: _items = [] lastItem = None for item in tile.bottomItems(): ic = item.count if not item.fromMap and (ic == None or ic > 0): if lastItem and lastItem.itemId == item.itemId and lastItem.stackable and lastItem.count < 100: # Stack. lCount = lastItem.count lastItem.count = min(100, lCount + ic) ic -= lastItem.count - lCount item.count = ic if ic or ic == None: _items.append(item) lastItem = item _items.reverse() items[tile.position] = _items if items != house.data["items"]: house.data["items"] = items house.save = True # Force save if house.save: log.msg("Saving house ", houseId) sql.runOperation("UPDATE `houses` SET `owner` = %s,`guild` = %s,`paid` = %s, `data` = %s WHERE `id` = %s", (house.owner, house.guild, house.paid, fastPickler(house.data) if house.data else '', houseId)) house.save = False commited = True else: log.msg("Not saving house", houseId) if force: log.msg("Full (forced) save took: %f" % (time.time() - t)) elif commited: log.msg("Full save took: %f" % (time.time() - t))