#!/usr/bin/python """ Copyright 2011, Dipesh Amin Copyright 2011, Stefan Beller tradey, a package, which implements an Automated Market Bot for "The Mana World" a 2D MMORPG. - Currently permissions are defined as: -1 (blocked), 0 (normal user), 5 (seller), 20 (admin). - An item will only be listed for a period of one week, and can be relisted for 3 weeks. - If a Trade in uncompleted within 5 minutes of a Trade Request, it is cancelled to prevent any disruptions to service. - The Bot supports the manaplus "right click and buy" feature; if an item is listed twice for the same price, the first shown in the list will be bought (i.e. the one added earlier). """ import logging import socket import sys import time import string from being import * try: import config except: print "no config file found. please move config.py.template to config.py and edit to your needs!" exit(0); from net.packet import * from net.protocol import * from net.packet_out import * from player import * import tradey import utils shop_broadcaster = utils.Broadcast() trader_state = utils.TraderState() ItemDB = utils.ItemDB() player_node = Player('') beingManager = BeingManager() user_tree = tradey.UserTree() sale_tree = tradey.ItemTree() ItemLog = utils.ItemLog() def process_whisper(nick, msg, mapserv): msg = filter(lambda x: x in string.printable, msg) user = user_tree.get_user(nick) broken_string = msg.split() if user != -10: if int(user.get("accesslevel")) == -1: # A user who has been blocked for abuse. mapserv.sendall(whisper(nick, "You can no longer use the bot. If you feel this is in error, please contact .")) return if msg == "!list": # Sends the list of items for sale. if len(sale_tree.root) != 0: mapserv.sendall(whisper(nick, "The following items are on sale:")) else: mapserv.sendall(whisper(nick, "No items for sale.")) for elem in sale_tree.root: if time.time() - float(elem.get('add_time')) < config.relist_time: # Check if an items time is up. msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + \ elem.get("itemId") + "|" + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" mapserv.sendall(whisper(nick, msg)) elif broken_string[0] == '!selllist': # Support for 4144's shop (Sell list) data = '\302\202B1' for elem in sale_tree.root: if time.time() - float(elem.get('add_time')) < config.relist_time: data += utils.encode_str(int(elem.get("itemId")), 2) data += utils.encode_str(int(elem.get("price")), 4) data += utils.encode_str(int(elem.get("amount")), 3) mapserv.sendall(whisper(nick, data)) elif broken_string[0] == '!buyitem': # 4144 buy command if len(broken_string) == 4: if broken_string[1].isdigit() and broken_string[2].isdigit() and broken_string[3].isdigit(): # Traditional 4144 shop. item_id = int(broken_string[1]) price = int(broken_string[2]) amount = int(broken_string[3]) for elem in sale_tree.root: if int(elem.get('amount')) >= amount and int(elem.get('price')) == price and int(elem.get('itemId')) == item_id: process_whisper(nick, '!buy ' + str(amount) + " " + elem.get('uid'), mapserv) return mapserv.sendall(whisper(nick, "Item not found. Please check and try again.")) else: mapserv.sendall(whisper(nick, "Syntax incorrect")) elif msg == "!info": # Send information related to a player. if user == -10: mapserv.sendall(whisper(nick, "Your current access level is 0.")) elif int(user.get('accesslevel')) > 0: mapserv.sendall(whisper(nick, "Your current access level is " + user.get('accesslevel') + ".")) items_for_sale = False for elem in sale_tree.root: if elem.get('name') == nick: if time.time() - float(elem.get('add_time')) > config.relist_time: msg = "[expired] [" else: msg = "[selling] [" msg += elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" + \ ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" if items_for_sale == False: mapserv.sendall(whisper(nick, "Your have the following items for sale:")) items_for_sale = True mapserv.sendall(whisper(nick, msg)) if items_for_sale == False: mapserv.sendall(whisper(nick, "Your have no items for sale.")) money = int(user.get('money')) mapserv.sendall(whisper(nick, "You have " + str(money) + "gp to collect.")) stall_msg = "You have " + str(int(user.get('stalls')) - int(user.get('used_stalls'))) + " free slots." mapserv.sendall(whisper(nick, stall_msg)) elif broken_string[0] == "!help": # Sends help information if len(broken_string) == 1: mapserv.sendall(whisper(nick, "Welcome to ManaMarket!")) mapserv.sendall(whisper(nick, "The basic commands for the bot are: !list, !find or , !buy , !add , !money, !relist , !info, !getback ")) mapserv.sendall(whisper(nick, "For a detailed description of each command, type !help e.g. !help !buy")) mapserv.sendall(whisper(nick, "For example:- to purchase an item shown in the list as:")) mapserv.sendall(whisper(nick, "[selling] [6] 5 [@@640|Iron Ore@@] for 1000gp each")) mapserv.sendall(whisper(nick, "you would type /whisper ManaMarket !buy 1 6" )) mapserv.sendall(whisper(nick, "This will purchase one of item 6 (Iron Ore).")) elif len(broken_string) == 2: if broken_string[1] == '!buy': mapserv.sendall(whisper(nick, "!buy - Request the purchase of an item or items.")) elif broken_string[1] == '!list': mapserv.sendall(whisper(nick, "!list - Displays a list of all items for sale.")) elif broken_string[1] == '!find': mapserv.sendall(whisper(nick, "!find or - Simple search to locate an item.")) elif broken_string[1] == '!buy': mapserv.sendall(whisper(nick, "!buy - Request the purchase of an item or items.")) elif broken_string[1] == '!add': mapserv.sendall(whisper(nick, "!add - Add an item to the sell list (requires that you have an account).")) elif broken_string[1] == '!money': mapserv.sendall(whisper(nick, "!money - Allows you to collect money for any sales made on your behalf.")) elif broken_string[1] == '!relist': mapserv.sendall(whisper(nick, "!relist - Allows you to relist an item which has expired.")) elif broken_string[1] == '!info': mapserv.sendall(whisper(nick, "!info - Displays basic information about your account.")) elif broken_string[1] == '!getback': mapserv.sendall(whisper(nick, "!getback - Allows you to retrieve an item that has expired or you no longer wish to sell.")) elif msg == "!money": # Trades any money earned through item sales. if user == -10: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return amount = int(user.get('money')) if amount == 0: mapserv.sendall(whisper(nick, "You have no money to collect.")) else: trader_state.money = nick if not trader_state.Trading.testandset(): mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly")) return player_id = beingManager.findId(nick) if player_id != -10: mapserv.sendall(trade_request(player_id)) trader_state.timer = time.time() else: mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!")) trader_state.reset() elif broken_string[0] == "!find": # Returns a list of items, with the corresponding Item Id - !find or . if len(broken_string) < 2: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return items_found = False item = " ".join(broken_string[1:]) # could be an id or an item name if item.isdigit(): # an id for elem in sale_tree.root: if ((time.time() - float(elem.get('add_time'))) < config.relist_time) \ and int(elem.get("itemId")) == int(item): # Check if an items time is up. msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \ + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" mapserv.sendall(whisper(nick, msg)) items_found = True else: # an item name for elem in sale_tree.root: if ((time.time() - float(elem.get('add_time'))) < config.relist_time) \ and item.lower() in ItemDB.getItem(int(elem.get("itemId"))).name.lower(): # Check if an items time is up. msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \ + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each" mapserv.sendall(whisper(nick, msg)) items_found = True if not items_found: mapserv.sendall(whisper(nick, "Item not found.")) elif msg == '!listusers': # Admin command - shows a list of all user. if user == -10: return if int(user.get("accesslevel")) != 20: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return data = '' for user in user_tree.root: name = user.get('name') accesslevel = user.get('accesslevel') slots = user.get('stalls') used_slots = user.get('used_stalls') money = user.get('money') data += name+" ("+accesslevel+") "+used_slots+"/"+slots+" "+money+'gp, ' # Format ManaMarket (20) 2/5 100000gp, if len(data) > 400: mapserv.sendall(whisper(nick, data[0:len(data)-2]+".")) data = '' mapserv.sendall(whisper(nick, data[0:len(data)-2]+".")) elif broken_string[0] == '!setslots': # Change the number of slots a user has - !setslots if user == -10: return if int(user.get("accesslevel")) != 20: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return if len(broken_string) < 3: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if broken_string[1].isdigit(): slot = int(broken_string[1]) name = " ".join(broken_string[2:]) user_info = user_tree.get_user(name) if user_info == -10: mapserv.sendall(whisper(nick, "User not found, check and try again.")) return user_tree.get_user(name).set('stalls', str(slot)) mapserv.sendall(whisper(nick, "Slots changed: "+name+" "+str(slot))) tradey.saveData("User: "+player_name+", Slots changed: "+str(slot)) user_tree.save() else: mapserv.sendall(whisper(nick, "Syntax incorrect.")) elif broken_string[0] == '!setaccess': # Change someones access level - !setaccess if user == -10: return if int(user.get("accesslevel")) != 20: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return if len(broken_string) < 3: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if (broken_string[1][0] == '-' and broken_string[1][1:].isdigit()) or broken_string[1].isdigit(): accesslevel = int(broken_string[1]) name = " ".join(broken_string[2:]) user_info = user_tree.get_user(name) if user_info == -10: mapserv.sendall(whisper(nick, "User not found, check and try again.")) return if int(user_info.get('accesslevel')) < int(user.get("accesslevel")) and accesslevel <= int(user.get("accesslevel")): user_tree.get_user(name).set('accesslevel', str(accesslevel)) mapserv.sendall(whisper(nick, "Access level changed:"+name+ " ("+str(accesslevel)+").")) user_tree.save() tradey.saveData("User: "+player_name+", Set Access Level: "+str(accesslevel)) else: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return else: mapserv.sendall(whisper(nick, "Syntax incorrect.")) elif broken_string[0] == "!adduser": # A command to give a user access to the bot - !adduser . if user == -10: return if int(user.get("accesslevel")) != 20: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return if len(broken_string) < 3: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if broken_string[1].isdigit() and broken_string[2].isdigit(): al = int(broken_string[1]) stalls = int(broken_string[2]) player_name = " ".join(broken_string[3:]) user_tree.add_user(player_name, stalls, al) mapserv.sendall(whisper(nick, "User Added with " + str(stalls) + " slots.")) tradey.saveData("User Added: "+player_name+", Slots: "+str(stalls)+", Access Level: "+str(al)) else: mapserv.sendall(whisper(nick, "Syntax incorrect.")) elif broken_string[0] == "!add": # Allows a player with the correct permissions to add an item for sale - !add if user == -10: mapserv.sendall(whisper(nick, "You are unable to add items.")) return if len(broken_string) < 3: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if int(user.get("accesslevel")) < 5: mapserv.sendall(whisper(nick, "You are unable to add items.")) return if int(user.get("used_stalls")) >= int(user.get("stalls")): mapserv.sendall(whisper(nick, "You have no free slots. You may remove an item or wait for something to be sold.")) return if broken_string[1].isdigit() and broken_string[2].isdigit(): amount = int(broken_string[1]) price = int(broken_string[2]) item_name = " ".join(broken_string[3:]) item_id = ItemDB.findId(item_name) if item_id == -10: mapserv.sendall(whisper(nick, "Item not found, check spelling.")) return item = Item() item.player = nick item.get = 1 # 1 = get, 0 = give item.id = item_id item.amount = amount item.price = price trader_state.item = item if not trader_state.Trading.testandset(): mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly")) return player_id = beingManager.findId(nick) if player_id != -10: mapserv.sendall(trade_request(player_id)) trader_state.timer = time.time() else: mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!")) trader_state.reset() else: mapserv.sendall(whisper(nick, "Syntax incorrect.")) elif broken_string[0] == "!buy": # Buy a given quantity of an item - !buy if len(broken_string) != 3: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if broken_string[1].isdigit() and broken_string[2].isdigit(): amount = int(broken_string[1]) uid = int(broken_string[2]) item_info = sale_tree.get_uid(uid) if item_info == -10: mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again.")) return if amount > int(item_info.get("amount")): mapserv.sendall(whisper(nick, "I do not have that many.")) return item = Item() item.get = 0 # 1 = get, 0 = give item.player = nick item.id = int(item_info.get("itemId")) item.uid = uid item.amount = amount item.price = int(item_info.get("price")) trader_state.item = item if not trader_state.Trading.testandset(): mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly")) return player_id = beingManager.findId(nick) if player_id != -10: mapserv.sendall(trade_request(player_id)) trader_state.timer = time.time() mapserv.sendall(whisper(nick, "That will be " + str(item.price * item.amount) + "gp.")) else: mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!")) trader_state.reset() else: mapserv.sendall(whisper(nick, "Syntax incorrect.")) elif broken_string[0] == "!removeuser": # Remove a user, for whatever reason - !removeuser if user == -10: return if len(broken_string) < 2: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if int(user.get("accesslevel")) != 20: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return player_name = " ".join(broken_string[1:]) check = user_tree.remove_user(player_name) if check == 1: mapserv.sendall(whisper(nick, "User Removed.")) tradey.saveData("User Removed: "+player_name) elif check == -10: mapserv.sendall(whisper(nick, "User removal failed. Please check spelling.")) elif broken_string[0] == "!relist": # Relist an item which has expired - !relist . if user == -10 or len(broken_string) != 2: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if int(user.get("accesslevel")) < 5: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return if broken_string[1].isdigit(): uid = int(broken_string[1]) item_info = sale_tree.get_uid(uid) if item_info == -10: mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again.")) return if item_info.get('name') != nick: mapserv.sendall(whisper(nick, "That doesn't belong to you!")) return time_relisted = int(item_info.get('relisted')) if int(item_info.get('relisted')) < 3: sale_tree.get_uid(uid).set('add_time', str(time.time())) sale_tree.get_uid(uid).set('relisted', str(time_relisted + 1)) sale_tree.save() mapserv.sendall(whisper(nick, "The item has been successfully relisted.")) else: mapserv.sendall(whisper(nick, "This item can no longer be relisted. Please collect it using !getback "+str(uid)+".")) return else: mapserv.sendall(whisper(nick, "Syntax incorrect.")) elif broken_string[0] == "!getback": # Trade the player back uid, remove from sale_items if trade successful - !getback . if user == -10 or len(broken_string) != 2: mapserv.sendall(whisper(nick, "Syntax incorrect.")) return if int(user.get("accesslevel")) < 5: mapserv.sendall(whisper(nick, "You don't have the correct permissions.")) return if broken_string[1].isdigit(): uid = int(broken_string[1]) item_info = sale_tree.get_uid(uid) if item_info == -10: mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again.")) return if item_info.get('name') != nick: mapserv.sendall(whisper(nick, "That doesn't belong to you!")) return item = Item() item.get = 0 item.player = nick item.id = int(item_info.get("itemId")) item.uid = uid item.amount = int(item_info.get("amount")) item.price = 0 trader_state.item = item if not trader_state.Trading.testandset(): mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly")) return player_id = beingManager.findId(nick) if player_id != -10: mapserv.sendall(trade_request(player_id)) trader_state.timer = time.time() else: mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!")) trader_state.reset() def main(): logging.basicConfig(filename='data/logs/activity.log', level=logging.INFO, format='%(asctime)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') logging.info("Bot Started.") account = config.account password = config.password character = config.character login = socket.socket() login.connect((config.server, config.port)) logging.info("Login connected") login_packet = PacketOut(0x0064) login_packet.write_int32(0) login_packet.write_string(account, 24) login_packet.write_string(password, 24) login_packet.write_int8(0x03); login.sendall(str(login_packet)) pb = PacketBuffer() id1 = accid = id2 = 0 charip = "" charport = 0 # Login server packet loop. while True: data = login.recv(1500) if not data: break pb.feed(data) for packet in pb: if packet.is_type(SMSG_LOGIN_DATA): # login succeeded packet.skip(2) id1 = packet.read_int32() accid = packet.read_int32() id2 = packet.read_int32() packet.skip(30) player_node.sex = packet.read_int8() charip = utils.parse_ip(packet.read_int32()) charport = packet.read_int16() login.close() break if charip: break assert charport char = socket.socket() char.connect((charip, charport)) logging.info("Char connected") char_serv_packet = PacketOut(CMSG_CHAR_SERVER_CONNECT) char_serv_packet.write_int32(accid) char_serv_packet.write_int32(id1) char_serv_packet.write_int32(id2) char_serv_packet.write_int16(0) char_serv_packet.write_int8(player_node.sex) char.sendall(str(char_serv_packet)) char.recv(4) pb = PacketBuffer() mapip = "" mapport = 0 # Character Server Packet loop. while True: data = char.recv(1500) if not data: break pb.feed(data) for packet in pb: if packet.is_type(SMSG_CHAR_LOGIN): packet.skip(2) slots = packet.read_int16() packet.skip(18) count = (len(packet.data)-22) / 106 for i in range(count): player_node.id = packet.read_int32() player_node.EXP = packet.read_int32() player_node.MONEY = packet.read_int32() packet.skip(62) player_node.name = packet.read_string(24) packet.skip(6) slot = packet.read_int8() packet.skip(1) logging.info("Character information recieved:") logging.info("Name: %s, Id: %s, EXP: %s, MONEY: %s, HP: %s/%s, MP: %s/%s, LEVEL: %s", \ player_node.name, player_node.id, player_node.EXP, player_node.MONEY, player_node.HP, \ player_node.MAX_HP, player_node.MP, player_node.MAX_MP, player_node.LEVEL) if slot == character: break char_select_packet = PacketOut(CMSG_CHAR_SELECT) char_select_packet.write_int8(character) char.sendall(str(char_select_packet)) elif packet.is_type(SMSG_CHAR_MAP_INFO): player_node.id = packet.read_int32() player_node.map = packet.read_string(16) mapip = utils.parse_ip(packet.read_int32()) mapport = packet.read_int16() char.close() break if mapip: break assert mapport beingManager.container[player_node.id] = Being(player_node.id, 42) mapserv = socket.socket() mapserv.connect((mapip, mapport)) logging.info("Map connected") mapserv_login_packet = PacketOut(CMSG_MAP_SERVER_CONNECT) mapserv_login_packet.write_int32(accid) mapserv_login_packet.write_int32(player_node.id) mapserv_login_packet.write_int32(id1) mapserv_login_packet.write_int32(id2) mapserv_login_packet.write_int8(player_node.sex) mapserv.sendall(str(mapserv_login_packet)) mapserv.recv(4) pb = PacketBuffer() shop_broadcaster.mapserv = mapserv # Map server packet loop while True: data = mapserv.recv(2048) if not data: break pb.feed(data) # For unfinished trades - one way to distrupt service would be leaving a trade active. if trader_state.Trading.test(): if time.time() - trader_state.timer > 5*60: logging.info("Trade Cancelled - Timeout.") trader_state.timer = time.time() mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) for packet in pb: if packet.is_type(SMSG_MAP_LOGIN_SUCCESS): # connected logging.info("Map login success.") packet.skip(4) coord_data = packet.read_coord_dir() player_node.x = coord_data[0] player_node.y = coord_data[1] player_node.direction = coord_data[2] logging.info("Starting Postion: %s %s %s", player_node.map, player_node.x, player_node.y) mapserv.sendall(str(PacketOut(CMSG_MAP_LOADED))) # map loaded # A Thread to send a shop broadcast: also keeps the network active to prevent timeouts. shop_broadcaster.start() elif packet.is_type(SMSG_WHISPER): msg_len = packet.read_int16() - 26 nick = packet.read_string(24) message = packet.read_raw_string(msg_len) logging.info("Whisper: " + nick + ": " + message) if nick != "guild": process_whisper(nick, utils.remove_colors(message), mapserv) elif packet.is_type(SMSG_PLAYER_STAT_UPDATE_1): stat_type = packet.read_int16() value = packet.read_int32() if stat_type == 0x0018: logging.info("Weight changed from %s/%s to %s/%s", \ player_node.WEIGHT, player_node.MaxWEIGHT, value, player_node.MaxWEIGHT) player_node.WEIGHT = value elif stat_type == 0x0019: logging.info("Max Weight: %s", value) player_node.MaxWEIGHT = value elif packet.is_type(SMSG_PLAYER_STAT_UPDATE_2): stat_type = packet.read_int16() value = packet.read_int32() if stat_type == 0x0014: logging.info("Money Changed from %s, to %s", player_node.MONEY, value) player_node.MONEY = value elif packet.is_type(SMSG_BEING_MOVE) or packet.is_type(SMSG_BEING_VISIBLE)\ or packet.is_type(SMSG_PLAYER_MOVE) or packet.is_type(SMSG_PLAYER_UPDATE_1)\ or packet.is_type(SMSG_PLAYER_UPDATE_2): being_id = packet.read_int32() packet.skip(8) job = packet.read_int16() if being_id not in beingManager.container: if job == 0 and id >= 110000000 and (packet.is_type(SMSG_BEING_MOVE)\ or packet.is_type(SMSG_BEING_VISIBLE)): continue # Add the being to the BeingManager, and request name. beingManager.container[being_id] = Being(being_id, job) requestName = PacketOut(0x0094) requestName.write_int32(being_id) mapserv.sendall(str(requestName)) elif packet.is_type(SMSG_BEING_NAME_RESPONSE): being_id = packet.read_int32() if being_id in beingManager.container: beingManager.container[being_id].name = packet.read_string(24) elif packet.is_type(SMSG_BEING_REMOVE): being_id = packet.read_int32() if being_id in beingManager.container: del beingManager.container[being_id] elif packet.is_type(SMSG_PLAYER_WARP): player_node.map = packet.read_string(16) player_node.x = packet.read_int16() player_node.y = packet.read_int16() logging.info("Player warped: %s %s %s", player_node.map, player_node.x, player_node.y) mapserv.sendall(str(PacketOut(CMSG_MAP_LOADED))) elif packet.is_type(SMSG_PLAYER_INVENTORY_ADD): item = Item() item.index = packet.read_int16() - inventory_offset item.amount = packet.read_int16() item.itemId = packet.read_int16() item.identified = packet.read_int8() packet.read_int8() item.refine = packet.read_int8() packet.skip(8) item.equipType = packet.read_int16() item.itemType = packet.read_int8() err = packet.read_int8() if err == 0: if item.index in player_node.inventory: player_node.inventory[item.index].amount += item.amount else: player_node.inventory[item.index] = item logging.info("Picked up: %s, Amount: %s", ItemDB.getItem(item.itemId).name, str(item.amount)) elif packet.is_type(SMSG_PLAYER_INVENTORY_REMOVE): index = packet.read_int16() - inventory_offset amount = packet.read_int16() logging.info("Remove item: %s, Amount: %s", ItemDB.getItem(player_node.inventory[index].itemId).name, str(amount)) if index in player_node.inventory: player_node.inventory[index].amount -= amount if player_node.inventory[index].amount == 0: del player_node.inventory[index] elif packet.is_type(SMSG_PLAYER_INVENTORY): player_node.inventory.clear() # Clear the inventory - incase of new index. packet.skip(2) number = (len(packet.data)-2) / 18 for loop in range(number): item = Item() item.index = packet.read_int16() - inventory_offset item.itemId = packet.read_int16() item.itemType = packet.read_int8() item.identified = packet.read_int8() item.amount = packet.read_int16() item.arrow = packet.read_int16() packet.skip(8) # Cards player_node.inventory[item.index] = item elif packet.is_type(SMSG_PLAYER_EQUIPMENT): packet.read_int16() number = (len(packet.data)) / 20 for loop in range(number): item = Item() item.index = packet.read_int16() - inventory_offset item.itemId = packet.read_int16() item.itemType = packet.read_int8() item.identified = packet.read_int8() packet.skip(2) item.equipType = packet.read_int16() packet.skip(1) item.refine = packet.read_int8() packet.skip(8) item.amount = 1 player_node.inventory[item.index] = item logging.info("Inventory information received:") for item in player_node.inventory: logging.info("Name: %s, Id: %s, Index: %s, Amount: %s.", \ ItemDB.getItem(player_node.inventory[item].itemId).name, \ player_node.inventory[item].itemId, item, player_node.inventory[item].amount) elif packet.is_type(SMSG_TRADE_REQUEST): name = packet.read_string(24) logging.info("Trade request: " + name) elif packet.is_type(SMSG_TRADE_RESPONSE): response = packet.read_int8() time.sleep(0.2) if response == 0: logging.info("Trade response: Too far away.") if trader_state.item: mapserv.sendall(whisper(trader_state.item.player, "You are too far away.")) elif trader_state.money: mapserv.sendall(whisper(trader_state.money, "You are too far away.")) trader_state.reset() elif response == 3: logging.info("Trade response: Trade accepted.") if trader_state.item: if trader_state.item.get == 1: # add mapserv.sendall(str(PacketOut(CMSG_TRADE_ADD_COMPLETE))) elif trader_state.item.get == 0: # buy if player_node.find_inventory_index(trader_state.item.id) != -10: mapserv.sendall(trade_add_item(player_node.find_inventory_index(trader_state.item.id), trader_state.item.amount)) mapserv.sendall(str(PacketOut(CMSG_TRADE_ADD_COMPLETE))) if trader_state.item.price == 0: # getback mapserv.sendall(str(PacketOut(CMSG_TRADE_OK))) trader_state.complete = 1 elif trader_state.money: # money amount = int(user_tree.get_user(trader_state.money).get('money')) mapserv.sendall(trade_add_item(0-inventory_offset, amount)) mapserv.sendall(str(PacketOut(CMSG_TRADE_ADD_COMPLETE))) mapserv.sendall(str(PacketOut(CMSG_TRADE_OK))) trader_state.complete = 1 else: logging.info("Trade response: Trade cancelled") trader_state.reset() elif packet.is_type(SMSG_TRADE_ITEM_ADD): amount = packet.read_int32() item_id = packet.read_int16() if trader_state.item and trader_state.money == 0: if trader_state.item.get == 1: # add if amount == trader_state.item.amount and item_id == trader_state.item.id: trader_state.complete = 1 mapserv.sendall(str(PacketOut(CMSG_TRADE_OK))) else: mapserv.sendall(whisper(trader_state.item.player, "Thats not the right item.")) mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) elif trader_state.item.get == 0: # buy if amount == trader_state.item.price * trader_state.item.amount and item_id == 0: mapserv.sendall(str(PacketOut(CMSG_TRADE_OK))) trader_state.complete = 1 elif item_id == 0 and amount != trader_state.item.price * trader_state.item.amount: trader_state.complete = 0 else: if item_id == 0: mapserv.sendall(whisper(trader_state.item.player, "Please verify you have the correct amount of money and try again.")) else: mapserv.sendall(whisper(trader_state.item.player, "Don't give me your itenz.")) mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) elif trader_state.money: # money mapserv.sendall(whisper(trader_state.money, "Don't give me your itenz.")) mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) logging.info("Trade item add: ItemId:%s Amount:%s", item_id, amount) # Note item_id = 0 is money elif packet.is_type(SMSG_TRADE_ITEM_ADD_RESPONSE): index = packet.read_int16() - inventory_offset amount = packet.read_int16() response = packet.read_int8() if response == 0: logging.info("Trade item add response: Successfully added item.") if trader_state.item: if trader_state.item.get == 0 and index != 0-inventory_offset: # Make sure the correct item is given! if player_node.inventory[index].itemId != trader_state.item.id or \ amount != trader_state.item.amount: mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) # If Trade item add successful - Remove the item from the inventory state. if index != 0-inventory_offset: # If it's not money logging.info("Remove item: %s, Amount: %s", ItemDB.getItem(player_node.inventory[index].itemId).name, str(amount)) if index in player_node.inventory: player_node.inventory[index].amount -= amount if player_node.inventory[index].amount == 0: del player_node.inventory[index] elif response == 1: logging.info("Trade item add response: Failed - player overweight.") mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) if trader_state.item: mapserv.sendall(whisper(trader_state.item.player, "You are carrying too much weight. Unload and try again.")) elif response == 2: if trader_state.item: mapserv.sendall(whisper(trader_state.item.player, "You have no free slots.")) logging.info("Trade item add response: Failed - No free slots.") mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) elif packet.is_type(SMSG_TRADE_OK): is_ok = packet.read_int8() # 0 is ok from self, and 1 is ok from other if is_ok == 0: logging.info("Trade OK: Self.") else: if trader_state.complete: mapserv.sendall(str(PacketOut(CMSG_TRADE_OK))) else: mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST))) mapserv.sendall(whisper(trader_state.item.player, "Trade Cancelled: Please check the traded items or money.")) logging.info("Trade Ok: Partner.") elif packet.is_type(SMSG_TRADE_CANCEL): trader_state.reset() logging.info("Trade Cancel.") elif packet.is_type(SMSG_TRADE_COMPLETE): commitMessage="" # The sale_tree is only ammended after a complete trade packet. if trader_state.item and trader_state.money == 0: if trader_state.item.get == 1: # !add sale_tree.add_item(trader_state.item.player, trader_state.item.id, trader_state.item.amount, trader_state.item.price) user_tree.get_user(trader_state.item.player).set('used_stalls', \ str(int(user_tree.get_user(trader_state.item.player).get('used_stalls')) + 1)) commitMessage = "Add" elif trader_state.item.get == 0: # !buy \ !getback seller = sale_tree.get_uid(trader_state.item.uid).get('name') item = sale_tree.get_uid(trader_state.item.uid) current_amount = int(item.get("amount")) sale_tree.get_uid(trader_state.item.uid).set("amount", str(current_amount - trader_state.item.amount)) if int(item.get("amount")) == 0: user_tree.get_user(sale_tree.get_uid(trader_state.item.uid).get('name')).set('used_stalls', \ str(int(user_tree.get_user(sale_tree.get_uid(trader_state.item.uid).get('name')).get('used_stalls'))-1)) sale_tree.remove_item_uid(trader_state.item.uid) current_money = int(user_tree.get_user(seller).get("money")) user_tree.get_user(seller).set("money", str(current_money + trader_state.item.price * trader_state.item.amount)) if trader_state.item.price * trader_state.item.amount != 0: ItemLog.add_item(int(item.get('itemId')), trader_state.item.amount, trader_state.item.price * trader_state.item.amount) commitMessage = "Buy or Getback" elif trader_state.money and trader_state.item == 0: # !money user_tree.get_user(trader_state.money).set('money', str(0)) commitMessage = "Money" sale_tree.save() user_tree.save() tradey.saveData(commitMessage) trader_state.reset() logging.info("Trade Complete.") else: pass # On Disconnect/Exit shop_broadcaster.stop() mapserv.close() if __name__ == '__main__': main()