-
-
Save sghanta/4e166f86ada4e9a3e19c446eaefa2741 to your computer and use it in GitHub Desktop.
TheManaWorld WhisperBot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
#README: http://forums.themanaworld.org/viewtopic.php?f=12&t=11712 | |
server = "server.themanaworld.org" | |
port = 6901 | |
account = "" | |
password = "" | |
character = 0 #slot character is in, 0 for first, 1 for second, 2 for third | |
charactername = "" | |
master = "" #character bot will direct public chat to | |
sit = 0 # become inconspicuous | |
color_replacement_regex = '' #r'\1 ' to keep em | |
file = open("wlog.txt", "a") | |
import string | |
import select | |
import socket | |
import struct | |
import time | |
import sys | |
import re | |
import os | |
from time import strftime as date | |
# http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python | |
console_width = int(os.popen('stty size', 'r').read().split()[1]) | |
packet_lengths = [ | |
10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
#0x0040 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 50, 3, -1, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2, | |
3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6, | |
#0x0080 | |
7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0, | |
7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6, | |
23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6, | |
8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3, | |
#0x00C0 | |
7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27, | |
3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1, | |
30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2, | |
3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10, | |
#0x0100 | |
2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1, | |
10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16, | |
6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1, | |
6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26, | |
#0x0140 | |
22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6, | |
110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42, | |
-1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182, | |
14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1, | |
#0x0180 | |
6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6, | |
90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6, | |
3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4, | |
11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3, | |
#0x01C0 | |
2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28, | |
8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6, | |
30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1, | |
-1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10, | |
#0x2000 | |
26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
] | |
class PacketBuffer: | |
def __init__(self): | |
self.buff = "" | |
def feed(self, data): | |
self.buff += data | |
def drop(self, count): | |
self.buff = self.buff[count:] | |
def __iter__(self): | |
return self | |
def next(self): | |
if len(self.buff) < 2: | |
raise StopIteration | |
pkttype = struct.unpack("<H", self.buff[:2])[0] | |
assert pkttype < len(packet_lengths) | |
assert packet_lengths[pkttype] != 0 | |
if packet_lengths[pkttype] < 0: | |
if len(self.buff) < 4: | |
raise StopIteration | |
pktlen = struct.unpack("<H", self.buff[2:4])[0] | |
assert pktlen >= 4 | |
else: | |
pktlen = packet_lengths[pkttype] | |
if len(self.buff) < pktlen: | |
raise StopIteration | |
packet = self.buff[:pktlen] | |
self.buff = self.buff[pktlen:] | |
return packet | |
def parse_ip(s): | |
return ".".join(map(str, map(ord, s))) | |
def whisper(nick, message): | |
return "\x96\0%s%s%s" % (struct.pack("<H", len(message)+28), nick.ljust(24, '\0'), message) | |
def main(): | |
login = socket.socket() | |
login.connect((server, port)) | |
print("login connected") | |
login.sendall("\x64\0\0\0\0\0%s%s\0" % | |
(account.ljust(24, '\0'), password.ljust(24, '\0'))) | |
pb = PacketBuffer() | |
id1 = accid = id2 = sex = 0 | |
charip = "" | |
charport = 0 | |
while True: | |
data = login.recv(1500) | |
if not data: | |
break | |
pb.feed(data) | |
for packet in pb: | |
if packet.startswith("\x69\0"): # login succeeded | |
id1, accid, id2 = struct.unpack("<LLL", packet[4:16]) | |
sex = ord(packet[46]) | |
packet = packet[47:] | |
charip = parse_ip(packet[:4]) | |
charport = struct.unpack("<H", packet[4:6])[0] | |
login.close() | |
break | |
if charip: | |
break | |
assert charport | |
char = socket.socket() | |
char.connect((charip, charport)) | |
print("char connected") | |
char.sendall("\x65\0%s\0\0%s" % (struct.pack("<LLL", accid, id1, id2), chr(sex))) | |
char.recv(4) | |
pb = PacketBuffer() | |
mapip = "" | |
mapport = 0 | |
charid = 0 | |
while True: | |
data = char.recv(1500) | |
if not data: | |
break | |
pb.feed(data) | |
for packet in pb: | |
if packet.startswith("\x6b\0"): | |
char.sendall("\x66\0%s" % chr(character)) | |
elif packet.startswith("\x71\0"): | |
charid = struct.unpack("<L", packet[2:6])[0] | |
mapip = parse_ip(packet[22:26]) | |
mapport = struct.unpack("<H", packet[26:28])[0] | |
char.close() | |
break | |
if mapip: | |
break | |
assert mapport | |
mapserv = socket.socket() | |
mapserv.connect((mapip, mapport)) | |
print("map connected") | |
mapserv.sendall("\x72\0%s" % struct.pack("<LLLLB", accid, charid, id1, id2, sex)) | |
mapserv.recv(4) | |
pb = PacketBuffer() | |
gotresponse = set() | |
while True: | |
data = mapserv.recv(1500) | |
if not data: | |
break | |
pb.feed(data) | |
for packet in pb: | |
if packet.startswith("\x73\0"): # connected | |
mapserv.sendall("\x7d\0") # map loaded | |
if sit: | |
mapserv.sendall("\x89\0\0\0\0\0\x02") # sit | |
elif packet.startswith("\x97\0"): | |
nick = packet[4:28].rstrip("\0") | |
message = packet[28:] | |
if nick == master: | |
data = "%s : %s" % (charactername, message) | |
mapserv.sendall("\x8c\0%s%s" % (struct.pack("<H", len(data)+4), data)) | |
time.sleep(0.5) | |
elif nick not in gotresponse: | |
gotresponse.add(nick) | |
file.write("[" + date('%H:%M:%S') + "] " + "!!! " + nick + ": " + message + "\n") | |
print "[" + date('%H:%M:%S') + "] " + "!!! " + nick + ": " + message | |
#mapserv.sendall(whisper(nick, "Please talk to %s." % master)) | |
time.sleep(0.5) | |
elif packet.startswith("\x8e\0"): # server speech | |
message = packet[4:] | |
print "[" + date('%H:%M:%S') + "] " + message | |
if "automaticly banned for spam" in message: | |
time.sleep(3) | |
elif packet.startswith("\x8d\0"): # char speech | |
message = re.sub(r'(##[0-9])',color_replacement_regex,packet[8:-1]) | |
print "[" + date('%H:%M:%S') + "] " + message | |
if len(message) > console_width: | |
print "" | |
# mapserv.sendall(whisper(master, message)) | |
file.write("[" + date('%H:%M:%S') + "] " + message + "\n") | |
file.flush() | |
time.sleep(0.1) | |
si,so,se = select.select([sys.stdin],[],[], 0.01) | |
for s in si: | |
if s == sys.stdin: | |
message = sys.stdin.readline()[:-1] | |
if len(message) > 0: | |
if message[0] == '/': | |
if len(message) > 1: | |
if (message[1] == 'q') or (message[1] == 'w'): | |
nick = string.split(message)[1] | |
text = string.join(string.split(message)[2:]) | |
mapserv.sendall(whisper(nick, text)) | |
break | |
data = "%s : %s" % (charactername, message) | |
mapserv.sendall("\x8c\0%s%s" % (struct.pack("<H", len(data)+4), data)) | |
file.write("[" + date('%H:%M:%S') + "] " + "Me: " + message + "\n") | |
# time.sleep(0.5) | |
if __name__ == '__main__': | |
main() | |
file.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment