From 8e33ce61d93beaf575dbf1b756a62e311f440640 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Sun, 21 Aug 2011 20:00:41 +0200 Subject: Adding files as in http://dl.dropbox.com/u/1539068/Tradey.tar.bz2 --- being.py | 30 + config.py | 6 + data/items.xml | 5540 +++++++++++++++++++++++++++++++++++++++++++++++++++++ data/sale.xml | 1 + data/user.xml | 1 + main.py | 1012 ++++++++++ net/__init__.py | 0 net/packet.py | 179 ++ net/packet_out.py | 50 + net/protocol.py | 64 + player.py | 31 + tradey.py | 88 + utils.py | 115 ++ 13 files changed, 7117 insertions(+) create mode 100644 being.py create mode 100644 config.py create mode 100644 data/items.xml create mode 100644 data/sale.xml create mode 100644 data/user.xml create mode 100644 main.py create mode 100644 net/__init__.py create mode 100644 net/packet.py create mode 100644 net/packet_out.py create mode 100644 net/protocol.py create mode 100644 player.py create mode 100644 tradey.py create mode 100644 utils.py diff --git a/being.py b/being.py new file mode 100644 index 0000000..9c51a2b --- /dev/null +++ b/being.py @@ -0,0 +1,30 @@ +def job_type(job): + if (job <= 25 or (job >= 4001 and job <= 4049)): + return "player" + elif (job >= 46 and job <= 1000): + return "npc" + elif (job > 1000 and job <= 2000): + return "monster" + elif (job == 45): + return "portal" + +class BeingManager: + def __init__(self): + self.container = {} + + def findId(self, name): + for i in self.container: + if self.container[i].name == name: + return i + return -10 + +class Being: + def __init__(self, being_id, job): + self.id = being_id + self.name = "" + self.x = 0 + self.y = 0 + self.action = "" + self.job = job + self.target = 0 + self.type = job_type(job) diff --git a/config.py b/config.py new file mode 100644 index 0000000..068d432 --- /dev/null +++ b/config.py @@ -0,0 +1,6 @@ +#server = "server.themanaworld.org" +server = "caliban.homeip.net" +port = 6901 +account = "" +password = "" +character = 0 #slot character is in, 0 for first, 1 for second, 2 for third diff --git a/data/items.xml b/data/items.xml new file mode 100644 index 0000000..1656c73 --- /dev/null +++ b/data/items.xml @@ -0,0 +1,5540 @@ + + + + + + + + hairstyles/hairstyle01.xml + + + hairstyles/hairstyle02.xml + + + hairstyles/hairstyle03.xml + + + hairstyles/hairstyle04.xml + + + hairstyles/hairstyle05.xml + + + hairstyles/hairstyle06.xml + + + hairstyles/hairstyle07.xml + + + hairstyles/hairstyle08.xml + + + hairstyles/hairstyle09.xml + + + hairstyles/hairstyle10.xml + + + hairstyles/hairstyle11.xml + + + hairstyles/hairstyle12.xml + + + hairstyles/hairstyle13.xml + + + hairstyles/hairstyle14.xml + + + hairstyles/hairstyle15.xml + + + hairstyles/hairstyle16.xml + + + hairstyles/hairstyle17.xml + + + hairstyles/hairstyle18.xml + + + + + player_male_base.xml + player_female_base.xml + + + + + + + + + weapon-dagger.xml + weapons/swords/short-sword-miss1.ogg + weapons/swords/short-sword-hit1.ogg + + + weapon-bow.xml + weapons/bows/bow_shoot_1.ogg + + + weapon-scythe.xml + + + weapon-dagger.xml + weapons/swords/short-sword-miss1.ogg + weapons/swords/short-sword-hit1.ogg + + + weapon-fist.xml + + + weapon-staff.xml + + + + + + + + + + + + + + + + equipment/head/santahat.xml + + + + + + + + + + + + weapon-dagger.xml + weapons/swords/short-sword-miss1.ogg + weapons/swords/short-sword-hit1.ogg + + + weapon-dagger.xml + weapons/knives/sharpknife-miss1.ogg + + + equipment/chest/leather-male.xml|#573a26,9e7654,d3b79e,ffffff;#b96b3d,fbf5f1 + equipment/chest/leather-female.xml|#412300,603100,8d4900;#ffff00 + + + equipment/head/fancyhat.xml + + + equipment/head/minershat.xml + + + + + equipment/feet/boots-male.xml|#623a34,f0c2b4 + equipment/feet/boots-female.xml|#623a34,f0c2b4 + + + + weapon-bow.xml + weapons/bows/bow_shoot_1.ogg + + + equipment/hands/generic-male.xml|#202020,505050 + equipment/hands/generic-female.xml|#202020,505050 + + + equipment/hands/generic-male.xml|#4e2e18,c8752f + equipment/hands/generic-female.xml|#4e2e18,c8752f + + + + + + weapon-dagger.xml + + + + + + + + + equipment/head/standardheadband.xml|#563f25,99784c,d8bd86,ffffff + + + equipment/head/silkheadband.xml + + + weapon-bow.xml + weapons/bows/bow_shoot_1.ogg + + + equipment/chest/leather-male.xml|#443c21,85794a,beb590,ffffff;#824035,d6a19a + equipment/chest/leather-female.xml|#251e06,443c21,71653b,a0945e;#b6574a + + + + + + weapon-axe-blacksmith.xml + + + + + + + + + + + + + + + equipment/hands/generic-male.xml|#202020,c0c0c0,ffffff,ffffff + equipment/hands/generic-female.xml|#202020,c0c0c0,ffffff,ffffff + + + equipment/chest/tnecksweater-male.xml|#a4b2b2,ffffff + equipment/chest/tnecksweater-female.xml|#a4b2b2,ffffff + + + + + + + + weapon-dagger.xml + + + weapon-dagger.xml + + + + + + + + + + weapon-dagger.xml + + + + + + + + + equipment/legs/shorts-male.xml|#a4b2b2,ffffff + equipment/legs/shorts-female.xml|#a4b2b2,ffffff + + + + + weapon-sword-sword.xml + + + + + + + + + + + + equipment/legs/shorts-male.xml|#255367,266c84,68b0c5,ffffff + equipment/legs/shorts-female.xml|#255367,266c84,68b0c5,ffffff + + + + + + + equipment/head/pumpkinhelmet.xml + + + equipment/head/axehat.xml + + + equipment/head/piratehat.xml + + + equipment/head/goggles.xml|#787878,f7f7f7 + + + equipment/head/goggles.xml|#783c00,ff973b + + + equipment/head/circlet.xml + + + equipment/head/eyepatch.xml + + + equipment/head/bandana.xml + + + weapon-scythe.xml + + + equipment/chest/vnecksweater-male.xml|#a4b2b2,ffffff + equipment/chest/vnecksweater-female.xml|#a4b2b2,ffffff + + + equipment/chest/chainmail-male.xml + equipment/chest/chainmail-female.xml + + + equipment/chest/lightplatemail-male.xml|#ddeeff + equipment/chest/lightplatemail-female.xml|#ddeeff + + + equipment/head/tophat.xml + + + equipment/head/funkywinter.xml + + + equipment/head/mushroom.xml + + + equipment/head/shroom.xml + + + + equipment/legs/skirt.xml|#a4b2b2,ffffff + + + equipment/head/xmaself.xml + + + equipment/head/mask.xml + + + + equipment/head/warlordhelm.xml + + + equipment/head/knighthelm.xml + + + equipment/head/infantryhelm.xml + + + equipment/head/crusadehelm.xml + + + + + equipment/legs/chaps-male.xml + equipment/legs/chaps-female.xml + + + equipment/head/cowboywhite.xml + + + equipment/head/cowboyblack.xml + + + equipment/chest/lightplatemail-male.xml|#573f10,9c8226,d3c04b,ffffff + equipment/chest/lightplatemail-female.xml|#573f10,9c8226,d3c04b,ffffff + + + equipment/head/crown.xml + + + equipment/head/devcap.xml|#9999ff + + + equipment/head/devcap.xml|#9999ff + + + equipment/chest/sorcerer-robe-male.xml|#5e7480,f1ffff,ffffff;#2554c7 + equipment/chest/sorcerer-robe-female.xml|#5e7480,f1ffff,ffffff;#2554c7 + + + equipment/chest/sorcerer-robe-male.xml|#000000;#2554c7 + equipment/chest/sorcerer-robe-female.xml|#000000;#2554c7 + + + equipment/chest/robe-male.xml|#5e7480,f1ffff,ffffff + equipment/chest/robe-female.xml|#5e7480,f1ffff,ffffff + + + equipment/chest/robe-male.xml|#000000 + equipment/chest/robe-female.xml|#000000 + + + equipment/chest/robe-male.xml|#804000 + equipment/chest/robe-female.xml|#804000 + + + equipment/head/cap.xml|#d94800 + + + equipment/feet/furboots-male.xml + equipment/feet/furboots-female.xml + + + equipment/head/serf.xml + + + + equipment/chest/warlordplate-male.xml + equipment/chest/warlordplate-female.xml + + + equipment/chest/warlordplate-male.xml|#573f10,9c8226,d3c04b,ffffff + equipment/chest/warlordplate-female.xml|#573f10,9c8226,d3c04b,ffffff + + + + + + + + + + + + + + + + + + equipment/head/gradcap.xml + + + + + equipment/head/nohmask.xml + + + equipment/head/demonmask.xml + + + + + + + + + + + equipment/chest/tanktop-male.xml|#a4b2b2,ffffff + equipment/chest/tanktop-female.xml|#a4b2b2,ffffff + + + equipment/chest/shorttanktop-male.xml|#a4b2b2,ffffff + equipment/chest/shorttanktop-female.xml|#a4b2b2,ffffff + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + equipment/chest/robe-male.xml|#ffffff + equipment/chest/robe-female.xml|#ffffff + + + equipment/head/highpriest-crown.xml + + + equipment/head/monster-skull-helm.xml + + + equipment/head/deserthat.xml|#ffffff + + + equipment/head/standardheadband.xml|#a4b2b2,ffffff + + + equipment/head/gmcap.xml|#bf0e08 + + + equipment/chest/robe-male.xml|#e40a0a + equipment/chest/robe-female.xml|#e40a0a + + + + + + + equipment/legs/assassin-male.xml + equipment/legs/assassin-female.xml + + + + + equipment/feet/boots-male.xml|#212121 + equipment/feet/boots-female.xml|#212121 + + + equipment/feet/boots-male.xml|#a4b2b2,ffffff + equipment/feet/boots-female.xml|#a4b2b2,ffffff + + + + + + + + equipment/hands/generic-male.xml|#a4b2b2,ffffff + equipment/hands/generic-female.xml|#a4b2b2,ffffff + + + + + + + + + + + + equipment/head/pinkiehat.xml + + + equipment/head/fluffyhat.xml + + + + + equipment/chest/assassin-male.xml + equipment/chest/assassin-female.xml + + + equipment/hands/assassin-male.xml + equipment/hands/assassin-female.xml + + + equipment/feet/assassin-boots-male.xml + equipment/feet/assassin-boots-female.xml + + + weapon-staff.xml + + + equipment/head/paladinhelm.xml + + + equipment/head/overlordhelm.xml + + + equipment/head/desert-helmet.xml + + + + + equipment/head/sailor-hat.xml + + + equipment/head/captain-hat.xml + + + equipment/head/terranitehelm.xml + + + equipment/chest/terranite-male.xml + equipment/chest/terranite-female.xml + + + equipment/legs/terranite-male.xml + equipment/legs/terranite-female.xml + + + equipment/head/guyfawkes.xml + + + equipment/head/fairy_hat.xml + + + equipment/legs/miniskirt-male.xml|#a4b2b2,ffffff + equipment/legs/miniskirt-female.xml|#a4b2b2,ffffff + + + + + + + + + + + + equipment/head/witch-doctor-mask.xml + + + equipment/chest/forest-armor-male.xml + equipment/chest/forest-armor-female.xml + + + equipment/chest/valentine-dress.xml|#bf0e08 + + + + + + + + + + equipment/chest/leather-male.xml|#573a26,c9866b,d3b79e,ffffff;#b96b3d,fbf5f1 + equipment/chest/leather-female.xml|#412300,c9866b,8d4900;#ffff00 + + + equipment/feet/bromenalboots-male.xml + equipment/feet/bromenalboots-female.xml + + + equipment/chest/bromenalchest-male.xml|#fbf5e9 + equipment/chest/bromenalchest-female.xml|#fbf5e9 + + + equipment/hands/bromenalgloves-male.xml + equipment/hands/bromenalgloves-female.xml + + + equipment/head/bromenalhelmet.xml + + + equipment/legs/bromenallegs-male.xml + equipment/legs/bromenallegs-female.xml + + + + equipment/chest/sorcerer-robe-male.xml|#ffffff + equipment/chest/sorcerer-robe-female.xml|#ffffff + + + + equipment/head/bowler-hat-brown.xml + + + equipment/head/pinkie-helmet.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + weapon-bow.xml + weapons/bows/bow_shoot_1.ogg + + + weapon-dagger.xml + + + equipment/chest/cotton-male.xml|#a4b2b2,ffffff + equipment/chest/cotton-female.xml|#a4b2b2,ffffff + + + equipment/head/rangerhat.xml + + + equipment/head/antlerhat.xml + + + equipment/head/christmastree.xml + + + equipment/head/santabeardhat.xml + + + + + + + + + + equipment/head/bunnyears.xml + + + weapon-dagger.xml + weapons/swords/short-sword-miss1.ogg + weapons/swords/sabre-hit1.ogg + + + equipment/head/mouboohead.xml + + + equipment/head/catears.xml|#774444;#777777 + + + equipment/head/paperbag.xml + + + equipment/head/moubootaurhead.xml + + + equipment/head/parsley-earplugs.xml + + + equipment/head/skullmask.xml + + + + + + + + + + + + + + + + + + + + + + + equipment/head/snowgoggles.xml + + + + + + equipment/override/skeleton.xml + graphics/particles/wisp.particle.xml + + + + + equipment/head/heart-glasses.xml + + + + + + + + + + equipment/head/rabbit-ears.xml|#ffffff + + + equipment/head/eggshell.xml + + + + + equipment/head/operamask.xml + + + equipment/head/jestermask.xml + + + equipment/head/witch-hat.xml + + + equipment/head/goblin-mask.xml + + + + + + + + + equipment/chest/cotton-male.xml|#580000,a40000,c02020,ff6060 + equipment/chest/cotton-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/chest/cotton-male.xml|#115511,22aa22,99dd99 + equipment/chest/cotton-female.xml|#115511,22aa22,99dd99 + + + equipment/chest/cotton-male.xml|#222255,6666ff + equipment/chest/cotton-female.xml|#222255,6666ff + + + equipment/chest/cotton-male.xml|#846211,dab333,fffb93,ffffff + equipment/chest/cotton-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/chest/cotton-male.xml|#16486e,498ec5,e4f2fc + equipment/chest/cotton-female.xml|#16486e,498ec5,e4f2fc + + + equipment/chest/cotton-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/chest/cotton-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/chest/cotton-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/chest/cotton-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/chest/cotton-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/chest/cotton-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/chest/cotton-male.xml|#4f0a76,8010c0,d699f7 + equipment/chest/cotton-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/chest/cotton-male.xml|#104010,208020,30c030 + equipment/chest/cotton-female.xml|#104010,208020,30c030 + + + + equipment/chest/vnecksweater-male.xml|#580000,a40000,c02020,ff6060 + equipment/chest/vnecksweater-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/chest/vnecksweater-male.xml|#115511,22aa22,99dd99 + equipment/chest/vnecksweater-female.xml|#115511,22aa22,99dd99 + + + equipment/chest/vnecksweater-male.xml|#222255,6666ff + equipment/chest/vnecksweater-female.xml|#222255,6666ff + + + equipment/chest/vnecksweater-male.xml|#846211,dab333,fffb93,ffffff + equipment/chest/vnecksweater-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/chest/vnecksweater-male.xml|#16486e,498ec5,e4f2fc + equipment/chest/vnecksweater-female.xml|#16486e,498ec5,e4f2fc + + + equipment/chest/vnecksweater-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/chest/vnecksweater-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/chest/vnecksweater-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/chest/vnecksweater-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/chest/vnecksweater-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/chest/vnecksweater-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/chest/vnecksweater-male.xml|#4f0a76,8010c0,d699f7 + equipment/chest/vnecksweater-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/chest/vnecksweater-male.xml|#104010,208020,30c030 + equipment/chest/vnecksweater-female.xml|#104010,208020,30c030 + + + + equipment/chest/tnecksweater-male.xml|#580000,a40000,c02020,ff6060 + equipment/chest/tnecksweater-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/chest/tnecksweater-male.xml|#115511,22aa22,99dd99 + equipment/chest/tnecksweater-female.xml|#115511,22aa22,99dd99 + + + equipment/chest/tnecksweater-male.xml|#222255,6666ff + equipment/chest/tnecksweater-female.xml|#222255,6666ff + + + equipment/chest/tnecksweater-male.xml|#846211,dab333,fffb93,ffffff + equipment/chest/tnecksweater-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/chest/tnecksweater-male.xml|#16486e,498ec5,e4f2fc + equipment/chest/tnecksweater-female.xml|#16486e,498ec5,e4f2fc + + + equipment/chest/tnecksweater-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/chest/tnecksweater-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/chest/tnecksweater-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/chest/tnecksweater-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/chest/tnecksweater-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/chest/tnecksweater-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/chest/tnecksweater-male.xml|#4f0a76,8010c0,d699f7 + equipment/chest/tnecksweater-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/chest/tnecksweater-male.xml|#104010,208020,30c030 + equipment/chest/tnecksweater-female.xml|#104010,208020,30c030 + + + + equipment/chest/robe-male.xml|#580000,a40000,c02020,ff6060 + equipment/chest/robe-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/chest/robe-male.xml|#115511,22aa22,99dd99 + equipment/chest/robe-female.xml|#115511,22aa22,99dd99 + + + equipment/chest/robe-male.xml|#222255,6666ff + equipment/chest/robe-female.xml|#222255,6666ff + + + equipment/chest/robe-male.xml|#846211,dab333,fffb93,ffffff + equipment/chest/robe-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/chest/robe-male.xml|#16486e,498ec5,e4f2fc + equipment/chest/robe-female.xml|#16486e,498ec5,e4f2fc + + + equipment/chest/robe-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/chest/robe-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/chest/robe-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/chest/robe-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/chest/robe-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/chest/robe-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/chest/robe-male.xml|#4f0a76,8010c0,d699f7 + equipment/chest/robe-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/chest/robe-male.xml|#104010,208020,30c030 + equipment/chest/robe-female.xml|#104010,208020,30c030 + + + + equipment/chest/tanktop-male.xml|#580000,a40000,c02020,ff6060 + equipment/chest/tanktop-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/chest/tanktop-male.xml|#115511,22aa22,99dd99 + equipment/chest/tanktop-female.xml|#115511,22aa22,99dd99 + + + equipment/chest/tanktop-male.xml|#222255,6666ff + equipment/chest/tanktop-female.xml|#222255,6666ff + + + equipment/chest/tanktop-male.xml|#846211,dab333,fffb93,ffffff + equipment/chest/tanktop-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/chest/tanktop-male.xml|#16486e,498ec5,e4f2fc + equipment/chest/tanktop-female.xml|#16486e,498ec5,e4f2fc + + + equipment/chest/tanktop-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/chest/tanktop-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/chest/tanktop-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/chest/tanktop-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/chest/tanktop-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/chest/tanktop-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/chest/tanktop-male.xml|#4f0a76,8010c0,d699f7 + equipment/chest/tanktop-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/chest/tanktop-male.xml|#104010,208020,30c030 + equipment/chest/tanktop-female.xml|#104010,208020,30c030 + + + + equipment/legs/skirt.xml|#580000,a40000,c02020,ff6060 + + + equipment/legs/skirt.xml|#115511,22aa22,99dd99 + + + equipment/legs/skirt.xml|#222255,6666ff + + + equipment/legs/skirt.xml|#846211,dab333,fffb93,ffffff + + + equipment/legs/skirt.xml|#16486e,498ec5,e4f2fc + + + equipment/legs/skirt.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/legs/skirt.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/legs/skirt.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/legs/skirt.xml|#4f0a76,8010c0,d699f7 + + + equipment/legs/skirt.xml|#104010,208020,30c030 + + + + equipment/legs/shorts-male.xml|#580000,a40000,c02020,ff6060 + equipment/legs/shorts-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/legs/shorts-male.xml|#115511,22aa22,99dd99 + equipment/legs/shorts-female.xml|#115511,22aa22,99dd99 + + + equipment/legs/shorts-male.xml|#222255,6666ff + equipment/legs/shorts-female.xml|#222255,6666ff + + + equipment/legs/shorts-male.xml|#846211,dab333,fffb93,ffffff + equipment/legs/shorts-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/legs/shorts-male.xml|#16486e,498ec5,e4f2fc + equipment/legs/shorts-female.xml|#16486e,498ec5,e4f2fc + + + equipment/legs/shorts-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/legs/shorts-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/legs/shorts-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/legs/shorts-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/legs/shorts-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/legs/shorts-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/legs/shorts-male.xml|#520a7b,8c23c7,ca87ef + equipment/legs/shorts-female.xml|#520a7b,8c23c7,ca87ef + + + equipment/legs/shorts-male.xml|#104010,208020,30c030 + equipment/legs/shorts-female.xml|#104010,208020,30c030 + + + + equipment/chest/shorttanktop-male.xml|#580000,a40000,c02020,ff6060 + equipment/chest/shorttanktop-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/chest/shorttanktop-male.xml|#115511,22aa22,99dd99 + equipment/chest/shorttanktop-female.xml|#115511,22aa22,99dd99 + + + equipment/chest/shorttanktop-male.xml|#222255,6666ff + equipment/chest/shorttanktop-female.xml|#222255,6666ff + + + equipment/chest/shorttanktop-male.xml|#846211,dab333,fffb93,ffffff + equipment/chest/shorttanktop-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/chest/shorttanktop-male.xml|#16486e,498ec5,e4f2fc + equipment/chest/shorttanktop-female.xml|#16486e,498ec5,e4f2fc + + + equipment/chest/shorttanktop-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/chest/shorttanktop-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/chest/shorttanktop-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/chest/shorttanktop-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/chest/shorttanktop-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/chest/shorttanktop-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/chest/shorttanktop-male.xml|#4f0a76,8010c0,d699f7 + equipment/chest/shorttanktop-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/chest/shorttanktop-male.xml|#104010,208020,30c030 + equipment/chest/shorttanktop-female.xml|#104010,208020,30c030 + + + + equipment/head/deserthat.xml|#580000,a40000,c02020,ff6060 + + + equipment/head/deserthat.xml|#115511,22aa22,99dd99 + + + equipment/head/deserthat.xml|#222255,6666ff + + + equipment/head/deserthat.xml|#846211,dab333,fffb93,ffffff + + + equipment/head/deserthat.xml|#16486e,498ec5,e4f2fc + + + equipment/head/deserthat.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/head/deserthat.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/head/deserthat.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/head/deserthat.xml|#4f0a76,8010c0,d699f7 + + + equipment/head/deserthat.xml|#104010,208020,30c030 + + + + equipment/head/standardheadband.xml|#580000,a40000,c02020,ff6060 + + + equipment/head/standardheadband.xml|#115511,22aa22,99dd99 + + + equipment/head/standardheadband.xml|#222255,6666ff + + + equipment/head/standardheadband.xml|#846211,dab333,fffb93,ffffff + + + equipment/head/standardheadband.xml|#16486e,498ec5,e4f2fc + + + equipment/head/standardheadband.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/head/standardheadband.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/head/standardheadband.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/head/standardheadband.xml|#4f0a76,8010c0,d699f7 + + + equipment/head/standardheadband.xml|#104010,208020,30c030 + + + + equipment/feet/boots-male.xml|#580000,a40000,c02020,ff6060 + equipment/feet/boots-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/feet/boots-male.xml|#115511,22aa22,99dd99 + equipment/feet/boots-female.xml|#115511,22aa22,99dd99 + + + equipment/feet/boots-male.xml|#222255,6666ff + equipment/feet/boots-female.xml|#222255,6666ff + + + equipment/feet/boots-male.xml|#846211,dab333,fffb93,ffffff + equipment/feet/boots-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/feet/boots-male.xml|#16486e,498ec5,e4f2fc + equipment/feet/boots-female.xml|#16486e,498ec5,e4f2fc + + + equipment/feet/boots-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/feet/boots-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/feet/boots-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/feet/boots-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/feet/boots-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/feet/boots-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/feet/boots-male.xml|#4f0a76,8010c0,d699f7 + equipment/feet/boots-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/feet/boots-male.xml|#104010,208020,30c030 + equipment/feet/boots-female.xml|#104010,208020,30c030 + + + + equipment/hands/generic-male.xml|#580000,a40000,c02020,ff6060 + equipment/hands/generic-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/hands/generic-male.xml|#115511,22aa22,99dd99 + equipment/hands/generic-female.xml|#115511,22aa22,99dd99 + + + equipment/hands/generic-male.xml|#222255,6666ff + equipment/hands/generic-female.xml|#222255,6666ff + + + equipment/hands/generic-male.xml|#846211,dab333,fffb93,ffffff + equipment/hands/generic-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/hands/generic-male.xml|#16486e,498ec5,e4f2fc + equipment/hands/generic-female.xml|#16486e,498ec5,e4f2fc + + + equipment/hands/generic-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/hands/generic-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/hands/generic-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/hands/generic-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/hands/generic-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/hands/generic-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/hands/generic-male.xml|#4f0a76,8010c0,d699f7 + equipment/hands/generic-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/hands/generic-male.xml|#104010,208020,30c030 + equipment/hands/generic-female.xml|#104010,208020,30c030 + + + + equipment/legs/miniskirt-male.xml|#580000,a40000,c02020,ff6060 + equipment/legs/miniskirt-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/legs/miniskirt-male.xml|#115511,22aa22,99dd99 + equipment/legs/miniskirt-female.xml|#115511,22aa22,99dd99 + + + equipment/legs/miniskirt-male.xml|#222255,6666ff + equipment/legs/miniskirt-female.xml|#222255,6666ff + + + equipment/legs/miniskirt-male.xml|#846211,dab333,fffb93,ffffff + equipment/legs/miniskirt-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/legs/miniskirt-male.xml|#16486e,498ec5,e4f2fc + equipment/legs/miniskirt-female.xml|#16486e,498ec5,e4f2fc + + + equipment/legs/miniskirt-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/legs/miniskirt-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/legs/miniskirt-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/legs/miniskirt-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/legs/miniskirt-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/legs/miniskirt-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/legs/miniskirt-male.xml|#4f0a76,8010c0,d699f7 + equipment/legs/miniskirt-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/legs/miniskirt-male.xml|#104010,208020,30c030 + equipment/legs/miniskirt-female.xml|#104010,208020,30c030 + + + + + + equipment/head/rabbit-ears.xml|#580000,a40000,c02020,ff6060 + + + equipment/head/rabbit-ears.xml|#115511,22aa22,99dd99 + + + equipment/head/rabbit-ears.xml|#222255,6666ff + + + equipment/head/rabbit-ears.xml|#846211,dab333,fffb93,ffffff + + + equipment/head/rabbit-ears.xml|#16486e,498ec5,e4f2fc + + + equipment/head/rabbit-ears.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/head/rabbit-ears.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/head/rabbit-ears.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/head/rabbit-ears.xml|#4f0a76,8010c0,d699f7 + + + equipment/head/rabbit-ears.xml|#104010,208020,30c030 + + + + equipment/head/wizard-hat.xml|#580000,a40000,c02020,ff6060 + + + equipment/head/wizard-hat.xml|#115511,22aa22,99dd99 + + + equipment/head/wizard-hat.xml|#222255,6666ff + + + equipment/head/wizard-hat.xml|#846211,dab333,fffb93,ffffff + + + equipment/head/wizard-hat.xml|#16486e,498ec5,e4f2fc + + + equipment/head/wizard-hat.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/head/wizard-hat.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/head/wizard-hat.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/head/wizard-hat.xml|#4f0a76,8010c0,d699f7 + + + equipment/head/wizard-hat.xml|#104010,208020,30c030 + + + + equipment/head/bowler-hat.xml|#580000,a40000,c02020,ff6060 + + + equipment/head/bowler-hat.xml|#115511,22aa22,99dd99 + + + equipment/head/bowler-hat.xml|#222255,6666ff + + + equipment/head/bowler-hat.xml|#846211,dab333,fffb93,ffffff + + + equipment/head/bowler-hat.xml|#16486e,498ec5,e4f2fc + + + equipment/head/bowler-hat.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/head/bowler-hat.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/head/bowler-hat.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/head/bowler-hat.xml|#4f0a76,8010c0,d699f7 + + + equipment/head/bowler-hat.xml|#104010,208020,30c030 + + + + equipment/chest/sorcerer-robe-male.xml|#580000,a40000,c02020,ff6060 + equipment/chest/sorcerer-robe-female.xml|#580000,a40000,c02020,ff6060 + + + equipment/chest/sorcerer-robe-male.xml|#115511,22aa22,99dd99 + equipment/chest/sorcerer-robe-female.xml|#115511,22aa22,99dd99 + + + equipment/chest/sorcerer-robe-male.xml|#222255,6666ff + equipment/chest/sorcerer-robe-female.xml|#222255,6666ff + + + equipment/chest/sorcerer-robe-male.xml|#846211,dab333,fffb93,ffffff + equipment/chest/sorcerer-robe-female.xml|#846211,dab333,fffb93,ffffff + + + equipment/chest/sorcerer-robe-male.xml|#16486e,498ec5,e4f2fc + equipment/chest/sorcerer-robe-female.xml|#16486e,498ec5,e4f2fc + + + equipment/chest/sorcerer-robe-male.xml|#56002f,930050,fe70bd,feb7de,ffffff + equipment/chest/sorcerer-robe-female.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/chest/sorcerer-robe-male.xml|#111111,222222,333333,444444,555555,aaaaaa + equipment/chest/sorcerer-robe-female.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/chest/sorcerer-robe-male.xml|#80280f,b04810,ef681f,ffb830 + equipment/chest/sorcerer-robe-female.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/chest/sorcerer-robe-male.xml|#4f0a76,8010c0,d699f7 + equipment/chest/sorcerer-robe-female.xml|#4f0a76,8010c0,d699f7 + + + equipment/chest/sorcerer-robe-male.xml|#104010,208020,30c030 + equipment/chest/sorcerer-robe-female.xml|#104010,208020,30c030 + + + + equipment/head/bowler-hat-brown.xml|#580000,a40000,c02020,ff6060 + + + equipment/head/bowler-hat-brown.xml|#115511,22aa22,99dd99 + + + equipment/head/bowler-hat-brown.xml|#222255,6666ff + + + equipment/head/bowler-hat-brown.xml|#846211,dab333,fffb93,ffffff + + + equipment/head/bowler-hat-brown.xml|#16486e,498ec5,e4f2fc + + + equipment/head/bowler-hat-brown.xml|#56002f,930050,fe70bd,feb7de,ffffff + + + equipment/head/bowler-hat-brown.xml|#111111,222222,333333,444444,555555,aaaaaa + + + equipment/head/bowler-hat-brown.xml|#80280f,b04810,ef681f,ffb830 + + + equipment/head/bowler-hat-brown.xml|#4f0a76,8010c0,d699f7 + + + equipment/head/bowler-hat-brown.xml|#104010,208020,30c030 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + equipment/head/candlehelmet.xml + + + + + + + + + equipment/head/yeti-mask.xml + + + equipment/head/wizard-hat.xml + + + + equipment/head/bowler-hat.xml + + + equipment/head/monocle.xml + + diff --git a/data/sale.xml b/data/sale.xml new file mode 100644 index 0000000..374d3f4 --- /dev/null +++ b/data/sale.xml @@ -0,0 +1 @@ + diff --git a/data/user.xml b/data/user.xml new file mode 100644 index 0000000..bc58f62 --- /dev/null +++ b/data/user.xml @@ -0,0 +1 @@ + diff --git a/main.py b/main.py new file mode 100644 index 0000000..3a217cd --- /dev/null +++ b/main.py @@ -0,0 +1,1012 @@ +""" This package 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 * +from config import * +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')) < 604800: # 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: + 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') + ".")) + mapserv.sendall(whisper(nick, "Your have the following items for sale:")) + for elem in sale_tree.root: + if elem.get('name') == nick: + if time.time() - float(elem.get('add_time')) > 604800: + 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" + mapserv.sendall(whisper(nick, msg)) + + 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'))) < 604800) \ + 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'))) < 604800) \ + 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))) + 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() + 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.")) + 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.")) + 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='logs/activity.log', level=logging.INFO, format='%(asctime)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + logging.info("Bot Started.") + + account = sys.argv[1] + password = sys.argv[2] + character = sys.argv[3] + + login = socket.socket() + login.connect((server, port)) + print("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: + #time.sleep(0.1) + 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)) + print("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(30) + player_node.HP = packet.read_int16() + player_node.MAX_HP = packet.read_int16() + player_node.MP = packet.read_int16() + player_node.MAX_MP = packet.read_int16() + packet.skip(8) + player_node.LEVEL = packet.read_int16() + packet.skip(14) + player_node.name = packet.read_string(24) + packet.skip(6) + slot = packet.read_int8() + packet.skip(1) + print "Character information recieved:" + print "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 == int(character): + break + + char_select_packet = PacketOut(CMSG_CHAR_SELECT) + char_select_packet.write_int8(int(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)) + print("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] + print "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_CHAT): # server speech + msg_len = packet.read_int16() - 2 + being_id = packet.read_int32() + message = packet.read_string(msg_len) + if "automaticly banned for spam" in message: + time.sleep(3) + + elif packet.is_type(SMSG_BEING_CHAT): # char speech + msg_len = packet.read_int16() - 2 + being_id = packet.read_int32() + message = packet.read_string(msg_len) + + elif packet.is_type(SMSG_WALK_RESPONSE): + packet.read_int32() + coord_data = packet.read_coord_pair() + player_node.x = coord_data[2] + player_node.y = coord_data[3] + + elif packet.is_type(SMSG_PLAYER_STAT_UPDATE_1): + stat_type = packet.read_int16() + value = packet.read_int32() + if stat_type == 0x0005: + player_node.HP = value + elif stat_type == 0x0006: + player_node.MaxHP = value + elif stat_type == 0x0007: + player_node.MP = value + elif stat_type == 0x0008: + player_node.MaxMP = value + elif stat_type == 0x000b: + player_node.LEVEL = value + print "Level changed: %s" % value + elif stat_type == 0x0018: + print "Weight changed from %s/%s to %s/%s" % (player_node.WEIGHT, player_node.MaxWEIGHT, value, player_node.MaxWEIGHT) + 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: + print "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 == 0x0001: + player_node.EXP = value + elif stat_type == 0x0014: + logging.info("Money Changed from %s, to %s", player_node.MONEY, value) + print "Money Changed from %s, to %s" % (player_node.MONEY, value) + player_node.MONEY = value + elif stat_type == 0x0016: + player_node.EXP_NEEDED = value + print "Exp Needed: %s" % player_node.EXP_NEEDED + + 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)) + + packet.skip(8) + + if (packet.is_type(SMSG_BEING_MOVE) or packet.is_type(SMSG_PLAYER_MOVE)): + packet.read_int32() + + packet.skip(22) + + if (packet.is_type(SMSG_BEING_MOVE) or packet.is_type(SMSG_PLAYER_MOVE)): + coord_data = packet.read_coord_pair() + beingManager.container[being_id].dst_x = coord_data[2] + beingManager.container[being_id].dst_y = coord_data[3] + else: + coord_data = packet.read_coord_dir() + beingManager.container[being_id].x = coord_data[0] + beingManager.container[being_id].y = coord_data[1] + beingManager.container[being_id].direction = coord_data[2] + + 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.") + mapserv.sendall(str(PacketOut(CMSG_MAP_LOADED))) + + elif packet.is_type(SMSG_BEING_ACTION): + src_being = packet.read_int32() + dst_being = packet.read_int32() + packet.skip(12) + param1 = packet.read_int16() + packet.skip(2) + action_type = packet.read_int8() + + if src_being in beingManager.container: + if action_type == 0: # Damage + beingManager.container[src_being].action = "attack" + beingManager.container[src_being].target = dst_being + + elif action_type == 0x02: # Sit + beingManager.container[src_being].action = "sit" + + elif action_type == 0x03: # Stand up + beingManager.container[src_being].action = "stand" + + 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 + + print "Picked up: %s, Amount: %s" % (ItemDB.getItem(item.itemId).name, item.amount) + 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() + + print "Remove item: %s, Amount: %s" % (ItemDB.getItem(player_node.inventory[index].itemId).name, amount) + 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 + + for item in player_node.inventory: + print "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): + print "SMSG_TRADE_REQUEST" + name = packet.read_string(24) + logging.info("Trade request: " + name) + + elif packet.is_type(SMSG_TRADE_RESPONSE): + print "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 + + elif response == 4: + logging.info("Trade response: Trade cancelled") + trader_state.reset() + + elif packet.is_type(SMSG_TRADE_ITEM_ADD): + print "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): + print "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 and \ + 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 + print "Remove item: %s, Amount: %s" % (ItemDB.getItem(player_node.inventory[index].itemId).name, amount) + 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): + print "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.") + print "SMSG_TRADE_CANCEL" + + elif packet.is_type(SMSG_TRADE_COMPLETE): + # 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)) + + 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) + + elif trader_state.money and trader_state.item == 0: # !money + user_tree.get_user(trader_state.money).set('money', str(0)) + + sale_tree.save() + user_tree.save() + trader_state.reset() + logging.info("Trade Complete.") + print "SMSG_TRADE_COMPLETE" + else: + pass + #print "Unhandled Packet: %s" % hex(packet.get_type()) + + # On Disconnect/Exit + shop_broadcaster.stop() + mapserv.close() + +if __name__ == '__main__': + main() diff --git a/net/__init__.py b/net/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/net/packet.py b/net/packet.py new file mode 100644 index 0000000..4442455 --- /dev/null +++ b/net/packet.py @@ -0,0 +1,179 @@ +import struct + +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, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +] + +class PacketOut: + def __init__(self, out): + self.buff = "" + self.write_int16(out) + + def __str__(self): + return self.buff + + def write_string(self, string_val, length): + self.buff += string_val.ljust(length, '\0') + + def write_int8(self, value): + self.buff += struct.pack("> 8) % 256 + d_1 = (tmp) % 256 + tmp = y + tmp <<= 4 + d_1 |= (tmp >> 8) % 256 + d_2 = tmp % 256 + # d_2 |= direction + self.buff += chr(d_0) + chr(d_1) + chr(d_2) + +class PacketIn: + def __init__(self, set_data, pkt_type): + self.data = set_data + self.pkttype = pkt_type + self.pos = 0 + + def is_type(self, pkt_type): + return self.pkttype == pkt_type + + def get_type(self): + return self.pkttype + + def read_string(self, length): + msg = self.data[self.pos:self.pos + length] + self.pos = self.pos + length + return msg[:msg.find('\0')] + + def read_raw_string(self, length): + msg = self.data[self.pos:self.pos + length] + self.pos = self.pos + length + return msg + + def read_int8(self): + int_value = struct.unpack("> 2) % 255 + dst_y = self.make_word(struct.unpack("> 6) % 255 + src_y = (self.make_word(struct.unpack("> 4) % 255 + self.pos = self.pos + 5 + return src_x, src_y, dst_x, dst_y + + def read_coord_dir(self): + cdata = self.data[self.pos:self.pos + 3] + x = (self.make_word(struct.unpack("> 6) % 255 + y = (self.make_word(struct.unpack("> 4) % 255 + dir = struct.unpack("= 4 + else: + pktlen = packet_lengths[pkttype] + + if len(self.buff) < pktlen: + raise StopIteration + + packet = PacketIn(self.buff[2:pktlen], pkttype) + self.buff = self.buff[pktlen:] + return packet diff --git a/net/packet_out.py b/net/packet_out.py new file mode 100644 index 0000000..6110f4d --- /dev/null +++ b/net/packet_out.py @@ -0,0 +1,50 @@ +from packet import * +from protocol import * + +def emote(emoteId): + emote_packet = PacketOut(CMSG_PLAYER_EMOTE) + emote_packet.write_int8(emoteId) + return str(emote_packet) + +def whisper(nick, message): + whisp_packet = PacketOut(CMSG_CHAT_WHISPER) + whisp_packet.write_int16(len(message) + 28) + whisp_packet.write_string(nick, 24) + whisp_packet.write_string(message, len(message)) + return str(whisp_packet) + +def chat(text): + chat_packet = PacketOut(CMSG_CHAT_MESSAGE) + mes = player_node.name + " : " + text + chat_packet.write_int16(len(mes) + 4 + 1) + chat_packet.write_string(mes, len(mes) + 1) + return str(chat_packet) + +def sit(val): + sit_packet = PacketOut(CMSG_PLAYER_CHANGE_ACT) + sit_packet.write_int32(0) + if val == True: + sit_packet.write_int8(2) + else: + sit_packet.write_int8(3) + return str(sit_packet) + +def trade_request(being_id): + trade_req_packet = PacketOut(CMSG_TRADE_REQUEST) + trade_req_packet.write_int32(being_id) + return str(trade_req_packet) + +def trade_respond(accept): + trade_respond_packet = PacketOut(CMSG_TRADE_RESPONSE) + if accept == True: + trade_respond_packet.write_int8(3) + elif accept == False: + trade_respond_packet.write_int8(4) + return str(trade_respond_packet) + +def trade_add_item(item_index, amount): + trade_add_packet = PacketOut(CMSG_TRADE_ITEM_ADD_REQUEST) + trade_add_packet.write_int16(item_index + inventory_offset) + trade_add_packet.write_int32(amount) + return str(trade_add_packet) + diff --git a/net/protocol.py b/net/protocol.py new file mode 100644 index 0000000..4a4b74f --- /dev/null +++ b/net/protocol.py @@ -0,0 +1,64 @@ +SMSG_LOGIN_DATA = 0x0069 +SMSG_CHAR_LOGIN = 0x006b +SMSG_CHAR_MAP_INFO = 0x0071 +SMSG_MAP_LOGIN_SUCCESS = 0x0073 +SMSG_MAP_LOGIN_SUCCESS = 0x0073 +CMSG_CHAR_SERVER_CONNECT = 0x0065 +CMSG_CHAR_SELECT = 0x0066 +CMSG_MAP_SERVER_CONNECT = 0x0072 +CMSG_CHAT_WHISPER = 0x0096 +CMSG_CHAT_MESSAGE = 0x008c +CMSG_MAP_LOADED = 0x007d + +SMSG_WHISPER = 0x0097 +SMSG_BEING_CHAT = 0x008d + +SMSG_PLAYER_CHAT = 0x008e +CMSG_PLAYER_CHANGE_ACT = 0x0089 + +SMSG_PLAYER_INVENTORY = 0x01ee +SMSG_PLAYER_INVENTORY_ADD = 0x00a0 +SMSG_PLAYER_INVENTORY_REMOVE = 0x00af +SMSG_PLAYER_EQUIPMENT = 0x00a4 +SMSG_PLAYER_STAT_UPDATE_1 = 0x00b0 +SMSG_PLAYER_STAT_UPDATE_2 = 0x00b1 + +SMSG_BEING_VISIBLE = 0x0078 +SMSG_BEING_MOVE = 0x007b +SMSG_BEING_REMOVE = 0x0080 +SMSG_PLAYER_MOVE = 0x01da +SMSG_PLAYER_WARP = 0x0091 +SMSG_PLAYER_UPDATE_1 = 0x01d8 +SMSG_PLAYER_UPDATE_2 = 0x01d9 +SMSG_BEING_NAME_RESPONSE = 0x0095 # Has to be requested +SMSG_BEING_ACTION = 0x008a + +CMSG_ITEM_PICKUP = 0x009f +CMSG_PLAYER_ATTACK = 0x0089 +CMSG_PLAYER_STOP_ATTACK = 0x0118 +CMSG_PLAYER_CHANGE_DIR = 0x009b +CMSG_PLAYER_CHANGE_DEST = 0x0085 +CMSG_PLAYER_EMOTE = 0x00bf +SMSG_WALK_RESPONSE = 0x0087 + +CMSG_TRADE_REQUEST = 0x00e4 +CMSG_TRADE_RESPONSE = 0x00e6 +CMSG_TRADE_ITEM_ADD_REQUEST = 0x00e8 +CMSG_TRADE_CANCEL_REQUEST = 0x00ed +CMSG_TRADE_ADD_COMPLETE = 0x00eb +CMSG_TRADE_OK = 0x00ef + +SMSG_TRADE_REQUEST = 0x00e5 #/**< Receiving a request to trade */ +SMSG_TRADE_RESPONSE = 0x00e7 +SMSG_TRADE_ITEM_ADD = 0x00e9 +SMSG_TRADE_ITEM_ADD_RESPONSE = 0x01b1 #/**< Not standard eAthena! */ +SMSG_TRADE_OK = 0x00ec +SMSG_TRADE_CANCEL = 0x00ee +SMSG_TRADE_COMPLETE = 0x00f0 + +SMSG_ITEM_VISIBLE = 0x009d +SMSG_ITEM_DROPPED = 0x009e +SMSG_ITEM_REMOVE = 0x00a1 + +inventory_offset = 2 +storage_offset = 1 diff --git a/player.py b/player.py new file mode 100644 index 0000000..a63218d --- /dev/null +++ b/player.py @@ -0,0 +1,31 @@ +class Item: + pass + +class Player: + def __init__(self, name): + self.inventory = {} + self.storage = [] + self.name = name + self.id = 0 + self.sex = 0 + self.map = "" + self.x = 0 + self.y = 0 + + self.EXP_NEEDED = 0 + self.EXP = 0 + self.MONEY = 0 + self.LEVEL = 0 + self.HP = 0 + self.MaxHP = 0 + self.MP = 0 + self.MaxMP = 0 + self.WEIGHT = 0 + self.MaxWEIGHT = 0 + + def find_inventory_index(self, item_id): + for item in self.inventory: + if item > 1: + if self.inventory[item].itemId == item_id: + return item + return -10 # Not found - bug somewhere! diff --git a/tradey.py b/tradey.py new file mode 100644 index 0000000..bb83960 --- /dev/null +++ b/tradey.py @@ -0,0 +1,88 @@ +import time +from xml.etree.ElementTree import * + +class UserTree: + def __init__(self): + self.tree = ElementTree(file="data/user.xml") + self.root = self.tree.getroot() + + def add_user(self, name, stalls, al): + if self.get_user(name) == -10: + user = SubElement(self.root, "user") + user.set("name", name) + user.set("stalls", str(stalls)) + user.set("used_stalls", str(0)) + user.set("money", str(0)) + user.set("id", str(0)) + user.set("accesslevel", str(al)) + self.save() + + def get_user(self, name): + for elem in self.root: + if elem.get("name") == name: + return elem + return -10 + + def remove_user(self, name): + for elem in self.root: + if elem.get("name") == name: + self.root.remove(elem) + self.save() + return 1 + return -10 + + def save(self): + # Be sure to call save() after any changes to the tree. + self.tree = ElementTree(self.root) + self.tree.write("data/user.xml") + +class ItemTree: + def __init__(self): + self.tree = ElementTree(file="data/sale.xml") + self.root = self.tree.getroot() + self.u_id = set() + + for elem in self.root: + self.u_id.add(int(elem.get("uid"))) + + def getId(self): + id_itter = 1 + while id_itter in self.u_id: + id_itter += 1 + self.u_id.add(id_itter) + return id_itter + + def remove_id(self, uid): + # Free up used id's. + self.u_id.remove(uid) + + def add_item(self, name, item_id, amount, price): + user = SubElement(self.root, "item") + user.set("name", name) + user.set("itemId", str(item_id)) + user.set("price", str(price)) + user.set("add_time", str(time.time())) + user.set("relisted", str(0)) + user.set("amount", str(amount)) + user.set("uid", str(self.getId())) + self.save() + + def get_uid(self, uid): + for elem in self.root: + if elem.get("uid") == str(uid): + return elem + return -10 + + def remove_item_uid(self, uid): + for elem in self.root: + if elem.get("uid") == str(uid): + self.root.remove(elem) + self.remove_id(uid) + self.save() + return 1 + return -10 + + def save(self): + # Be sure to call save() after any changes to the tree. + self.tree = ElementTree(self.root) + self.tree.write("data/sale.xml") diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..3215457 --- /dev/null +++ b/utils.py @@ -0,0 +1,115 @@ +from xml.etree.ElementTree import ElementTree +from player import Item + +import struct +import time +import mutex +import threading +from net.packet_out import * + +# Process a recieved ip address. +def parse_ip(a): + return "%s.%s.%s.%s" % ((a % 256),((a >> 8) % 256),((a >> 16) % 256),((a >> 24) % 256)) + +# Remove colors from a message +def remove_colors(msg): + if len(msg) > 2: + for f in range(len(msg)-2): + while (len(msg) > f + 2) and (msg[f] == "#")\ + and (msg[f+1] == "#"): + msg = msg[0:f]+msg[f+3:] + return msg + +# Encode string - used with 4144 shop compatibility. +def encode_str(value, size): + output = '' + base = 94 + start = 33 + while value: + output += struct.pack(' 500: + item_struct = Item() + item_struct.name = item.get('name') + if item.get('weight'): + item_struct.weight = item.get('weight') + item_struct.description = item.get('description') + self.item_names[int(item.get('id'))] = item_struct + + def getItem(self, item_id): + return self.item_names[item_id] + + def findId(self, name): + for item_id in self.item_names: + if self.item_names[item_id].name == name: + return item_id + return -10 #Not found + +class ItemLog: + """ Writes all sales to a log file, for later processing.""" + def __init__(self): + self.log_file = 'logs/sale.log' + + def add_item(self, item_id, amount, price): + file_node = open(self.log_file, 'a') + file_node.write(str(item_id)+" "+str(amount)+" "+str(price)+" "+str(time.time())+"\n") + file_node.close() + +class TraderState: + """ Stores information regarding a trade request""" + def __init__(self): + self.Trading = mutex.mutex() + self.item = 0 + self.money = 0 + self.complete = 0 + self.timer = 0 + + def reset(self): + self.Trading.unlock() + self.item = 0 + self.complete = 0 + self.money = 0 + self.timer = 0 + +class Broadcast: + """Send a message to the server every 5 minutes to avoid a timeout.""" + + def __init__(self): + self.mapserv = 0 + self.Active = False + self.Timer = 0 + self.shop_broadcast = threading.Thread(target=self.send_broadcast, args=()) + + def send_broadcast(self): + while self.Active: + if (time.time() - self.Timer) > 5 * 60: + self.mapserv.sendall(emote(193)) + self.Timer = time.time() + print "shop_broadcast" + else: + time.sleep(0.1) + + def start(self): + self.Active = True + self.shop_broadcast.start() + + def stop(self): + self.Active = False + self.shop_broadcast.join() -- cgit v1.2.3-70-g09d2