main.py 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274
  1. #!/usr/bin/python
  2. """
  3. Copyright 2011, Dipesh Amin <yaypunkrock@gmail.com>
  4. Copyright 2011, Stefan Beller <stefanbeller@googlemail.com>
  5. This file is part of tradey, a trading bot in The Mana World
  6. see www.themanaworld.org
  7. This program is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2 of the License, or (at your option)
  10. any later version.
  11. This program is distributed in the hope that it will be useful, but WITHOUT
  12. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. more details.
  15. You should have received a copy of the GNU General Public License along with
  16. this program. If not, see <http://www.gnu.org/licenses/>.
  17. Additionally to the GPL, you are *strongly* encouraged to share any modifications
  18. you do on these sources.
  19. """
  20. import logging
  21. import logging.handlers
  22. import socket
  23. import sys
  24. import time
  25. import string
  26. try:
  27. import config
  28. except:
  29. print "no config file found. please move config.py.template to config.py and edit to your needs!"
  30. sys.exit(0);
  31. from being import *
  32. from net.packet import *
  33. from net.protocol import *
  34. from net.packet_out import *
  35. from player import *
  36. import tradey
  37. import utils
  38. import eliza
  39. from onlineusers import SqliteDbManager
  40. from ircbot import IRCBot
  41. from sdnotify import SystemdNotifier
  42. chatbot = eliza.eliza()
  43. shop_broadcaster = utils.Broadcast()
  44. trader_state = utils.TraderState()
  45. ItemDB = utils.ItemDB()
  46. player_node = Player('')
  47. beingManager = BeingManager()
  48. user_tree = tradey.UserTree()
  49. sale_tree = tradey.ItemTree()
  50. ItemLog = utils.ItemLog()
  51. logger = logging.getLogger('ManaLogger')
  52. db_manager = SqliteDbManager(config.sqlite3_dbfile)
  53. ircbot = IRCBot()
  54. sd = SystemdNotifier()
  55. # How long to wait between WATCHDOG=1 systemd keepalives, in seconds
  56. sd_min_keepalive_rate = 5
  57. def process_whisper(nick, msg, mapserv):
  58. msg = filter(lambda x: x in utils.allowed_chars, msg)
  59. if len(msg) == 0:
  60. return
  61. # Infinite chat loop anyone?
  62. if nick == "guild":
  63. return
  64. user = user_tree.get_user(nick)
  65. broken_string = msg.split()
  66. if len(broken_string) == 0:
  67. return
  68. if user != -10:
  69. if int(user.get("accesslevel")) == -1: # A user who has been blocked for abuse.
  70. if int(user.get("used_stalls")) == 0 and int(user.get("money")) == 0:
  71. mapserv.sendall(whisper(nick, "You can no longer use the bot. If you feel this is in error, please contact" + config.admin))
  72. return
  73. allowed_commands = ['!money', '!help', '!getback', '!info' ]
  74. if not broken_string[0] in allowed_commands:
  75. mapserv.sendall(whisper(nick, "Your access level has been set to blocked! If you feel this is in error, please contact" + config.admin))
  76. mapserv.sendall(whisper(nick, "Though, you still can do the following: "+str(allowed_commands)))
  77. return
  78. if msg == "!list":
  79. # Sends the list of items for sale.
  80. if len(sale_tree.root) != 0:
  81. mapserv.sendall(whisper(nick, "The following items are on sale:"))
  82. else:
  83. mapserv.sendall(whisper(nick, "No items for sale."))
  84. for elem in sale_tree.root:
  85. if time.time() - float(elem.get('add_time')) < config.relist_time: # Check if an items time is up.
  86. msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + \
  87. elem.get("itemId") + "|" + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each"
  88. mapserv.sendall(whisper(nick, msg))
  89. elif broken_string[0] == '!selllist':
  90. # Support for 4144's shop (Sell list)
  91. data = '\302\202B1'
  92. for elem in sale_tree.root:
  93. if time.time() - float(elem.get('add_time')) < config.relist_time:
  94. data += utils.encode_str(int(elem.get("itemId")), 2)
  95. data += utils.encode_str(int(elem.get("price")), 4)
  96. data += utils.encode_str(int(elem.get("amount")), 3)
  97. mapserv.sendall(whisper(nick, data))
  98. elif broken_string[0] == '!buyitem':
  99. # 4144 buy command
  100. if len(broken_string) == 4:
  101. if broken_string[1].isdigit() and broken_string[2].isdigit() and broken_string[3].isdigit():
  102. # Traditional 4144 shop.
  103. item_id = int(broken_string[1])
  104. price = int(broken_string[2])
  105. amount = int(broken_string[3])
  106. for elem in sale_tree.root:
  107. if int(elem.get('amount')) >= amount and int(elem.get('price')) == price and int(elem.get('itemId')) == item_id:
  108. process_whisper(nick, '!buy ' + str(amount) + " " + elem.get('uid'), mapserv)
  109. return
  110. mapserv.sendall(whisper(nick, "Item not found. Please check and try again."))
  111. else:
  112. mapserv.sendall(whisper(nick, "Syntax incorrect"))
  113. elif msg == "!info":
  114. # Send information related to a player.
  115. if user == -10:
  116. mapserv.sendall(whisper(nick, "Your current access level is 0. Request access in [@@https://forums.themanaworld.org/viewtopic.php?f=14&t=14010|ManaMarket's forum thread@@]"))
  117. elif int(user.get('accesslevel')) > 0:
  118. mapserv.sendall(whisper(nick, "Your current access level is " + user.get('accesslevel') + "."))
  119. items_for_sale = False
  120. for elem in sale_tree.root:
  121. if elem.get('name') == nick:
  122. if time.time() - float(elem.get('add_time')) > config.relist_time:
  123. msg = "[expired] ["
  124. else:
  125. msg = "[selling] ["
  126. msg += elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" + \
  127. ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each"
  128. if items_for_sale == False:
  129. mapserv.sendall(whisper(nick, "Your have the following items for sale:"))
  130. items_for_sale = True
  131. mapserv.sendall(whisper(nick, msg))
  132. if items_for_sale == False:
  133. mapserv.sendall(whisper(nick, "You have no items for sale."))
  134. money = int(user.get('money'))
  135. mapserv.sendall(whisper(nick, "You have " + str(money) + "gp to collect."))
  136. stall_msg = "You have " + str(int(user.get('stalls')) - int(user.get('used_stalls'))) + " free slots."
  137. mapserv.sendall(whisper(nick, stall_msg))
  138. elif broken_string[0] == "!help":
  139. # Sends help information
  140. if len(broken_string) == 1:
  141. mapserv.sendall(whisper(nick, "Welcome to ManaMarket!"))
  142. mapserv.sendall(whisper(nick, "The basic commands for the bot are: !list, !find <id> or <Item Name>, !buy <amount> <uid>, !add <amount> <price> <Item Name>, !money, !relist <uid>, !info, !getback <uid> "))
  143. mapserv.sendall(whisper(nick, "For a detailed description of each command, type !help <command> e.g. !help !buy"))
  144. mapserv.sendall(whisper(nick, "For example to purchase an item shown in the list as:"))
  145. mapserv.sendall(whisper(nick, "[selling] [6] 5 [@@640|Iron Ore@@] for 1000gp each"))
  146. mapserv.sendall(whisper(nick, "you would type /whisper ManaMarket !buy 1 6" ))
  147. mapserv.sendall(whisper(nick, "This will purchase one of item 6 (Iron Ore)."))
  148. if user != -10:
  149. if int(user.get('accesslevel')) >= 5:
  150. mapserv.sendall(whisper(nick,"---"))
  151. mapserv.sendall(whisper(nick, "Ah, you have sellers access level. How lovely!")) # the first words the ticket seller told me when i was in london for the first time. How lovely!
  152. mapserv.sendall(whisper(nick, "Use !add to tell me which items I should trade for you:"))
  153. mapserv.sendall(whisper(nick, "For example !add 10 1000 Iron Ore would tell me to sell 10 [@@640|Iron Ore@@] for a price of 1000 gp"))
  154. mapserv.sendall(whisper(nick, "Later you can whisper me !money to get back your money. In the example given, I'd give you 10*1000 = 10000gp"))
  155. mapserv.sendall(whisper(nick, "When you just want to know, which items you have given me or how much money I have for you can whisper me !info"))
  156. mapserv.sendall(whisper(nick,"If you want to get back an unsold item, whisper me !getback <uid>"))
  157. if int(user.get('accesslevel')) == 20:
  158. mapserv.sendall(whisper(nick, "You're my master! How should I serve you?"))
  159. mapserv.sendall(whisper(nick, "You also have access to the following commands: !listusers, !setslots <slots> <name>, !setaccess <access level > <name>, !adduser <access level> <slot> <name>"))
  160. elif len(broken_string) == 2:
  161. if broken_string[1] == '!buy':
  162. mapserv.sendall(whisper(nick, "!buy <amount> <uid> - Request the purchase of an item or items."))
  163. elif broken_string[1] == '!list':
  164. mapserv.sendall(whisper(nick, "!list - Displays a list of all items for sale."))
  165. elif broken_string[1] == '!find':
  166. mapserv.sendall(whisper(nick, "!find <id> or <Item Name> - Simple search to locate an item."))
  167. elif broken_string[1] == '!add':
  168. mapserv.sendall(whisper(nick, "!add <amount> <price> <Item Name> - Add an item to the sell list (requires that you have an account)."))
  169. elif broken_string[1] == '!money':
  170. mapserv.sendall(whisper(nick, "!money - Allows you to collect money for any sales made on your behalf."))
  171. elif broken_string[1] == '!relist':
  172. mapserv.sendall(whisper(nick, "!relist <uid> - Allows you to relist an item which has expired."))
  173. elif broken_string[1] == '!info':
  174. mapserv.sendall(whisper(nick, "!info - Displays basic information about your account."))
  175. elif broken_string[1] == '!getback':
  176. mapserv.sendall(whisper(nick, "!getback <uid> - Allows you to retrieve an item that has expired or you no longer wish to sell."))
  177. elif broken_string[1] == '!lastseen':
  178. mapserv.sendall(whisper(nick, "!lastseen <nick> - Show when <nick> was online the last time."))
  179. elif broken_string[1] == '!mail':
  180. mapserv.sendall(whisper(nick, "!mail <nick> <message> - Send a message to <nick>."))
  181. elif broken_string[1] == '!irc':
  182. mapserv.sendall(whisper(nick, "!irc <on|off> - Enable/disable IRC mode (the channel is also bridged to Discord)."))
  183. elif user != -10:
  184. if int(user.get('accesslevel')) >= 10 and broken_string[1] == '!listusers':
  185. mapserv.sendall(whisper(nick, "!listusers - Lists all users which have a special accesslevel, e.g. they are blocked, seller or admin"))
  186. elif int(user.get('accesslevel')) >= 10 and broken_string[1] == '!adduser':
  187. mapserv.sendall(whisper(nick, "!adduser <access level> <slots> <name> - Add a user to the bot, a seller should be added with access level 5."))
  188. elif int(user.get('accesslevel')) == 20 and broken_string[1] == '!setslots':
  189. mapserv.sendall(whisper(nick, "!setslots <slots> <name> - Sets the number of slots available to a given user."))
  190. elif int(user.get('accesslevel')) == 20 and broken_string[1] == '!setaccess':
  191. mapserv.sendall(whisper(nick, "!setaccess <access level> <name> - Sets access level for the player: -1 is blocked, 5 is seller and 20 is admin" ))
  192. elif msg == "!money":
  193. # Trades any money earned through item sales.
  194. if user == -10:
  195. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  196. return
  197. amount = int(user.get('money'))
  198. if amount == 0:
  199. mapserv.sendall(whisper(nick, "You have no money to collect."))
  200. else:
  201. if not trader_state.Trading.testandset():
  202. mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly"))
  203. return
  204. trader_state.money = nick
  205. player_id = beingManager.findId(nick)
  206. if player_id != -10:
  207. mapserv.sendall(trade_request(player_id))
  208. trader_state.timer = time.time()
  209. else:
  210. mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!"))
  211. trader_state.reset()
  212. elif broken_string[0] == "!find":
  213. # Returns a list of items, with the corresponding Item Id - !find <id> or <item name>.
  214. if len(broken_string) < 2:
  215. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  216. return
  217. items_found = False
  218. item = " ".join(broken_string[1:]) # could be an id or an item name
  219. if item.isdigit(): # an id
  220. for elem in sale_tree.root:
  221. if ((time.time() - float(elem.get('add_time'))) < config.relist_time) \
  222. and int(elem.get("itemId")) == int(item): # Check if an items time is up.
  223. msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \
  224. + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each"
  225. mapserv.sendall(whisper(nick, msg))
  226. items_found = True
  227. else: # an item name
  228. for elem in sale_tree.root:
  229. if ((time.time() - float(elem.get('add_time'))) < config.relist_time) \
  230. and item.lower() in ItemDB.getItem(int(elem.get("itemId"))).name.lower(): # Check if an items time is up.
  231. msg = "[selling] [" + elem.get("uid") + "] " + elem.get("amount") + " [@@" + elem.get("itemId") + "|" \
  232. + ItemDB.getItem(int(elem.get("itemId"))).name + "@@] for " + elem.get("price") + "gp each"
  233. mapserv.sendall(whisper(nick, msg))
  234. items_found = True
  235. if not items_found:
  236. mapserv.sendall(whisper(nick, "Item not found."))
  237. elif msg == '!tradestate':
  238. # Admin command - return trade state.
  239. if user == -10:
  240. return
  241. if int(user.get("accesslevel")) != 20:
  242. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  243. return
  244. if trader_state.Trading.test():
  245. mapserv.sendall(whisper(nick, "I'm busy with a trade."))
  246. else:
  247. mapserv.sendall(whisper(nick, "I'm free."))
  248. elif broken_string[0] == '!identify':
  249. if user == -10:
  250. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  251. return
  252. elif len(broken_string) != 2:
  253. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  254. return
  255. elif int(user.get("accesslevel")) < 10:
  256. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  257. return
  258. if broken_string[1].isdigit():
  259. uid = int(broken_string[1])
  260. item_info = sale_tree.get_uid(uid)
  261. if item_info == -10:
  262. mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again."))
  263. return
  264. weight = ItemDB.item_names[int(item_info.get('itemId'))].weight*int(item_info.get("amount"))
  265. mapserv.sendall(whisper(nick, "That item/s belongs to: "+item_info.get("name")))
  266. mapserv.sendall(whisper(nick, "The weight used is: "+str(weight)+"/"+str(player_node.MaxWEIGHT)))
  267. elif msg == '!listusers':
  268. # Admin command - shows a list of all user.
  269. if user == -10:
  270. return
  271. if int(user.get("accesslevel")) < 10:
  272. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  273. return
  274. data = ''
  275. total_money = 0
  276. total_slots_reserved = 0
  277. total_slots_used = 0
  278. no_users = 0
  279. for user in user_tree.root:
  280. no_users += 1
  281. name = user.get('name')
  282. accesslevel = user.get('accesslevel')
  283. slots = user.get('stalls')
  284. total_slots_reserved += int(slots)
  285. used_slots = user.get('used_stalls')
  286. total_slots_used += int(used_slots)
  287. money = user.get('money')
  288. total_money += int(money)
  289. data += name+" ("+accesslevel+") "+used_slots+"/"+slots+" "+money+'gp, '
  290. # Format ManaMarket (20) 2/5 100000gp,
  291. if len(data) > 400:
  292. mapserv.sendall(whisper(nick, data[0:len(data)-2]+"."))
  293. data = ''
  294. if len(data) > 0:
  295. mapserv.sendall(whisper(nick, data[0:len(data)-2]+"."))
  296. mapserv.sendall(whisper(nick,"Number of users:"+str(no_users)+ ", Sale slots used: "+ \
  297. str(total_slots_used)+"/"+str(total_slots_reserved)+ ", Total Money: "+str(total_money)+\
  298. ", Char slots used: "+str(len(player_node.inventory))+", Weight Used: "+\
  299. str(player_node.WEIGHT)+"/"+str(player_node.MaxWEIGHT)))
  300. elif broken_string[0] == '!setslots':
  301. # Change the number of slots a user has - !setslots <slots> <name>
  302. if user == -10:
  303. return
  304. if int(user.get("accesslevel")) != 20:
  305. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  306. return
  307. if len(broken_string) < 3:
  308. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  309. return
  310. if broken_string[1].isdigit():
  311. slot = int(broken_string[1])
  312. name = " ".join(broken_string[2:])
  313. user_info = user_tree.get_user(name)
  314. if user_info == -10:
  315. mapserv.sendall(whisper(nick, "User not found, check and try again."))
  316. return
  317. user_tree.get_user(name).set('stalls', str(slot))
  318. mapserv.sendall(whisper(nick, "Slots changed: "+name+" "+str(slot)))
  319. tradey.saveData("User: "+name+", Slots changed: "+str(slot))
  320. user_tree.save()
  321. else:
  322. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  323. elif broken_string[0] == '!setaccess':
  324. # Change someones access level - !setaccess <access level> <name>
  325. if user == -10:
  326. return
  327. if int(user.get("accesslevel")) != 20:
  328. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  329. return
  330. if len(broken_string) < 3:
  331. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  332. return
  333. if (broken_string[1][0] == '-' and broken_string[1][1:].isdigit()) or broken_string[1].isdigit():
  334. accesslevel = int(broken_string[1])
  335. name = " ".join(broken_string[2:])
  336. user_info = user_tree.get_user(name)
  337. if user_info == -10:
  338. mapserv.sendall(whisper(nick, "User not found, check and try again."))
  339. return
  340. if int(user_info.get('accesslevel')) < int(user.get("accesslevel")) and accesslevel <= int(user.get("accesslevel")):
  341. user_tree.get_user(name).set('accesslevel', str(accesslevel))
  342. mapserv.sendall(whisper(nick, "Access level changed:"+name+ " ("+str(accesslevel)+")."))
  343. user_tree.save()
  344. tradey.saveData("User: "+name+", Set Access Level: "+str(accesslevel))
  345. else:
  346. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  347. return
  348. else:
  349. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  350. elif broken_string[0] == "!adduser":
  351. # A command to give a user access to the bot - !adduser <access level> <stall> <player name>.
  352. if user == -10:
  353. return
  354. if int(user.get("accesslevel")) < 10:
  355. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  356. return
  357. if len(broken_string) < 3:
  358. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  359. return
  360. if broken_string[1].isdigit() and broken_string[2].isdigit():
  361. if int(broken_string[1]) > user.get("accesslevel"):
  362. mapserv.sendall(whisper(nick, "You can't give someone a higher accesslevel than your own."))
  363. return
  364. al = int(broken_string[1])
  365. stalls = int(broken_string[2])
  366. player_name = " ".join(broken_string[3:])
  367. pl_user = user_tree.get_user(player_name)
  368. if pl_user == -10:
  369. user_tree.add_user(player_name, stalls, al)
  370. mapserv.sendall(whisper(nick, "User Added with " + str(stalls) + " slots."))
  371. tradey.saveData("User Added: "+player_name+", Slots: "+str(stalls)+", Access Level: "+str(al))
  372. else:
  373. pl_user.set("accesslevel", str(al))
  374. pl_user.set("stalls", str(stalls))
  375. mapserv.sendall(whisper(nick, "User Added with " + str(stalls) + " slots."))
  376. tradey.saveData("User Added: "+player_name+", Slots: "+str(stalls)+", Access Level: "+str(al))
  377. else:
  378. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  379. elif broken_string[0] == "!add":
  380. # Allows a player with the correct permissions to add an item for sale - !add <amount> <price> <item name>
  381. if user == -10:
  382. mapserv.sendall(whisper(nick, "You are unable to add items. Request access in [@@https://forums.themanaworld.org/viewtopic.php?f=14&t=14010|ManaMarket's forum thread@@]"))
  383. return
  384. if len(broken_string) < 3:
  385. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  386. return
  387. if int(user.get("accesslevel")) < 5:
  388. mapserv.sendall(whisper(nick, "You are unable to add items."))
  389. return
  390. if int(user.get("used_stalls")) >= int(user.get("stalls")):
  391. mapserv.sendall(whisper(nick, "You have no free slots. You may remove an item or wait for something to be sold."))
  392. return
  393. if broken_string[1].isdigit() and broken_string[2].isdigit():
  394. amount = int(broken_string[1])
  395. price = int(broken_string[2])
  396. item_name = " ".join(broken_string[3:])
  397. item_id = ItemDB.findId(item_name)
  398. weight = ItemDB.item_names[item_id].weight*amount
  399. if item_id == -10:
  400. mapserv.sendall(whisper(nick, "Item not found, check spelling."))
  401. return
  402. elif item_id in config.nosell:
  403. mapserv.sendall(whisper(nick, "That item can't be added to ManaMarket, as its too heavy."))
  404. return
  405. elif int(weight) + player_node.WEIGHT > player_node.MaxWEIGHT:
  406. mapserv.sendall(whisper(nick, "I've not got enough room left to carry those. Please try again later. "))
  407. return
  408. elif ItemDB.item_names[item_id].weight > 10 and amount > 150:
  409. mapserv.sendall(whisper(nick, "Sorry, as each of those items weighs more than 10g you can only add a maximum quantity of 150."))
  410. return
  411. if amount > 1 and ItemDB.getItem(item_id).type != 'equip-ammo' and 'equip' in ItemDB.getItem(item_id).type:
  412. mapserv.sendall(whisper(nick, "You can only add one piece of equipment per slot."))
  413. return
  414. elif price == 0 or price > 50000000:
  415. mapserv.sendall(whisper(nick, "Please use a valid price between 1-50000000gp."))
  416. return
  417. elif amount == 0:
  418. mapserv.sendall(whisper(nick, "You can't add 0 of an item."))
  419. return
  420. item = Item()
  421. item.player = nick
  422. item.get = 1 # 1 = get, 0 = give
  423. item.id = item_id
  424. item.amount = amount
  425. item.price = price
  426. if not trader_state.Trading.testandset():
  427. mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly"))
  428. return
  429. trader_state.item = item
  430. player_id = beingManager.findId(nick)
  431. if player_id != -10:
  432. mapserv.sendall(trade_request(player_id))
  433. trader_state.timer = time.time()
  434. else:
  435. mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!"))
  436. trader_state.reset()
  437. else:
  438. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  439. elif broken_string[0] == "!buy":
  440. # Buy a given quantity of an item - !buy <amount> <uid>
  441. if len(broken_string) != 3:
  442. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  443. return
  444. if broken_string[1].isdigit() and broken_string[2].isdigit():
  445. amount = int(broken_string[1])
  446. uid = int(broken_string[2])
  447. item_info = sale_tree.get_uid(uid)
  448. if item_info == -10:
  449. mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again."))
  450. return
  451. if amount > int(item_info.get("amount")):
  452. mapserv.sendall(whisper(nick, "I do not have that many."))
  453. return
  454. if item_info.get("name") == nick:
  455. mapserv.sendall(whisper(nick, "You can not buy your own items. To get back the item whisper me !getback "+broken_string[2]))
  456. return
  457. item = Item()
  458. item.get = 0 # 1 = get, 0 = give
  459. item.player = nick
  460. item.id = int(item_info.get("itemId"))
  461. item.uid = uid
  462. item.amount = amount
  463. item.price = int(item_info.get("price"))
  464. if not trader_state.Trading.testandset():
  465. mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly"))
  466. return
  467. trader_state.item = item
  468. player_id = beingManager.findId(nick)
  469. if player_id != -10:
  470. mapserv.sendall(trade_request(player_id))
  471. trader_state.timer = time.time()
  472. mapserv.sendall(whisper(nick, "That will be " + str(item.price * item.amount) + "gp."))
  473. else:
  474. mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!"))
  475. trader_state.reset()
  476. else:
  477. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  478. elif broken_string[0] == "!removeuser":
  479. # Remove a user, for whatever reason - !removeuser <player name>
  480. if user == -10:
  481. return
  482. if len(broken_string) < 2:
  483. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  484. return
  485. if int(user.get("accesslevel")) != 20:
  486. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  487. return
  488. player_name = " ".join(broken_string[1:])
  489. check = user_tree.remove_user(player_name)
  490. if check == 1:
  491. mapserv.sendall(whisper(nick, "User Removed."))
  492. tradey.saveData("User Removed: "+player_name)
  493. elif check == -10:
  494. mapserv.sendall(whisper(nick, "User removal failed. Please check spelling."))
  495. elif broken_string[0] == "!relist":
  496. # Relist an item which has expired - !relist <uid>.
  497. if user == -10 or len(broken_string) != 2:
  498. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  499. return
  500. if int(user.get("accesslevel")) < 5:
  501. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  502. return
  503. if broken_string[1].isdigit():
  504. uid = int(broken_string[1])
  505. item_info = sale_tree.get_uid(uid)
  506. if item_info == -10:
  507. mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again."))
  508. return
  509. if item_info.get('name') != nick:
  510. mapserv.sendall(whisper(nick, "That doesn't belong to you!"))
  511. return
  512. time_relisted = int(item_info.get('relisted'))
  513. if int(item_info.get('relisted')) < 3:
  514. sale_tree.get_uid(uid).set('add_time', str(time.time()))
  515. sale_tree.get_uid(uid).set('relisted', str(time_relisted + 1))
  516. sale_tree.save()
  517. mapserv.sendall(whisper(nick, "The item has been successfully relisted."))
  518. user_tree.get_user(nick).set('last_use', str(time.time()))
  519. user_tree.save()
  520. else:
  521. mapserv.sendall(whisper(nick, "This item can no longer be relisted. Please collect it using !getback "+str(uid)+"."))
  522. return
  523. else:
  524. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  525. elif broken_string[0] == "!getback":
  526. # Trade the player back uid, remove from sale_items if trade successful - !getback <uid>.
  527. if user == -10 or len(broken_string) != 2:
  528. mapserv.sendall(whisper(nick, "Syntax incorrect."))
  529. return
  530. if int(user.get("accesslevel")) < 5 and int(user.get("accesslevel")) > 0:
  531. mapserv.sendall(whisper(nick, "You don't have the correct permissions."))
  532. return
  533. if broken_string[1].isdigit():
  534. uid = int(broken_string[1])
  535. item_info = sale_tree.get_uid(uid)
  536. if item_info == -10:
  537. mapserv.sendall(whisper(nick, "Item not found. Please check the uid number and try again."))
  538. return
  539. if item_info.get('name') != nick:
  540. mapserv.sendall(whisper(nick, "That doesn't belong to you!"))
  541. return
  542. item = Item()
  543. item.get = 0
  544. item.player = nick
  545. item.id = int(item_info.get("itemId"))
  546. item.uid = uid
  547. item.amount = int(item_info.get("amount"))
  548. item.price = 0
  549. if not trader_state.Trading.testandset():
  550. mapserv.sendall(whisper(nick, "I'm currently busy with a trade. Try again shortly"))
  551. return
  552. trader_state.item = item
  553. player_id = beingManager.findId(nick)
  554. if player_id != -10:
  555. mapserv.sendall(trade_request(player_id))
  556. trader_state.timer = time.time()
  557. else:
  558. mapserv.sendall(whisper(nick, "Where are you?!? I can't trade with somebody who isn't here!"))
  559. trader_state.reset()
  560. elif broken_string[0] == "!lastseen":
  561. who = msg[10:].strip()
  562. if len(who) == 0:
  563. mapserv.sendall(whisper(nick, "Usage: !lastseen <nick>"))
  564. else:
  565. ls_info = db_manager.get_lastseen_info(who)
  566. mapserv.sendall(whisper(nick, ls_info))
  567. elif broken_string[0] == "!mail":
  568. if user == -10:
  569. mapserv.sendall(whisper(nick, "Your current access level is 0. Request access in [@@https://forums.themanaworld.org/viewtopic.php?f=14&t=14010|ManaMarket's forum thread@@]"))
  570. return
  571. to_, msg_ = utils.parse_mail_cmdargs(msg[6:].strip())
  572. if to_ == "" or msg_ == "":
  573. mapserv.sendall(whisper(nick, "Usage: !mail <nick> <message> OR !mail \"nick with spaces\" <message>"))
  574. else:
  575. db_manager.send_mail(nick, to_, msg_)
  576. mapserv.sendall(whisper(nick, "Message to \"%s\" sent" % (to_)))
  577. elif broken_string[0] == "!irc":
  578. if len(broken_string) < 2:
  579. mapserv.sendall(whisper(nick, "Incorrect syntax."))
  580. return
  581. if broken_string[1] == "on":
  582. if user == -10:
  583. user_tree.add_user(nick, 0, 0)
  584. tradey.saveData("Stub User Added: "+nick+", Slots: 0, Access Level: 0")
  585. user = user_tree.get_user(nick)
  586. user.set("irc", "on")
  587. mapserv.sendall(whisper(nick, "IRC relay mode is now enabled (the channel is also bridged to Discord)."))
  588. elif broken_string[1] == "off":
  589. if user != -10:
  590. user.set("irc", "off")
  591. if int(user.get("accesslevel")) == 0 and int(user.get("stalls")) == 0 and int(user.get("money")) == 0:
  592. user_tree.remove_user(nick)
  593. tradey.saveData("Stub User Removed: "+nick)
  594. mapserv.sendall(whisper(nick, "IRC relay mode is now disabled."))
  595. elif user != -10 and user.get("irc") == "on":
  596. if not ircbot.isAFK(msg): # if not an AFK message
  597. ircbot.send(nick, msg)
  598. db_manager.forEachOnline(broadcast_if_irc_on, nick, "TMW.%s: %s" % (nick, msg))
  599. else:
  600. response = chatbot.respond(msg)
  601. logger.info("Bot Response: "+response)
  602. mapserv.sendall(whisper(nick, response))
  603. #mapserv.sendall(whisper(nick, "Command not recognised, please whisper me !help for a full list of commands."))
  604. def broadcast_from_irc(nick, msg):
  605. db_manager.forEachOnline(broadcast_if_irc_on, "IRC", u"IRC.%s: %s" % (nick, msg))
  606. def broadcast_if_irc_on(pl, sender_nick, msg):
  607. if sender_nick == pl:
  608. return
  609. pl_user = user_tree.get_user(pl)
  610. if pl_user != -10 and pl_user.get("irc") == "on":
  611. mapserv.sendall(whisper(pl, msg.encode("utf-8", "ignore")))
  612. def main():
  613. # Use rotating log files.
  614. log_handler = logging.handlers.RotatingFileHandler('data/logs/activity.log', maxBytes=1048576*3, backupCount=5)
  615. logger.setLevel(logging.INFO)
  616. formatter = logging.Formatter('%(asctime)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
  617. log_handler.setFormatter(formatter)
  618. logger.addHandler(log_handler)
  619. logger.info("Bot Started.")
  620. account = config.account
  621. password = config.password
  622. character = config.character
  623. login = socket.socket()
  624. login.connect((config.server, config.port))
  625. logger.info("Login connected")
  626. login_packet = PacketOut(0x0064)
  627. login_packet.write_int32(6) # <= CLIENT VERSION
  628. login_packet.write_string(account, 24)
  629. login_packet.write_string(password, 24)
  630. login_packet.write_int8(0x03); # <= FLAGS
  631. login.sendall(str(login_packet))
  632. pb = PacketBuffer()
  633. id1 = accid = id2 = 0
  634. charip = ""
  635. charport = 0
  636. # Login server packet loop.
  637. while True:
  638. data = login.recv(1500)
  639. if not data:
  640. break
  641. pb.feed(data)
  642. for packet in pb:
  643. if packet.is_type(SMSG_LOGIN_DATA): # login succeeded
  644. packet.skip(2)
  645. id1 = packet.read_int32()
  646. accid = packet.read_int32()
  647. id2 = packet.read_int32()
  648. packet.skip(30)
  649. player_node.sex = packet.read_int8()
  650. charip = utils.parse_ip(packet.read_int32())
  651. charport = packet.read_int16()
  652. login.close()
  653. break
  654. if charip:
  655. break
  656. assert charport
  657. if charip == "127.0.0.1" and config.server != "127.0.0.1":
  658. charip = config.server
  659. char = socket.socket()
  660. char.connect((charip, charport))
  661. logger.info("Char connected")
  662. char_serv_packet = PacketOut(CMSG_CHAR_SERVER_CONNECT)
  663. char_serv_packet.write_int32(accid)
  664. char_serv_packet.write_int32(id1)
  665. char_serv_packet.write_int32(id2)
  666. char_serv_packet.write_int16(1) # this should match MIN_CLIENT_VERSION in tmwa/src/char/char.hpp
  667. char_serv_packet.write_int8(player_node.sex)
  668. char.sendall(str(char_serv_packet))
  669. char.recv(4)
  670. pb = PacketBuffer()
  671. mapip = ""
  672. mapport = 0
  673. # Character Server Packet loop.
  674. while True:
  675. data = char.recv(1500)
  676. if not data:
  677. break
  678. pb.feed(data)
  679. for packet in pb:
  680. if packet.is_type(SMSG_CHAR_LOGIN):
  681. packet.skip(2)
  682. slots = packet.read_int16()
  683. packet.skip(18)
  684. count = (len(packet.data)-22) / 106
  685. for i in range(count):
  686. player_node.id = packet.read_int32()
  687. player_node.EXP = packet.read_int32()
  688. player_node.MONEY = packet.read_int32()
  689. packet.skip(62)
  690. player_node.name = packet.read_string(24)
  691. packet.skip(6)
  692. slot = packet.read_int8()
  693. packet.skip(1)
  694. logger.info("Character information recieved:")
  695. logger.info("Name: %s, Id: %s, EXP: %s, MONEY: %s", \
  696. player_node.name, player_node.id, player_node.EXP, player_node.MONEY)
  697. if slot == character:
  698. break
  699. char_select_packet = PacketOut(CMSG_CHAR_SELECT)
  700. char_select_packet.write_int8(character)
  701. char.sendall(str(char_select_packet))
  702. elif packet.is_type(SMSG_CHAR_MAP_INFO):
  703. player_node.id = packet.read_int32()
  704. player_node.map = packet.read_string(16)
  705. mapip = utils.parse_ip(packet.read_int32())
  706. mapport = packet.read_int16()
  707. char.close()
  708. break
  709. if mapip:
  710. break
  711. assert mapport
  712. if mapip == "127.0.0.1" and charip != "127.0.0.1":
  713. mapip = charip
  714. beingManager.container[player_node.id] = Being(player_node.id, 42)
  715. global mapserv
  716. mapserv = socket.socket()
  717. mapserv.connect((mapip, mapport))
  718. logger.info("Map connected")
  719. mapserv_login_packet = PacketOut(CMSG_MAP_SERVER_CONNECT)
  720. mapserv_login_packet.write_int32(accid)
  721. mapserv_login_packet.write_int32(player_node.id)
  722. mapserv_login_packet.write_int32(id1)
  723. mapserv_login_packet.write_int32(id2)
  724. mapserv_login_packet.write_int8(player_node.sex)
  725. mapserv.sendall(str(mapserv_login_packet))
  726. mapserv.recv(4)
  727. pb = PacketBuffer()
  728. shop_broadcaster.mapserv = mapserv
  729. db_manager.mapserv = mapserv
  730. db_manager.start()
  731. ircbot.broadcastFunc = broadcast_from_irc
  732. ircbot.start()
  733. # Functionality for systemd watchdog keepalives
  734. last_notify = None
  735. def notify_systemd():
  736. global last_sd_notify
  737. sd.notify("WATCHDOG=1")
  738. last_sd_notify = time.time()
  739. return True
  740. notify_systemd()
  741. # Map server packet loop
  742. print "Entering map packet loop\n";
  743. while True:
  744. data = mapserv.recv(2048)
  745. if not data:
  746. break
  747. pb.feed(data)
  748. # If it's been more than five seconds since we last notified systemd that we're still alive, do so now.
  749. if time.time() - last_notify > sd_min_keepalive_rate:
  750. notify_systemd()
  751. # For unfinished trades - one way to distrupt service would be leaving a trade active.
  752. if trader_state.Trading.test():
  753. if time.time() - trader_state.timer > 2*60:
  754. logger.info("Trade Cancelled - Timeout.")
  755. trader_state.timer = time.time()
  756. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  757. for packet in pb:
  758. if packet.is_type(SMSG_MAP_LOGIN_SUCCESS): # connected
  759. logger.info("Map login success.")
  760. packet.skip(4)
  761. coord_data = packet.read_coord_dir()
  762. player_node.x = coord_data[0]
  763. player_node.y = coord_data[1]
  764. player_node.direction = coord_data[2]
  765. logger.info("Starting Postion: %s %s %s", player_node.map, player_node.x, player_node.y)
  766. mapserv.sendall(str(PacketOut(CMSG_MAP_LOADED))) # map loaded
  767. # A Thread to send a shop broadcast: also keeps the network active to prevent timeouts.
  768. shop_broadcaster.start()
  769. elif packet.is_type(SMSG_PVP_SET):
  770. packet.skip(12)
  771. elif packet.is_type(SMSG_PVP_MAP_MODE):
  772. packet.skip(2)
  773. elif packet.is_type(SMSG_QUEST_SET_VAR):
  774. packet.skip(6)
  775. elif packet.is_type(SMSG_QUEST_PLAYER_VARS):
  776. nb = (packet.read_int16() - 4) / 6
  777. for loop in range(nb):
  778. packet.skip(6)
  779. elif packet.is_type(SMSG_NPC_COMMAND):
  780. packet.skip(14)
  781. elif packet.is_type(SMSG_BEING_MOVE3):
  782. nb = (packet.read_int16() - 14) / 1
  783. packet.skip(10)
  784. for loop in range(nb):
  785. packet.skip(1)
  786. elif packet.is_type(SMSG_MAP_MASK):
  787. packet.skip(8)
  788. elif packet.is_type(SMSG_MAP_MUSIC):
  789. nb = (packet.read_int16() - 4) / 1
  790. for loop in range(nb):
  791. packet.skip(1)
  792. elif packet.is_type(SMSG_NPC_CHANGETITLE):
  793. nb = (packet.read_int16() - 10) / 1
  794. packet.skip(6)
  795. for loop in range(nb):
  796. packet.skip(1)
  797. elif packet.is_type(SMSG_SCRIPT_MESSAGE):
  798. nb = (packet.read_int16() - 5) / 1
  799. packet.skip(1)
  800. for loop in range(nb):
  801. packet.skip(1)
  802. elif packet.is_type(SMSG_PLAYER_CLIENT_COMMAND):
  803. nb = (packet.read_int16() - 4) / 1
  804. for loop in range(nb):
  805. packet.skip(1)
  806. elif packet.is_type(SMSG_MAP_SET_TILES_TYPE):
  807. packet.skip(32)
  808. elif packet.is_type(SMSG_PLAYER_HP):
  809. packet.skip(8)
  810. elif packet.is_type(SMSG_PLAYER_HP_FULL):
  811. packet.skip(12)
  812. elif packet.is_type(SMSG_WHISPER):
  813. msg_len = packet.read_int16() - 26
  814. nick = packet.read_string(24)
  815. message = packet.read_raw_string(msg_len)
  816. # Clean up the logs.
  817. if nick != 'AuctionBot':
  818. logger.info("Whisper: " + nick + ": " + message)
  819. process_whisper(nick, utils.remove_colors(message), mapserv)
  820. elif packet.is_type(SMSG_PLAYER_STAT_UPDATE_1):
  821. stat_type = packet.read_int16()
  822. value = packet.read_int32()
  823. if stat_type == 0x0018:
  824. logger.info("Weight changed from %s/%s to %s/%s", \
  825. player_node.WEIGHT, player_node.MaxWEIGHT, value, player_node.MaxWEIGHT)
  826. player_node.WEIGHT = value
  827. elif stat_type == 0x0019:
  828. logger.info("Max Weight: %s", value)
  829. player_node.MaxWEIGHT = value
  830. elif packet.is_type(SMSG_PLAYER_STAT_UPDATE_2):
  831. stat_type = packet.read_int16()
  832. value = packet.read_int32()
  833. if stat_type == 0x0014:
  834. logger.info("Money Changed from %s, to %s", player_node.MONEY, value)
  835. player_node.MONEY = value
  836. elif packet.is_type(SMSG_BEING_MOVE) or packet.is_type(SMSG_BEING_VISIBLE)\
  837. or packet.is_type(SMSG_PLAYER_MOVE) or packet.is_type(SMSG_PLAYER_UPDATE_1)\
  838. or packet.is_type(SMSG_PLAYER_UPDATE_2):
  839. being_id = packet.read_int32()
  840. packet.skip(8)
  841. job = packet.read_int16()
  842. if being_id not in beingManager.container:
  843. if job == 0 and id >= 110000000 and (packet.is_type(SMSG_BEING_MOVE)\
  844. or packet.is_type(SMSG_BEING_VISIBLE)):
  845. continue
  846. # Add the being to the BeingManager, and request name.
  847. beingManager.container[being_id] = Being(being_id, job)
  848. requestName = PacketOut(0x0094)
  849. requestName.write_int32(being_id)
  850. mapserv.sendall(str(requestName))
  851. elif packet.is_type(SMSG_BEING_NAME_RESPONSE):
  852. being_id = packet.read_int32()
  853. if being_id in beingManager.container:
  854. beingManager.container[being_id].name = packet.read_string(24)
  855. elif packet.is_type(SMSG_BEING_REMOVE):
  856. being_id = packet.read_int32()
  857. if being_id in beingManager.container:
  858. del beingManager.container[being_id]
  859. elif packet.is_type(SMSG_PLAYER_WARP):
  860. player_node.map = packet.read_string(16)
  861. player_node.x = packet.read_int16()
  862. player_node.y = packet.read_int16()
  863. logger.info("Player warped: %s %s %s", player_node.map, player_node.x, player_node.y)
  864. mapserv.sendall(str(PacketOut(CMSG_MAP_LOADED)))
  865. elif packet.is_type(SMSG_PLAYER_INVENTORY_ADD):
  866. item = Item()
  867. item.index = packet.read_int16() - inventory_offset
  868. item.amount = packet.read_int16()
  869. item.itemId = packet.read_int16()
  870. packet.skip(14)
  871. err = packet.read_int8()
  872. if err == 0:
  873. if item.index in player_node.inventory:
  874. player_node.inventory[item.index].amount += item.amount
  875. else:
  876. player_node.inventory[item.index] = item
  877. logger.info("Picked up: %s, Amount: %s, Index: %s", ItemDB.getItem(item.itemId).name, str(item.amount), str(item.index))
  878. elif packet.is_type(SMSG_PLAYER_INVENTORY_REMOVE):
  879. index = packet.read_int16() - inventory_offset
  880. amount = packet.read_int16()
  881. logger.info("Remove item: %s, Amount: %s, Index: %s", ItemDB.getItem(player_node.inventory[index].itemId).name, str(amount), str(index))
  882. player_node.remove_item(index, amount)
  883. elif packet.is_type(SMSG_PLAYER_INVENTORY):
  884. player_node.inventory.clear() # Clear the inventory - incase of new index.
  885. packet.skip(2)
  886. number = (len(packet.data)-2) / 18
  887. for loop in range(number):
  888. item = Item()
  889. item.index = packet.read_int16() - inventory_offset
  890. item.itemId = packet.read_int16()
  891. packet.skip(2)
  892. item.amount = packet.read_int16()
  893. packet.skip(10)
  894. player_node.inventory[item.index] = item
  895. elif packet.is_type(SMSG_PLAYER_EQUIPMENT):
  896. packet.read_int16()
  897. number = (len(packet.data)) / 20
  898. for loop in range(number):
  899. item = Item()
  900. item.index = packet.read_int16() - inventory_offset
  901. item.itemId = packet.read_int16()
  902. packet.skip(16)
  903. item.amount = 1
  904. player_node.inventory[item.index] = item
  905. logger.info("Inventory information received:")
  906. for item in player_node.inventory:
  907. logger.info("Name: %s, Id: %s, Index: %s, Amount: %s.", \
  908. ItemDB.getItem(player_node.inventory[item].itemId).name, \
  909. player_node.inventory[item].itemId, item, player_node.inventory[item].amount)
  910. errorOccured = player_node.check_inventory(user_tree, sale_tree)
  911. if errorOccured:
  912. logger.info(errorOccured)
  913. shop_broadcaster.stop()
  914. sys.exit(1)
  915. else:
  916. logger.info("Inventory Check Passed.")
  917. elif packet.is_type(SMSG_TRADE_REQUEST):
  918. name = packet.read_string(24)
  919. logger.info("Trade request: " + name)
  920. mapserv.sendall(trade_respond(False))
  921. elif packet.is_type(SMSG_TRADE_RESPONSE):
  922. response = packet.read_int8()
  923. time.sleep(0.2)
  924. if response == 0:
  925. logger.info("Trade response: Too far away.")
  926. if trader_state.item:
  927. mapserv.sendall(whisper(trader_state.item.player, "You are too far away."))
  928. elif trader_state.money:
  929. mapserv.sendall(whisper(trader_state.money, "You are too far away."))
  930. trader_state.reset()
  931. elif response == 3:
  932. logger.info("Trade response: Trade accepted.")
  933. if trader_state.item:
  934. if trader_state.item.get == 1: # add
  935. mapserv.sendall(str(PacketOut(CMSG_TRADE_ADD_COMPLETE)))
  936. elif trader_state.item.get == 0: # buy
  937. if player_node.find_inventory_index(trader_state.item.id) != -10:
  938. mapserv.sendall(trade_add_item(player_node.find_inventory_index(trader_state.item.id), trader_state.item.amount))
  939. mapserv.sendall(str(PacketOut(CMSG_TRADE_ADD_COMPLETE)))
  940. if trader_state.item.price == 0: # getback
  941. mapserv.sendall(str(PacketOut(CMSG_TRADE_OK)))
  942. trader_state.complete = 1
  943. else:
  944. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  945. logger.info("Trade response: Trade accepted (buy) - the item could not be added.")
  946. mapserv.sendall(whisper(trader_state.item.player, "Sorry, a problem has occured."))
  947. elif trader_state.money: # money
  948. amount = int(user_tree.get_user(trader_state.money).get('money'))
  949. mapserv.sendall(trade_add_item(0-inventory_offset, amount))
  950. mapserv.sendall(str(PacketOut(CMSG_TRADE_ADD_COMPLETE)))
  951. mapserv.sendall(str(PacketOut(CMSG_TRADE_OK)))
  952. else:
  953. logger.info("Trade response: Trade cancelled")
  954. trader_state.reset()
  955. elif packet.is_type(SMSG_TRADE_ITEM_ADD):
  956. amount = packet.read_int32()
  957. item_id = packet.read_int16()
  958. if trader_state.item and trader_state.money == 0:
  959. if trader_state.item.get == 1: # add
  960. if amount == trader_state.item.amount and item_id == trader_state.item.id:
  961. trader_state.complete = 1
  962. mapserv.sendall(str(PacketOut(CMSG_TRADE_OK)))
  963. elif item_id == 0 and amount > 0:
  964. mapserv.sendall(whisper(trader_state.item.player, "Why are you adding money?!?!"))
  965. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  966. else:
  967. mapserv.sendall(whisper(trader_state.item.player, "Please check the correct item or quantity has been added."))
  968. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  969. elif trader_state.item.get == 0: # buy
  970. if item_id == 0 and amount == trader_state.item.price * trader_state.item.amount:
  971. mapserv.sendall(str(PacketOut(CMSG_TRADE_OK)))
  972. trader_state.complete = 1
  973. elif item_id == 0 and amount != trader_state.item.price * trader_state.item.amount:
  974. trader_state.complete = 0
  975. else:
  976. mapserv.sendall(whisper(trader_state.item.player, "Don't give me your itenz."))
  977. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  978. elif trader_state.money: # money
  979. mapserv.sendall(whisper(trader_state.money, "Don't give me your itenz."))
  980. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  981. logger.info("Trade item add: ItemId:%s Amount:%s", item_id, amount)
  982. # Note item_id = 0 is money
  983. elif packet.is_type(SMSG_TRADE_ITEM_ADD_RESPONSE):
  984. index = packet.read_int16() - inventory_offset
  985. amount = packet.read_int16()
  986. response = packet.read_int8()
  987. if response == 0:
  988. logger.info("Trade item add response: Successfully added item.")
  989. if trader_state.item:
  990. if trader_state.item.get == 0 and index != 0-inventory_offset: # Make sure the correct item is given!
  991. # index & amount are Always 0
  992. if player_node.inventory[index].itemId != trader_state.item.id or \
  993. amount != trader_state.item.amount:
  994. logger.info("Index: %s" % index)
  995. logger.info("P.ItemId: %s" % player_node.inventory[index].itemId)
  996. logger.info("T.ItemId: %s" % trader_state.item.id)
  997. logger.info("P.Amount: %s" % amount)
  998. logger.info("T.Amount: %s" % trader_state.item.amount)
  999. #mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  1000. # If Trade item add successful - Remove the item from the inventory state.
  1001. if index != 0: # If it's not money
  1002. logger.info("Remove item: %s, Amount: %s, Index: %s", ItemDB.getItem(player_node.inventory[index].itemId).name, str(amount),str(index))
  1003. player_node.remove_item(index, amount)
  1004. else:
  1005. # The money amount isn't actually sent by the server - odd?!?!?.
  1006. if trader_state.money:
  1007. logger.info("Trade: Money Added.")
  1008. trader_state.complete = 1
  1009. elif response == 1:
  1010. logger.info("Trade item add response: Failed - player overweight.")
  1011. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  1012. if trader_state.item:
  1013. mapserv.sendall(whisper(trader_state.item.player, "You are carrying too much weight. Unload and try again."))
  1014. elif response == 2:
  1015. if trader_state.item:
  1016. mapserv.sendall(whisper(trader_state.item.player, "You have no free slots."))
  1017. logger.info("Trade item add response: Failed - No free slots.")
  1018. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  1019. else:
  1020. logger.info("Trade item add response: Failed - unknown reason.")
  1021. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  1022. if trader_state.item:
  1023. mapserv.sendall(whisper(trader_state.item.player, "Sorry, a problem has occured."))
  1024. elif packet.is_type(SMSG_TRADE_OK):
  1025. is_ok = packet.read_int8() # 0 is ok from self, and 1 is ok from other
  1026. if is_ok == 0:
  1027. logger.info("Trade OK: Self.")
  1028. else:
  1029. if trader_state.complete:
  1030. mapserv.sendall(str(PacketOut(CMSG_TRADE_OK)))
  1031. else:
  1032. mapserv.sendall(str(PacketOut(CMSG_TRADE_CANCEL_REQUEST)))
  1033. if trader_state.item:
  1034. mapserv.sendall(whisper(trader_state.item.player, "Trade Cancelled: Please check the traded items or money."))
  1035. logger.info("Trade Ok: Partner.")
  1036. elif packet.is_type(SMSG_TRADE_CANCEL):
  1037. trader_state.reset()
  1038. logger.info("Trade Cancel.")
  1039. elif packet.is_type(SMSG_TRADE_COMPLETE):
  1040. commitMessage=""
  1041. # The sale_tree is only ammended after a complete trade packet.
  1042. if trader_state.item and trader_state.money == 0:
  1043. if trader_state.item.get == 1: # !add
  1044. sale_tree.add_item(trader_state.item.player, trader_state.item.id, trader_state.item.amount, trader_state.item.price)
  1045. user_tree.get_user(trader_state.item.player).set('used_stalls', \
  1046. str(int(user_tree.get_user(trader_state.item.player).get('used_stalls')) + 1))
  1047. user_tree.get_user(trader_state.item.player).set('last_use', str(time.time()))
  1048. commitMessage = "Add"
  1049. elif trader_state.item.get == 0: # !buy \ !getback
  1050. seller = sale_tree.get_uid(trader_state.item.uid).get('name')
  1051. item = sale_tree.get_uid(trader_state.item.uid)
  1052. current_amount = int(item.get("amount"))
  1053. sale_tree.get_uid(trader_state.item.uid).set("amount", str(current_amount - trader_state.item.amount))
  1054. if int(item.get("amount")) == 0:
  1055. user_tree.get_user(sale_tree.get_uid(trader_state.item.uid).get('name')).set('used_stalls', \
  1056. str(int(user_tree.get_user(sale_tree.get_uid(trader_state.item.uid).get('name')).get('used_stalls'))-1))
  1057. sale_tree.remove_item_uid(trader_state.item.uid)
  1058. current_money = int(user_tree.get_user(seller).get("money"))
  1059. user_tree.get_user(seller).set("money", str(current_money + trader_state.item.price * trader_state.item.amount))
  1060. if trader_state.item.price * trader_state.item.amount != 0:
  1061. ItemLog.add_item(int(item.get('itemId')), trader_state.item.amount, trader_state.item.price * trader_state.item.amount, item.get('name'))
  1062. commitMessage = "Buy or Getback"
  1063. elif trader_state.money and trader_state.item == 0: # !money
  1064. user_tree.get_user(trader_state.money).set('money', str(0))
  1065. commitMessage = "Money"
  1066. sale_tree.save()
  1067. user_tree.save()
  1068. tradey.saveData(commitMessage)
  1069. trader_state.reset()
  1070. logger.info("Trade Complete.")
  1071. errorOccured = player_node.check_inventory(user_tree, sale_tree)
  1072. if errorOccured:
  1073. logger.info(errorOccured)
  1074. shop_broadcaster.stop()
  1075. sys.exit(1)
  1076. else:
  1077. pass
  1078. # On Disconnect/Exit
  1079. logger.info("Server disconnect.")
  1080. db_manager.stop()
  1081. shop_broadcaster.stop()
  1082. mapserv.close()
  1083. if __name__ == '__main__':
  1084. main()