Advertisement
ryuzakivgc

scripts

Oct 27th, 2011
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Don't touch anything here if you don't know what you do.
  2. var noPlayer = '*';
  3.  
  4. var mafia = new function() {
  5.     // Remember to update this if you are updating mafia
  6.     // Otherwise mafia game won't get reloaded
  7.     this.version = "2011-06-03.0";
  8.  
  9.     var defaultTheme = {
  10.       name: "default",
  11.       sides: [
  12.         { "side": "mafia", "translation": "Mafia"
  13.         },
  14.         { "side": "mafia1", "translation": "French Canadian Mafia"
  15.         },
  16.         { "side": "mafia2", "translation": "Italian Mafia"
  17.         },
  18.         { "side": "village", "translation": "Good people"
  19.         },
  20.         { "side": "werewolf", "translation": "WereWolf"
  21.         },
  22.         { "side": "godfather", "translation": "Godfather"
  23.         }
  24.       ],
  25.       roles: [{
  26.           "role": "villager",
  27.           "translation": "Villager",
  28.           "side": "village",
  29.           "help": "You dont have any special commands during the night! Vote to remove people in the day!",
  30.           "actions": {}
  31.       }, {
  32.           "role": "inspector",
  33.           "translation": "Inspector",
  34.           "side": "village",
  35.           "help": "Type /Inspect [name] to find his/her identity!",
  36.           "actions": { "night": {"inspect": {"target": "AnyButSelf", "common": "Self", "priority": 30} } }
  37.       }, {
  38.           "role": "bodyguard",
  39.           "translation": "Bodyguard",
  40.           "side": "village",
  41.           "help": "Type /Protect [name] to protect someone!",
  42.           "actions": { "night": {"protect": {"target": "AnyButSelf", "common": "Role", "priority": 5, "broadcast": "role"} },
  43.                        "startup": "role-reveal"}
  44.       }, {
  45.           "role": "mafia",
  46.           "translation": "Mafia",
  47.           "side": "mafia",
  48.           "help": "Type /Kill [name] to kill someone!",
  49.           "actions": { "night": {"kill": {"target": "AnyButTeam", "common": "Team", "priority": 11, "broadcast": "team"} },
  50.                        "startup": "team-reveal"}
  51.       }, {
  52.           "role": "werewolf",
  53.           "translation": "WereWolf",
  54.           "side": "werewolf",
  55.           "help": "Type /Kill [name] to kill someone!",
  56.           "actions": { "night": {"kill": {"target": "AnyButSelf", "common": "Self", "priority": 10} },
  57.                        "distract": {"mode": "ChangeTarget", "hookermsg": "You tried to distract the Werewolf (what an idea, srsly), you were ravishly devoured, yum!", "msg": "The ~Distracter~ came to you last night! You devoured her instead!"},
  58.                        "avoidHax": ["kill"] }
  59.       }, {
  60.           "role": "hooker",
  61.           "translation": "Pretty Lady",
  62.           "side": "village",
  63.           "help": "Type /Distract [name] to distract someone! Vote to remove people in the day!",
  64.           "actions": { "night": {"distract": {"target": "AnyButSelf", "common": "Self", "priority": 1} } }
  65.       }, {
  66.           "role": "mayor",
  67.           "translation": "Mayor",
  68.           "side": "village",
  69.           "help": "You dont have any special commands during the night! Vote to remove people in the day! (your vote counts as 2)",
  70.           "actions": { "vote": 2 }
  71.       }, {
  72.           "role": "spy",
  73.           "translation": "Spy",
  74.           "side": "village",
  75.           "help": "You can find out who is going to get killed next!(no command for this ability) Vote to remove people in the day!",
  76.           "actions": { "hax": {"kill": { "revealTeam": 0.33, "revealPlayer": 0.1} } }
  77.       }, {
  78.           "role": "godfather",
  79.           "translation": "Godfather",
  80.           "side": "godfather",
  81.           "help": "Type /Kill [name] to kill someone! You can kill 2 targets, Type /kill [name2] again to select your second target!",
  82.           "actions": { "night": {"kill": {"target": "AnyButSelf", "common": "Self", "priority": 20, "limit": 2} },
  83.                        "distract": {"mode": "ChangeTarget", "hookermsg": "You tried to seduce the Godfather... you were killed instead!", "msg": "The ~Distracter~ came to you last night! You killed her instead!"},
  84.                        "avoidHax": ["kill"] }
  85.       }, {
  86.           "role": "vigilante",
  87.           "translation": "Vigilante",
  88.           "side": "village",
  89.           "help": "Type /Kill [name] to kill someone!(dont kill the good people!)",
  90.           "actions": { "night": {"kill": {"target": "AnyButSelf", "common": "Self", "priority": 19} } }
  91.       }, {
  92.           "role": "mafia1",
  93.           "translation": "French Canadian Mafia",
  94.           "side": "mafia1",
  95.           "help": "Type /Kill [name] to kill someone!",
  96.           "actions": { "night": {"kill": {"target": "AnyButTeam", "common": "Team", "priority": 12, "broadcast": "team"} },
  97.                        "startup": "team-reveal"}
  98.       }, {
  99.           "role": "mafia2",
  100.           "translation": "Italian Mafia",
  101.           "side": "mafia2",
  102.           "help": "Type /Kill [name] to kill someone!",
  103.           "actions": { "night": {"kill": {"target": "AnyButTeam", "common": "Team", "priority": 11, "broadcast": "team"} },
  104.                        "startup": "team-reveal"}
  105.       }, {
  106.           "role": "conspirator1",
  107.           "translation": "French Canadian Conspirator",
  108.           "side": "mafia1",
  109.           "help": "You dont have any special commands during the night! You are sided French Canadian Mafia. Vote to remove people in the day!",
  110.           "actions": { "inspect": {"revealAs": "villager"},
  111.                        "startup": "team-reveal"}
  112.       }, {
  113.           "role": "conspirator2",
  114.           "translation": "Italian Conspirator",
  115.           "side": "mafia2",
  116.           "help": "You dont have any special commands during the night! You are sided Italian Mafia. Vote to remove people in the day!",
  117.           "actions": { "inspect": {"revealAs": "villager"},
  118.                        "startup": "team-reveal"}
  119.       }, {
  120.           "role": "mafiaboss1",
  121.           "translation": "Don French Canadian Mafia",
  122.           "side": "mafia1",
  123.           "help": "Type /Kill [name] to kill someone! You can't be distracted!",
  124.           "actions": { "night": {"kill": {"target": "AnyButTeam", "common": "Team", "priority": 12, "broadcast": "team"} },
  125.                       "distract": {"mode": "ignore"},
  126.                       "startup": "team-reveal"}
  127.       }, {
  128.           "role": "mafiaboss2",
  129.           "translation": "Don Italian Mafia",
  130.           "side": "mafia2",
  131.           "help": "Type /Kill [name] to kill someone! You can't be distracted!",
  132.           "actions": { "night": {"kill": {"target": "AnyButTeam", "common": "Team", "priority": 11, "broadcast": "team"} },
  133.                       "distract": {"mode": "ignore"},
  134.                       "startup": "team-reveal"}
  135.       }, {
  136.           "role": "samurai",
  137.           "translation": "Samurai",
  138.           "side": "village",
  139.           "help": "Type /Kill [name] during the day phase to kill someone! You will be revealed when you kill, so make wise choices! You are allied with the Good people.",
  140.           "actions": { "standby": {"kill": {"target": "AnyButSelf", "msg": "You can kill now using /kill [name] :",
  141.                                    "killmsg": "~Self~ pulls out a sword and strikes it through ~Target~'s chest!"} } }
  142.       }, {
  143.           "role": "miller",
  144.           "translation": "Miller",
  145.           "side": "village",
  146.           "help": "You dont have any special commands during the night! Vote to remove people in the day! Oh, and insp sees you as Mafia",
  147.           "actions": { "inspect": {"revealAs": "mafia"} }
  148.       }, {
  149.           "role": "truemiller",
  150.           "translation": "Miller",
  151.           "side": "village",
  152.           "help": "You dont have any special commands during the night! Vote to remove people in the day!",
  153.           "actions": { "inspect": {"revealAs": "mafia"}, "lynch": {"revealAs": "mafia"}, "startup": {"revealAs": "villager"}, "onlist": "mafia" }
  154.       }, {
  155.           "role": "miller1",
  156.           "translation": "Miller",
  157.           "side": "village",
  158.           "help": "You dont have any special commands during the night! Vote to remove people in the day!",
  159.           "actions": { "inspect": {"revealAs": "mafia1"}, "lynch": {"revealAs": "mafia1"}, "startup": {"revealAs": "villager"}, "onlist": "mafia2" }
  160.       }, {
  161.           "role": "miller2",
  162.           "translation": "Miller",
  163.           "side": "village",
  164.           "help": "You dont have any special commands during the night! Vote to remove people in the day!",
  165.           "actions": { "inspect": {"revealAs": "mafia2"}, "lynch": {"revealAs": "mafia2"}, "startup": {"revealAs": "villager"}, "onlist": "mafia1" }
  166.       }],
  167.       roles1: ["bodyguard", "mafia", "inspector", "werewolf", "hooker", "villager", "truemiller",
  168.                "villager", "mafia", "villager", "mayor"],
  169.       roles2: ["bodyguard", "mafia1", "mafia1", "inspector", "hooker", "villager", "mafia2",
  170.                "mafia2", "villager", "villager", "villager", "mayor", "villager", "spy", "villager",
  171.                "miller1", "miller2", "mafiaboss1", "villager", "vigilante", "villager", "godfather",
  172.                "mafiaboss2", "samurai", "villager", "villager", "werewolf", "mafia1",
  173.                "mafia2", "bodyguard"],
  174.       villageCantLoseRoles: ["mayor", "vigilante", "samurai"]
  175.     };
  176.  
  177.     // Street Fighter is on a break.
  178.     var sfTheme = {"name":"Street Fighter IV","sides":[{"side":"mafia","translation":"Gen's"},{"side":"mafia1","translation":"Juri's"},{"side":"mafia2","translation":"Evil Ryu's"},{"side":"village","translation":"Good people"},{"side":"werewolf","translation":"Akuma"},{"side":"godfather","translation":"M.Bison"}],"roles":[{"role":"villager","translation":"Dan","side":"village","help":"You dont have any special commands during the night! Vote to remove people in the day!","actions":{}},{"role":"inspector","translation":"Chun-Li","side":"village","help":"Type /Inspect [name] to find his/her identity!","actions":{"night":{"inspect":{"target":"AnyButSelf","common":"Self","priority":30}}}},{"role":"bodyguard","translation":"Rufus","side":"village","help":"Type /Protect [name] to protect someone!","actions":{"night":{"protect":{"target":"AnyButSelf","common":"Role","priority":5,"broadcast":"role"}},"startup":"role-reveal"}},{"role":"mafia","translation":"Gen","side":"mafia","help":"Type /Kill [name] to kill someone!","actions":{"night":{"kill":{"target":"AnyButTeam","common":"Team","priority":11,"broadcast":"team"}},"startup":"team-reveal"}},{"role":"werewolf","translation":"Akuma","side":"werewolf","help":"Type /Kill [name] to kill someone!","actions":{"night":{"kill":{"target":"AnyButSelf","common":"Self","priority":10}},"distract":{"mode":"ChangeTarget","hookermsg":"You tried to distract AKUMA! (what an idea, srsly), you were killed with a lot of violence o.o !","msg":"The ~Distracter~ came to you last night! You devoured her instead !"},"avoidHax":["kill"]}},{"role":"hooker","translation":"Candy","side":"village","help":"Type /Distract [name] to distract someone! Vote to remove people in the day!","actions":{"night":{"distract":{"target":"AnyButSelf","common":"Self","priority":1}}}},{"role":"mayor","translation":"Ryu","side":"village","help":"You dont have any special commands during the night! Vote to remove people in the day! (your vote counts as 2)","actions":{"vote":2}},{"role":"spy","translation":"C.Viper","side":"village","help":"You can find out who is going to get killed next!(no command for this ability) Vote to remove people in the day!","actions":{"hax":{"kill":{"revealTeam":0.33,"revealPlayer":0.1}}}},{"role":"godfather","translation":"M.Bison","side":"godfather","help":"Type /Kill [name] to kill someone! You can kill 2 targets, Type /kill [name2] again to select your second target!","actions":{"night":{"kill":{"target":"AnyButSelf","common":"Self","priority":20,"limit":2}},"distract":{"mode":"ChangeTarget","hookermsg":"You tried to seduce M.Bison, you just were killed!","msg":"The ~Distracter~ came to you last night! You killed her instead!"},"avoidHax":["kill"]}},{"role":"vigilante","translation":"Dhalsim","side":"village","help":"Type /Kill [name] to kill someone!(dont kill the good people!)","actions":{"night":{"kill":{"target":"AnyButSelf","common":"Self","priority":19}}}},{"role":"mafia1","translation":"Juri","side":"mafia1","help":"Type /Kill [name] to kill someone!","actions":{"night":{"kill":{"target":"AnyButTeam","common":"Team","priority":12,"broadcast":"team"}},"startup":"team-reveal"}},{"role":"mafia2","translation":"Evil Ryu","side":"mafia2","help":"Type /Kill [name] to kill someone!","actions":{"night":{"kill":{"target":"AnyButTeam","common":"Team","priority":11,"broadcast":"team"}},"startup":"team-reveal"}},{"role":"conspirator1","translation":"French Canadian Conspirator","side":"mafia1","help":"You dont have any special commands during the night! You are sided French Canadian Mafia. Vote to remove people in the day!","actions":{"inspect":{"revealAs":"villager"},"startup":"team-reveal"}},{"role":"conspirator2","translation":"Italian Conspirator","side":"mafia2","help":"You dont have any special commands during the night! You are sided Italian Mafia. Vote to remove people in the day!","actions":{"inspect":{"revealAs":"villager"},"startup":"team-reveal"}},{"role":"mafiaboss1","translation":"Don Juri's boss","side":"mafia1","help":"Type /Kill [name] to kill someone! You can't be distracted!","actions":{"night":{"kill":{"target":"AnyButTeam","common":"Team","priority":12,"broadcast":"team"}},"distract":{"mode":"ignore"},"startup":"team-reveal"}},{"role":"mafiaboss2","translation":"Don Evil Ryu's boss","side":"mafia2","help":"Type /Kill [name] to kill someone! You can't be distracted!","actions":{"night":{"kill":{"target":"AnyButTeam","common":"Team","priority":11,"broadcast":"team"}},"distract":{"mode":"ignore"},"startup":"team-reveal"}},{"role":"samurai","translation":"Fei Long","side":"village","help":"Type /Kill [name] during the day phase to kill someone! You will be revealed when you kill, so make wise choices! You are allied with the Good people.","actions":{"standby":{"kill":{"target":"AnyButSelf","msg":"You can kill now using /kill [name] :","killmsg":"~Self~ pulls out a sword and strikes it through ~Target~'s chest!"}}}},{"role":"miller","translation":"Lolrole","side":"village","help":"You dont have any special commands during the night! Vote to remove people in the day! Oh, and insp sees you as Mafia","actions":{"inspect":{"revealAs":"mafia"}}}],"roles1":["bodyguard","mafia","inspector","werewolf","hooker","villager","mafia","villager","miller","villager","mayor"],"roles2":["bodyguard","mafia1","mafia1","inspector","hooker","villager","mafia2","mafia2","villager","villager","villager","mayor","villager","spy","villager","villager","villager","mafiaboss1","villager","vigilante","villager","godfather","mafiaboss2","samurai","villager","villager","werewolf","mafia1","mafia2","bodyguard"],"villageCantLoseRoles":["mayor","vigilante","samurai"]};
  179.  
  180.     var hpTheme = {"villageCantLoseRoles": ["mayor", "hooker", "samurai"], "name": "Harry Potter", "roles": [{"translation": "Muggle", "role": "villager", "side": "village", "actions": {}, "help": "You have no magical powers, so all you can do is vote to remove people in the day!"}, {"translation": "Harry Potter", "role": "inspector", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Inspect [name] to cast a spell to figure out a person\'s role!"}, {"translation": "Hagrid", "role": "bodyguard", "side": "village", "actions": {"startup": "role-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "Type /Protect [name] to protect someone, you large oaf you!"}, {"translation": "Snape", "role": "werewolf", "side": "werewolf", "actions": {"vote": 2, "avoidHax": ["kill"], "kill": {"mode": "ignore"}, "distract": {"msg": "The ~Distracter~ came to you last night! You killed the fool.", "mode": "ChangeTarget", "hookermsg": "You tried to distract Severus Snape (what an idea, srsly), and were promptly killed, sorry!"}}, "help": "You can not be killed at night. Your vote counts as two during the day, and you are immune to the charms of the Pretty Lady.  You are all alone in the world!"}, {"translation": "Hermione Granger", "role": "hooker", "side": "village", "actions": {"night": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Distract [name] at night to Stupify them! Vote to remove people in the day!"}, {"translation": "Dumbledore", "role": "mayor", "side": "village", "actions": {"vote": 3}, "help": "You dont have any special commands during the night. Pull your rank during the day, as your votes count as three. "}, {"translation": "Argus Filch", "role": "spy", "side": "village", "actions": {"hax": {"kill": {"revealPlayer": 0.14999999999999999, "revealTeam": 0.40000000000000002}}}, "help": "You can find out who is going to get killed next!(no command for this ability) Vote to remove people in the day. Being superbly creepy, you can a bonus to detection over normal spies."}, {"translation": "Fred Weasley", "role": "mafia1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] at night to dispose of someone!"}, {"translation": "George Weasley", "role": "mafia1.5", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] at night to dispose of someone!"}, {"translation": "Momma Weasley", "role": "mafia1.6", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "Type /Kill [name] at night to dispose of someone!  You are working with Fred and George (Not Ron), and you can protect one of the two per night."}, {"translation": "Death Eater", "role": "mafia2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Head Death Eater", "role": "mafia2.5", "side": "mafia2", "actions": {"vote": -1, "inspect": {"revealAs": "villager"}, "startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!  You are seen to the inspector as a Muggle.  Your vote counts as -1.  Use it to save your fellow Death Eaters!"}, {"translation": "Auror", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ whips out his wand and points it at ~Target~, causing ~Target~ to drop dead!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to kill someone! You will be revealed when you kill, so make wise choices! You are allied with the Good people."}, {"translation": "Voldemort", "role": "evilsamurai", "side": "mafia2", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "Voldemort casts Avada Kedavra, and ~Target~ falls to the ground dead!", "target": "AnyButSelf"}}, "startup": "team-reveal"}, "help": "Type /Kill [name] during the day phase to kill someone! You may only kill once per day, but you will not be revealed.  You are allied with the Death Eaters."}, {"translation": "Nearly Headless Nick", "role": "miller", "side": "village", "actions": {"inspect": {"revealAs": "mafia1"}}, "help": "You dont have any special commands during the night! Unfortunately, though, people are afraid of your flopping head and so the Inspector sees you as evil."}, {"translation": "Peeves", "role": "miller1.5", "side": "village", "actions": {"inspect": {"revealAs": "mafia2"}}, "help": "You dont have any special commands during the night! Unfortunately, though, everyone hates you and so the Inspector sees you as evil."}, {"translation": "Draco Malfoy", "role": "mafia3", "side": "mafia3", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 2, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! Even the Bodyguard cannot stop you!"}, {"translation": "Lucius Malfoy", "role": "mafia3.5", "side": "mafia3", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 2, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! Even the Bodyguard cannot stop you!"}], "sides": [{"translation": "Weasley Brothers", "side": "mafia1"}, {"translation": "Death Eaters", "side": "mafia2"}, {"translation": "Malfoys", "side": "mafia3"}, {"translation": "Hogwarts", "side": "village"}, {"translation": "Snape", "side": "werewolf"}], "roles2": ["bodyguard", "mafia1", "mafia1.5", "inspector", "hooker", "villager", "mafia2", "mafia2", "villager", "villager", "werewolf", "mayor", "evilsamurai", "spy", "samurai", "villager", "miller", "mafia1.6", "mafia2.5", "samurai", "villager", "villager", "miller1.5", "villager", "villager", "mafia3", "mafia3.5"], "roles1": ["bodyguard", "mafia1", "inspector", "mafia1.5", "hooker", "villager", "villager", "miller", "villager", "mayor"]};
  181.  
  182.     var potatoTheme = {"villageCantLoseRoles": ["mayor", "vigilante", "samurai"], "name": "Potato", "roles": [{"translation": "Potato", "role": "villager", "side": "village", "actions": {}, "help": "You are delicious victim. You dont have any special commands during the night! Vote to remove people in the day!"}, {"translation": "Mr. Potato", "role": "inspector", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "Thanks to the fact you have eyes, you check out who is bad and who\'s good. Type /Inspect [name] to find his/her identity!"}, {"translation": "Ms. Potato", "role": "bodyguard", "side": "village", "actions": {"startup": "role-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "You are the lovely Mr. Potato wife. You love him so much, you can even protect him from dying. Thankfully, you can use this abilities on other people as well. Type /Protect [name] to protect someone!"}, {"translation": "Rabbit", "role": "mafia", "side": "mafia", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "You LOVE potatos. Type /Kill [name] to eat someone!"}, {"translation": "Mean Rabbit", "role": "werewolf", "side": "werewolf", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The French Fries came to you last night! You devoured her instead !", "mode": "ChangeTarget", "hookermsg": "You tried to distract the Mean Rabbit (what an idea, srsly), you were ravishly devoured, yum !"}, "night": {"kill": {"priority": 10, "target": "AnyButSelf", "common": "Self"}}}, "help": "You look like innocent rabbit, but you ADORE potatos. Type /kill to kill. If you see the delicous French Fries, you eat her instead."}, {"translation": "French Fries", "role": "hooker", "side": "village", "actions": {"night": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Thanks to your AMAZING tanning, you look like an adorable potato. Type /Distract [name] to distract someone! Vote to remove people in the day! Note: You are part of the good people - the potatos"}, {"translation": "Sweet Potato", "role": "mayor", "side": "village", "actions": {"vote": 4}, "help": "You have an amazing taste. Thanks to this, you can attract many people to vote with you off. You dont have any special commands during the night! Vote to remove people in the day! (your vote counts as 4)"}, {"translation": "Watermelon", "role": "godfather", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "You are the orange\'s biggest enemy. You are the only one to know that the orange role is a bad person, who the inspector sees as a French Fries. You must tell him that he is bad. But how? You are able to inspect people, to find out who is the orange. But make sure you are not confusing the real pl with the orange!"}, {"translation": "Orange", "role": "godfather1", "side": "godfather", "actions": {"inspect": {"revealAs": "hooker"}, "kill": {"mode": "ignore"}, "night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "You just look like a potato. however, your shell is really bitter. Thanks to this, you can\'t die. Your partner is the Mean deer(godfather). You must find him yourself, which may be hard. But don\'t worry, /inspect will help you doing the. when you get inspected you are seen as the French Fries (pl)"}, {"translation": "Mean Deer", "role": "godfather2", "side": "godfather1", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You killed her instead!", "mode": "ChangeTarget", "hookermsg": "You tried to seduce the Godfather, you just were killed!"}, "night": {"kill": {"priority": 20, "limit": 2, "target": "AnyButSelf", "common": "Self"}}}, "help": "You look like an innocent dear, but you are evil deer who likes potatos and rabbits. Type /Kill [name] to kill someone! You are able to kill 2 people a day. Your partner is the Orange. He don\'t know who you are and he don\'t know who he is. he can find you using his inspecting skills."}, {"translation": "outlaw", "role": "vigilante", "side": "village", "actions": {"night": {"kill": {"priority": 19, "target": "AnyButSelf", "common": "Self"}}}, "help": "You love the potatoes, but hate see them dying. You decide by your own to kill (/kill) someone each night, hoping it\'s a bad guy."}, {"translation": "French Rabbits", "role": "mafia1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "You LOVE potatoes. Type /Kill [name] to kill someone!"}, {"translation": "Italian Deers", "role": "mafia2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "You LOVE potatoes. Type /Kill [name] to kill someone!"}, {"translation": "French Rabbit Conspirator", "role": "conspirator1", "side": "mafia1", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You LOVE potatoes. You dont have any special commands during the night! You are sided French Canadian Mafia. Vote to remove people in the day!"}, {"translation": "Italian Deer Conspirator", "role": "conspirator2", "side": "mafia2", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You LOVE potatoes. You dont have any special commands during the night! You are sided Italian Mafia. Vote to remove people in the day!"}, {"translation": "Don French Rabbit Mafia", "role": "mafiaboss1", "side": "mafia1", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "You LOVE potatoes. Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Don Italian Deer Mafia", "role": "mafiaboss2", "side": "mafia2", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "You LOVE potatoes. Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Potato Cowboy", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ pulls out a sword and strikes it through ~Target~\'s chest!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to kill someone! You will be revealed when you kill, so make wise choices! You are allied with the Good people."}, {"translation": "Potato Sadface", "role": "miller", "side": "village", "actions": {"inspect": {"revealAs": "mafia"}, "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "and insp sees you as Mafia, However, you protect him."}], "sides": [{"translation": "Rabbit", "side": "mafia"}, {"translation": "French Rabbits", "side": "mafia1"}, {"translation": "Italian Deers", "side": "mafia2"}, {"translation": "Potatoes", "side": "village"}, {"translation": "Mean Rabbit", "side": "werewolf"}, {"translation": "Mean Deer", "side": "godfather"}], "roles2": ["bodyguard", "mafia1", "mafia1", "inspector", "hooker", "villager", "mafia2", "mafia2", "villager", "villager", "villager", "mayor", "villager", "spy", "villager", "villager", "villager", "mafiaboss1", "villager", "vigilante", "villager", "godfather2", "godfather1", "godfather0", "mafiaboss2", "samurai", "villager", "villager", "werewolf", "mafia1", "mafia2", "bodyguard"], "roles1": ["bodyguard", "mafia", "inspector", "werewolf", "hooker", "villager", "mafia", "villager", "miller", "villager", "mayor"]};
  183.  
  184.     var ssbbTheme = {"villageCantLoseRoles": ["mayor", "vigilante", "samurai", "samus"], "name": "SSBB", "roles": [{"translation": "Mario", "role": "villager", "side": "village", "actions": {}, "help": "You dont have any special commands during the night! Vote to remove people in the day!"}, {"translation": "Lucas", "role": "inspector", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Inspect [name] to find his/her identity!"}, {"translation": "Donkey Kong", "role": "bodyguard", "side": "village", "actions": {"startup": "role-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "Type /Protect [name] to protect someone!"}, {"translation": "Bowser", "role": "mafia", "side": "mafia", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Wolf", "role": "werewolf", "side": "wolf", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You devoured her instead !", "mode": "ChangeTarget", "hookermsg": "You tried to distract Wolf (what an idea, srsly), you were ravishly shot at!"}, "night": {"kill": {"priority": 10, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Peach", "role": "hooker", "side": "village", "actions": {"night": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Distract [name] to distract someone! Vote to remove people in the day!"}, {"translation": "Captain Falcon", "role": "mayor", "side": "village", "actions": {"vote": 3, "standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ pulls out a fist and punches it through ~Target~\'s chest!", "target": "AnyButSelf"}}}, "help": "You dont have any special commands during the night! Vote to remove people in the day! /Kill To remove people people with a falcon punch! (your vote counts as 3)"}, {"translation": "Snake", "role": "spy", "side": "village", "actions": {"hax": {"kill": {"revealPlayer": 0.20000000000000001, "revealTeam": 0.40000000000000002}}}, "help": "You can find out who is going to get killed next!(no command for this ability) Vote to remove people in the day!"}, {"translation": "Jigglypuff", "role": "godfather", "side": "godfather", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You killed her instead!", "mode": "ChangeTarget", "hookermsg": "You tried to seduce the Marshmallow, you just were rested!"}, "night": {"kill": {"priority": 20, "limit": 2, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone! You can kill 2 targets, Type /kill [name2] again to select your second target!"}, {"translation": "Ike", "role": "vigilante", "side": "village", "actions": {"night": {"kill": {"priority": 19, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone using a sword!(dont kill the good people!)"}, {"translation": "Samus", "role": "samus", "side": "village", "actions": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}, "night": {"kill": {"priority": 19, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone using a missile! (dont kill the good people!) Type /distract to distract someone"}, {"translation": "Ganondorf", "role": "mafia1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Wario", "role": "mafia2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Waddle Doo", "role": "mafia3", "side": "mafia3", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Moblin", "role": "conspirator1", "side": "mafia1", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night! You are sided Hyrulian Mafia. Vote to remove people in the day!"}, {"translation": "Waluigi", "role": "conspirator2", "side": "mafia2", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night! You are sided Italian Mafia. Vote to remove people in the day!"}, {"translation": "WaddleDee", "role": "conspirator3", "side": "mafia3", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night! You are sided Penguin Mafia. Vote to remove people in the day!"}, {"translation": "Ganon", "role": "mafiaboss1", "side": "mafia1", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Wario-Man", "role": "mafiaboss2", "side": "mafia2", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "King Dedede", "role": "mafiaboss3", "side": "mafia3", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Marth", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "Marth pulls out a sword and strikes it through ~Target~\'s chest!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to kill someone! You will not be revealed when you kill! You are allied with the Good people."}, {"translation": "MetaKnight", "role": "miller", "side": "village", "actions": {"inspect": {"revealAs": "mafia"}}, "help": "You dont have any special commands during the night! Vote to remove people in the day! Oh, and insp sees you as Mafia"}], "sides": [{"translation": "Koopa", "side": "mafia"}, {"translation": "Hyrulian Mafia", "side": "mafia1"}, {"translation": "Italian Mafia", "side": "mafia2"}, {"translation": "Penguin Mafia", "side": "mafia3"}, {"translation": "Good people", "side": "village"}, {"translation": "Wolf", "side": "wolf"}, {"translation": "Marshmellow", "side": "godfather"}], "roles2": ["bodyguard", "mafia1", "mafia1", "inspector", "hooker", "villager", "mafia2", "mafia2", "villager", "villager", "villager", "mayor", "villager", "spy", "mafia3", "mafia3", "villager", "mafiaboss1", "villager", "vigilante", "samus", "godfather", "mafiaboss2", "samurai", "villager", "mafiaboss3", "werewolf", "mafia1", "mafia2", "bodyguard"], "roles1": ["bodyguard", "mafia", "inspector", "werewolf", "hooker", "villager", "mafia", "villager", "miller", "villager", "mayor"]};
  185.  
  186.     var ffTheme = {"villageCantLoseRoles": ["mayor", "vigilante", "samurai"], "name": "FF", "roles": [{"translation": "Moogle", "role": "villager", "side": "village", "actions": {}, "help": "As a moogle, it is your job to get the village to win by voting during the day!"}, {"translation": "Locke", "role": "inspector", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Inspect [name] to find his/her identity! Be careful to not die!"}, {"translation": "Auron", "role": "bodyguard", "side": "village", "actions": {"startup": "role-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "Type /Protect [name] to protect someone! Try to survive!"}, {"translation": "Garland", "role": "mafia", "side": "mafia", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 15, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You, Garland, will knock them all down!"}, {"translation": "Kefka", "role": "werewolf", "side": "werewolf", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You destroyed her instead !", "mode": "ChangeTarget", "hookermsg": "You tried to distract Kefka (how foolish...), you were killed instead !"}, "night": {"kill": {"priority": 3, "target": "AnyButTeam", "common": "Self"}}}, "help": "With insane agility, you outspeed even bodyguards. Strike hard with /kill [name]!"}, {"translation": "Tifa", "role": "hooker", "side": "village", "actions": {"night": {"distract": {"priority": 2, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Distract [name] to fool around with someone! Those you mess with can do nothing!"}, {"translation": "Cecil", "role": "mayor", "side": "village", "actions": {"vote": -1}, "help": "Conflicted to the core, your vote counts as -1. Use this to lead the village to victory."}, {"translation": "Kuja", "role": "mayor2", "side": "werewolf", "actions": {"vote": 2}, "help": "You\'re just here for a bit of fun. If you can find and partner up with Kefka, hopefully you can screw the heroes over! Your vote counts as 2."}, {"translation": "Zidane", "role": "spy", "side": "village", "actions": {"hax": {"kill": {"revealPlayer": 0.14999999999999999, "revealTeam": 0.40000000000000002}}}, "help": "You have the ability to sense danger. Use these skills to figure out who is going to die!"}, {"translation": "Sephiroth", "role": "godfather", "side": "godfather", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "Sephiroth pulls out a sword and swiftly strikes it through ~Target~\'s chest!", "target": "AnyButSelf"}}, "avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You killed her instead!", "mode": "ChangeTarget", "hookermsg": "You tried to mess with Sephiroth, you just were killed!"}, "night": {"kill": {"priority": 20, "limit": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone! You can kill twice, once during standby and once at night. You will not be revealed, so have fun! "}, {"translation": "Lightning", "role": "vigilante", "side": "village", "actions": {"night": {"kill": {"priority": 19, "target": "AnyButSelf", "common": "Self"}}}, "help": "Allied with the heroes, it is your goal to assist them and win! Type /kill [name] during the night."}, {"translation": "Jecht", "role": "mafia1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Team up with Seymour and Yunalesca to bring Sin to victory! Type /kill [name] during the night!"}, {"translation": "Larsa Solidor", "role": "mafia2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "House Solidor unite! Use /kill [name] to weaken the heroes."}, {"translation": "Yunalesca", "role": "conspirator1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Stop those who threaten to ruin Sin\'s plans. Type /distract [name] during the night."}, {"translation": "Judge Gabranth", "role": "conspirator2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"protect": {"priority": 4, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "You\'re House Solidor\'s personal bodyguard. Type /protect [name] to defend Larsa or Vayne!"}, {"translation": "Seymour", "role": "mafiaboss1", "side": "mafia1", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted by foolish mortals."}, {"translation": "Vayne Solidor", "role": "mafiaboss2", "side": "mafia2", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "As head of House Solidor, it is your duty to crush the heroes. Type /kill [name]. You cannot be distracted."}, {"translation": "Cloud", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ pulls out a Buster Sword and strikes it through ~Target~\'s chest!", "target": "AnyButSelf"}}}, "help": "Lead the heroes to victory by typing /kill [name] during a standby phase! "}, {"translation": "Cactuar", "role": "miller", "side": "village", "actions": {"inspect": {"revealAs": "werewolf"}}, "help": "You dont have any special commands during the night! Vote to remove people in the day! Inspector will think you\'re a bad guy!"}], "sides": [{"translation": "Garland", "side": "mafia"}, {"translation": "Sin", "side": "mafia1"}, {"translation": "House Solidor", "side": "mafia2"}, {"translation": "Heroes", "side": "village"}, {"translation": "Kefka\'s Posse", "side": "werewolf"}, {"translation": "Sephiroth", "side": "godfather"}], "roles2": ["bodyguard", "mafia1", "conspirator1", "inspector", "hooker", "villager", "mafia2", "conspirator2", "villager", "miller", "vigilante", "mayor", "werewolf", "spy", "villager", "villager", "mafia", "mafiaboss1", "mafiaboss2", "godfather", "villager", "samurai", "mayor2", "miller", "villager", "villager", "villager", "miller", "miller", "mafia"], "roles1": ["bodyguard", "mafia", "inspector", "werewolf", "hooker", "villager", "mafia", "mayor", "miller", "villager", "villager"]};
  187.  
  188.     var darknessTheme = {"villageCantLoseRoles": ["mayor", "vigilante", "samurai"], "name": "Darkness", "roles": [{"translation": "Scared People", "role": "villager", "side": "village", "actions": {}, "help": "You dont have any special commands during the night of course you are so frightened! Vote to remove people in the day!"}, {"translation": "Detective", "role": "inspector", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Inspect [name] to find his/her identity!"}, {"translation": "Charm", "role": "bodyguard", "side": "village", "actions": {"startup": "role-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "Type /Protect [name] to protect someone and hope not to die!"}, {"translation": "Ghosts", "role": "mafia", "side": "mafia", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone with your scream!"}, {"translation": "Anubis", "role": "werewolf", "side": "werewolf", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You devoured her instead and was delighted!", "mode": "ChangeTarget", "hookermsg": "You tried to distract Anubis (what an idea, srsly), you were ravishly devoured, for a treat and tributed to Anubis!"}, "night": {"kill": {"priority": 10, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone with your dark underworld powers of Egypt!"}, {"translation": "Lady Ghastly", "role": "hooker", "side": "village", "actions": {"night": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Distract [name] to distract someone! Vote to remove people in the day!"}, {"translation": "President", "role": "mayor", "side": "village", "actions": {"vote": 5}, "help": "You dont have any special commands during the night! Vote to remove people in the day! (your vote counts as 5)"}, {"translation": "Sneaky", "role": "spy", "side": "village", "actions": {"hax": {"kill": {"revealPlayer": 0.10000000000000001, "revealTeam": 0.33000000000000002}}}, "help": "You can find out who is going to get killed next!(no command for this ability) Vote to remove people in the day!"}, {"translation": "Grim Reaper", "role": "godfather", "side": "godfather", "actions": {"vote": 5, "avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You killed her instead and sent her below!", "mode": "ChangeTarget", "hookermsg": "You tried to seduce the Grim Reaper, you just were killed and sent to the Underworld!"}, "night": {"kill": {"priority": 20, "limit": 2, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone! You can kill 2 targets, Type /kill [name2] again to select your second target! (your vote counts as 5)"}, {"translation": "Angels", "role": "vigilante", "side": "village", "actions": {"night": {"kill": {"priority": 19, "target": "AnyButSelf", "common": "Self"}, "distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone with holy engergy!(dont kill the scared people!) You are also cute enough to distract people! Type /Distract [name] to distract someone!"}, {"translation": "Vampires", "role": "mafia1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone with your fangs!"}, {"translation": "Deadly Ghosts", "role": "mafia2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone with an evil laughter and a scream!"}, {"translation": "Prince Vamp", "role": "conspirator1", "side": "mafia1", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night of course you are a good looking bat/vampire! You are sided Vampires. Vote to remove people in the day!"}, {"translation": "Prince Ghost", "role": "conspirator2", "side": "mafia2", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night of course your scared of the night but you aren\'t of the day! You are sided Deadly Ghosts. Vote to remove people in the day!"}, {"translation": "Lord Vamp", "role": "mafiaboss1", "side": "mafia1", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted, meaning your teeth keep you safe!"}, {"translation": "Lord Ghost", "role": "mafiaboss2", "side": "mafia2", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted of course it goes just straight through your heart!"}, {"translation": "Holy Orb", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ A light comes out and strikes it through ~Target~\'s body!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to kill someone! You will be revealed when you kill, so make wise choices! You are allied with the Good people."}, {"translation": "Holy Orb", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ A holy light comes out and strikes it through ~Target~\'s body!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to kill someone! You will be revealed when you kill, so make wise choices! You are allied with the Good people."}, {"translation": "Hades", "role": "samurai", "side": "mafia2", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Hades~ A dark blade is pulled out and is thrust through ~Target~\'s body with an evil laugh!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to kill someone! You not will be revealed when you kill, so make wise choices! You are allied with mafia2."}, {"translation": "Mr. Ghost", "role": "miller", "side": "village", "actions": {"inspect": {"revealAs": "mafia"}}, "help": "You dont have any special commands during the night of course your just a ghost and love the daylight! Vote to remove people in the day! Oh, and insp sees you as Mafia"}], "sides": [{"translation": "Ghosts", "side": "mafia"}, {"translation": "Vampires", "side": "mafia1"}, {"translation": "Deadly Ghosts", "side": "mafia2"}, {"translation": "Scared People", "side": "village"}, {"translation": "Anubis", "side": "werewolf"}, {"translation": "Grim Reaper", "side": "godfather"}], "roles2": ["bodyguard", "mafia1", "mafia1", "inspector", "hooker", "villager", "mafia2", "mafia2", "villager", "villager", "villager", "mayor", "villager", "spy", "villager", "villager", "villager", "mafiaboss1", "villager", "vigilante", "villager", "godfather", "mafiaboss2", "samurai", "villager", "villager", "werewolf", "mafia1", "mafia2", "bodyguard"], "roles1": ["bodyguard", "mafia", "inspector", "werewolf", "hooker", "villager", "mafia", "villager", "miller", "villager", "mayor"]};
  189.  
  190.     var internetTheme = {"villageCantLoseRoles": ["mayor", "vigilante", "samurai"], "name": "Internet", "roles": [{"translation": "Fish", "role": "villager", "side": "village", "actions": {}, "help": "Your cannon fodder! Vote to remove people in the day!"}, {"translation": "PRO", "role": "inspector", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Inspect [name] to find his/her identity!"}, {"translation": "Scapegoat", "role": "bodyguard", "side": "village", "actions": {"startup": "role-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "I\'m sure you know what this means. Type /Protect [name] to protect someone!"}, {"translation": "Mooks", "role": "mafia", "side": "mafia", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Munchkin", "role": "werewolf", "side": "werewolf", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You pwned them instead !", "mode": "ChangeTarget", "hookermsg": "You tried to edit the Munchkin, and he crushed you with his cheapness!"}, "night": {"kill": {"priority": 10, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to pwn someone! FUNTIME!"}, {"translation": "Ninja Editor", "role": "hooker", "side": "village", "actions": {"night": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Distract [name] to distract someone! Vote to remove people in the day!"}, {"translation": "Big Fish", "role": "mayor", "side": "village", "actions": {"vote": 3}, "help": "You lead the cannon fodder! Vote to remove people in the day! (your vote counts as 3)"}, {"translation": "Haxer", "role": "spy", "side": "village", "actions": {"hax": {"kill": {"revealPlayer": 0.14999999999999999, "revealTeam": 0.53000000000000003}}}, "help": "You can find out who is going to get killed next!(no command for this ability) Vote to remove people in the day!"}, {"translation": "Ubertroll", "role": "godfather", "side": "godfather", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You killed her instead!", "mode": "ChangeTarget", "hookermsg": "You tried to edit the Ubertroll, how dumb can you be?! You got trolled!"}, "night": {"kill": {"priority": 20, "limit": 3, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone! You can kill 3 targets!"}, {"translation": "Noob Hunter", "role": "vigilante", "side": "village", "actions": {"night": {"kill": {"priority": 19, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone!(dont kill the users!)"}, {"translation": "Noobs", "role": "mafia1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Trolls", "role": "mafia2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Noob Worshipper", "role": "conspirator1", "side": "mafia1", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night! You are sided with the Noobs. Vote to remove people in the day!"}, {"translation": "Troll Worshipper", "role": "conspirator2", "side": "mafia2", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night! You are sided with the Trolls. Vote to remove people in the day!"}, {"translation": "Noob Supreme", "role": "mafiaboss1", "side": "mafia1", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Troll Supreme", "role": "mafiaboss2", "side": "mafia2", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Troll Hunter", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ deletes ~Target~ from the current mafia game!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to delete someone! You will be revealed when you delete, so make wise choices! You are allied with the Good people."}, {"translation": "Unlucky Sap", "role": "miller", "side": "village", "actions": {"vote": 0, "inspect": {"revealAs": "mafia"}}, "help": "You dont have any special commands during the night! And you can\'t vote in the day! Oh, and PRO sees you as Mook. You really drew the short straw!"}, {"translation": "Pathetic Sap", "role": "sap", "side": "village", "actions": {"vote": 0, "inspect": {"revealAs": "godfather"}}, "help": "You dont have any special commands during the night! And you can\'t vote in the day! Oh, and PRO sees you as Ubertroll. You really drew the short straw!"}, {"translation": "Administrator", "role": "admin", "side": "authority", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ bans ~Target~ from the current mafia game!", "target": "Any"}}}, "help": "Type /Kill [name] during the day phase to ban someone! You will be revealed when you ban, so make wise choices! You are allied with the Authority! You can\'t see the mod, but he can see you."}, {"translation": "Moderator", "role": "mod", "side": "authority", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"protect": {"priority": 2, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}, "kill": {"priority": 21, "broadcast": "role", "target": "Any", "common": "Role"}}}, "help": "Use /protect to protect the Admin! You are allied with authority! You can also /kill someone in the same night that you protect the admin [you strike last]. The Ninja Editor can\'t distract you either!"}], "sides": [{"translation": "Mooks", "side": "mafia"}, {"translation": "Noobs", "side": "mafia1"}, {"translation": "Trolls", "side": "mafia2"}, {"translation": "Users", "side": "village"}, {"translation": "Auth", "side": "authority"}, {"translation": "Munchkin", "side": "werewolf"}, {"translation": "Ubertroll", "side": "godfather"}], "roles2": ["bodyguard", "mafia1", "mafia1", "inspector", "hooker", "villager", "mafia2", "mafia2", "villager", "sap", "villager", "mayor", "villager", "spy", "admin", "villager", "vigilante", "mod", "mafiaboss1", "vigilante", "villager", "godfather", "samurai", "mafiaboss2", "villager", "villager", "werewolf", "mafia1", "mafia2", "bodyguard", "villager", "conspiritor1", "conspiritor2"], "roles1": ["bodyguard", "mafia", "inspector", "werewolf", "hooker", "villager", "mafia", "villager", "miller", "villager", "mayor"]};
  191.  
  192.     //var mafiaTheme = {"villageCantLoseRoles": ["Mayor", "Vigilante", "Samurai"], "name": "Mafia", "roles": [{"translation": "Fish", "role": "villager", "side": "village", "actions": {}, "help": "Your cannon fodder! Vote to remove people in the day!"}, {"translation": "PRO", "role": "inspector", "side": "village", "actions": {"night": {"inspect": {"priority": 30, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Inspect [name] to find his/her identity!"}, {"translation": "Meat Shield", "role": "bodyguard", "side": "village", "actions": {"startup": "role-reveal", "night": {"protect": {"priority": 5, "broadcast": "role", "target": "AnyButSelf", "common": "Role"}}}, "help": "I\'m sure you know what this means. Type /Protect [name] to protect someone!"}, {"translation": "Mooks", "role": "mafia", "side": "mafia", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Munchkin", "role": "werewolf", "side": "werewolf", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You devoured her instead !", "mode": "ChangeTarget", "hookermsg": "You tried to distract the Munchkin,and he crushed you with his cheapness!"}, "night": {"kill": {"priority": 10, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone! DINNERTIME!"}, {"translation": "Rand Bait", "role": "hooker", "side": "village", "actions": {"night": {"distract": {"priority": 1, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Distract [name] to distract someone! Vote to remove people in the day!"}, {"translation": "Big Fish", "role": "mayor", "side": "village", "actions": {"vote": 3}, "help": "You lead the cannon fodder! Vote to remove people in the day! (your vote counts as 3)"}, {"translation": "Haxer", "role": "spy", "side": "village", "actions": {"hax": {"kill": {"revealPlayer": 0.14999999999999999, "revealTeam": 0.53000000000000003}}}, "help": "You can find out who is going to get killed next!(no command for this ability) Vote to remove people in the day!"}, {"translation": "Ubertroll", "role": "godfather", "side": "godfather", "actions": {"avoidHax": ["kill"], "distract": {"msg": "The ~Distracter~ came to you last night! You killed her instead!", "mode": "ChangeTarget", "hookermsg": "You tried to seduce the Ubertroll, how dumb can you be?! You got trolled!"}, "night": {"kill": {"priority": 20, "limit": 3, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone! You can kill 3 targets!"}, {"translation": "Noob Hunter", "role": "vigilante", "side": "village", "actions": {"night": {"kill": {"priority": 19, "target": "AnyButSelf", "common": "Self"}}}, "help": "Type /Kill [name] to kill someone!(dont kill the good people!)"}, {"translation": "Noobs", "role": "mafia1", "side": "mafia1", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Trolls", "role": "mafia2", "side": "mafia2", "actions": {"startup": "team-reveal", "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone!"}, {"translation": "Noob Worshipper", "role": "conspirator1", "side": "mafia1", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night! You are sided French Canadian Mafia. Vote to remove people in the day!"}, {"translation": "Troll Worshipper", "role": "conspirator2", "side": "mafia2", "actions": {"inspect": {"revealAs": "villager"}, "startup": "team-reveal"}, "help": "You dont have any special commands during the night! You are sided Italian Mafia. Vote to remove people in the day!"}, {"translation": "Noob Supreme", "role": "mafiaboss1", "side": "mafia1", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 12, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Troll Supreme", "role": "mafiaboss2", "side": "mafia2", "actions": {"startup": "team-reveal", "distract": {"mode": "ignore"}, "night": {"kill": {"priority": 11, "broadcast": "team", "target": "AnyButTeam", "common": "Team"}}}, "help": "Type /Kill [name] to kill someone! You can\'t be distracted!"}, {"translation": "Troll Hunter", "role": "samurai", "side": "village", "actions": {"standby": {"kill": {"msg": "You can kill now using /kill [name] :", "killmsg": "~Self~ bans ~Target~ from the current mafia game!", "target": "AnyButSelf"}}}, "help": "Type /Kill [name] during the day phase to kill someone! You will be revealed when you kill, so make wise choices! You are allied with the Good people."}, {"translation": "Unlucky Sap", "role": "miller", "side": "village", "actions": {"vote": 0, "inspect": {"revealAs": "mafia"}}, "help": "You dont have any special commands during the night! And you can\'t vote in the day! Oh, and insp sees you as Mook. You really drew the short straw!"}, {"translation": "Pathetic Sap", "role": "sap", "side": "village", "actions": {"vote": 0, "inspect": {"revealAs": "godfather"}}, "help": "You dont have any special commands during the night! And you can\'t vote in the day! Oh, and insp sees you as Ubertroll. You really drew the short straw!"}], "sides": [{"translation": "Mooks", "side": "mafia"}, {"translation": "Noobs", "side": "mafia1"}, {"translation": "Trolls", "side": "mafia2"}, {"translation": "PROs", "side": "village"}, {"translation": "Munchkin", "side": "werewolf"}, {"translation": "Ubertroll", "side": "godfather"}], "roles2": ["bodyguard", "mafia1", "mafia1", "inspector", "hooker", "villager", "mafia2", "mafia2", "villager", "villager", "villager", "mayor", "villager", "spy", "villager", "villager", "villager", "mafiaboss1", "villager", "vigilante", "villager", "godfather", "mafiaboss2", "samurai", "villager", "villager", "werewolf", "mafia1", "mafia2", "bodyguard", "sap", "conspiritor1", "conspiritor2"], "roles1": ["bodyguard", "mafia", "inspector", "werewolf", "hooker", "villager", "mafia", "villager", "miller", "villager", "mayor"]};
  193.  
  194.     /* ThemeManager is a object taking care of saving and loading themes
  195.      * in mafia game */
  196.     function ThemeManager() {
  197.         this.themeInfo = [];
  198.         this.themes = {};
  199.     }
  200.     ThemeManager.prototype.toString = function() { return "[object ThemeManager]"; }
  201.  
  202.     ThemeManager.prototype.save = function(name, url, resp) {
  203.         var fname = "mafiathemes/theme_" + name.toLowerCase();
  204.         sys.writeToFile(fname, resp);
  205.         var done = false;
  206.         for (var i = 0; i < this.themeInfo.length; ++i) {
  207.             if (cmp(name, this.themeInfo[i][0])) {
  208.                 done = true;
  209.                 this.themeInfo[i] = [name, url, fname, true];
  210.                 break;
  211.             }
  212.         }
  213.         if (!done) {
  214.             this.themeInfo.push([name, url, fname, true]);
  215.         }
  216.         sys.writeToFile("mafiathemes/metadata.json", JSON.stringify({'meta': this.themeInfo}));
  217.     }
  218.  
  219.     ThemeManager.prototype.loadTheme = function(plain_theme) {
  220.         var theme = new Theme();
  221.         try {
  222.             theme.sideTranslations = {};
  223.             theme.roles = {};
  224.             theme.nightPriority = [];
  225.             theme.standbyRoles = [];
  226.             theme.haxRoles = {};
  227.        
  228.             // Init from the theme
  229.             for (var i in plain_theme.sides) {
  230.                 theme.addSide(plain_theme.sides[i]);
  231.             }
  232.             for (var i in plain_theme.roles) {
  233.                 theme.addRole(plain_theme.roles[i]);
  234.             }
  235.             theme.roles1 = plain_theme.roles1;
  236.             var i = 2;
  237.             while ("roles"+i in plain_theme) {
  238.                 theme["roles"+i] = plain_theme["roles"+i];
  239.               ++i;
  240.             }
  241.             theme.roleLists = i-1;
  242.             theme.villageCantLoseRoles = plain_theme.villageCantLoseRoles;
  243.             theme.name = plain_theme.name;
  244.             theme.author = plain_theme.author;
  245.             theme.killmsg = plain_theme.killmsg;
  246.             theme.killusermsg = plain_theme.killusermsg;
  247.             theme.generateRoleInfo();
  248.             theme.enabled = true;
  249.             return theme;
  250.         } catch (err) {
  251.             if (typeof sys == 'object')
  252.                 sys.sendAll("+MafiaBot: Couldn't use theme " + plain_theme.name + ": "+err+".", mafiachan);
  253.             else
  254.                 print("+MafiaBot: Couldn't use theme: " + plain_theme.name + ": "+err+".");
  255.         }
  256.     }
  257.  
  258.     ThemeManager.prototype.loadThemes = function() {
  259.         if (typeof sys !== "object") return;
  260.         this.themes = {};
  261.         this.themes["default"] = this.loadTheme(defaultTheme);
  262.         var content = sys.getFileContent("mafiathemes/metadata.json");
  263.         if (!content) return;
  264.         var parsed = JSON.parse(content);
  265.         if (parsed.hasOwnProperty("meta")) {
  266.             this.themeInfo = parsed.meta;
  267.         }
  268.         for (var i = 0; i < this.themeInfo.length; ++i) {
  269.             if (!this.themeInfo[i][3]) continue;
  270.             try {
  271.                 var theme = this.loadTheme(JSON.parse(sys.getFileContent(this.themeInfo[i][2])));
  272.                 this.themes[theme.name.toLowerCase()] = theme;
  273.             } catch(err) {
  274.                 sys.sendAll("+MafiaBot: Error loading cached themes: " + err, mafiachan);
  275.             }
  276.         }
  277.     }
  278.     ThemeManager.prototype.saveToFile = function(plain_theme) {
  279.         if (typeof sys != "object") return;
  280.         var fname = "mafiathemes/theme_" + plain_theme.name.toLowerCase();
  281.         sys.writeToFile(fname, JSON.stringify(plain_theme));
  282.         this.themeInfo.push([plain_theme.name, "", fname, true]);
  283.         sys.writeToFile("mafiathemes/metadata.json", JSON.stringify({'meta': this.themeInfo}));
  284.     }
  285.  
  286.     ThemeManager.prototype.loadWebTheme = function(url, announce, update) {
  287.         if (typeof sys != 'object') return;
  288.         var manager = this;
  289.         sys.webCall(url, function(resp) {
  290.             try {
  291.                 var plain_theme = JSON.parse(resp);
  292.                 var theme = manager.loadTheme(plain_theme);
  293.                 var lower = theme.name.toLowerCase();
  294.                 if (manager.themes.hasOwnProperty(lower) && !update) {
  295.                     sys.sendAll("+MafiaBot: Won't update " + theme.name + " with /add, use /update to force an update", mafiachan);
  296.                     return;
  297.                 }
  298.                 manager.themes[lower] = theme;
  299.                 manager.save(theme.name, url, resp, update);
  300.                 if (announce) {
  301.                     sys.sendAll("+MafiaBot: Loaded theme " + theme.name, mafiachan);
  302.                 }
  303.             } catch (err) {
  304.                 sys.sendAll("+MafiaBot: Couldn't download theme from "+url, mafiachan);
  305.                 sys.sendAll("+MafiaBot: " + err, mafiachan);
  306.                 return;
  307.             }
  308.         });
  309.     }
  310.  
  311.     ThemeManager.prototype.remove = function(src, name) {
  312.         name = name.toLowerCase()
  313.         if (name in this.themes) {
  314.             delete this.themes[name];
  315.             for (var i = 0; i < this.themeInfo.length; ++i) {
  316.                 if (cmp(name, this.themeInfo[i][0])) {
  317.                     //this.themeInfo[i][3] = false;
  318.                     this.themeInfo.splice(i,1);
  319.                     break;
  320.                 }
  321.             }
  322.             sys.writeToFile("mafiathemes/metadata.json", JSON.stringify({'meta': this.themeInfo}));
  323.             sendChanMessage(src, "+MafiaBot: theme " + name + " removed.");
  324.         }
  325.     }
  326.  
  327.     ThemeManager.prototype.enable = function(src, name) {
  328.         name = name.toLowerCase()
  329.         if (name in this.themes) {
  330.             this.themes[name].enabled = true;
  331.             sendChanMessage(src, "+MafiaBot: theme " + name + " enabled.");
  332.         }
  333.     }
  334.  
  335.     ThemeManager.prototype.disable = function(src, name) {
  336.         name = name.toLowerCase()
  337.         if (name in this.themes) {
  338.             this.themes[name].enabled = false;
  339.             sendChanMessage(src, "+MafiaBot: theme " + name + " disabled.");
  340.         }
  341.     }
  342.    
  343.     /* Theme is a small helper to organize themes
  344.      * inside the mafia game */
  345.     function Theme() {}
  346.     Theme.prototype.toString = function() { return "[object Theme]"; }
  347.  
  348.     Theme.prototype.addSide = function(obj) {
  349.         this.sideTranslations[obj.side] = obj.translation;
  350.     }
  351.     Theme.prototype.addRole = function(obj) {
  352.         this.roles[obj.role] = obj;
  353.  
  354.         if ("hax" in obj.actions) {
  355.             for(var i in obj.actions.hax) {
  356.                 var action = i;
  357.                 if (!(action in this.haxRoles)) {
  358.                     this.haxRoles[action] = [];
  359.                 }
  360.                 this.haxRoles[action].push(obj.role);
  361.             }
  362.         }
  363.         if ("night" in obj.actions) {
  364.             for (var i in obj.actions.night) {
  365.                 var priority = obj.actions.night[i].priority;
  366.                 var action = i;
  367.                 var role = obj.role;
  368.                 this.nightPriority.push({'priority': priority, 'action': action, 'role': role});
  369.             }
  370.             this.nightPriority.sort(function(a,b) { return a.priority - b.priority });
  371.         }
  372.         if ("standby" in obj.actions) {
  373.             for (var i in obj.actions.standby) {
  374.                 this.standbyRoles.push(obj.role);
  375.             }
  376.         }
  377.     }
  378.     Theme.prototype.generateRoleInfo = function() {
  379.         var sep = "*** *********************************************************************** ***";
  380.         var roles = [sep];
  381.         for (var r in this.roles) {
  382.           try {
  383.             var role = this.roles[r];
  384.             roles.push("Β±Role: " + role.translation);
  385.  
  386.             // check which abilities the role has
  387.             var abilities = "";
  388.             if (role.actions.night) {
  389.                 for (var a in role.actions.night) {
  390.                     var ability = role.actions.night[a];
  391.                     abilities += "Can " + a + " " + ("limit" in ability ? ability.limit + " persons" : "one person") +" during the night. ";
  392.                     if ("avoidHax" in role.actions && role.actions.avoidHax.indexOf(a) != -1) {
  393.                         abilities += "(Can't be detected by spies.) ";
  394.                     }
  395.                 }
  396.             }
  397.             if (role.actions.standby) {
  398.                 for (var a in role.actions.standby) {
  399.                     var ability = role.actions.standby[a];
  400.                     abilities += "Can " + a + " " + ("limit" in ability ? ability.limit + " persons" : "one person") +" during the standby. ";
  401.                 }
  402.             }
  403.             if ("vote" in role.actions) {
  404.                 abilities += "Vote counts as " + role.actions.vote + ". ";
  405.             }
  406.             if ("kill" in role.actions && role.actions.kill.mode == "ignore") {
  407.                 abilities += "Can't be nightkilled. ";
  408.             }
  409.             if ("hax" in role.actions && Object.keys) {
  410.                 var haxy = Object.keys(role.actions.hax);
  411.                 abilities += "Gets hax on " + (haxy.length > 1 ? haxy.splice(0,haxy.length-1).join(", ")+" and ":"") + haxy + ". ";
  412.             }
  413.             if ("inspect" in role.actions) {
  414.                 abilities += "Reveals as " + this.roles[role.actions.inspect.revealAs].translation + " when inspected. ";
  415.             }
  416.             if ("distract" in role.actions) {
  417.                 if (role.actions.distract.mode == "ChangeTarget")
  418.                     abilities += "Kills any distractors. ";
  419.                 if (role.actions.distract.mode == "ignore")
  420.                     abilities += "Ignores any distractors. ";
  421.             }
  422.             if (typeof role.side == "string") {
  423.                 abilities += "Sided with " + this.trside(role.side) + ". ";
  424.             } else if (typeof role.side == "object") {
  425.                 var plop = Object.keys(role.side.random);
  426.                 var tran = [];
  427.                 for(var p in plop) {
  428.                    tran.push(this.trside(p));
  429.                 }
  430.                 abilities += "Sided with " + (tran.length > 1 ? tran.splice(0,tran.length-1).join(", ")+" or ":"") + tran + ". ";
  431.             }
  432.             roles.push("Β±Ability: " + abilities);
  433.  
  434.             // check on which player counts the role appears
  435.             var parts = [];
  436.             var end = 0;
  437.             for(var i = 1; i <= this.roleLists; ++i) {
  438.                 var r = "roles"+i;
  439.                 var start = this[r].indexOf(role.role);
  440.                 var last = end;
  441.                 end = this[r].length;
  442.                 if (start >= 0) {
  443.                     ++start;
  444.                     start = start > last ? start : 1+last;
  445.                     if(parts.length > 0 && parts[parts.length-1][1] == start-1) {
  446.                         parts[parts.length-1][1] = end;
  447.                     } else {
  448.                         parts.push([start,end]);
  449.                         if (parts.length > 1) {
  450.                             parts[parts.length-2] = parts[parts.length-2][0] < parts[parts.length-2][1] ? parts[parts.length-2].join("-") : parts[parts.length-2][1];
  451.                         }
  452.                     }
  453.                 }
  454.             }
  455.             if (parts.length > 0) {
  456.                 parts[parts.length-1] = parts[parts.length-1][0] < parts[parts.length-1][1] ? parts[parts.length-1].join("-") : parts[parts.length-1][1];
  457.             }
  458.             roles.push("Β±Game: " + parts.join(", ") + " Players");
  459.  
  460.             roles.push(sep);
  461.           } catch (err) {
  462.             sys.sendAll("+MafiaBot: Error adding role " + role.translation + "(" + role.role + ") to /roles", mafiachan);
  463.             throw err;
  464.           }
  465.         }
  466.         this.roleInfo = roles;
  467.     }
  468.  
  469.     /* Theme Loading and Storing */
  470.     Theme.prototype.trside = function(side) {
  471.         return this.sideTranslations[side];
  472.     }
  473.     Theme.prototype.trrole = function(role) {
  474.         return this.roles[role].translation;
  475.     }
  476.     Theme.prototype.getHaxRolesFor = function(command) {
  477.         if (command in this.haxRoles) {
  478.             return this.haxRoles[command];
  479.         }
  480.         return [];
  481.     }
  482.        this.isInGame = function(player) {
  483.         if (mafia.state == "entry") {
  484.             return this.signups.indexOf(player) != -1;
  485.         }
  486.         return player in this.players;
  487.     };
  488.     // init
  489.     this.themeManager = new ThemeManager();
  490.    
  491.     this.hasCommand = function(name, command, state) {
  492.         var player = this.players[name];
  493.         return (state in player.role.actions && command in player.role.actions[state]);
  494.     };
  495.     this.correctCase = function(string) {
  496.         var lstring = string.toLowerCase();
  497.         for (var x in this.players) {
  498.             if (x.toLowerCase() == lstring)
  499.                 return this.players[x].name;
  500.         }
  501.         return noPlayer;
  502.     };
  503.     this.clearVariables = function() {
  504.         /* hash : playername => playerstruct */
  505.         this.players = {};
  506.         this.signups = [];
  507.         this.state = "blank";
  508.         this.ticks = 0;
  509.         this.votes = {};
  510.         this.voteCount = 0;
  511.         this.ips = [];
  512.         this.resetTargets();
  513.     };
  514.     this.lastAdvertise = 0;
  515.     this.resetTargets = function() {
  516.         this.teamTargets = {};
  517.         this.roleTargets = {};
  518.         for (var p in this.players) {
  519.             this.players[p].targets = {};
  520.             this.players[p].dayKill = undefined;
  521.             this.players[p].guarded = undefined;
  522.         }
  523.     };
  524.     this.clearVariables();
  525.     /* callback for /start */
  526.     this.startGame = function(src, commandData) {
  527.         if (mafia.state != "blank") {
  528.             sys.sendMessage(src, "Β±Game: A game is going on. Wait until it's finished to start another one", mafiachan);
  529.             sys.sendMessage(src, "Β±Game: You can join the game by typing /join !", mafiachan);
  530.             return;
  531.         }
  532.         var previous = mafia.theme ? mafia.theme.name : undefined;
  533.        
  534.         mafia.theme = mafia.themeManager.themes["default"];
  535.  
  536.         if (commandData != noPlayer) {
  537.             var themeName = commandData.toLowerCase();
  538.             if (themeName in mafia.themeManager.themes) {
  539.                 if (!mafia.themeManager.themes[themeName].enabled) {
  540.                     sys.sendMessage(src, "Β±Game: This theme is disabled!", mafiachan);
  541.                 }
  542.                 mafia.theme = mafia.themeManager.themes[themeName];
  543.             } else {
  544.                 sys.sendMessage(src, "Β±Game: No such theme!", mafiachan);
  545.                 return;
  546.             }
  547.         }
  548.         // games need to go default, theme, default, theme...
  549.         // what a waste ._.
  550.         if (sys.auth(src) < 1) {
  551.             if (previous == "default" && mafia.theme.name == "default") {
  552.                 sys.sendMessage(src, "Β±Game: Can't repeat normal game!", mafiachan);
  553.                 return;
  554.             }
  555.             else if (previous !== undefined && previous !== "default" && mafia.theme.name != "default") {
  556.                 sys.sendMessage(src, "Β±Game: Can't repeat themed game!", mafiachan);
  557.                 return;
  558.             }
  559.         }
  560.  
  561.         sys.sendAll("", mafiachan);
  562.         sys.sendAll("*** ************************************************************************************", mafiachan);
  563.         sys.sendAll("Β±Game: " + sys.name(src) + " started a game with theme "+mafia.theme.name+"!", mafiachan);
  564.         sys.sendAll("Β±Game: Type /Join to enter the game!", mafiachan);
  565.         sys.sendAll("*** ************************************************************************************", mafiachan);
  566.         sys.sendAll("", mafiachan);
  567.  
  568.         if (sys.playersOfChannel(mafiachan).length < 20) {
  569.             var time = parseInt(sys.time());
  570.             if (false && time > mafia.lastAdvertise + 60*15) {
  571.                 mafia.lastAdvertise = time;
  572.                 sys.sendAll("", 0);
  573.                 sys.sendAll("*** ************************************************************************************", 0);
  574.                 sys.sendAll("Β±Game: " + sys.name(src) + " started a mafia game!", 0);
  575.                 sys.sendAll("Β±Game: Go in the #Mafia Channel and type /Join to enter the game!", 0);
  576.                 sys.sendAll("*** ************************************************************************************", 0);
  577.                 sys.sendAll("", 0);
  578.             }
  579.         }
  580.         mafia.clearVariables();
  581.         mafia.state = "entry";
  582.  
  583.         mafia.ticks = 60;
  584.     };
  585.     /* callback for /end */
  586.     this.endGame = function(src) {
  587.         if (mafia.state == "blank") {
  588.             sys.sendMessage(src, "Β±Game: No game is going on.",mafiachan);
  589.             return;
  590.         }
  591.         sys.sendAll("*** ************************************************************************************", mafiachan);
  592.        
  593.         sys.sendAll("Β±Game: " + (src ? sys.name(src) : 'MafiaBot') + " has stopped the game!", mafiachan);
  594.         sys.sendAll("*** ************************************************************************************", mafiachan);
  595.         sys.sendAll("", mafiachan);
  596.  
  597.         mafia.clearVariables();
  598.     };
  599.     /* called every second */
  600.     this.tickDown = function() {
  601.         if (this.ticks <= 0) {
  602.             return;
  603.         }
  604.         this.ticks = this.ticks - 1;
  605.         if (this.ticks == 0)
  606.             this.callHandler(this.state);
  607.         else {
  608.             if (this.ticks == 30 && this.state == "entry") {
  609.                 sys.sendAll("", mafiachan);
  610.                 sys.sendAll("Β±Game: Hurry up, you only have "+this.ticks+" seconds more to join!", mafiachan);
  611.                 sys.sendAll("", mafiachan);
  612.             }
  613.         }
  614.     };
  615.     this.sendPlayer = function(player, message) {
  616.         var id = sys.id(player);
  617.         if (id == undefined)
  618.             return;
  619.         sys.sendMessage(id, message, mafiachan);
  620.     };
  621.     this.getPlayersForTeam = function(side) {
  622.         var team = [];
  623.         for (var p in this.players) {
  624.             var player = this.players[p];
  625.             if (player.role.side == side) {
  626.                 team.push(player.name);
  627.             }
  628.         }
  629.         return team;
  630.     };
  631.     this.getPlayersForTeamS = function(side) {
  632.         return mafia.getPlayersForTeam(side).join(", ");
  633.     };
  634.     this.getPlayersForRole = function(role) {
  635.         var team = []
  636.         for (var p in this.players) {
  637.             var player = this.players[p];
  638.             if (player.role.role == role) {
  639.                 team.push(player.name);
  640.             }
  641.         }
  642.         return team;
  643.     };
  644.     this.getPlayersForRoleS = function(role) {
  645.         return mafia.getPlayersForRole(role).join(", ");
  646.     };
  647.     this.getCurrentRoles = function() {
  648.         var list = []
  649.         for (var p in this.players) {
  650.             if (typeof this.players[p].role.actions.onlist === "string")
  651.                 list.push(this.theme.trrole(this.players[p].role.actions.onlist));
  652.             else
  653.                 list.push(this.players[p].role.translation);
  654.         }
  655.          /* Sorting to not give out the order of the roles per player */
  656.         return list.sort().join(", ");
  657.     };
  658.     this.getCurrentPlayers = function() {
  659.         var list = [];
  660.         for (var p in this.players) {
  661.             list.push(this.players[p].name);
  662.         }
  663.         return list.sort().join(", ");
  664.  
  665.     }
  666.     this.player = function(role) {
  667.         for (var p in this.players) {
  668.             if (mafia.players[p].role.role == role) //Checks sequentially all roles to see if this is the good one
  669.                 return x;
  670.         }
  671.         return noPlayer;
  672.     };
  673.     this.removePlayer = function(player) {
  674.         //sys.sendAll("removing player " + player.name, mafiachan);
  675.         for (var action in player.role.actions.night) {
  676.             var targetMode = player.role.actions.night[action].target;
  677.             var team = this.getPlayersForTeam(player.role.side);
  678.             var role = this.getPlayersForRole(player.role.role);
  679.             if ((targetMode == 'AnyButSelf' || targetMode == 'Any')
  680.              || (targetMode == 'AnyButTeam' && team.length == 1)
  681.              || (targetMode == 'AnyButRole' && role.length == 1)) {
  682.                 this.removeTarget(player, action);
  683.             }
  684.         }
  685.         delete this.players[player.name];
  686.     };
  687.     this.kill = function(player) {
  688.         if (this.theme.killmsg) {
  689.             sys.sendAll(this.theme.killmsg.replace(/~Player~/g, player.name).replace(/~Role~/g, player.role.translation), mafiachan);
  690.         } else {
  691.             sys.sendAll("Β±Kill: " + player.name + " (" + player.role.translation + ") died!", mafiachan);
  692.         }
  693.         this.removePlayer(player);
  694.     };
  695.     this.removeTargets = function(player) {
  696.         for (var action in player.role.actions.night) {
  697.             this.removeTarget(player, action);
  698.         }
  699.     };
  700.     this.removeTarget = function(player, action) {
  701.         var targetMode = player.role.actions.night[action].common;
  702.         if (targetMode == 'Self') {
  703.             player.targets[action] = [];
  704.         } else if (targetMode == 'Team') {
  705.             if (!(player.role.side in this.teamTargets)) {
  706.                 this.teamTargets[player.role.side] = {};
  707.             }
  708.             this.teamTargets[player.role.side][action] = [];
  709.         } else if (targetMode == 'Role') {
  710.             if (!(player.role.role in this.roleTargets)) {
  711.                 this.roleTargets[player.role.role] = {};
  712.             }
  713.             this.roleTargets[player.role.role][action] = [];
  714.         }
  715.     };
  716.     this.removeTarget2 = function(player, target) {
  717.         // TODO: implement
  718.     };
  719.     this.getTargetsFor = function(player, action) {
  720.         var commonTarget = player.role.actions.night[action].common;
  721.         if (commonTarget == 'Self') {
  722.             if (!(action in player.targets)) {
  723.                 player.targets[action] = [];
  724.             }
  725.             return player.targets[action];
  726.         } else if (commonTarget == 'Team') {
  727.             if (!(player.role.side in this.teamTargets)) {
  728.                 this.teamTargets[player.role.side] = {};
  729.             }
  730.             if (!(action in this.teamTargets[player.role.side])) {
  731.                 this.teamTargets[player.role.side][action]= [];
  732.             }
  733.             return this.teamTargets[player.role.side][action];
  734.         } else if (commonTarget == 'Role') {
  735.             if (!(player.role.role in this.roleTargets)) {
  736.                 this.roleTargets[player.role.role] = {};
  737.             }
  738.             if (!(action in this.roleTargets[player.role.role])) {
  739.                 this.roleTargets[player.role.role][action]= [];
  740.             }
  741.             return this.roleTargets[player.role.role][action];
  742.         }
  743.     };
  744.     this.setTarget = function(player, target, action) {
  745.         var commonTarget = player.role.actions.night[action].common;
  746.         var limit = 1;
  747.         if (player.role.actions.night[action].limit !== undefined) {
  748.             limit = player.role.actions.night[action].limit;
  749.         }
  750.         var list;
  751.         if (commonTarget == 'Self') {
  752.             if (!(action in player.targets)) {
  753.                 player.targets[action] = [];
  754.             }
  755.             list = player.targets[action];
  756.         } else if (commonTarget == 'Team') {
  757.             if (!(player.role.side in this.teamTargets)) {
  758.                 this.teamTargets[player.role.side] = {};
  759.             }
  760.             if (!(action in this.teamTargets[player.role.side])) {
  761.                 this.teamTargets[player.role.side][action]= [];
  762.             }
  763.             list = this.teamTargets[player.role.side][action];
  764.         } else if (commonTarget == 'Role') {
  765.             if (!(player.role.role in this.roleTargets)) {
  766.                 this.roleTargets[player.role.role] = {};
  767.             }
  768.             if (!(action in this.roleTargets[player.role.role])) {
  769.                 this.roleTargets[player.role.role][action]= [];
  770.             }
  771.             list = this.roleTargets[player.role.role][action];
  772.         }
  773.         if (list.indexOf(target.name) == -1) {
  774.             list.push(target.name);
  775.             if (list.length > limit) {
  776.                 list.splice(0, 1);
  777.             }
  778.         }
  779.         if (this.ticks > 0 && limit > 1)
  780.             this.sendPlayer(player.name, "Β±Game: Your target(s) are " + list.join(', ') + "!");
  781.     };
  782.     this.testWin = function() {
  783.         outer:
  784.         for (var p in mafia.players) {
  785.             var winSide = mafia.players[p].role.side;
  786.             if (winSide != 'village') {
  787.                 for (var i in mafia.theme.villageCantLoseRoles) {
  788.                      if (mafia.player(mafia.theme.villageCantLoseRoles[i]) != noPlayer)
  789.                         // baddies shouldn't win if vigi, mayor or samurai is alive
  790.                         continue outer;
  791.                 }
  792.             }
  793.             var players = [];
  794.             var goodPeople = [];
  795.             for (var x in mafia.players) {
  796.                 if (mafia.players[x].role.side == winSide) {
  797.                     players.push(x);
  798.                 } else if (winSide == 'village') {
  799.                     // if winSide = villy all people must be good people
  800.                     continue outer;
  801.                 } else if (mafia.players[x].role.side == 'village') {
  802.                     goodPeople.push(x);
  803.                 } else {
  804.                     // some other baddie team alive
  805.                     return false;
  806.                 }
  807.             }
  808.  
  809.             if (players.length >= goodPeople.length) {
  810.                 sys.sendAll("Β±Game: The " + mafia.theme.trside(winSide) + " (" + players.join(', ') + ") wins!", mafiachan);
  811.                 if (goodPeople.length > 0) {
  812.                     sys.sendAll("Β±Game: The " + mafia.theme.trside('village') + " (" + goodPeople.join(', ') + ") lose!", mafiachan);
  813.                 }
  814.                 sys.sendAll("*** ************************************************************************************", mafiachan);
  815.                 mafia.clearVariables();
  816.                 return true;
  817.             }
  818.         }
  819.         return false;
  820.     };
  821.     this.handlers = {
  822.         entry: function () {
  823.             sys.sendAll("*** ************************************************************************************", mafiachan);
  824.             sys.sendAll("Times Up! :", mafiachan);
  825.  
  826.             if (mafia.signups.length < 5) {
  827.                 sys.sendAll("Well, Not Enough Players! :", mafiachan);
  828.                 sys.sendAll("You need at least 5 players to join (Current; " + mafia.signups.length + ").", mafiachan);
  829.                 sys.sendAll("*** ************************************************************************************", mafiachan);
  830.                 mafia.clearVariables();
  831.                 return;
  832.             }
  833.  
  834.             /* Creating the roles list */
  835.             var i = 1;
  836.             while (mafia.signups.length > mafia.theme["roles"+i].length) {
  837.                ++i;
  838.             }
  839.             var srcArray = mafia.theme["roles"+i].slice(0, mafia.signups.length);
  840.  
  841.             srcArray = shuffle(srcArray);
  842.  
  843.             for (var i = 0; i < srcArray.length; ++i) {
  844.                 mafia.players[mafia.signups[i]] = {'name': mafia.signups[i], 'role': mafia.theme.roles[srcArray[i]], 'targets': {}};
  845.                 if (typeof mafia.theme.roles[srcArray[i]].side == "object") {
  846.                     if ("random" in mafia.theme.roles[srcArray[i]].side) {
  847.                         var cum = 0;
  848.                         var val = sys.rand(1,100)/100;
  849.                         for(var side in mafia.theme.roles[srcArray[i]].side.random) {
  850.                             cum += mafia.theme.roles[srcArray[i]].side.random[side];
  851.                             if (cum >= val) {
  852.                                 mafia.players[mafia.signups[i]].role.side = side;
  853.                                 break;
  854.                             }
  855.                         }
  856.                         if (typeof mafia.players[mafia.signups[i]].role.side == "object") {
  857.                             sys.sendAll("+MafiaBot: Broken theme...", mafiachan);
  858.                             return;
  859.                         }
  860.                     } else {
  861.                         sys.sendAll("+MafiaBot: Broken theme...", mafiachan);
  862.                         return;
  863.                     }
  864.                 }
  865.             }
  866.  
  867.             sys.sendAll("The Roles have been Decided! :", mafiachan);
  868.             for (var p in mafia.players) {
  869.                 var player = mafia.players[p];
  870.                 var role = player.role;
  871.  
  872.                 if (typeof role.actions.startup == "object" && typeof role.actions.startup.revealAs == "string") {
  873.                     mafia.sendPlayer(player.name, "Β±Game: You are a " + mafia.theme.trrole(role.actions.startup.revealAs) + "!");
  874.                 } else {
  875.                     mafia.sendPlayer(player.name, "Β±Game: You are a " + role.translation + "!");
  876.                 }
  877.                 mafia.sendPlayer(player.name, "Β±Game: " + role.help);
  878.  
  879.                 if (role.actions.startup == "team-reveal") {
  880.                     mafia.sendPlayer(player.name, "Β±Game: Your team is " + mafia.getPlayersForTeamS(role.side) + ".");
  881.                 }
  882.                 if (role.actions.startup == "team-revealif") {
  883.                     if (role.actions.startup["team-revealif"].indexOf(role.side) != -1) {
  884.                         mafia.sendPlayer(player.name, "Β±Game: Your team is " + mafia.getPlayersForTeamS(role.side) + ".");
  885.                     }
  886.                 }
  887.                 if (role.actions.startup == "role-reveal") {
  888.                     mafia.sendPlayer(player.name, "Β±Game: People with your role are " + mafia.getPlayersForRoleS(role.role) + ".");
  889.                 }
  890.  
  891.                 if (typeof role.actions.startup == "object" && role.actions.startup.revealRole) {
  892.                     mafia.sendPlayer(player.name, "Β±Game: The " + mafia.theme.roles[role.actions.startup.revealRole].translation + " is " + mafia.getPlayersForRoleS(player.role.actions.startup.revealRole) + "!");
  893.                 }
  894.             }
  895.             sys.sendAll("Current Roles: " + mafia.getCurrentRoles() + ".", mafiachan);
  896.             sys.sendAll("Current Players: " + mafia.getCurrentPlayers() + ".", mafiachan);
  897.             sys.sendAll("Time: Night", mafiachan);
  898.             sys.sendAll("Make your moves, you only have 30 seconds! :", mafiachan);
  899.             sys.sendAll("*** ************************************************************************************", mafiachan);
  900.  
  901.             mafia.ticks = 30;
  902.             mafia.state = "night";
  903.             mafia.resetTargets();
  904.         }
  905.     ,
  906.         night : function() {
  907.             sys.sendAll("*** ************************************************************************************", mafiachan);
  908.             sys.sendAll("Times Up! :", mafiachan);
  909.  
  910.             var nightkill = false;
  911.             var getTeam = function(role, commonTarget) {
  912.                 var team = [];
  913.                 if (commonTarget == 'Role') {
  914.                     team = mafia.getPlayersForRole(role.role);
  915.                 } else if (commonTarget == 'Team') {
  916.                     team = mafia.getPlayersForTeam(role.side);
  917.                 }
  918.                 return team;
  919.             }
  920.  
  921.             for (var i in mafia.theme.nightPriority) {
  922.                 var o = mafia.theme.nightPriority[i];
  923.                 var names = mafia.getPlayersForRole(o.role);
  924.                 var command = o.action;
  925.                 if ("command" in mafia.theme.roles[o.role].actions.night[o.action]) {
  926.                     command = mafia.theme.roles[o.role].actions.night[o.action].command; // translate to real command
  927.                 }
  928.                 for (var j = 0; j < names.length; ++j) {
  929.                     if (!mafia.isInGame(names[j])) continue;
  930.                     var player = mafia.players[names[j]];
  931.                     //sys.sendAll(player.name + " is " + o.role + ", action is " +o.action , mafiachan);
  932.                     var targets = mafia.getTargetsFor(player, o.action);
  933.                     //sys.sendAll("targets are " + targets, mafiachan);
  934.                    
  935.                     if (command == "distract") {
  936.                         if (targets.length == 0) continue;
  937.                         var target = targets[0];
  938.                         if (!mafia.isInGame(target)) continue;
  939.                         target = mafia.players[target];
  940.                         var distractMode = target.role.actions.distract;
  941.                         if (distractMode === undefined) {}
  942.                         else if (distractMode.mode == "ChangeTarget") {
  943.                             mafia.sendPlayer(player.name, "Β±Game: " + distractMode.hookermsg);
  944.                             mafia.sendPlayer(target.name, "Β±Game: " + distractMode.msg.replace(/~Distracter~/g, player.role.translation));
  945.                             mafia.kill(player);
  946.                             nightkill = true;
  947.                             mafia.removeTargets(target);
  948.                             continue;
  949.                         } else if (distractMode.mode == "ignore") {
  950.                             mafia.sendPlayer(target.name, "Β±Game: " + distractMode.msg);
  951.                             continue;
  952.                         } else if (typeof distractMode.mode == "object" && (typeof distractMode.mode.ignore == "string" && distractMode.mode.ignore == player.role.role || typeof distractMode.mode.ignore == "object" && typeof distractMode.mode.ignore.indexOf == "function" && distractMode.mode.ignore.indexOf(player.role.role) > -1)) {
  953.                             if (distractMode.msg)
  954.                                 mafia.sendPlayer(target.name, "Β±Game: " + distractMode.msg);
  955.                             continue;
  956.                         } else if (typeof distractMode.mode == "object" && typeof distractMode.mode.killif == "object" && typeof distractMode.mode.killif.indexOf == "function" && distractMode.mode.killif.indexOf(player.role.role) > -1) {
  957.                             if (distractMode.hookermsg)
  958.                                 mafia.sendPlayer(player.name, "Β±Game: " + distractMode.hookermsg);
  959.                             if (distractMode.msg)
  960.                                 mafia.sendPlayer(target.name, "Β±Game: " + distractMode.msg.replace(/~Distracter~/g, player.role.translation));
  961.                             mafia.kill(player);
  962.                             nightkill = true;
  963.                             mafia.removeTargets(target);
  964.                             continue;
  965.                         }
  966.                             mafia.sendPlayer(target.name, "Β±Game: The " + player.role.translation +" came to you last night! You were too busy being distracted!");
  967.                         mafia.removeTargets(target);
  968.                         /* warn role / teammates */
  969.                         if ("night" in target.role.actions) {
  970.                             for (var action in target.role.actions.night) {
  971.                                 var team = getTeam(target.role, target.role.actions.night[action].common);
  972.                                 for (var x in team) {
  973.                                     if (team[x] != target.name) {
  974.                                         mafia.sendPlayer(team[x], "Β±Game: Your teammate was too busy with the " + player.role.translation + " during the night, you decided not to " + action + " anyone during the night!");
  975.                                     }
  976.                                 }
  977.                             }
  978.                         }
  979.                     }
  980.                     else if (command == "protect") {
  981.                         for (var t in targets) {
  982.                             var target = targets[t];
  983.                             if (mafia.isInGame(target)) {
  984.                                 mafia.players[target].guarded = true;
  985.                             }
  986.                         }
  987.                     }
  988.                     else if (command == "inspect") {
  989.                         if (targets.length == 0) continue;
  990.                         var target = targets[0];
  991.                         if (!mafia.isInGame(target)) continue;
  992.                         target = mafia.players[target];
  993.                         var inspectMode = target.role.actions.inspect;
  994.                         if (inspectMode === undefined) {
  995.                             mafia.sendPlayer(player.name, "Β±Info: " + target.name + " is the " + target.role.translation + "!!");
  996.                         } else {
  997.                             if (inspectMode.revealAs !== undefined) {
  998.                                 mafia.sendPlayer(player.name, "Β±Info: " + target.name + " is the " + mafia.theme.trrole(inspectMode.revealAs) + "!!");
  999.                             }
  1000.                             if (inspectMode.revealSide !== undefined) {
  1001.                                 mafia.sendPlayer(player.name, "Β±Info: " + target.name + " is sided with the " + mafia.theme.trside(target.role.side) + "!!");
  1002.                             }
  1003.                         }
  1004.                     }
  1005.                     else if (command == "kill") {
  1006.                         for (var t in targets) {
  1007.                             var target = targets[t];
  1008.                             if (!mafia.isInGame(target)) continue;
  1009.                             target = mafia.players[target];
  1010.                             var revenge = false;
  1011.                             var revengetext = "Β±Game: You were killed during the night!";
  1012.                             if ("kill" in target.role.actions && target.role.actions.kill.mode == "killattacker") {
  1013.                                 revenge = true;
  1014.                                 if (target.role.actions.kill.msg)
  1015.                                     revengetext = target.role.actions.kill.msg;
  1016.                             }
  1017.                             if (target.guarded) {
  1018.                                 mafia.sendPlayer(player.name, "Β±Game: Your target (" + target.name + ") was protected!");
  1019.                             } else if ("kill" in target.role.actions && target.role.actions.kill.mode == "ignore") {
  1020.                                 mafia.sendPlayer(player.name, "Β±Game: Your target (" + target.name + ") evaded the kill!");
  1021.                             } else {
  1022.                                 if (mafia.theme.killusermsg) {
  1023.                                     mafia.sendPlayer(target.name, mafia.theme.killusermsg);
  1024.                                 } else {
  1025.                                     mafia.sendPlayer(target.name, "Β±Game: You were killed during the night!");
  1026.                                 }
  1027.                                 mafia.kill(target);
  1028.                                 nightkill = true;
  1029.                             }
  1030.                             if (revenge) {
  1031.                                 mafia.sendPlayer(player.name, revengetext);
  1032.                                 mafia.kill(player);
  1033.                                 nightkill = true;
  1034.                             }
  1035.                         }
  1036.                     }
  1037.                 }
  1038.             }
  1039.  
  1040.             if (!nightkill) {
  1041.                 sys.sendAll("No one died! :", mafiachan);
  1042.             }
  1043.  
  1044.             if (mafia.testWin()) {
  1045.                 return;
  1046.             }
  1047.  
  1048.             mafia.ticks = 30;
  1049.             if (mafia.players.length >= 15) {
  1050.                 mafia.ticks = 40;
  1051.             } else if (mafia.players.length <= 4) {
  1052.                 mafia.ticks = 15;
  1053.             }
  1054.  
  1055.             sys.sendAll("*** ************************************************************************************", mafiachan);
  1056.  
  1057.             sys.sendAll("Current Roles: " + mafia.getCurrentRoles() + ".", mafiachan);
  1058.             sys.sendAll("Current Players: " + mafia.getCurrentPlayers() + ".", mafiachan);
  1059.             sys.sendAll("Time: Day", mafiachan);
  1060.             sys.sendAll("You have " + mafia.ticks + " seconds to debate who are the bad guys! :", mafiachan);
  1061.             for (var role in mafia.theme.standbyRoles) {
  1062.                 var names = mafia.getPlayersForRole(mafia.theme.standbyRoles[role]);
  1063.                 for (var j = 0; j < names.length; ++j) {
  1064.                     for (var k in mafia.players[names[j]].role.actions.standby) {
  1065.                         mafia.sendPlayer(names[j], mafia.players[names[j]].role.actions.standby[k].msg);
  1066.                     }
  1067.                 }
  1068.             }
  1069.             sys.sendAll("*** ************************************************************************************", mafiachan);
  1070.  
  1071.             mafia.state = "standby";
  1072.         }
  1073.     ,
  1074.         standby : function() {
  1075.             mafia.ticks = 30;
  1076.  
  1077.             sys.sendAll("*** ************************************************************************************", mafiachan);
  1078.  
  1079.             sys.sendAll("Current Roles: " + mafia.getCurrentRoles() + ".", mafiachan);
  1080.             sys.sendAll("Current Players: " + mafia.getCurrentPlayers() + ".", mafiachan);
  1081.             sys.sendAll("Time: Day", mafiachan);
  1082.             sys.sendAll("It's time to vote someone off, type /Vote [name],  you only have " + mafia.ticks + " seconds! :", mafiachan);
  1083.             sys.sendAll("*** ************************************************************************************", mafiachan);
  1084.  
  1085.             mafia.state = "day";
  1086.             mafia.votes = {};
  1087.             mafia.voteCount = 0;
  1088.         }
  1089.     ,
  1090.         day : function() {
  1091.             sys.sendAll("*** ************************************************************************************", mafiachan);
  1092.             sys.sendAll("Times Up! :", mafiachan);
  1093.  
  1094.             var voted = {};
  1095.             for (var pname in mafia.votes) {
  1096.                 var player = mafia.players[pname];
  1097.                 var target = mafia.votes[pname];
  1098.                 if (!(target in voted)) {
  1099.                     voted[target] = 0;
  1100.                 }
  1101.                 if (player.role.actions.vote !== undefined) {
  1102.                     voted[target] += player.role.actions.vote;
  1103.                 } else {
  1104.                     voted[target] += 1;
  1105.                 }
  1106.             }
  1107.             var tie = true;
  1108.             var maxi = 0;
  1109.             var downed = noPlayer;
  1110.             for (var x in voted) {
  1111.                 if (voted[x] == maxi) {
  1112.                     tie = true;
  1113.                 } else if (voted[x] > maxi) {
  1114.                     tie = false;
  1115.                     maxi = voted[x];
  1116.                     downed = x;
  1117.                 }
  1118.             }
  1119.  
  1120.             if (tie) {
  1121.                 sys.sendAll("No one was voted off! :", mafiachan);
  1122.                 sys.sendAll("*** ************************************************************************************", mafiachan);
  1123.             } else {
  1124.                 var roleName = typeof mafia.players[downed].role.actions.lynch == "object" && typeof mafia.players[downed].role.actions.lynch.revealAs == "string" ? mafia.theme.trrole(mafia.players[downed].role.actions.lynch.revealAs) : mafia.players[downed].role.translation
  1125.                 sys.sendAll("Β±Game: " + downed + " (" + roleName + ") was removed from the game!", mafiachan);
  1126.                 mafia.removePlayer(mafia.players[downed]);
  1127.  
  1128.                 if (mafia.testWin())
  1129.                     return;
  1130.             }
  1131.  
  1132.             sys.sendAll("Current Roles: " + mafia.getCurrentRoles() + ".", mafiachan);
  1133.             sys.sendAll("Current Players: " + mafia.getCurrentPlayers() + ".", mafiachan);
  1134.             sys.sendAll("Time: Night", mafiachan);
  1135.             sys.sendAll("Make your moves, you only have 30 seconds! :", mafiachan);
  1136.             sys.sendAll("*** ************************************************************************************", mafiachan);
  1137.  
  1138.             mafia.ticks = 30;
  1139.             mafia.state = "night";
  1140.             mafia.resetTargets();
  1141.         }
  1142.     };
  1143.     this.callHandler = function(state) {
  1144.         if (state in this.handlers)
  1145.             this.handlers[state]();
  1146.     };
  1147.     this.showCommands = function(src) {
  1148.         sys.sendMessage(src, "", mafiachan);
  1149.         sys.sendMessage(src, "Server Commands:", mafiachan);
  1150.         for (x in mafia.commands["user"]) {
  1151.             sys.sendMessage(src, "/" + cap(x) + " - " + mafia.commands["user"][x][1], mafiachan);
  1152.         }
  1153.         if (sys.auth(src) > 0) {
  1154.             sys.sendMessage(src, "Authority Commands:", mafiachan);
  1155.             for (x in mafia.commands["auth"]) {
  1156.                 sys.sendMessage(src, "/" + cap(x) + " - " + mafia.commands["auth"][x][1], mafiachan);
  1157.             }
  1158.         }
  1159.         sys.sendMessage(src, "", mafiachan);
  1160.     };
  1161.     this.showHelp = function(src) {
  1162.         var help = [
  1163.             "*** *********************************************************************** ***",
  1164.             "Β±Game: The objective in this game on how to win depends on the role you are given.",
  1165.             "*** *********************************************************************** ***",
  1166.             "Β±Role: Mafia",
  1167.             "Β±Win: Eliminate the WereWolf and the Good People!",
  1168.             "*** *********************************************************************** ***",
  1169.             "Β±Role: WereWolf",
  1170.             "Β±Win: Eliminate everyone else in the game!",
  1171.             "*** *********************************************************************** ***",
  1172.             "Β±Role: Good people (Inspector, Bodyguard, Pretty Lady, Villager, Mayor, Spy, Vigilante, Samurai)",
  1173.             "Β±Win: Eliminate the WereWolf, Mafia (French and Italian if exists) and the Godfather!",
  1174.             "*** *********************************************************************** ***",
  1175.             "Β±Role: French Canadian Mafia, Don French Canadian Mafia",
  1176.             "Β±Win: Eliminate the Italian Mafia, Godfather and the Good People!",
  1177.             "*** *********************************************************************** ***",
  1178.             "Β±Role: Italian Mafia, Don Italian Mafia",
  1179.             "Β±Win: Eliminate the French Canadian Mafia, Godfather and the Good People!",
  1180.             "*** *********************************************************************** ***",
  1181.             "Β±More: Type /roles for more info on the characters in the game!",
  1182.             "Β±More: Type /rules to see some rules you should follow during a game!",
  1183.             "*** *********************************************************************** ***",
  1184.             ""
  1185.         ];
  1186.         dump(src, help);
  1187.     };
  1188.     this.showRoles = function(src, commandData) {
  1189.         var themeName = "default";
  1190.         if (mafia.state != "blank") {
  1191.             themeName = mafia.theme.name.toLowerCase();
  1192.         }
  1193.         if (commandData != noPlayer) {
  1194.             themeName = commandData.toLowerCase();
  1195.             if (!mafia.themeManager.themes.hasOwnProperty(themeName)) {
  1196.                 sys.sendMessage(src, "Β±Game: No such theme!", mafiachan);
  1197.                 return;
  1198.             }
  1199.         }
  1200.         if (themeName == "default2") {
  1201.         var roles = [
  1202.             "*** *********************************************************************** ***",
  1203.             "Β±Role: Villager",
  1204.             "Β±Ability: The Villager has no command during night time. They can only vote during the day!",
  1205.             "Β±Game: 6-30 Players",
  1206.             "*** *********************************************************************** ***",
  1207.             "Β±Role: Inspector",
  1208.             "Β±Ability: The Inspector can find out the identity of a player during the Night. ",
  1209.             "Β±Game: 5-30 Players",
  1210.             "*** *********************************************************************** ***",
  1211.             "Β±Role: Bodyguard",
  1212.             "Β±Ability: The Bodyguard can protect one person during the night from getting killed, but the bodyguard cant protect itself.",
  1213.             "Β±Game: 5-30 Players",
  1214.             "*** *********************************************************************** ***",
  1215.             "Β±Role: Pretty Lady",
  1216.             "Β±Ability: The Pretty Lady can distract people during the night thus cancelling their move, unless it's the WereWolf.",
  1217.             "Β±Game: 5-30 Players",
  1218.             "*** *********************************************************************** ***",
  1219.             "Β±Role: Samurai",
  1220.             "Β±Ability: The Samurai can kill people during the standby phase, but he will be revealed when doing so.",
  1221.             "Β±Game: 25-30 Players",
  1222.             "*** *********************************************************************** ***",
  1223.             "Β±Role: Mafia",
  1224.             "Β±Ability: The Mafia is a group of 2 people. They get one kill each night. They strike after the WereWolf.",
  1225.             "Β±Game: 5-12 Players",
  1226.             "*** *********************************************************************** ***",
  1227.             "Β±Role: WereWolf",
  1228.             "Β±Ability: The WereWolf is solo. To win it has to kill everyone else in the game. The Werewolf strikes first.",
  1229.             "Β±Game: 5-12 27-30 Players",
  1230.             "*** *********************************************************************** ***",
  1231.             "Β±Role: Italian Mafia",
  1232.             "Β±Ability: The Italian Mafia is a group of 2-3 people. They get one kill each night. They strike before the French Canadian Mafia.",
  1233.             "Β±Game: 12-30 Players",
  1234.             "*** *********************************************************************** ***",
  1235.             "Β±Role: Italian Conspirator",
  1236.             "Β±Ability: Italian Conspirator is sided with Italian Mafia, but doesn't have any special commands. Shows up as a Villager to inspector.",
  1237.             "Β±Game: -",
  1238.             "*** *********************************************************************** ***",
  1239.             "Β±Role: Don Italian Mafia",
  1240.             "Β±Ability: Don Italian Mafia is sided with Italian Mafia. He kills with Italian mafia each night. He can't be distracted.",
  1241.             "Β±Game: 24-30 Players",
  1242.             "*** *********************************************************************** ***",
  1243.             "Β±Role: French Canadian Mafia",
  1244.             "Β±Ability: The French Canadian Mafia is a group of 2-4 people. They get one kill each night. They strike after the Italian Mafia.",
  1245.             "Β±Game: 12-30 Players",
  1246.             "*** *********************************************************************** ***",
  1247.             "Β±Role: French Canadian Conspirator",
  1248.             "Β±Ability: French Canadian Conspirator is sided with French Canadian Mafia, but doesn't have any special commands. Shows up as a Villager to inspector.",
  1249.             "Β±Game: -",
  1250.             "*** *********************************************************************** ***",
  1251.             "Β±Role: Don French Canadian Mafia",
  1252.             "Β±Ability: Don French Canadian Mafia is sided with French Canadian Mafia. He kills with French Canadian mafia each night. He can't be distracted.",
  1253.             "Β±Game: 18-30 Players",
  1254.             "*** *********************************************************************** ***",
  1255.             "Β±Role: Mayor",
  1256.             "Β±Ability: The Mayor has no command during the night but his/her vote counts as 2.",
  1257.             "Β±Game: 10-30 Players",
  1258.             "*** *********************************************************************** ***",
  1259.             "Β±Role: Spy",
  1260.             "Β±Ability: The Spy has 33% chance of finding out who is going to get killed by The Italian or French Canadian Mafia during the night. And 10% chance to find out who is the killer!",
  1261.             "Β±Game: 13-30 Players",
  1262.             "*** *********************************************************************** ***",
  1263.             "Β±Role: Vigilante",
  1264.             "Β±Ability: The Vigilante can kill a person during the night! He/she strikes after The French Canadian and Italian Mafia.",
  1265.             "Β±Game: 20-30 Players",
  1266.             "*** *********************************************************************** ***",
  1267.             "Β±Role: Godfather",
  1268.             "Β±Ability: The Godfather can kill 2 people during the night! He/she strikes Last!",
  1269.             "Β±Game: 22-30 Players",
  1270.             "*** *********************************************************************** ***",
  1271.             ""
  1272.         ];
  1273.         } else {
  1274.             roles = mafia.themeManager.themes[themeName].roleInfo;
  1275.         }
  1276.         dump(src, roles);
  1277.     };
  1278.     this.showRules = function(src) {
  1279.         var rules = [
  1280.             "",
  1281.             "     Server Rules: ",
  1282.             "Β±Rule: No Spamming / flooding ",
  1283.             "Β±Rule: No insulting- especially not auth. ",
  1284.             "Β±Rule: No asking for auth.",
  1285.             "Β±Rule: No trolling.",
  1286.             "",
  1287.             "     Game Rules: ",
  1288.             "Β±Rule: Do not quote any of the Bots.",
  1289.             "Β±Rule: Do not quit the game before you are dead.",
  1290.             "Β±Rule: Do not talk once your dead or voted off. ",
  1291.             "Β±Rule: Do not use a hard to type name.",
  1292.             "Β±Rule: Do not group together to ruin the game",
  1293.             "Β±Rule: DO NOT REVEAL YOUR PARTNER IF YOU ARE MAFIA",
  1294.             "",
  1295.             "Β±Game: Disobey them and you will be banned/muted/kicked according to the mod/admin's wish!",
  1296.             ""
  1297.         ];
  1298.         dump(src, rules);
  1299.     };
  1300.     this.showThemes = function(src) {
  1301.         var l = [];
  1302.         for (var t in mafia.themeManager.themes) {
  1303.             l.push(mafia.themeManager.themes[t].name);
  1304.         }
  1305.         var text = ["+MafiaBot: Installed themes are: " + l.join(", ")];
  1306.         dump(src, text);
  1307.     };
  1308.     this.showThemeInfo = function(src) {
  1309.         mafia.themeManager.themeInfo.sort(function(a,b) {return a[0].localeCompare(b[0]);});
  1310.         var mess = [];
  1311.         mess.push("<table><tr><th>Theme</th><th>URL</th><th>Author</th><th>Enabled</th></tr>")
  1312.         for (var i = 0; i < mafia.themeManager.themeInfo.length; ++i) {
  1313.             var info = mafia.themeManager.themeInfo[i];
  1314.             var theme = mafia.themeManager.themes[info[0].toLowerCase()];
  1315.             if (!theme) continue;
  1316.             mess.push('<tr><td>' + theme.name + '</td><td><a href="' + info[1] + '">' + info[1] + '</a></td><td>' + (theme.author ? theme.author : "unknown") + '</td><td>' + (theme.enabled ? "yes" : "no")+ '</td></tr>');
  1317.         }
  1318.         mess.push("</table>");
  1319.         sys.sendHtmlMessage(src, mess.join(""), mafiachan);
  1320.     }
  1321.  
  1322.     // Auth commands
  1323.     this.pushUser = function(src, name) {
  1324.         var id = sys.id(name);
  1325.         if (id) {
  1326.             name = sys.name(id);
  1327.             mafia.signups.push(name);
  1328.             mafia.ips.push(sys.ip(id));
  1329.         } else {
  1330.             mafia.signups.push(name);
  1331.         }
  1332.         sys.sendAll("Β±Game: " + name + " joined the game!", mafiachan);
  1333.     };
  1334.     this.addTheme = function(src, url) {
  1335.         if (sys.auth(src) < 2) {
  1336.             sendChanMessage(src, "+MafiaBot: admin+ command.");
  1337.             return;
  1338.         }
  1339.         mafia.themeManager.loadWebTheme(url, true, false);
  1340.     }
  1341.     this.updateTheme = function(src, url) {
  1342.         if (sys.auth(src) < 2) {
  1343.             sendChanMessage(src, "+MafiaBot: admin+ command.");
  1344.             return;
  1345.         }
  1346.         mafia.themeManager.loadWebTheme(url, true, true);
  1347.     };
  1348.     this.removeTheme = function(src, name) {
  1349.         if (sys.auth(src) < 2) {
  1350.             sendChanMessage(src, "+MafiaBot: admin+ command.");
  1351.             return;
  1352.         }
  1353.         mafia.themeManager.remove(src, name);
  1354.     };
  1355.     this.disableTheme = function(src, name) {
  1356.         mafia.themeManager.disable(src, name);
  1357.     };
  1358.     this.enableTheme = function(src, name) {
  1359.         mafia.themeManager.enable(src, name);
  1360.     };
  1361.  
  1362.  
  1363.     this.importOld = function(src, name) {
  1364.     (function() {
  1365. sys.sendAll("+MafiaBot: Importing old themes", mafiachan)
  1366.     this.themeManager.loadTheme(defaultTheme);
  1367.     this.themeManager.saveToFile(defaultTheme);
  1368.    
  1369.     this.themeManager.loadTheme(sfTheme);
  1370.     this.themeManager.saveToFile(sfTheme);
  1371.    
  1372.     this.themeManager.loadTheme(hpTheme);
  1373.     this.themeManager.saveToFile(hpTheme);
  1374.    
  1375.     this.themeManager.loadTheme(potatoTheme);
  1376.     this.themeManager.saveToFile(potatoTheme);
  1377.    
  1378.     this.themeManager.loadTheme(ssbbTheme);
  1379.     this.themeManager.saveToFile(ssbbTheme);
  1380.    
  1381.     this.themeManager.loadTheme(ffTheme);
  1382.     this.themeManager.saveToFile(ffTheme);
  1383.    
  1384.     this.themeManager.loadTheme(darknessTheme);
  1385.     this.themeManager.saveToFile(darknessTheme);
  1386.  
  1387.     this.themeManager.loadTheme(internetTheme);
  1388.     this.themeManager.saveToFile(internetTheme);
  1389.  
  1390.     this.themeManager.loadThemes();
  1391.     }).apply(mafia, []);
  1392.     }
  1393.  
  1394.     this.commands = {
  1395.         user: {
  1396.             commands : [this.showCommands, "To see the various commands."],
  1397.             start: [this.startGame, "Starts a Game of Mafia."],
  1398.             help: [this.showHelp, "For info on how to win in a game."],
  1399.             roles: [this.showRoles, "For info on all the Roles in the game."],
  1400.             rules: [this.showRules, "To see the Rules for the Game/Server."],
  1401.             themes: [this.showThemes, "To view installed themes."],
  1402.             themeinfo: [this.showThemeInfo, "To view installed themes (more details)."]
  1403.         },
  1404.         auth: {
  1405.             push: [this.pushUser, "To push users to a Mafia game."],
  1406.             end: [this.endGame, "To cancel a Mafia game!"],
  1407.             add: [this.addTheme, "To add a Mafia Theme!"],
  1408.             update: [this.updateTheme, "To update a Mafia Theme!"],
  1409.             remove: [this.removeTheme, "To remove a Mafia Theme!"],
  1410.             disable: [this.disableTheme, "To disable a Mafia Theme!"],
  1411.             enable: [this.enableTheme, "To enable a disabled Mafia Theme!"],
  1412.             importold: [this.importOld, ""]
  1413.         }
  1414.     };
  1415.     this.handleCommand = function(src, message) {
  1416.         var command;
  1417.         var commandData = '*';
  1418.         var pos = message.indexOf(' ');
  1419.  
  1420.         if (pos != -1) {
  1421.             command = message.substring(0, pos).toLowerCase();
  1422.             commandData = message.substr(pos+1);
  1423.         } else {
  1424.             command = message.substr(0).toLowerCase();
  1425.         }
  1426.         if (command in this.commands["user"]) {
  1427.             this.commands["user"][command][0](src, commandData);
  1428.             return;
  1429.         }
  1430.         if (this.state == "entry") {
  1431.             if (command == "join") {
  1432.                 if (this.isInGame(sys.name(src))) {
  1433.                     sys.sendMessage(src, "Β±Game: You already joined!", mafiachan);
  1434.                     return;
  1435.                 }
  1436.                 if (this.ips.indexOf(sys.ip(src))!=-1) {
  1437.                     sys.sendMessage(src, "Β±Game: This IP is already in list. You cannot register two times!", mafiachan);
  1438.                     return;
  1439.                 }
  1440.                 if (this.signups.length >= this.theme["roles"+this.theme.roleLists].length) {
  1441.                     sys.sendMessage(src, "Β±Game: There can't be more than " + this.theme["roles"+this.theme.roleLists].length + " players!", mafiachan);
  1442.                     return;
  1443.                 }
  1444.                 var name = sys.name(src);
  1445.                 for (x in name) {
  1446.                     var code = name.charCodeAt(x);
  1447.                     if (name[x] != ' ' && name[x] != '.' && (code < 'a'.charCodeAt(0) || code > 'z'.charCodeAt(0))
  1448.                         && (code < 'A'.charCodeAt(0) || code > 'Z'.charCodeAt(0)) && name[x] != '-' && name[x] != '_' && name[x] !='<' && name[x] != '>' && (code < '0'.charCodeAt(0) || code > '9'.charCodeAt(0)))
  1449.                     {
  1450.                         sys.sendMessage(src, "Β±Name: You're not allowed to have the following character in your name: " + name[x] + ".", mafiachan);
  1451.                         sys.sendMessage(src, "Β±Rule: You must change it if you want to join!", mafiachan);
  1452.                         return;
  1453.                     }
  1454.                 }
  1455.                 if (name.length > 12) {
  1456.                     sys.sendMessage(src, "Β±Name: You're not allowed to have more than 12 letters in your name!", mafiachan);
  1457.                     sys.sendMessage(src, "Β±Rule: You must change it if you want to join!", mafiachan);
  1458.                     return;
  1459.                 }
  1460.                 this.signups.push(name);
  1461.                 this.ips.push(sys.ip(src));
  1462.                 sys.sendAll("Β±Game: " + name + " joined the game!", mafiachan);
  1463.  
  1464.                 if (this.signups.length == this.theme["roles"+this.theme.roleLists].length) {
  1465.                     this.ticks = 1;
  1466.                 }
  1467.                 return;
  1468.             }
  1469.             if (command == "unjoin") {
  1470.                 if (this.isInGame(sys.name(src))) {
  1471.                     var name = sys.name(src);
  1472.                     delete this.ips[this.ips.indexOf(sys.ip(src))];
  1473.                     this.signups.splice(this.signups.indexOf(name), 1);
  1474.                     sys.sendAll("Β±Game: " + name + " unjoined the game!", mafiachan);
  1475.                     return;
  1476.                 } else {
  1477.                     sys.sendMessage(src, "Β±Game: You haven't even joined!", mafiachan);
  1478.                     return;
  1479.                 }
  1480.             }
  1481.         } else if (this.state == "night") {
  1482.             var name = sys.name(src);
  1483.             //sys.sendAll(name + " used /" + command + " on " + commandData, mafiachan);
  1484.             if (this.isInGame(name) && this.hasCommand(name, command, "night")) {
  1485.                 commandData = this.correctCase(commandData);
  1486.                 if (!this.isInGame(commandData)) {
  1487.                     sys.sendMessage(src, "Β±Hint: That person is not playing!", mafiachan);
  1488.                     return;
  1489.                 }
  1490.                 var player = mafia.players[name];
  1491.                 var target = mafia.players[commandData];
  1492.  
  1493.                 if (player.role.actions.night[command].target != "Self" && commandData == name) {
  1494.                     sys.sendMessage(src, "Β±Hint: Nope, this wont work... You can't target yourself!", mafiachan);
  1495.                     return;
  1496.                 }
  1497.                 else if (player.role.actions.night[command].target == 'AnyButTeam' && player.role.side == target.role.side
  1498.                  || player.role.actions.night[command].target == 'AnyButRole' && player.role.role == target.role.role) {
  1499.                     sys.sendMessage(src, "Β±Hint: Nope, this wont work... You can't target your partners!", mafiachan);
  1500.                     return;
  1501.                 }
  1502.  
  1503.                 sys.sendMessage(src, "Β±Game: You have chosen to " + command + " " + commandData + "!", mafiachan);
  1504.                 this.setTarget(player, target, command);
  1505.  
  1506.                 var broadcast = player.role.actions.night[command].broadcast;
  1507.                 if (broadcast !== undefined) {
  1508.                     var team = [];
  1509.                     if (broadcast == "team") {
  1510.                         team = this.getPlayersForTeam(player.role.side);
  1511.                     } else if (broadcast == "role") {
  1512.                         team = this.getPlayersForRole(player.role.role);
  1513.                     }
  1514.                     for (x in team) {
  1515.                         if (team[x] != name) {
  1516.                             this.sendPlayer(team[x], "Β±Game: Your partner(s) have decided to " + command + " '" + commandData + "'!");
  1517.                         }
  1518.                     }
  1519.                 }
  1520.  
  1521.                 /* Hax-related to command */
  1522.                 // some roles can get "hax" from other people using some commands...
  1523.                 // however, roles can have avoidHax: ["kill", "distract"] in actions..
  1524.                 if ("avoidHax" in player.role.actions && player.role.actions.avoidHax.indexOf(command) != -1) {
  1525.                     return
  1526.                 }
  1527.                 var haxRoles = mafia.theme.getHaxRolesFor(command);
  1528.                 for (var i in haxRoles) {
  1529.                     var role = haxRoles[i];
  1530.                     var haxPlayers = this.getPlayersForRole(role);
  1531.                     for (j in haxPlayers) {
  1532.                         var haxPlayer = haxPlayers[j];
  1533.                         var r = Math.random();
  1534.                         var roleName = this.theme.trside(player.role.side);
  1535.                         if (r < mafia.theme.roles[role].actions.hax[command].revealTeam) {
  1536.                             this.sendPlayer(haxPlayer, "Β±Game: The " + roleName + " are going to kill " + commandData + "!");
  1537.                         }
  1538.                         if (r < mafia.theme.roles[role].actions.hax[command].revealPlayer) {
  1539.                             this.sendPlayer(haxPlayer, "Β±Game: " + name + " is one of The " + roleName + "!");
  1540.                         }
  1541.                     }
  1542.                 }
  1543.  
  1544.                 return;
  1545.             }
  1546.         } else if (this.state == "day") {
  1547.             if (this.isInGame(sys.name(src)) && command == "vote") {
  1548.                 commandData = this.correctCase(commandData);
  1549.                 if (!this.isInGame(commandData)) {
  1550.                     sys.sendMessage(src, "Β±Game: That person is not playing!", mafiachan);
  1551.                     return;
  1552.                 }
  1553.                 if (sys.name(src) in this.votes) {
  1554.                     sys.sendMessage(src, "Β±Rule: You already voted!", mafiachan);
  1555.                     return;
  1556.                 }
  1557.                 sys.sendAll("Β±Game:" + sys.name(src) + " voted for " + commandData + "!", mafiachan);
  1558.                 this.votes[sys.name(src)] = commandData;
  1559.                 this.voteCount+=1;
  1560.  
  1561.                 if (this.voteCount == Object.keys(mafia.players).length) {
  1562.                     mafia.ticks = 1;
  1563.                 } else if (mafia.ticks < 8) {
  1564.                     mafia.ticks = 8;
  1565.                 }
  1566.                 return;
  1567.             }
  1568.         } else if (mafia.state == "standby") {
  1569.             var name = sys.name(src);
  1570.             if (this.isInGame(name) && this.hasCommand(name, command, "standby")) {
  1571.                 if (command == "kill") {
  1572.                     if (mafia.players[name].dayKill) {
  1573.                         sys.sendMessage(src, "Β±Game: You already killed!", mafiachan);
  1574.                         return;
  1575.                     }
  1576.                     commandData = this.correctCase(commandData);
  1577.                     if (!this.isInGame(commandData)) {
  1578.                         sys.sendMessage(src, "Β±Game: That person is not playing!", mafiachan);
  1579.                         return;
  1580.                     }
  1581.                     sys.sendAll("*** ************************************************************************************", mafiachan);
  1582.                     sys.sendAll("Β±Game: " + this.players[name].role.actions.standby[command].killmsg.replace(/~Self~/g, name).replace(/~Target~/g, commandData), mafiachan);
  1583.                     this.kill(mafia.players[commandData]);
  1584.                     this.players[name].dayKill = true;
  1585.  
  1586.                     if (this.testWin()) {
  1587.                         return;
  1588.                     }
  1589.                     sys.sendAll("*** ************************************************************************************", mafiachan);
  1590.                 }
  1591.                 return;
  1592.             }
  1593.         }
  1594.         if (command == "join") {
  1595.             sys.sendMessage(src, "Β±Game: You can't join now!", mafiachan);
  1596.             return;
  1597.         }
  1598.  
  1599.         if (sys.auth(src) == 0)
  1600.             throw ("no valid command");
  1601.  
  1602.         if (command in this.commands["auth"]) {
  1603.             this.commands["auth"][command][0](src, commandData);
  1604.             return;
  1605.         }
  1606.  
  1607.         throw ("no valid command");
  1608.     }
  1609. }();
  1610.  
  1611.  
  1612. /* stolen from here: http://snippets.dzone.com/posts/show/849 */
  1613. function shuffle(o) {
  1614.     for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
  1615.     return o;
  1616. }
  1617.  
  1618. /* stolen from here: http://stackoverflow.com/questions/1026069/capitalize-first-letter-of-string-in-javascript */
  1619. function cap(string) {
  1620.     return string.charAt(0).toUpperCase() + string.slice(1);
  1621. }
  1622.  
  1623. function dump(src, mess) {
  1624.     for (x in mess) {
  1625.         sys.sendMessage(src, mess[x], mafiachan);
  1626.     }
  1627. }
  1628.  
  1629. function isNonNegative(n) {
  1630.     return typeof n == 'number' && !isNaN(n) && n >= 0;
  1631. }
  1632.  
  1633. (function() {
  1634.     var strTable = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D";
  1635.  
  1636.         var table = new Array();
  1637.         for (var i = 0; i < strTable.length; ++i) {
  1638.           table[i] = parseInt("0x" + strTable[i]);
  1639.         }
  1640.  
  1641.  
  1642.     /* Number */
  1643.     crc32 = function(str, crc ) {
  1644.         if( crc === undefined ) crc = 0;
  1645.         var n = 0; //a number between 0 and 255
  1646.         var x = 0; //an hex number
  1647.  
  1648.         crc = crc ^ (-1);
  1649.         for( var i = 0, iTop = str.length; i < iTop; i++ ) {
  1650.             n = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
  1651.             x = "0x" + table[n];
  1652.             crc = ( crc >>> 8 ) ^ x;
  1653.         }
  1654.         return crc ^ (-1);
  1655.     };
  1656. })();
  1657.  
  1658. var suspectVoting = new function() {
  1659.     var canVote = function(src) {
  1660.         if (!sys.dbRegistered(sys.name(src))) {
  1661.             return false;
  1662.         }
  1663.         if (sys.ratedBattles(sys.name(src), poll.tier) < 30) {
  1664.             return false;
  1665.         }
  1666.         if (sys.ladderRating(src, poll.tier) <= 1000) {
  1667.             return false;
  1668.         }
  1669.         return true;
  1670.     }
  1671.     var getVote = function(src) {
  1672.          var name = sys.name(src).toLowerCase();
  1673.          for (var i in poll.voters) {
  1674.              if (name == poll.voters[i].name) {
  1675.                  return poll.voters[i];
  1676.              }
  1677.          }
  1678.     }
  1679.     poll = {
  1680.         'running': false,
  1681.         'subject': 'Chandelure',
  1682.         'answers': ['ban', 'no ban'],
  1683.         'tier': 'Dream World',
  1684.         'voters': [],
  1685.     };
  1686.     poll.canVote = canVote;
  1687.     poll.getVote = getVote;
  1688.     var savePoll = function() {
  1689.         delete poll.canVote;
  1690.         delete poll.getVote;
  1691.         var s = JSON.stringify(poll);
  1692.         sys.writeToFile('suspectvoting.json',s);
  1693.         poll.canVote = canVote;
  1694.         poll.getVote = getVote;
  1695.     }
  1696.     var loadPoll = function() {
  1697.         try {
  1698.             poll = JSON.parse(sys.getFileContent('suspectvoting.json'));
  1699.             poll.canVote = canVote;
  1700.             poll.getVote = getVote;
  1701.         } catch (err) {}
  1702.     }
  1703.     loadPoll();
  1704.  
  1705.     var userCommands = {
  1706.         'votinghelp': function(src, commandData) {
  1707.             sendChanMessage(src, "*** Suspect Voting commands ***");
  1708.             sendChanMessage(src, "/vote [subject] [answer]: to vote in a suspect voting");
  1709.             sendChanMessage(src, "/removeVote [subject]: to remove your vote in a suspect voting");
  1710.             if (sys.auth(src) < 3 && sys.name(src) != "Lamperi") return;
  1711.             sendChanMessage(src, "*** Owner commands ***");
  1712.             sendChanMessage(src, "/whiteList [person]: to approve one's vote in suspect voting");
  1713.             sendChanMessage(src, "/startVoting: to start a suspect voting");
  1714.             sendChanMessage(src, "/stopVoting: to stop running suspect voting");
  1715.             sendChanMessage(src, "/getResults [subject]: to get results of a suspect voting");
  1716.             sendChanMessage(src, "/newPoll [subject:tier:answer1:answer2:...]: to make a new voting");
  1717.         },
  1718.         'vote': function(src, commandData) {
  1719.              if (!poll.running) {
  1720.                  sendChanMessage(src, "+Bot: There's no poll running.");
  1721.                  return;
  1722.              }
  1723.              if (commandData.substr(0, poll.subject.length).toLowerCase() != poll.subject.toLowerCase()) {
  1724.                  sendChanMessage(src, "+Bot: The subject of this poll is: " + poll.subject + ". Please do /vote " + poll.subject + " [your answer]");
  1725.                  return;
  1726.              }
  1727.              var answer = commandData.substr(poll.subject.length+1);
  1728.              if (poll.canVote(src)) {
  1729.                  if (answer == '') {
  1730.                      var vote = poll.getVote(src);
  1731.                      if (vote !== undefined) {
  1732.                          var d = new Date();
  1733.                          d.setTime(vote.time*1000);
  1734.                          sendChanMessage(src, "+Bot: You have previously voted '" + vote.answer + "' from IP " + vote.ip + " with rating " + vote.rating + " on " + d.toUTCString());
  1735.                          return;
  1736.                      }
  1737.                      sendChanMessage(src, "+Bot: You haven't voted yet. Valid votes in this poll are: " + poll.answers.join(", "));
  1738.                      return;
  1739.                  }
  1740.                  if (poll.answers.indexOf(answer) == -1) {
  1741.                      sendChanMessage(src, "+Bot: Only valid votes in this poll are: " + poll.answers.join(", "));
  1742.                      return;
  1743.                  }
  1744.                  var ip = sys.ip(src);
  1745.                  var name = sys.name(src).toLowerCase();
  1746.                  for (var i in poll.voters) {
  1747.                      if (ip == poll.voters[i].ip) {
  1748.                          if (name != poll.voters[i].name) {
  1749.                              sendChanMessage(src, "+Bot: Sorry, your IP address has already voted as " + poll.voters[i].name+". The vote will not change.");
  1750.                              return;
  1751.                          }
  1752.                          poll.voters[i].rating = sys.ladderRating(src, poll.tier);
  1753.                          poll.voters[i].answer = answer;
  1754.                          poll.voters[i].time = parseInt(sys.time());
  1755.                          savePoll();
  1756.                          sendChanMessage(src, "+Bot: Your vote has been updated.");
  1757.                          return;
  1758.                      } else if (name == poll.voters[i].name) {
  1759.                          poll.voters[i].ip = sys.ip(src);
  1760.                          poll.voters[i].rating = sys.ladderRating(src, poll.tier);
  1761.                          poll.voters[i].answer = answer;
  1762.                          poll.voters[i].time = parseInt(sys.time());
  1763.                          savePoll();
  1764.                          sendChanMessage(src, "+Bot: Your vote has been updated.");
  1765.                          return;
  1766.                      }
  1767.                  }
  1768.                  var o = {
  1769.                      'ip': ip,
  1770.                      'name': name,
  1771.                      'rating': sys.ladderRating(src, poll.tier),
  1772.                      'answer': answer,
  1773.                      'time': parseInt(sys.time()),
  1774.                      'whitelisted': false
  1775.                  };
  1776.                  poll.voters.push(o);
  1777.                  savePoll();
  1778.                  sendChanMessage(src, "+Bot: Your vote has been registered. Don't forget to post on the associated topic on the forum saying you voted.");
  1779.                  return;
  1780.              } else {
  1781.                  sendChanMessage(src, "+Bot: Sorry, you can't take part in this poll. Your name needs to be registered, you must have over 1000 points and enough battles (you have " + sys.ratedBattles(sys.name(src), poll.tier) + "/30 battles.");
  1782.              }
  1783.         } ,
  1784.         'removevote': function(src, commandData) {
  1785.             if (commandData.substr(0, poll.subject.length).toLowerCase() != poll.subject.toLowerCase()) {
  1786.                 sendChanMessage(src, "+Bot: The subject of this poll is: " + poll.subject + ". Do /removeVote " + poll.subject + " to remove your vote.");
  1787.                 return;
  1788.             }
  1789.             var name = sys.name(src).toLowerCase();
  1790.             for (var i in poll.voters) {
  1791.                     if (name == poll.voters[i].name) {
  1792.                         poll.voters.splice(i,1);
  1793.                         savePoll();
  1794.                         sendChanMessage(src, "+Bot: Your vote has been removed.");
  1795.                         return;
  1796.                     }
  1797.             }
  1798.             sendChanMessage(src, "+Bot: You haven't voted with that name.");
  1799.         }
  1800.     };
  1801.  
  1802.     var ownerCommands = {
  1803.         'whitelist': function(src, commandData) {
  1804.         var target = commandData.toLowerCase();
  1805.             for (var i = 0; i < poll.voters.length; ++i) {
  1806.                 var voter = poll.voters[i];
  1807.                 if (voter.name == target) {
  1808.                     if (voter.whitelisted) {
  1809.                         voter.whitelisted = false;
  1810.                         sendChanMessage(src, '+Bot: ' + voter.name + "'s vote was disapproved.");
  1811.                     } else {
  1812.                         voter.whitelisted = true;
  1813.                         sendChanMessage(src, '+Bot: ' + voter.name + "'s vote was approved.");
  1814.                     }
  1815.                     return;
  1816.                 }
  1817.             }
  1818.             sendChanMessage(src, '+Bot: ' + voter.name + ' has not voted.');
  1819.             savePoll();
  1820.         },
  1821.         'startvoting': function(src, commandData) {
  1822.             sendChanMessage(src, '+Bot: The Poll is running again.');
  1823.             sys.sendAll('');
  1824.             sys.sendAll('+Bot: The Suspect Voting of ' + cap(poll.subject) +' is now running!');
  1825.             sys.sendAll('');
  1826.             poll.running = true;
  1827.             savePoll();
  1828.         },
  1829.         'stopvoting': function(src, commandData) {
  1830.             sendChanMessage(src, '+Bot: The Votes are frozen now.');
  1831.             sys.sendAll('');
  1832.             sys.sendAll('+Bot: The Suspect Voting of ' + cap(poll.subject) +' has ended!');
  1833.             sys.sendAll('');
  1834.             poll.running = false;
  1835.             savePoll();
  1836.         },
  1837.         'getresults': function(src, commandData) {
  1838.             var results = {};
  1839.             var unscaled = {};
  1840.             for (var i = 0; i < poll.answers.length; ++i) {
  1841.                 results[poll.answers[i]] = 0;
  1842.                 unscaled[poll.answers[i]] = 0;
  1843.             }
  1844.             var total_users = poll.voters.length;
  1845.             var vote_count = 0;
  1846.             var p = sys.totalPlayersByTier(poll.tier);
  1847.             var divider1 = Math.log(p/2);
  1848.             var divider2 = Math.exp(1/divider1);
  1849.             sendChanMessage(src, "+Bot: Following people voted:")
  1850.             for (var i = 0; i < total_users; ++i) {
  1851.                 var voter = poll.voters[i];
  1852.                 sendChanMessage(src, "+Bot: " + voter.name+" voted for "+voter.answer+" with rating " + voter.rating + ". Approved: " + voter.whitelisted);
  1853.                 if (voter.whitelisted === false) continue;
  1854.                 var x = voter.rating;
  1855. //                if (x>1700) x = 1700;
  1856.                 var votes = (Math.exp( Math.pow(x/1000,4) / divider1 ) / divider2 - 1) * 10;
  1857.                 results[voter.answer] += votes;
  1858.                 unscaled[voter.answer] += 1;
  1859.                 ++vote_count;
  1860.             }
  1861.             var sum = 0;
  1862.             for (var i = 0; i < poll.answers.length; ++i) {
  1863.                 sum += results[poll.answers[i]];
  1864.             }
  1865.             if (sum > 0) {
  1866.                 sendChanMessage(src, '+Bot: The Results of Suspect Voting of ' + cap(poll.subject) + ' is:');
  1867.                 for (var i = 0; i < poll.answers.length; ++i) {
  1868.                     var v = results[poll.answers[i]];
  1869.                     var u = unscaled[poll.answers[i]];
  1870.                     sendChanMessage(src, 'Option "' + poll.answers[i] + '" had ' + v + ' votes. (' + 100*v/sum + '%, '+u+' persons)');
  1871.                 }
  1872.                 sendChanMessage(src, 'Total of ' + total_users + ' took part and ' + vote_count + ' were approved. Total sum of the votes is ' + sum + '.');
  1873.             } else {
  1874.                 if (total_users == 0) {
  1875.                     sendChanMessage(src, '+Bot: No one has voted yet.');
  1876.                 } else {
  1877.                     sendChanMessage(src, '+Bot: No one has been approved. Use /whitelist [username] to approve votes.');
  1878.                 }
  1879.             }
  1880.         },
  1881.         'clearpoll': function(src, commandData) {
  1882.             sendChanMessage(src, '+Bot: Sorry, not implemented! Just use /eval poll.voters=[]')
  1883.         },
  1884.         'newpoll': function(src, commandData) {
  1885.             var params = commandData.split(":");
  1886.             if (params.length < 4) {
  1887.                 sendChanMessage(src, '+Bot: Usage: /newPoll subject:tier:answer1:answer2:...');
  1888.                 return;
  1889.             }
  1890.             var s = JSON.stringify(poll);
  1891.             var fn = 'oldSuspectVoting'+sys.time()+'.json';
  1892.             sys.writeToFile(fn,s);
  1893.             sendChanMessage(src, '+Bot: Old poll saved to '+fn);
  1894.  
  1895.             var newSubject = params[0];
  1896.             var newTier = params[1];
  1897.             var newAnswers = params.splice(2);
  1898.             poll.subject = newSubject;
  1899.             poll.tier = newTier;
  1900.             poll.answers = newAnswers;
  1901.             poll.voters = [];
  1902.             poll.running = false;
  1903.             savePoll();
  1904.             sendChanMessage(src, '+Bot: The poll successfully updated!');
  1905.         }
  1906.     };
  1907.  
  1908.     this.afterLogIn = function(src) {
  1909.         if (poll.running) {
  1910.             if (poll.canVote(src) && poll.getVote(src) === undefined) {
  1911.                 sendChanMessage(src, '+Bot: A Suspect Voting is going on! Use /vote ' + poll.subject + ' [answer] to vote!');
  1912.             }
  1913.         }
  1914.     }
  1915.  
  1916.     this.handleCommand = function(src, message) {
  1917.         var command;
  1918.         var commandData = '';
  1919.         var pos = message.indexOf(' ');
  1920.  
  1921.         if (pos != -1) {
  1922.             command = message.substring(0, pos).toLowerCase();
  1923.             commandData = message.substr(pos+1);
  1924.         } else {
  1925.             command = message.substr(0).toLowerCase();
  1926.         }
  1927.         if (command in userCommands) {
  1928.             userCommands[command](src, commandData);
  1929.             return;
  1930.         }
  1931.         if (command in ownerCommands && (sys.auth(src) >= 3 || sys.name(src) == "Lamperi")) {
  1932.             ownerCommands[command](src, commandData);
  1933.             return;
  1934.         }
  1935.         throw "no valid command";
  1936.     };
  1937.  
  1938. }();
  1939.  
  1940.  
  1941. /*
  1942.  * Prototype: MemoryHash
  1943.  * Functions:
  1944.  *  - add(key,value)
  1945.  *  - get(key)
  1946.  *  - remove(key)
  1947.  *  - removeIf(callBack)
  1948.  *  - clear()
  1949.  *  - save()
  1950.  *  - escapeValue(val)
  1951.  *
  1952.  *  All keys and values must be strings.
  1953.  */
  1954. function MemoryHash(filename)
  1955. {
  1956.     this.hash = {};
  1957.     this.fname = filename;
  1958.  
  1959.     var contents = sys.getFileContent(this.fname);
  1960.     if (contents !== undefined) {
  1961.         var lines = contents.split("\n");
  1962.         for(var i = 0; i < lines.length; ++i) {
  1963.             var line = lines[i];
  1964.             var key_value = line.split("*");
  1965.             var key = key_value[0];
  1966.             var value = key_value[1];
  1967.             if (key.length > 0) {
  1968.                 if (value === undefined)
  1969.                     value = '';
  1970.                 this.hash[key] = value;
  1971.             }
  1972.         }
  1973.     }
  1974. }
  1975.  
  1976. MemoryHash.prototype.add = function(key, value)
  1977. {
  1978.     this.hash[key] = value;
  1979.     // it doesn't matter if we add a duplicate,
  1980.     // when we remove something eventually,
  1981.     // duplicates will be deleted
  1982.     sys.appendToFile(this.fname, key +'*' + value + '\n');
  1983. }
  1984.  
  1985. MemoryHash.prototype.get = function(key)
  1986. {
  1987.     return this.hash[key];
  1988. }
  1989.  
  1990. MemoryHash.prototype.remove = function(key)
  1991. {
  1992.     delete this.hash[key];
  1993.     this.save();
  1994. }
  1995.  
  1996. MemoryHash.prototype.removeIf = function(test)
  1997. {
  1998.     var i;
  1999.     var toDelete = []
  2000.     for (i in this.hash) {
  2001.         if (test(this, i)) {
  2002.             toDelete.push(i);
  2003.         }
  2004.     }
  2005.     for (i in toDelete) {
  2006.         delete this.hash[toDelete[i]];
  2007.     }
  2008. }
  2009.  
  2010. MemoryHash.prototype.clear = function()
  2011. {
  2012.     this.hash = {};
  2013.     this.save();
  2014. }
  2015.  
  2016. MemoryHash.prototype.save = function()
  2017. {
  2018.     var lines = [];
  2019.     for (var i in this.hash) {
  2020.         lines.push(i +'*' + this.hash[i] + '\n');
  2021.     }
  2022.     sys.writeToFile(this.fname, lines.join(""))
  2023. }
  2024.  
  2025. MemoryHash.prototype.escapeValue = function(value)
  2026. {
  2027.     return value.replace(/\*\n/g,'');
  2028. }
  2029.  
  2030. /* End of prototype MemoryHash */
  2031.  
  2032. function POUser(id)
  2033. {
  2034.     /* user's id */
  2035.     this.id = id;
  2036.     /* whether user is megauser or not */
  2037.     this.megauser = false;
  2038.     /* whether user is muted or not */
  2039.     this.mute = {active: false, by: null, expires: 0, time: null, reason: null};
  2040.     /* whether user is mafiabanned or not */
  2041.     this.mban = {active: false, by: null, expires: 0, time: null, reason: null};
  2042.     /* whether user is secrectly muted */
  2043.     this.smute = {active: false, by: null, expires: 0, time: null, reason: null};
  2044.     /* caps counter for user */
  2045.     this.caps = 0;
  2046.     /* whether user is impersonating someone */
  2047.     this.impersonation = undefined;
  2048.     /* last time user said something */
  2049.     this.timecount = parseInt(sys.time());
  2050.     /* counter on how many lines user has said recently */
  2051.     this.floodcount = 0;
  2052.     /* counts coins */
  2053.     this.coins = 0;
  2054.     /* whether user has enabled battling only in same tier */
  2055.     this.sametier = undefined;
  2056.  
  2057.     /* check if user is megauser */
  2058.     if (megausers.indexOf("*" + sys.name(id) + "*") != -1)
  2059.         this.megauser = true;
  2060.  
  2061.     /* check if user is banned or mafiabanned */
  2062.     var data;
  2063.     var loopArgs = [["mute", mutes], ["mban", mbans], ["smute", smutes]];
  2064.     for (var i = 0; i < 3; ++i) {
  2065.         var action = loopArgs[i][0];
  2066.         if (data = loopArgs[i][1].get(sys.ip(id))) {
  2067.             this[action].active=true;
  2068.             var args = data.split(":");
  2069.             this[action].time = parseInt(args[0]);
  2070.             if (args.length == 5) {
  2071.                 this[action].by = args[1];
  2072.                 this[action].expires = parseInt(args[2]);
  2073.                 this[action].reason = args[4];
  2074.             }
  2075.         }
  2076.     }
  2077. }
  2078.  
  2079. POUser.prototype.toString = function() {
  2080.     return "[object POUser]";
  2081. }
  2082.  
  2083. POUser.prototype.expired = function(thingy) {
  2084.     return this[thingy].expires != 0 && this[thingy].expires < sys.time();
  2085. }
  2086.  
  2087. POUser.prototype.activate = function(thingy, by, expires, reason, persistent) {
  2088.     this[thingy].active = true;
  2089.     this[thingy].by = by;
  2090.     this[thingy].expires = expires;
  2091.     this[thingy].time = parseInt(sys.time());
  2092.     this[thingy].reason = reason;
  2093.     if (persistent) {
  2094.         var table = {"mute": mutes, "smute": smutes, "mban": mbans}
  2095.         table[thingy].add(sys.ip(this.id), sys.time() + ":" + by + ":" + expires + ":" + sys.name(this.id) + ":" + reason);
  2096.     }
  2097.     if (thingy == "mute") {
  2098.         if (typeof trollchannel != "undefined" && sys.channel(trollchannel) !== undefined && !sys.isInChannel(this.id, trollchannel)) {
  2099.             sys.putInChannel(this.id, trollchannel);
  2100.         }
  2101.     }
  2102.     if (thingy == "mban") {
  2103.         sys.kick(this.id, mafiachan);
  2104.         var name = mafia.correctCase(sys.name(this.id));
  2105.         if (mafia.isInGame(name)) {
  2106.             mafia.removePlayer(name);
  2107.             mafia.testWin();
  2108.         }
  2109.     }
  2110. }
  2111.  
  2112. POUser.prototype.un = function(thingy) {
  2113.     this[thingy].active = false;
  2114.     this[thingy].expires = 0;
  2115.     var table = {"mute": mutes, "smute": smutes, "mban": mbans}
  2116.     table[thingy].remove(sys.ip(this.id));
  2117.  
  2118.     if (thingy == "mute") {
  2119.         if (typeof trollchannel != "undefined" && sys.channel(trollchannel) !== undefined && sys.isInChannel(this.id, trollchannel)) {
  2120.             sys.kick(this.id, trollchannel);
  2121.             if (sys.isInChannel(this.id, 0) != true) {
  2122.                 sys.putInChannel(this.id, 0)
  2123.             }
  2124.         }
  2125.     }
  2126. }
  2127.  
  2128. function POChannel(id)
  2129. {
  2130.     this.id = id;
  2131.     this.master = undefined;
  2132.     this.perm = false;
  2133.     this.inviteonly = 0;
  2134.     this.invitelist = [];
  2135.     this.topic = "";
  2136.     this.muteall = undefined;
  2137.     this.meoff = undefined;
  2138. }
  2139.  
  2140. function POGlobal(id)
  2141. {
  2142.     this.mafia = undefined;
  2143.     this.coins = 0;
  2144. }
  2145.  
  2146. SESSION.identifyScriptAs("PO Scripts v0.002");
  2147. SESSION.registerUserFactory(POUser);
  2148. SESSION.registerChannelFactory(POChannel);
  2149. SESSION.registerGlobalFactory(POGlobal);
  2150.  
  2151.  
  2152. if (SESSION.global() !== undefined) {
  2153.     // keep the state of mafia if it hasn't been updated
  2154.     if (SESSION.global().mafia === undefined || SESSION.global().mafia.version !== undefined && SESSION.global().mafia.version < mafia.version) {
  2155.         SESSION.global().mafia = mafia;
  2156.         if (mafiachan !== undefined) {
  2157.             sys.sendAll("+MafiaBot: Mafia game was updated!", mafiachan);
  2158.             mafia.themeManager.loadThemes();
  2159.         }
  2160.     } else {
  2161.         mafia = SESSION.global().mafia;
  2162.     }
  2163. }
  2164.  
  2165.  
  2166. var commands = {
  2167.     user:
  2168.     [
  2169.         "/rules: To see the rules",
  2170.         "/me [message]: to speak with *** before its name",
  2171.         "/players: to get the number of players online",
  2172.         "/ranking: to get your ranking in your tier",
  2173.         "/selfkick: to kick any ghosts left behind...",
  2174.         "/join: allows you to join a tournament.",
  2175.         "/auth [owners/admins/mods]: allows you to view the auth of that class, will show all auth if left blank",
  2176.         "/megausers: to see the list of people who have power over tournaments.",
  2177.         "/unjoin: allows you to leave a tournament.",
  2178.         "/viewround: allows you to view the pairings for the round.",
  2179.         "/viewtiers: shows the last tourneys, which can't be started yet",
  2180.         "/sameTier [on/off]: to force or not the same tier when people challenge you",
  2181.         "/tourrankings: view recent tourney winners",
  2182.         "/tourranking [tier]: view recent tourney winners of specific tier",
  2183.         "/tourdetails [user]: view tourney winning stats of specific user",
  2184.         "/lastwinners: view details about last tournaments",
  2185.         "/uptime: view server uptime"
  2186.     ],
  2187.     megauser:
  2188.     [
  2189.         "/tour tier:number: starts a tier tournament consisting of number of players.",
  2190.         "/endtour: ends the current tournament.",
  2191.         "/dq name: DQs someone in the tournament.",
  2192.         "/changecount [entrants]: Change the number of entrants during the signup phase.",
  2193.         "/push name: Adds someone in the tournament.",
  2194.         "/sub name1:name2: Replaces someone with someone else.",
  2195.         "/cancelBattle name1: Allows the user or his/her opponent to forfeit his/her current battle so he/she can battle again his/her opponent."
  2196.     ],
  2197.     channel:
  2198.     [
  2199.         "/topic [topic]: to read or change the topic of a channel. Only works if you're the first to log on a channel.",
  2200.         "/ck [person]: to kick someone from your channel",
  2201.         "/inviteonly [on|off]: to change channel to inviteonly",
  2202.         "/invite [person]: to send a person an invite"
  2203.     ],
  2204.     mod:
  2205.     [
  2206.         "/k [person] : to kick someone",
  2207.         "/banlist [search term]: to search the banlist, shows full list if no search term is entered.",
  2208.         "/mutelist [search term]: to search the mutelist, shows full list if no search term is entered.",
  2209.         "/smutelist [search term]: to search the smutelist, shows full list if no search term is entered.",
  2210.         "/mafiabans [search term]: to search the mafiabanlist, shows full list if no search team is entered.",
  2211.         "/rangebans: list range bans",
  2212.         "/[mute/unmute] [person] : You know what i mean :p.",
  2213.         "/silence [x]: To call forth x minute of silence in the main chat (except for auth)",
  2214.         "/silenceoff: To undo that",
  2215.         "/silence [x] [channel]: To call forth x minute of silence in a specific channel (except for auth)",
  2216.         "/silenceoff [channel]: To undo that on a specific channel",
  2217.         "/mafiaban [person]: To ban a player from Mafia",
  2218.         "/mafiaunban [person]: To unban a player from Mafia",
  2219.         "/meon, /meoff: to deal with /me happy people",
  2220.         "/meon [channel], /meoff [channel]: to deal with /me happy people on some channel",
  2221.         "/perm [on/off]: To make the current channel a permanent channel or not -- i.e. the channel wouldn't be destroyed on log off",
  2222.         "/userinfo [person]: to display various info about the person",
  2223.         "/tempban [user]:[minutes]: To temporary ban someone (0 < minute <= 60)",
  2224.         "/tempunban [user]: To unban temporary banned user (standard unban doens't work)",
  2225.     ],
  2226.     admin:
  2227.     [
  2228.         "/memorydump: To see the state of the memory.",
  2229.         "/megauser[off] xxx: Tourney powers.",
  2230.         "/aliases xxx: See the aliases of an IP.",
  2231.         "/ban [name]: To ban a user.",
  2232.         "/unban [name]: To unban a user.",
  2233.         "/destroychan [channel]: Will destroy a channel (Certain channels are immune obviously...)",
  2234.         "/smute xxx: To secretly mute a user. Can't smute auth.",
  2235.         "/sunmute xxx: To secretly unmute a user.",
  2236.         "/channelusers [channel]: to display people on a channel"
  2237.     ],
  2238.     owner:
  2239.     [
  2240.         "/changeRating [player] -- [tier] -- [rating]: to change the rating of a rating abuser",
  2241.         "/stopBattles: to stop all new battles. When you want to close the server, do that",
  2242.         "/imp [person] : to impersonate someone",
  2243.         "/impOff : to stop impersonating.",
  2244.         "/clearpass [name]: to clear a password",
  2245.         "/sendAll [message] : to send a message to everyone.",
  2246.         "/changeAuth [auth] [person]: to play the mega admin",
  2247.         "/showteam xxx: To help people who have problems with event moves or invalid teams.",
  2248.         "/rangeban [ip] [comment]: to make a range ban",
  2249.         "/rangeunban: [ip] to unban a range",
  2250.         "/purgemutes [time]: to purge old mutes. Time is given in seconds. Defaults is 4 weeks.",
  2251.         "/purgembans [time]: to purge old mafiabans. Time is given in seconds. Defaults is 1 week.",
  2252.         "/writetourstats: to force a writing of tour stats to tourstats.json",
  2253.         "/reloadtourstats : to force a reload of tour stats from tourstats.json",
  2254.         "/resettourstats: to reset tournament winners",
  2255.         "/updateScripts: updates scripts from the web"
  2256.     ]
  2257. };
  2258.  
  2259. ({
  2260. /* Executed every second */
  2261. stepEvent: function() {
  2262.     try {
  2263.         mafia.tickDown();
  2264.     } catch(err) {
  2265.         sys.sendAll("+MafiaBot: error occurred: " + err, mafiachan);
  2266.     }
  2267. }
  2268. ,
  2269.  
  2270. repeatStepEvent: function(globalCounter) {
  2271.     if (stepCounter != globalCounter) {
  2272.         return;
  2273.     }
  2274.  
  2275.     stepCounter = stepCounter+1;
  2276.     sys.callLater("script.repeatStepEvent(" + stepCounter + ")", 1);
  2277.  
  2278.     /* Using script. instead of this. so as to stop it when this function is removed */
  2279.     script.stepEvent();
  2280. }
  2281.  
  2282. ,
  2283. startStepEvent: function() {
  2284.     stepCounter = 0;
  2285.  
  2286.     this.repeatStepEvent(0);
  2287. }
  2288. ,
  2289. serverStartUp : function() {
  2290.     startUpTime = parseInt(sys.time());
  2291.     scriptChecks = 0;
  2292.     this.init();
  2293. }
  2294.        
  2295. ,
  2296. init : function() {
  2297.     lastMemUpdate = 0;
  2298.     this.startStepEvent();
  2299.  
  2300.     var dwlist = ["Rattata", "Raticate", "Nidoran-F", "Nidorina", "Nidoqueen", "Nidoran-M", "Nidorino", "Nidoking", "Oddish", "Gloom", "Vileplume", "Bellossom", "Bellsprout", "Weepinbell", "Victreebel", "Ponyta", "Rapidash", "Farfetch'd", "Doduo", "Dodrio", "Exeggcute", "Exeggutor", "Lickitung", "Lickilicky", "Tangela", "Tangrowth", "Kangaskhan", "Sentret", "Furret", "Cleffa", "Clefairy", "Clefable", "Igglybuff", "Jigglypuff", "Wigglytuff", "Mareep", "Flaaffy", "Ampharos", "Hoppip", "Skiploom", "Jumpluff", "Sunkern", "Sunflora", "Stantler", "Poochyena", "Mightyena", "Lotad", "Ludicolo", "Lombre", "Taillow", "Swellow", "Surskit", "Masquerain", "Bidoof", "Bibarel", "Shinx", "Luxio", "Luxray", "Psyduck", "Golduck", "Growlithe", "Arcanine", "Scyther", "Scizor", "Tauros", "Azurill", "Marill", "Azumarill", "Bonsly", "Sudowoodo", "Girafarig", "Miltank", "Zigzagoon", "Linoone", "Electrike", "Manectric", "Castform", "Pachirisu", "Buneary", "Lopunny", "Glameow", "Purugly", "Natu", "Xatu", "Skitty", "Delcatty", "Eevee", "Vaporeon", "Jolteon", "Flareon", "Espeon", "Umbreon", "Leafeon", "Glaceon", "Eevee", "Bulbasaur", "Charmander", "Squirtle", "Ivysaur", "Venusaur", "Charmeleon", "Charizard", "Wartortle", "Blastoise", "Croagunk", "Toxicroak", "Turtwig", "Grotle", "Torterra", "Chimchar", "Infernape", "Monferno", "Piplup", "Prinplup", "Empoleon", "Treecko", "Sceptile", "Grovyle", "Torchic", "Combusken", "Blaziken", "Mudkip", "Marshtomp", "Swampert", "Caterpie", "Metapod", "Butterfree", "Pidgey", "Pidgeotto", "Pidgeot", "Spearow", "Fearow", "Zubat", "Golbat", "Crobat", "Aerodactyl", "Hoothoot", "Noctowl", "Ledyba", "Ledian", "Yanma", "Yanmega", "Murkrow", "Honchkrow", "Delibird", "Wingull", "Pelipper", "Swablu", "Altaria", "Starly", "Staravia", "Staraptor", "Gligar", "Gliscor", "Drifloon", "Drifblim", "Skarmory", "Tropius", "Chatot", "Slowpoke", "Slowbro", "Slowking", "Krabby", "Kingler", "Horsea", "Seadra", "Kingdra", "Goldeen", "Seaking", "Magikarp", "Gyarados", "Omanyte", "Omastar", "Kabuto", "Kabutops", "Wooper", "Quagsire", "Qwilfish", "Corsola", "Remoraid", "Octillery", "Gallade", "Mantine", "Mantyke", "Carvanha", "Sharpedo", "Wailmer", "Houndoom", "Pikachu", "Raichu", "Wailord", "Barboach", "Whiscash", "Clamperl", "Gorebyss", "Huntail", "Relicanth", "Luvdisc", "Buizel", "Floatzel", "Finneon", "Lumineon", "Tentacool", "Tentacruel", "Corphish", "Crawdaunt", "Lileep", "Cradily", "Anorith", "Armaldo", "Feebas", "Milotic", "Shellos", "Gastrodon", "Lapras", "Dratini", "Dragonair", "Dragonite", "Elekid", "Electabuzz", "Electivire", "Poliwag", "Poliwrath", "Politoed", "Poliwhirl", "Vulpix", "Ninetales", "Musharna", "Munna", "Darmanitan", "Darumaka", "Mamoswine", "Togekiss", "Burmy", "Smeargle", "Wormadam", "Mothim", "Volbeat", "Illumise", "Sableye", "Meowth", "Persian", "Abra", "Kadabra", "Alakazam", "Drowzee", "Hypno", "Mr. Mime", "Spinarak", "Ariados", "Wobbuffet", "Snubbull", "Granbull", "Smoochum", "Jynx", "Ralts", "Kirlia", "Gardevoir", "Mawile", "Meditite", "Medicham", "Spoink", "Grumpig", "Shuppet", "Banette", "Stunky", "Skuntank", "Bronzor", "Bronzong", "Spiritomb"];
  2301.     /* use hash for faster lookup */
  2302.     dwpokemons = {};
  2303.     for(var dwpok in dwlist) {
  2304.         dwpokemons[sys.pokeNum(dwlist[dwpok])] = true;
  2305.     }
  2306.  
  2307.     var lclist = ["Bulbasaur", "Charmander", "Squirtle", "Croagunk", "Turtwig", "Chimchar", "Piplup", "Treecko","Torchic","Mudkip"]
  2308.     lcpokemons = [];
  2309.     for(var dwpok in lclist) {
  2310.         lcpokemons.push(sys.pokeNum(lclist[dwpok]));
  2311.     }
  2312.     bannedGSC = [sys.moveNum("Perish Song"), sys.moveNum("Hypnosis"), sys.moveNum("Mean Look")];
  2313.  
  2314.     var inconsistentList = ["Remoraid", "Bidoof", "Snorunt", "Smeargle", "Bibarel", "Octillery", "Glalie"];
  2315.     inpokemons = [];
  2316.     for(var inpok in inconsistentList) {
  2317.         inpokemons.push(sys.pokeNum(inconsistentList[inpok]));
  2318.     }
  2319.  
  2320.     var breedingList = ["Bulbasaur", "Ivysaur", "Venusaur", "Charmander", "Charmeleon", "Charizard", "Squirtle", "Wartortle", "Blastoise", "Croagunk", "Toxicroak", "Turtwig", "Grotle", "Torterra", "Chimchar", "Monferno", "Infernape", "Piplup", "Prinplup", "Empoleon", "Treecko", "Grovyle", "Sceptile", "Torchic", "Combusken", "Blaziken", "Mudkip", "Marshtomp", "Swampert", "Mamoswine", "Togekiss"];
  2321.     breedingpokemons = [];
  2322.     for(var inpok in breedingList) {
  2323.         breedingpokemons.push(sys.pokeNum(breedingList[inpok]));
  2324.     }
  2325.  
  2326.     /* restore mutes, smutes, mafiabans, rangebans, megausers */
  2327.     mutes = new MemoryHash("mutes.txt");
  2328.     mbans = new MemoryHash("mbans.txt");
  2329.     smutes = new MemoryHash("smutes.txt");
  2330.     rangebans = new MemoryHash("rangebans.txt");
  2331.    
  2332.         rules = [ "",
  2333.     "*** Rules ***",
  2334.     "",
  2335.     "Rule #1 - Do Not Abuse CAPS:",
  2336.     "- The occasional word in CAPS is acceptable, however repeated use is not.",
  2337.     "Rule #2 - No Flooding the Chat:",
  2338.     "- Please do not post a large amount of short messages when you can easily post one or two long messages.",
  2339.     "Rule #3 - Do not Challenge Spam:",
  2340.     "- If a person refuses your challenge, this means they do not want to battle you. Find someone else to battle with.",
  2341.     "Rule #4 - Don't ask for battles in the main chat:",
  2342.     "- There is a 'Find Battle' tab that you can use to find a battle immediately. If after a while you cannot find a match, then you can ask for one in the chat.",
  2343.     "Rule #5 - No Trolling/Flaming/Insulting of Any kind:",
  2344.     "- Behaving stupidly and excessive vulgarity will not be tolerated, using words including 'fuck' is a bad starting point.",
  2345.     "Rule #6 - Be Respectable of Each Others Cultures:",
  2346.     "- Not everyone speaks the same language. This server is not an English-Only Server. Do not tell someone to only speak a certain language.",
  2347.     "Rule #7 - No Advertising:",
  2348.     "- There will be absolutely no advertising on the server.",
  2349.     "Rule #8 - No Obscene or Pornographic Content Allowed:",
  2350.     "- This includes links, texts, images, and any other kind of media. This will result in a instant ban.",
  2351.     "Rule #9 - Do not ask for Auth:",
  2352.     "- Authority is given upon merit. By asking you have pretty much eliminated your chances at becoming an Auth in the future.",
  2353.     "Rule #10 - Do not Insult Auth:",
  2354.     "- Insulting Auth will result in immediate punishment. "   ];
  2355.  
  2356.     if (typeof tempBans == 'undefined') {
  2357.         tempBans = {};
  2358.     }
  2359.  
  2360.     if (typeof VarsCreated != 'undefined')
  2361.         return;
  2362.  
  2363.     key = function(a,b) {
  2364.         return a + "*" + sys.name(b);
  2365.     }
  2366.  
  2367.     saveKey = function(thing, id, val) {
  2368.         sys.saveVal(key(thing,id), val);
  2369.     }
  2370.  
  2371.     getKey = function(thing, id) {
  2372.         return sys.getVal(key(thing,id));
  2373.     }
  2374.  
  2375.     cmp = function(a, b) {
  2376.         return a.toLowerCase() == b.toLowerCase();
  2377.     }
  2378.  
  2379.     battlesStopped = false;
  2380.  
  2381.     megausers = sys.getVal("megausers");
  2382.  
  2383.     muteall = false;
  2384.  
  2385.     maxPlayersOnline = 0;
  2386.  
  2387.     lineCount = 0;
  2388.     tourmode = 0;
  2389.  
  2390.     tourwinners = [];
  2391.     tourstats = {};
  2392.     tourrankingsbytier = {};
  2393.     try {
  2394.         var jsonObject = JSON.parse(sys.getFileContent('tourstats.json'));
  2395.         tourwinners = jsonObject.tourwinners;
  2396.         tourstats = jsonObject.tourstats;
  2397.         tourrankingsbytier = jsonObject.tourrankingsbytier;
  2398.     } catch (err) {
  2399.         print('Could not read tourstats, initing to null stats.');
  2400.         print('Error: ' + err);
  2401.     }
  2402.  
  2403.     border = "»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»:";
  2404.  
  2405.     pokeNatures = [];
  2406.  
  2407.     var list = "Heatran-Eruption/Quiet=Suicune-ExtremeSpeed/Relaxed|Sheer Cold/Relaxed|Aqua Ring/Relaxed|Air Slash/Relaxed=Raikou-ExtremeSpeed/Rash|Weather Ball/Rash|Zap Cannon/Rash|Aura Sphere/Rash=Entei-ExtremeSpeed/Adamant|Flare Blitz/Adamant|Howl/Adamant|Crush Claw/Adamant";
  2408.  
  2409.     var sepPokes = list.split('=');
  2410.     for (var x in sepPokes) {
  2411.         sepMovesPoke = sepPokes[x].split('-');
  2412.         sepMoves = sepMovesPoke[1].split('|');
  2413.  
  2414.         var poke = sys.pokeNum(sepMovesPoke[0]);
  2415.         pokeNatures[poke] = [];
  2416.  
  2417.         for (var y = 0; y < sepMoves.length; ++y) {
  2418.             movenat = sepMoves[y].split('/');
  2419.             pokeNatures[poke][sys.moveNum(movenat[0])] = sys.natureNum(movenat[1]);
  2420.         }
  2421.     }
  2422.  
  2423.     /* Permanent channels */
  2424.     var channelDataFile = 'channels.json';
  2425.     try {
  2426.         channelData = JSON.parse(sys.getFileContent(channelDataFile));
  2427.     } catch (err) {
  2428.         print('Could not read channelData.');
  2429.         print('Error: ' + err);
  2430.         channelData = {};
  2431.     }
  2432.     /* global updater */
  2433.     updateChannelTopic = function(channelName, topic) {
  2434.         if (typeof(channelData) == "undefined") {
  2435.             channelData = {};
  2436.         }
  2437.         if (!(channelName in channelData)) {
  2438.             channelData[channelName] = {};
  2439.             channelData.perm = false;
  2440.         }
  2441.         channelData[channelName].topic = topic;
  2442.         sys.writeToFile(channelDataFile, JSON.stringify(channelData));
  2443.     }
  2444.     updateChannelPerm = function(channelName, perm) {
  2445.         if (!(channelName in channelData)) {
  2446.             channelData[channelName] = {};
  2447.             channelData[channelName].topic = '';
  2448.         }
  2449.         channelData[channelName].perm = perm;
  2450.         sys.writeToFile(channelDataFile, JSON.stringify(channelData));
  2451.     }
  2452.  
  2453.     var createPermChannel = function(name, defaultTopic) {
  2454.         var cid;
  2455.         if (sys.existChannel(name)) {
  2456.             cid = sys.channelId(name);
  2457.         } else {
  2458.             cid = sys.createChannel(name);
  2459.         }
  2460.         SESSION.channels(cid).topic = defaultTopic;
  2461.         SESSION.channels(cid).perm = true;
  2462.         if (name in channelData) {
  2463.             SESSION.channels(cid).topic = channelData[name].topic;
  2464.         }
  2465.         return cid;
  2466.     }
  2467.  
  2468.     mafiachan = createPermChannel("Mafia Channel", "Use /help to get started!");
  2469.  
  2470.     staffchannel = createPermChannel("Indigo Plateau", "Welcome to the Staff Channel! Discuss of all what users shouldn't hear here! Or more serious stuff...");
  2471.  
  2472.     tourchannel = createPermChannel("Tournaments", 'Useful commands are "/join" (to join a tournament), "/unjoin" (to leave a tournament), "/viewround" (to view the status of matches) and "/megausers" (for a list of users who manage tournaments). Please read the full Tournament Guidelines: http://pokemon-online.eu/forums/showthread.php?2079-Tour-Rules');
  2473.  
  2474.     createPermChannel("League", "Challenge the PO League here! For more information, please visit this link: http://pokemon-online.eu/forums/forumdisplay.php?36-PO-League");
  2475.  
  2476.     trollchannel = createPermChannel("Mute City", 'This is a place to talk if you have been muted! Please behave, next stop will be bans.');
  2477.     /* restore topic for main */
  2478.     var mainName = sys.channel(0);
  2479.     if (mainName in channelData) {
  2480.         SESSION.channels(0).topic = channelData[mainName].topic;
  2481.     }
  2482.  
  2483.     /* global utility helpers */
  2484.     getSeconds = function(s) {
  2485.         var parts = s.split(" ")
  2486.         var secs = 0;
  2487.         for (var i = 0; i < parts.length; ++i) {
  2488.             var c = (parts[i][parts[i].length-1]).toLowerCase();
  2489.             var mul = 60;
  2490.             if (c == "s") { mul = 1; }
  2491.             else if (c == "m") { mul = 60; }
  2492.             else if (c == "h") { mul = 60*60; }
  2493.             else if (c == "d") { mul = 24*60*60; }
  2494.             else if (c == "w") { mul = 7*24*60*60; }
  2495.             secs += mul * parseInt(parts[i]);
  2496.         }
  2497.         return secs;
  2498.     };
  2499.     getTimeString = function(sec) {
  2500.         s = [];
  2501.         var n;
  2502.         var d = [[7*24*60*60, "week"], [24*60*60, "day"], [60*60, "hour"], [60, "minute"], [1, "second"]];
  2503.         for (j = 0; j < 5; ++j) {
  2504.             n = parseInt(sec / d[j][0]);
  2505.             if (n > 0) {
  2506.                 s.push((n + " " + d[j][1] + (n > 1 ? "s" : "")));
  2507.                 sec -= n * d[j][0];
  2508.                 if (s.length >= 2) break;
  2509.             }
  2510.         }
  2511.         return s.join(", ");
  2512.     };
  2513.  
  2514.     sendChanMessage = function(id, message) {
  2515.         sys.sendMessage(id, message, channel);
  2516.     }
  2517.    
  2518.     isChannelMaster = function(id) {
  2519.         return SESSION.channels(channel).master == sys.name(id).toLowerCase();
  2520.     }
  2521.  
  2522.     sendChanAll = function(message) {
  2523.         sys.sendAll(message, channel);
  2524.     }
  2525.    
  2526.     sendMainTour = function(message) {
  2527.         sys.sendAll(message, 0);
  2528.         sys.sendAll(message, tourchannel);
  2529.     }
  2530.  
  2531.     mafia.themeManager.loadThemes();
  2532.     VarsCreated = true;
  2533. } /* end of init */
  2534.  
  2535. ,
  2536.  
  2537. issueBan : function(type, src, tar, commandData) {
  2538.         var memoryhash = {"mute": mutes, "mban": mbans, "smute": smutes}[type];
  2539.         var bot = type == "mban" ? "+MafiaBot" : "+Bot";
  2540.         var verb = {"mute": "muted", "mban": "banned from mafia", "smute": "secretly muted"}[type];
  2541.         var nomi = {"mute": "mute", "mban": "ban from mafia", "smute": "secret mute"}[type];
  2542.         var sendAll = (type == "smute") ? function(line) { sys.sendAll(line, staffchannel); } : sys.sendAll;
  2543.  
  2544.         var expires = 0;
  2545.         var reason = "";
  2546.         var timeString = "";
  2547.         if (tar == undefined) {
  2548.             var data = commandData.split(":");
  2549.             if (data.length > 1) {
  2550.                 commandData = data[0];
  2551.                 tar = sys.id(commandData);
  2552.                 reason = data[1];
  2553.                 if (data.length > 2) {
  2554.                     var secs = getSeconds(data[2]);
  2555.                     if (secs > 0) {
  2556.                         timeString = " for " + getTimeString(secs);
  2557.                         expires = secs + parseInt(sys.time());
  2558.                     }
  2559.                 }
  2560.             }
  2561.         }
  2562.         if (reason == "") {
  2563.            sendChanMessage(src, bot+": You need to give a reason to the " + nomi + "!");
  2564.            return;
  2565.         }
  2566.         if (tar == undefined) {
  2567.             ip = sys.dbIp(commandData);
  2568.             var alias=sys.aliases(ip);
  2569.             var y=0;
  2570.             var z;
  2571.             for(var x in alias) {
  2572.                 z = sys.dbAuth(alias[x])
  2573.                 if (z > y) {
  2574.                     y=z
  2575.                 }
  2576.             }
  2577.             if(y>=sys.auth(src)) {
  2578.                sendChanMessage(src, bot+": Can't do that to higher auth!");
  2579.                return;
  2580.             }
  2581.             if(sys.dbIp(commandData) != undefined) {
  2582.                 ip = sys.dbIp(commandData)
  2583.                 if (memoryhash.get(ip)) {
  2584.                     sendChanMessage(src, bot+": He/she's already " + verb + ".");
  2585.                     return;
  2586.                 }
  2587.                 sendAll(bot+": " + commandData + " was " + verb + " by " + sys.name(src) + timeString + "! [Reason: " + reason + "]");
  2588.                 memoryhash.add(ip, sys.time() + ":" + sys.name(src) + ":" + expires + ":" + commandData + ":" + reason);
  2589.                 return;
  2590.             }
  2591.  
  2592.             sendChanMessage(src, bot+": Couldn't find " + commandData);
  2593.             return;
  2594.         }
  2595.         if (SESSION.users(tar)[type].active) {
  2596.             sendChanMessage(src, bot+": He/she's already " + verb + ".");
  2597.             return;
  2598.         }
  2599.         if (sys.auth(tar) >= sys.auth(src)) {
  2600.             sendChanMessage(src, bot+": You dont have sufficient auth to " + nomi + " " + commandData + ".");
  2601.             return;
  2602.         }
  2603.         SESSION.users(tar).activate(type, sys.name(src), expires, reason, true);
  2604.         sendAll(bot+": " + commandData + " was " + verb + " by " + sys.name(src) + timeString + "! [Reason: " + reason + "]");
  2605.         //if (expires > 0) {
  2606.             //if (type != "smute")
  2607.                 //sendChanMessage(tar, bot+": Your " + nomi + " will end automatically at " + new Date(expires*1000).toUTCString());
  2608.             //sendChanMessage(src, bot+": The " + nomi + " you issued will end automatically at " + new Date(expires*1000).toUTCString());
  2609.             //sendChanMessage(src, bot+": " + commandData + " was " + verb + " by " + sys.name(src) + timeString + "!");
  2610.         //}
  2611. }
  2612.  
  2613. ,
  2614.  
  2615. beforeChannelJoin : function(src, channel) {
  2616.     var index = SESSION.channels(channel).invitelist.indexOf(src);
  2617.     if (index != -1) {
  2618.         // allow to bypass all limits if invited
  2619.         SESSION.channels(channel).invitelist.splice(index, 1);
  2620.         return;
  2621.     }
  2622.     if (SESSION.channels(channel).inviteonly > sys.auth(src)) {
  2623.         sys.sendMessage(src, "+Guard: Sorry, but this channel is for higher authority!")
  2624.         sys.stopEvent();
  2625.         return;
  2626.     }
  2627.     if (channel == trollchannel && (!SESSION.users(src).mute.active && sys.auth(src) == 0)) {
  2628.         sys.sendMessage(src, "+Guard: Sorry, the access to that place is restricted!");
  2629.         sys.stopEvent();
  2630.         return;
  2631.     }
  2632.     if (channel == staffchannel && (!SESSION.users(src).megauser && sys.auth(src) <= 0 || sys.name(src) == "Emac") || channel == sys.channelId("shanaindigo") && !SESSION.users(src).megauser && sys.auth(src) <= 0) {
  2633.         sys.sendMessage(src, "+Guard: Sorry, the access to that place is restricted!");
  2634.         sys.stopEvent();
  2635.         return;
  2636.     }
  2637.     if (channel == mafiachan && SESSION.users(src).mban.active) {
  2638.         if (SESSION.users(src).expired("mban")) {
  2639.             SESSION.users(src).un("mban");
  2640.             sys.sendMessage(src, "+MafiaBot: Your ban from Mafia expired.");
  2641.             sys.sendAll("+MafiaBot: " + sys.name(src) + "'s ban from Mafia expired.", mafiachan);
  2642.         } else {
  2643.  
  2644.             var mbaninfo = SESSION.users(src).mban;
  2645.             sendChanMessage(src, "+Guard: You are banned from Mafia" + (mbaninfo.by ? " by " + mbaninfo.by : '')+". " + (mbaninfo.expires > 0 ? "Ban expires in " + getTimeString(mbaninfo.expires - parseInt(sys.time())) + ". " : '') + (mbaninfo.reason ? "[Reason: " + mbaninfo.reason + "]" : ''));
  2646.             sys.stopEvent();
  2647.             return;
  2648.         }
  2649.     }
  2650. } /* end of beforeChannelJoin */
  2651.  
  2652. ,
  2653.  
  2654. afterChannelCreated : function (chan, name, src) {
  2655.     if (name in channelData) {
  2656.         SESSION.channels(chan).topic = channelData[name].topic;
  2657.         SESSION.channels(chan).perm = channelData[name].perm;
  2658.     }
  2659.     if (src == 0)
  2660.         return;
  2661.  
  2662.     SESSION.channels(chan).master = sys.name(src).toLowerCase();
  2663. } /* end of afterChannelCreated */
  2664.  
  2665. ,
  2666.  
  2667. afterChannelJoin : function(player, chan) {
  2668.     if (typeof(SESSION.channels(chan).topic) != 'undefined') {
  2669.         sys.sendMessage(player, "Welcome Message: " + SESSION.channels(chan).topic, chan);
  2670.     }
  2671.     if (typeof(SESSION.channels(chan).master) != 'undefined' && sys.name(player).toLowerCase() == SESSION.channels(chan).master) {
  2672.         sys.sendMessage(player, "+ChannelBot: use /topic <topic> to change the welcome message of this channel", chan);
  2673.         return;
  2674.     }
  2675. } /* end of afterChannelJoin */
  2676.  
  2677. ,
  2678.  
  2679. beforeChannelDestroyed : function(channel) {
  2680.     if (channel == tourchannel || (SESSION.channels(channel).perm == true) ) {
  2681.         sys.stopEvent();
  2682.         return;
  2683.     }
  2684. } /* end of beforeChannelDestroyed */
  2685. ,
  2686.  
  2687. afterNewMessage : function (message) {
  2688.     if (message == "Script Check: OK") {
  2689.         sys.sendAll("+ScriptBot: Scripts were updated!");
  2690.         if (typeof(scriptChecks)=='undefined')
  2691.             scriptChecks = 0;
  2692.         scriptChecks += 1;
  2693.         this.init();
  2694.     }
  2695. } /* end of afterNewMessage */
  2696.  
  2697. ,
  2698.  
  2699. beforeLogIn : function(src) {
  2700.     var ip = sys.ip(src);
  2701.     if (ip in tempBans) {
  2702.         var time = parseInt(sys.time());
  2703.         if (time > tempBans[ip].time) {
  2704.             delete tempBans[ip];
  2705.         } else {
  2706.             sys.stopEvent();
  2707.         }
  2708.     }
  2709. }
  2710.  
  2711. ,
  2712.  
  2713. afterLogIn : function(src) {
  2714.     if (sys.ip(src).substr(0, 7) == "125.237" && sys.name(src).toLowerCase() != "ava") {
  2715.         sys.kick(src);
  2716.         return;
  2717.     }
  2718.  
  2719.     for (var subip in rangebans.hash) {
  2720.         if (sys.ip(src).substr(0, subip.length) == subip && sys.name(src).toLowerCase() != "downpour") {
  2721.             sys.kick(src);
  2722.             return;
  2723.         }
  2724.     }
  2725.  
  2726.     sys.sendMessage(src, "*** Type in /Rules to see the rules. ***");
  2727.     sys.sendMessage(src, "+CommandBot: Use !commands to see the commands!");
  2728.  
  2729.     if (sys.numPlayers() > maxPlayersOnline) {
  2730.         maxPlayersOnline = sys.numPlayers();
  2731.     }
  2732.  
  2733.     if (maxPlayersOnline > sys.getVal("MaxPlayersOnline")) {
  2734.         sys.saveVal("MaxPlayersOnline", maxPlayersOnline);
  2735.     }
  2736.  
  2737.     sys.sendMessage(src, "+CountBot: Max number of players online was " + sys.getVal("MaxPlayersOnline") + ".");
  2738.     sys.sendMessage(src, "");
  2739.     if (tourmode == 1){
  2740.         sys.sendMessage(src,"*** A " + tourtier + " tournament is in its signup phase, " + this.tourSpots() + " space(s) are left!");
  2741.         sys.sendMessage(src, "");
  2742.         sys.sendMessage(src, border);
  2743.         sys.sendMessage(src, "");
  2744.  
  2745.     } else if (tourmode == 2){
  2746.         sys.sendMessage(src, "");
  2747.         sys.sendMessage(src, border);
  2748.         sys.sendMessage(src, "");
  2749.         sys.sendMessage(src, "~~Server~~: A tournament (" + tourtier + ") is currently running.");
  2750.         sys.sendMessage(src, "");
  2751.         sys.sendMessage(src, border);
  2752.         sys.sendMessage(src, "");
  2753.     }
  2754.     suspectVoting.afterLogIn(src);
  2755.  
  2756.  
  2757.     if (SESSION.users(src).megauser)
  2758.         sys.appendToFile("staffstats.txt", sys.name(src) + "~" + src + "~" + sys.time() + "~" + "Connected as MU" + "\n");
  2759.     if (sys.auth(src) > 0 && sys.auth(src) <= 3)
  2760.         sys.appendToFile("staffstats.txt", sys.name(src) + "~" + src + "~" + sys.time() + "~" + "Connected as Auth" + "\n");
  2761.  
  2762.     authChangingTeam = (sys.auth(src) > 0 && sys.auth(src) <= 3);
  2763.     this.afterChangeTeam(src);
  2764.  
  2765.     if (SESSION.users(src).mute.active)
  2766.         sys.putInChannel(src, trollchannel);
  2767.     if (sys.auth(src) > 0 && sys.auth(src) <= 3 || SESSION.users(src).megauser == true && sys.name(src) != "Emac")
  2768.         sys.putInChannel(src, staffchannel);
  2769. } /* end of afterLogin */
  2770.  
  2771. ,
  2772.  
  2773. beforeLogOut : function(src) {
  2774.     if (SESSION.users(src).megauser)
  2775.         sys.appendToFile("staffstats.txt", sys.name(src) + "~" + src + "~" + sys.time() + "~" + "Disconnected as MU" + "\n");
  2776.     if (sys.auth(src) > 0 && sys.auth(src) <= 3)
  2777.         sys.appendToFile("staffstats.txt", sys.name(src) + "~" + src + "~" + sys.time() + "~" + "Disconnected as Auth" + "\n");
  2778. }
  2779.  
  2780. ,
  2781.  
  2782. beforeChangeTeam : function(src) {
  2783.     authChangingTeam = (sys.auth(src) > 0 && sys.auth(src) <= 3);
  2784. }
  2785.  
  2786. ,
  2787.  
  2788. afterChangeTeam : function(src)
  2789. {
  2790.     if (/[\u0430-\u044f]/.test(sys.name(src))) {
  2791.         sys.sendMessage(src, '+Bot: You are kicked for using bad characters in your name.');
  2792.         sys.kick(src);
  2793.         return;
  2794.     }
  2795.     if (sys.name(src).toLowerCase() == 'evil heart') {
  2796.         sys.sendAll('*** WARNING ***', staffchannel);
  2797.         sys.sendAll('+WarningBot: Evil Heart logged in', staffchannel);
  2798.         sys.sendAll('*** END OF WARNING ***', staffchannel);
  2799.     }
  2800.  
  2801.     if (megausers.indexOf("*" + sys.name(src) + "*") != -1) {
  2802.         if(!SESSION.users(src).megauser) {
  2803.             sys.appendToFile("staffstats.txt", sys.name(src) + "~" + src + "~" + sys.time() + "~" + "Changed name to MU" + "\n");
  2804.         }
  2805.         SESSION.users(src).megauser = true;
  2806.     } else {
  2807.         if(SESSION.users(src).megauser) {
  2808.             sys.appendToFile("staffstats.txt", "~" + src + "~" + sys.time() + "~" + "Changed name from MU" + "\n");
  2809.         }
  2810.         SESSION.users(src).megauser = false;
  2811.     }
  2812.     if (authChangingTeam === false) {
  2813.         if (sys.auth(src) > 0 && sys.auth(src) <= 3)
  2814.             sys.appendToFile("staffstats.txt", sys.name(src) + "~" + src + "~" + sys.time() + "~" + "Changed name to Auth" + "\n");
  2815.     } else if (authChangingTeam === true) {
  2816.         if (!(sys.auth(src) > 0 && sys.auth(src) <= 3))
  2817.             sys.appendToFile("staffstats.txt", "~" + src + "~" + sys.time() + "~" + "Changed name from Auth" + "\n");
  2818.     }
  2819.  
  2820.     SESSION.users(src).sametier = getKey("forceSameTier", src) == "1";
  2821.  
  2822.     if (sys.gen(src) >= 4) {
  2823.     for (var i = 0; i < 6; i++) {
  2824.         var poke = sys.teamPoke(src, i);
  2825.         if (poke in pokeNatures) {
  2826.             for (x in pokeNatures[poke]) {
  2827.                 if (sys.hasTeamPokeMove(src, i, x) && sys.teamPokeNature(src, i) != pokeNatures[poke][x])
  2828.                 {
  2829.                     sys.sendMessage(src, "+CheckBot: " + sys.pokemon(poke) + " with " + sys.move(x) + " must be a " + sys.nature(pokeNatures[poke][x]) + " nature. Change it in the teambuilder.");
  2830.                     sys.changePokeNum(src, i, 0);
  2831.                 }
  2832.             }
  2833.         }
  2834.     }
  2835.    }
  2836.  
  2837.    if (sys.gen(src) == 2) {
  2838.         for (var i = 0; i <= 6; i++) {
  2839.             if (sys.hasTeamPokeMove(src, i, bannedGSC[0])
  2840.                 && sys.hasTeamPokeMove(src, i, bannedGSC[1])
  2841.                 && sys.hasTeamPokeMove(src, i, bannedGSC[2])) {
  2842.                 sys.sendMessage(src, "+CheckBot: PerishTrapSleep is banned in GSC.");
  2843.                 sys.changePokeNum(src, i, 0);
  2844.             }
  2845.         }
  2846.     }
  2847.     this.dreamWorldAbilitiesCheck(src, false);
  2848.     this.littleCupCheck(src, false);
  2849.     this.inconsistentCheck(src, false);
  2850.     this.monotypecheck(src);
  2851.     this.weatherlesstiercheck(src);
  2852.     this.shanaiAbilityCheck(src, false)
  2853.  
  2854. } /* end of afterChangeTeam */
  2855.  
  2856. ,
  2857. userCommand: function(src, command, commandData, tar) {
  2858.     if (command == "commands" || command == "command") {
  2859.         if (commandData == undefined) {
  2860.             sendChanMessage(src, "*** Commands ***");
  2861.             for(var x = 0; x < commands["user"].length; ++x) {
  2862.                 sendChanMessage(src, commands["user"][x]);
  2863.             }
  2864.             sendChanMessage(src, "*** Other Commands ***");
  2865.             sendChanMessage(src, "/commands channel: To know of channel commands");
  2866.             if (SESSION.users(src).megauser || sys.auth(src) > 0) {
  2867.                 sendChanMessage(src, "/commands megauser: To know of megauser commands");
  2868.             }
  2869.             if (sys.auth(src) > 0) {
  2870.                 sendChanMessage(src, "/commands mod: To know of moderator commands");
  2871.             }
  2872.             if (sys.auth(src) > 1) {
  2873.                 sendChanMessage(src, "/commands admin: To know of admin commands");
  2874.             }
  2875.             if (sys.auth(src) > 2) {
  2876.                 sendChanMessage(src, "/commands owner: To know of owner commands");
  2877.             }
  2878.             sendChanMessage(src, "/commands suspectVoting: To know the commands of suspect voting");
  2879.             sendChanMessage(src, "");
  2880.             sendChanMessage(src, "Commands starting with \"|\" will be forwarded to Shanai if she's online.");
  2881.             sendChanMessage(src, "");
  2882.             return;
  2883.         }
  2884.  
  2885.         commandData = commandData.toLowerCase();
  2886.         if ( (commandData == "mod" && sys.auth(src) > 0)
  2887.             || (commandData == "admin" && sys.auth(src) > 1)
  2888.             || (commandData == "owner" & sys.auth(src) > 2)
  2889.             || (commandData == "megauser" && (sys.auth(src) > 0 || SESSION.users(src).megauser))
  2890.             || (commandData == "channel") ) {
  2891.             sendChanMessage(src, "*** " + commandData.toUpperCase() + " Commands ***");
  2892.             for(x in commands[commandData]) {
  2893.                 sendChanMessage(src, commands[commandData][x]);
  2894.             }
  2895.         }
  2896.         if (commandData == "suspectvoting") {
  2897.             suspectVoting.handleCommand(src, "votinghelp");
  2898.         }
  2899.        
  2900.         return;
  2901.     }
  2902.     if (command == "me" && !muteall && !SESSION.channels(channel).muteall) {
  2903.         if ((typeof(meoff) != "undefined" && meoff != false && (channel == tourchannel || channel == 0))
  2904.             || SESSION.channels(channel).meoff === true) {
  2905.             sendChanMessage(src, "+Bot: /me was turned off.");
  2906.             return;
  2907.         }
  2908.         if (commandData === undefined)
  2909.             return;
  2910.         if (channel == mafiachan && mafia.ticks > 0 && mafia.state!="blank" && !mafia.isInGame(sys.name(src)) && sys.auth(src) <= 0) {
  2911.             sys.sendMessage(src, "Β±Game: You're not playing, so shush! Go in another channel to talk!", mafiachan);
  2912.             return;
  2913.     }
  2914.  
  2915.         var m = commandData.toLowerCase();
  2916.         if (m.indexOf("nigger") != -1 || m.indexOf("drogendealer") != -1 || m.indexOf("penis") != -1 ||  m.indexOf("vagina")  != -1 || m.indexOf("fuckface") != -1
  2917.             || m.indexOf("herp") != -1 || /\bderp/i.test(m) || m.indexOf("hurr") != -1) {
  2918.             sys.stopEvent();
  2919.             return;
  2920.         }
  2921.        
  2922.         if (sys.auth(src) == 0 && SESSION.users(src).smute.active) {
  2923.             sendChanMessage(src, "*** " + sys.name(src) + " " + commandData);
  2924.             sys.stopEvent();
  2925.             this.afterChatMessage(src, '/'+command+ ' '+commandData);
  2926.             return;
  2927.         }
  2928.         commandData=this.html_escape(commandData)
  2929.         sys.sendHtmlAll("<span style='color:#0483c5'><timestamp/> *** <b>" + sys.name(src) + "</b> " + commandData + "</span>", channel);
  2930.         this.afterChatMessage(src, '/'+command+' '+commandData);
  2931.         return;
  2932.     }
  2933.     if (command == "megausers") {
  2934.         sendChanMessage(src, "");
  2935.         sendChanMessage(src, "*** MEGA USERS ***");
  2936.         sendChanMessage(src, "");
  2937.         var spl = megausers.split('*');
  2938.         for (var x = 0; x < spl.length; ++x) {
  2939.             if (spl[x].length > 0)
  2940.                 sendChanMessage(src, spl[x]);
  2941.         }
  2942.         sendChanMessage(src, "");
  2943.         return;
  2944.     }
  2945.     if (command == "rules") {
  2946.         for (rule in rules) {
  2947.             sendChanMessage(src, rules[rule]);
  2948.         }
  2949.         return;
  2950.     }
  2951.     if (command == "players") {
  2952.         sendChanMessage(src, "+CountBot: There are " + sys.numPlayers() + " players online.");
  2953.         return;
  2954.     }
  2955.     if (command == "ranking") {
  2956.         var rank = sys.ranking(src);
  2957.         if (rank == undefined) {
  2958.             sendChanMessage(src, "+RankingBot: You are not ranked in " + sys.tier(src) + " yet!");
  2959.         } else {
  2960.             sendChanMessage(src, "+RankingBot: Your rank in " + sys.tier(src) + " is " + rank + "/" + sys.totalPlayersByTier(sys.tier(src)) + "!");
  2961.         }
  2962.         return;
  2963.     }
  2964.     if (command == "auth") {
  2965.         var authlist = sys.dbAuths().sort()
  2966.         sendChanMessage(src, "");
  2967.         if(commandData == "owners") {
  2968.             sendChanMessage(src, "*** Owners ***")
  2969.             for(x in authlist) {
  2970.                 if(sys.dbAuth(authlist[x]) == 3) {
  2971.                     if(sys.id(authlist[x]) == undefined) {
  2972.                        sendChanMessage(src, authlist[x] + " (Offline)")
  2973.                     }
  2974.                     if(sys.id(authlist[x]) != undefined) {
  2975.                         sys.sendHtmlMessage(src, '<timestamp/><font color = "green">' + sys.name(sys.id(authlist[x])) + ' (Online)</font>',channel)
  2976.                     }
  2977.                 }
  2978.             }
  2979.             sendChanMessage(src, "");
  2980.         }
  2981.         if(commandData == "admins" || commandData == "administrators") {
  2982.             sendChanMessage(src, "*** Administrators ***")
  2983.             for(x in authlist) {
  2984.                 if(sys.dbAuth(authlist[x]) == 2) {
  2985.                     if(sys.id(authlist[x]) == undefined) {
  2986.                         sendChanMessage(src, authlist[x] + " (Offline)")
  2987.                     }
  2988.                     if(sys.id(authlist[x]) != undefined) {
  2989.                         sys.sendHtmlMessage(src, '<timestamp/><font color = "green">' + sys.name(sys.id(authlist[x])) + ' (Online)</font>',channel)
  2990.                     }
  2991.                 }
  2992.             }
  2993.             sys.sendMessage(src, "");
  2994.         }
  2995.         if(commandData == "mods" || commandData == "moderators") {
  2996.             sendChanMessage(src, "*** Moderators ***")
  2997.             for(x in authlist) {
  2998.                 if(sys.dbAuth(authlist[x]) == 1) {
  2999.                     if(sys.id(authlist[x]) == undefined) {
  3000.                         sendChanMessage(src, authlist[x] + " (Offline)")
  3001.                     }
  3002.                     if(sys.id(authlist[x]) != undefined) {
  3003.                         sys.sendHtmlMessage(src, '<timestamp/><font color = "green">' + sys.name(sys.id(authlist[x])) + ' (Online)</font>',channel)
  3004.                     }
  3005.                 }
  3006.             }
  3007.             sys.sendMessage(src, "");
  3008.         }
  3009.  
  3010.         if(commandData != "moderators" && commandData != "mods" && commandData != "administrators" && commandData != "admins" && commandData != "owners") {
  3011.  
  3012.             sendChanMessage(src, "*** Owners ***")
  3013.             for(x in authlist) {
  3014.                 if(sys.dbAuth(authlist[x]) == 3) {
  3015.                     if(sys.id(authlist[x]) == undefined) {
  3016.                         sendChanMessage(src, authlist[x] + " (Offline)")
  3017.                     }
  3018.                     if(sys.id(authlist[x]) != undefined) {
  3019.                         sys.sendHtmlMessage(src, '<timestamp/><font color = "green">' + sys.name(sys.id(authlist[x])) + ' (Online)</font>',channel)
  3020.                     }
  3021.                 }
  3022.             }
  3023.             sendChanMessage(src, "");
  3024.             sendChanMessage(src, "*** Administrators ***")
  3025.             for(x in authlist) {
  3026.                 if(sys.dbAuth(authlist[x]) == 2) {
  3027.                     if(sys.id(authlist[x]) == undefined) {
  3028.                         sendChanMessage(src, authlist[x] + " (Offline)")
  3029.                     }
  3030.                     if(sys.id(authlist[x]) != undefined) {
  3031.                         sys.sendHtmlMessage(src, '<timestamp/><font color = "green">' + sys.name(sys.id(authlist[x])) + ' (Online)</font>',channel)
  3032.                     }
  3033.                 }
  3034.  
  3035.             }
  3036.             sendChanMessage(src, "");
  3037.             sendChanMessage(src, "*** Moderators ***")
  3038.             for(x in authlist) {
  3039.                 if(sys.dbAuth(authlist[x]) == 1) {
  3040.                     if(sys.id(authlist[x]) == undefined) {
  3041.                         sendChanMessage(src, authlist[x] + " (Offline)")
  3042.                     }
  3043.                     if(sys.id(authlist[x]) != undefined) {
  3044.                         sys.sendHtmlMessage(src, '<timestamp/><font color = "green">' + sys.name(sys.id(authlist[x])) + ' (Online)</font>',channel)
  3045.                     }
  3046.                 }
  3047.             }
  3048.         }
  3049.         return;
  3050.     }
  3051.     if (command == "sametier") {
  3052.         if (commandData == "on")
  3053.             sendChanMessage(src, "+SleepBot: You enforce same tier in your battles.");
  3054.         else
  3055.             sendChanMessage(src, "+SleepBot: You allow different tiers in your battles.");
  3056.         SESSION.users(src).sametier = commandData == "on";
  3057.         saveKey("forceSameTier", src, SESSION.users(src).sametier * 1);
  3058.         return;
  3059.     }
  3060.     if (command == "unjoin") {
  3061.         if (tourmode == 0) {
  3062.             sendChanMessage(src, "+TourneyBot: Wait till the tournament has started.");
  3063.             return;
  3064.         }
  3065.         var name2 = sys.name(src).toLowerCase();
  3066.  
  3067.         if (tourmembers.indexOf(name2) != -1) {
  3068.             tourmembers.splice(tourmembers.indexOf(name2),1);
  3069.             delete tourplayers[name2];
  3070.             sys.sendAll("+TourneyBot: " + sys.name(src) + " left the tournament!", tourchannel);
  3071.             return;
  3072.         }
  3073.         if (tourbattlers.indexOf(name2) != -1) {
  3074.             battlesStarted[Math.floor(tourbattlers.indexOf(name2)/2)] = true;
  3075.             sys.sendAll("+TourneyBot: " + sys.name(src) + " left the tournament!", tourchannel);
  3076.             this.tourBattleEnd(this.tourOpponent(name2), name2);
  3077.         }
  3078.         return;
  3079.     }
  3080.     if (command == "selfkick" || command == "sk") {
  3081.         var src_ip = sys.ip(src);
  3082.         var players = sys.playerIds();
  3083.         var players_length = players.length;
  3084.         for (var i = 0; i < players_length; ++i) {
  3085.             var current_player = players[i];
  3086.             if ((src != current_player) && (src_ip == sys.ip(current_player))) {
  3087.                 sys.kick(current_player);
  3088.                 sys.sendMessage(src, "+Bot: Your ghost was kicked...")
  3089.             }
  3090.         }
  3091.         return;
  3092.     }
  3093.  
  3094.     if (command == "join"){
  3095.         if (!sys.isInChannel(src, tourchannel)) {
  3096.             sendChanMessage(src, "+TourBot: You must be in the tournaments channel to join a tournament!");
  3097.             return;
  3098.         }
  3099.         if (tourmode != 1){
  3100.             sendChanMessage(src, "Sorry, you are unable to join because a tournament is not currently running or has passed the signups phase.");
  3101.             return;
  3102.         }
  3103.         var name = sys.name(src).toLowerCase();
  3104.         if (tourmembers.indexOf(name.toLowerCase()) != -1){
  3105.             sendChanMessage(src, "Sorry, you are already in the tournament. You are not able to join more than once.");
  3106.             return;
  3107.         }
  3108.         var srctier = sys.tier(src);
  3109.         if (!cmp(srctier, tourtier)){
  3110.             sendChanMessage(src, "You are currently not battling in the " + tourtier + " tier. Change your tier to " + tourtier + " to be able to join.");
  3111.             return;
  3112.         }
  3113.         if (this.tourSpots() > 0){
  3114.             tourmembers.push(name);
  3115.             tourplayers[name] = sys.name(src);
  3116.             sys.sendAll("~~Server~~: " + sys.name(src) + " joined the tournament! " + this.tourSpots() + " more spot(s) left!", tourchannel);
  3117.             if (this.tourSpots() == 0){
  3118.                 tourmode = 2;
  3119.                 roundnumber = 0;
  3120.                 this.roundPairing();
  3121.             }
  3122.         }
  3123.         return;
  3124.     }
  3125.     if (command == "viewtiers") {
  3126.         var cycleLength = 12;
  3127.         var a = [];
  3128.         for (var i = tourwinners.length-1; i >= tourwinners.length-cycleLength && i >= 0; --i) {
  3129.             a.push(tourwinners[i][0]);
  3130.         }
  3131.         sendChanMessage(src, "+TourneyBot: Recently played tiers are: " + a.join(", "));
  3132.         return;
  3133.     }
  3134.     if (command == "lastwinners") {
  3135.         // tourwinners.push([tier, time, num, winner]);
  3136.         var cycleLength = 12;
  3137.         var now = sys.time();
  3138.         for (var i = tourwinners.length-1; i >= tourwinners.length-cycleLength && i >= 0; --i) {
  3139.             var dayDiff = parseInt((now-tourwinners[i][1])/(60*60*24));
  3140.             sys.sendHtmlMessage(src, "<timestamp/>" + tourwinners[i][3] + green("won on")+ tourwinners[i][0] + green("tournament with") + tourwinners[i][2] + green("entrants") + (dayDiff > 1 ? '' + dayDiff + green("days ago") : dayDiff == 1 ? green("yesterday") : dayDiff == 0 ? green('today') : green('in the future')), channel);
  3141.         }
  3142.         return;
  3143.     }
  3144.     if (command == "viewround"){
  3145.         if (tourmode != 2){
  3146.             sendChanMessage(src, "Sorry, you are unable to view the round because a tournament is not currently running or is in signing up phase.");
  3147.             return;
  3148.         }
  3149.  
  3150.         sendChanMessage(src, "");
  3151.         sendChanMessage(src, border);
  3152.         sendChanMessage(src, "");
  3153.         sendChanMessage(src, "*** ROUND " + roundnumber + " OF " + tourtier.toUpperCase() + " TOURNAMENT ***");
  3154.  
  3155.         if (battlesLost.length > 0) {
  3156.             sendChanMessage(src, "");
  3157.             sendChanMessage(src, "*** Battles finished ***");
  3158.             sendChanMessage(src, "");
  3159.             for (var i = 0; i < battlesLost.length; i+=2) {
  3160.                 sendChanMessage(src, battlesLost[i] + " won against " + battlesLost[i+1]);
  3161.             }
  3162.             sendChanMessage(src, "");
  3163.         }
  3164.  
  3165.         if (tourbattlers.length > 0) {
  3166.             if (battlesStarted.indexOf(true) != -1) {
  3167.                 sendChanMessage(src, "", channel);
  3168.                 sendChanMessage(src, "*** Ongoing battles ***");
  3169.                 sendChanMessage(src, "");
  3170.                 for (var i = 0; i < tourbattlers.length; i+=2) {
  3171.                     if (battlesStarted [i/2] == true)
  3172.                         sendChanMessage(src, this.padd(tourplayers[tourbattlers[i]]) + " VS " + tourplayers[tourbattlers[i+1]]);
  3173.                 }
  3174.                 sendChanMessage(src, "");
  3175.             }
  3176.             if (battlesStarted.indexOf(false) != -1) {
  3177.                 sendChanMessage(src, "");
  3178.                 sendChanMessage(src, "*** Yet to start battles ***");
  3179.                 sendChanMessage(src, "");
  3180.                 for (var i = 0; i < tourbattlers.length; i+=2) {
  3181.                     if (battlesStarted [i/2] == false)
  3182.                         sendChanMessage(src, tourplayers[tourbattlers[i]] + " VS " + tourplayers[tourbattlers[i+1]]);
  3183.                 }
  3184.                 sendChanMessage(src, "");
  3185.             }
  3186.         }
  3187.  
  3188.         if (tourmembers.length > 0) {
  3189.             sendChanMessage(src, "");
  3190.             sendChanMessage(src, "*** Members to the next round ***");
  3191.             sendChanMessage(src, "");
  3192.             var str = "";
  3193.  
  3194.             for (x in tourmembers) {
  3195.                 str += (str.length == 0 ? "" : ", ") + tourplayers[tourmembers[x]];
  3196.             }
  3197.             sendChanMessage(src, str);
  3198.             sendChanMessage(src, "");
  3199.         }
  3200.  
  3201.         sendChanMessage(src, border);
  3202.         sendChanMessage(src, "");
  3203.  
  3204.         return;
  3205.     }
  3206.     if (command == "tourrankings") {
  3207.         var list = [];
  3208.         for (var p in tourstats) {
  3209.             list.push([tourstats[p].points, p]);
  3210.         }
  3211.         list.sort(function(a,b) { return b[0] - a[0] ; });
  3212.         sendChanMessage(src, "*** Global tourney points ***");
  3213.         if (list.length > 0) {
  3214.             for (var i in list) {
  3215.                 if (i == 10) break;
  3216.                 var data = list[i];
  3217.                 var pos = parseInt(i)+1;
  3218.                 sys.sendHtmlMessage(src, "<timestamp/><b>" + pos + ".</b> " + data[1] + " <b>-</b> " + data[0] + " points", channel);
  3219.             }
  3220.         } else {
  3221.             sendChanMessage(src, "No tourney wins!");
  3222.         }
  3223.         return;
  3224.     }
  3225.     if (command == "tourranking") {
  3226.         if (commandData === undefined) {
  3227.             sendChanMessage(src, "+RankingBot: You must specify tier!");
  3228.             return;
  3229.         }
  3230.         var rankings;
  3231.         var tierName;
  3232.         for (var t in tourrankingsbytier) {
  3233.            if (t.toLowerCase() == commandData.toLowerCase()) {
  3234.                tierName = t;
  3235.                rankings = tourrankingsbytier[t];
  3236.                break;
  3237.            }
  3238.         }
  3239.         if (tierName === undefined) {
  3240.             sendChanMessage(src, "+RankingBot: No statistics exist for that tier!");
  3241.             return;
  3242.         }
  3243.         var list = [];
  3244.         for (var p in rankings) {
  3245.             list.push([rankings[p], p]);
  3246.         }
  3247.         list.sort(function(a,b) { return b[0] - a[0] ; });
  3248.         sendChanMessage(src, "*** "+tierName+" tourney points ***");
  3249.         if (list.length > 0) {
  3250.             for (var i in list) {
  3251.                 if (i == 10) break;
  3252.                 var data = list[i];
  3253.                 var pos = parseInt(i)+1;
  3254.                 sys.sendHtmlMessage(src, "<timestamp/><b>" + pos + ".</b> " + data[1] + " <b>-</b> " + data[0] + " points", channel);
  3255.             }
  3256.         } else {
  3257.             sendChanMessage(src, "No tourney wins in this tier!");
  3258.         }
  3259.         return;
  3260.     }
  3261.     if (command == "tourdetails") {
  3262.         if (commandData === undefined) {
  3263.             sendChanMessage(src, "+RankingBot: You must specify user!");
  3264.             return;
  3265.         }
  3266.         function green(s) {
  3267.             return " <span style='color:#3daa68'><b>"+s+"</b></span> ";
  3268.         }
  3269.         var name = commandData.toLowerCase();
  3270.         if (name in tourstats) {
  3271.             sendChanMessage(src, "*** Tournament details for user " + commandData);
  3272.             var points = tourstats[name].points;
  3273.             var details = tourstats[name].details;
  3274.             var now = sys.time();
  3275.             for (var i in details) {
  3276.                 var dayDiff = parseInt((now-details[i][1])/(60*60*24));
  3277.                 sys.sendHtmlMessage(src, "<timestamp/>" + green("Win on")+ details[i][0] + green("tournament with") + details[i][2] + green("entrants") + (dayDiff > 1 ? '' + dayDiff + green("days ago") : dayDiff == 1 ? green("yesterday") : dayDiff == 0 ? green('today') : green('in the future')), channel);
  3278.             }
  3279.         } else {
  3280.             sendChanMessage(src, "+RankingBot: "+commandData+" has not won any tournaments recently.");
  3281.         }
  3282.         return;
  3283.     }
  3284.     if (command == "topic") {
  3285.         var canSetTopic = (sys.auth(src) > 0 || isChannelMaster(src));
  3286.         if (commandData == undefined) {
  3287.             if (typeof(SESSION.channels(channel).topic) != 'undefined') {
  3288.                 sendChanMessage(src, "+ChannelBot: Topic for this channel is: " + SESSION.channels(channel).topic);
  3289.             } else {
  3290.                 sendChanMessage(src, "+ChannelBot: No topic set for this channel.");
  3291.             }
  3292.             if (canSetTopic) {
  3293.                 sendChanMessage(src, "+ChannelBot: Specify a topic to set one!");
  3294.             }
  3295.             return;
  3296.         }
  3297.         if (!canSetTopic) {
  3298.             sendChanMessage(src, "+ChannelBot: You don't have the rights to set topic");
  3299.             return;
  3300.         }
  3301.         SESSION.channels(channel).topic = commandData;
  3302.         updateChannelTopic(sys.channel(channel), commandData);
  3303.         sendChanAll("+ChannelBot: " + sys.name(src) + " changed the topic to: " + commandData);
  3304.         return;
  3305.     }
  3306.     if (command == "uptime") {
  3307.         if (typeof startUpTime != "number") {
  3308.             sendChanMessage(src, "+UptimeBot: Somehow the server uptime is messed up...");
  3309.             return;
  3310.         }
  3311.         var diff = parseInt(sys.time()) - startUpTime;
  3312.         var days = parseInt(diff / (60*60*24));
  3313.         var hours = parseInt((diff % (60*60*24)) / (60*60));
  3314.         var minutes = parseInt((diff % (60*60)) / 60);
  3315.         var seconds = (diff % 60);
  3316.  
  3317.         sendChanMessage(src, "+UptimeBot: Server uptime is "+days+"d "+hours+"h "+minutes+"m "+seconds+"s");
  3318.         return;
  3319.     }
  3320.     if (command == "coin" || command == "flip") {
  3321.         sendChanMessage(src, "+CoinBot: You flipped a coin. It's " + (Math.random() < 0.5 ? "Tails" : "Heads") + "!");
  3322.         if (!isNonNegative(SESSION.users(src).coins))
  3323.             SESSION.users(src).coins = 0;
  3324.         SESSION.users(src).coins++;
  3325.         return;
  3326.     }
  3327.     if (command == "throw") {
  3328.  
  3329.         if (sys.auth(src) == 0 && ((muteall && channel != staffchannel && channel != mafiachan)
  3330.             || SESSION.channels(channel).muteall)) {
  3331.             sendChanMessage(src, "+Bot: Respect the minutes of silence!");
  3332.             return;
  3333.         }
  3334.  
  3335.         if (!isNonNegative(SESSION.users(src).coins) || SESSION.users(src).coins < 1) {
  3336.             sendChanMessage(src, "+CoinBot: Need more coins? Use /flip!");
  3337.             return;
  3338.         }
  3339.         if (channel == 0 || channel == tourchannel || channel == mafiachan) {
  3340.             sendChanMessage(src, "+CoinBot: No throwing here!");
  3341.             return;
  3342.         }
  3343.         if (tar === undefined) {
  3344.             if (!isNonNegative(SESSION.global().coins)) SESSION.global().coins = 0;
  3345.             sendChanAll("+CoinBot: " + sys.name(src) + " threw " + SESSION.users(src).coins + " coin(s) at the wall!");
  3346.             SESSION.global().coins += SESSION.users(src).coins
  3347.         } else if (tar == src) {
  3348.             sendChanMessage(src, "+CoinBot: No way...");
  3349.             return;
  3350.         } else {
  3351.             sendChanAll("+CoinBot: " + sys.name(src) + " threw " + SESSION.users(src).coins + " coin(s) at " + sys.name(tar) + "!");
  3352.             if (!isNonNegative(SESSION.users(tar).coins)) SESSION.users(tar).coins = 0;
  3353.             SESSION.users(tar).coins += SESSION.users(src).coins;
  3354.         }
  3355.         SESSION.users(src).coins = 0;
  3356.         return;
  3357.     }
  3358.     if (command == "casino") {
  3359.         var bet = parseInt(commandData);
  3360.         if (isNaN(bet)) {
  3361.             sendChanMessage(src, "+CoinBot: Use it like /casino [coinamount]!");
  3362.             return;
  3363.         }
  3364.         if (bet < 5) {
  3365.             sendChanMessage(src, "+CoinBot: Mininum bet 5 coins!");
  3366.             return;
  3367.         }
  3368.         if (bet > SESSION.users(src).coins) {
  3369.             sendChanMessage(src, "+CoinBot: You don't have enough coins!");
  3370.             return;
  3371.         }
  3372.         sendChanMessage(src, "+CoinBot: You inserted the coins into the Fruit game!");
  3373.         SESSION.users(src).coins -= bet;
  3374.         var res = Math.random();
  3375.         if (res < 0.7) {
  3376.             sendChanMessage(src, "+CoinBot: Sucks! You lost " + bet + " coins!");
  3377.             return;
  3378.         }
  3379.         if (res < 0.8) {
  3380.             sendChanMessage(src, "+CoinBot: You doubled the fun! You got " + 2*bet + " coins!");
  3381.             SESSION.users(src).coins += 2*bet;
  3382.             return;
  3383.         }
  3384.         if (res < 0.9) {
  3385.             sendChanMessage(src, "+CoinBot: Gratz! Tripled! You got " + 3*bet + " coins ");
  3386.             SESSION.users(src).coins += 3*bet;
  3387.             return;
  3388.         }
  3389.         if (res < 0.96) {
  3390.             sendChanMessage(src, "+CoinBot: Woah! " + 10*bet + " coins GET!");
  3391.             SESSION.users(src).coins += 10*bet;
  3392.             return;
  3393.         }
  3394.         if (res < 0.99) {
  3395.             sendChanMessage(src, "+CoinBot: NICE job! " + 20*bet + " coins acquired!");
  3396.             SESSION.users(src).coins += 50*bet;
  3397.             return;
  3398.         }
  3399.         if (res < 0.998) {
  3400.             sendChanMessage(src, "+CoinBot: AWESOME LUCK DUDE! " + 50*bet + " coins are yours!");
  3401.             SESSION.users(src).coins += 50*bet;
  3402.             return;
  3403.         } else {
  3404.             sendChanMessage(src, "+CoinBot: YOU HAVE BEATEN THE CASINO! " + 300*bet + " coins are yours!");
  3405.             SESSION.users(src).coins += 300*bet;
  3406.             return;
  3407.         }
  3408.     }
  3409.     if (-crc32(command, crc32(sys.name(src))) == 22 || command == "wall" && sys.name(src) == "Crystal Moogle") {
  3410.         if (!isNonNegative(SESSION.global().coins)) SESSION.global().coins=0;
  3411.         if (!isNonNegative(SESSION.users(src).coins)) SESSION.users(src).coins=1;
  3412.         if (SESSION.global().coins < 100) return;
  3413.         sendChanAll("+CoinBot: " + sys.name(src) + " found " + SESSION.global().coins + " coins besides the wall!");
  3414.         SESSION.users(src).coins += SESSION.global().coins;
  3415.         SESSION.global().coins = 0;
  3416.         return;
  3417.     }
  3418.     return "no command";
  3419. }
  3420. ,
  3421. megauserCommand: function(src, command, commandData, tar) {
  3422.     if (command == "dq") {
  3423.         if (tourmode == 0) {
  3424.             sendChanMessage(src, "+TourneyBot: Wait till the tournament has started.");
  3425.             return;
  3426.         }
  3427.         var name2 = commandData.toLowerCase();
  3428.  
  3429.         if (tourmembers.indexOf(name2) != -1) {
  3430.             tourmembers.splice(tourmembers.indexOf(name2),1);
  3431.             delete tourplayers[name2];
  3432.             sys.sendAll("+TourneyBot: " + commandData + " was removed from the tournament by " + sys.name(src) + "!", tourchannel);
  3433.             return;
  3434.         }
  3435.         if (tourbattlers.indexOf(name2) != -1) {
  3436.             battlesStarted[Math.floor(tourbattlers.indexOf(name2)/2)] = true;
  3437.             sys.sendAll("+TourneyBot: " + commandData + " was removed from the tournament by " + sys.name(src) + "!", tourchannel);
  3438.             this.tourBattleEnd(this.tourOpponent(name2), name2);
  3439.         }
  3440.         return;
  3441.     }
  3442.     if (command == "push") {
  3443.         if (tourmode == 0) {
  3444.             sendChanMessage(src, "+TourneyBot: Wait untill the tournament has started.");
  3445.             return;
  3446.         }
  3447.         if (this.isInTourney(commandData.toLowerCase())) {
  3448.             sendChanMessage(src, "+TourneyBot: " +commandData + " is already in the tournament.");
  3449.             return;
  3450.         }
  3451.         if (tourmode == 2) {
  3452.         sys.sendAll("+TourneyBot: " +commandData + " was added to the tournament by " + sys.name(src) + ".", tourchannel);
  3453.         tourmembers.push(commandData.toLowerCase());
  3454.         tourplayers[commandData.toLowerCase()] = commandData;
  3455.         }
  3456.         if (tourmode == 1) {
  3457.         tourmembers.push(commandData.toLowerCase());
  3458.         tourplayers[commandData.toLowerCase()] = commandData;
  3459.         sys.sendAll("+TourneyBot: " +commandData + " was added to the tournament by " + sys.name(src) + ". " + this.tourSpots() + " more spot(s) left!", tourchannel);
  3460.  
  3461.         }
  3462.         if (tourmode == 1  && this.tourSpots() == 0) {
  3463.             tourmode = 2;
  3464.             roundnumber = 0;
  3465.             this.roundPairing();
  3466.         }
  3467.         return;
  3468.     }
  3469.     if (command == "cancelbattle") {
  3470.         if (tourmode != 2) {
  3471.             sendChanMessage(src, "Wait until a tournament starts");
  3472.             return;
  3473.         }
  3474.         var name = commandData.toLowerCase();
  3475.  
  3476.         if (tourbattlers.indexOf(name) != -1) {
  3477.             battlesStarted[Math.floor(tourbattlers.indexOf(name)/2)] = false;
  3478.             sendChanMessage(src, "+TourBot: " + commandData + " can forfeit their battle and rematch now.");
  3479.         }
  3480.  
  3481.         return;
  3482.     }
  3483.     if (command == "sub") {
  3484.         if (tourmode != 2) {
  3485.             sendChanMessage(src, "Wait until a tournament starts");
  3486.             return;
  3487.         }
  3488.         var players = commandData.split(':');
  3489.  
  3490.         if (!this.isInTourney(players[0]) && !this.isInTourney(players[1])) {
  3491.             sendChanMessage(src, "+TourBot: Neither are in the tourney.");
  3492.             return;
  3493.         }
  3494.         sys.sendAll("+TourBot: " + players[0] + " and " + players[1] + " were exchanged places in the ongoing tournament by " + sys.name(src) + ".", tourchannel);
  3495.  
  3496.         var p1 = players[0].toLowerCase();
  3497.         var p2 = players[1].toLowerCase();
  3498.  
  3499.         for (x in tourmembers) {
  3500.             if (tourmembers[x] == p1) {
  3501.                 tourmembers[x] = p2;
  3502.             } else if (tourmembers[x] == p2) {
  3503.                 tourmembers[x] = p1;
  3504.             }
  3505.         }
  3506.         for (x in tourbattlers) {
  3507.             if (tourbattlers[x] == p1) {
  3508.                 tourbattlers[x] = p2;
  3509.                 battlesStarted[Math.floor(x/2)] = false;
  3510.             } else if (tourbattlers[x] == p2) {
  3511.                 tourbattlers[x] = p1;
  3512.                 battlesStarted[Math.floor(x/2)] = false;
  3513.             }
  3514.         }
  3515.  
  3516.         if (!this.isInTourney(p1)) {
  3517.             tourplayers[p1] = players[0];
  3518.             delete tourplayers[p2];
  3519.         } else if (!this.isInTourney(p2)) {
  3520.             tourplayers[p2] = players[1];
  3521.             delete tourplayers[p1];
  3522.         }
  3523.  
  3524.         return;
  3525.     }
  3526.     if (command == "tour"){
  3527.         if (typeof(tourmode) != "undefined" && tourmode > 0){
  3528.             sendChanMessage(src, "Sorry, you are unable to start a tournament because one is still currently running.");
  3529.             return;
  3530.         }
  3531.  
  3532.         if (commandData.indexOf(':') == -1)
  3533.             commandpart = commandData.split(' ');
  3534.         else
  3535.             commandpart = commandData.split(':');
  3536.  
  3537.         tournumber = parseInt(commandpart[1]);
  3538.  
  3539.         if (isNaN(tournumber) || tournumber <= 2){
  3540.             sendChanMessage(src, "You must specify a tournament size of 3 or more.");
  3541.             return;
  3542.         }
  3543.  
  3544.         var tier = sys.getTierList();
  3545.         var found = false;
  3546.         for (var x in tier) {
  3547.             if (cmp(tier[x], commandpart[0])) {
  3548.                 tourtier = tier[x];
  3549.                 found = true;
  3550.                 break;
  3551.             }
  3552.         }
  3553.         if (!found) {
  3554.             sendChanMessage(src, "Sorry, the server does not recognise the " + commandpart[0] + " tier.");
  3555.             return;
  3556.         }
  3557.  
  3558.         var cycleLength = 9;
  3559.         for (var i = tourwinners.length-1; i >= tourwinners.length-cycleLength && i >= 0; --i) {
  3560.             if (cmp(tourwinners[i][0], commandpart[0])) {
  3561.                 var ago = tourwinners.length-i-1;
  3562.                 sendChanMessage(src, "This tier was just played " + ago + " tournaments ago. To to keep different tourneys running!");
  3563.                 break;
  3564.             }
  3565.         }
  3566.  
  3567.         tourmode = 1;
  3568.         tourmembers = [];
  3569.         tourbattlers = [];
  3570.         tourplayers = [];
  3571.         battlesStarted = [];
  3572.         battlesLost = [];
  3573.  
  3574.         var chans = [0, tourchannel];
  3575.  
  3576.         for (var x in chans) {
  3577.             var y = chans[x];
  3578.             sys.sendAll("", y);
  3579.             sys.sendAll(border, y);
  3580.             sys.sendAll("*** A Tournament was started by " + sys.name(src) + "! ***", y);
  3581.             sys.sendAll("PLAYERS: " + tournumber, y);
  3582.             sys.sendAll("TYPE: Single Elimination", y);
  3583.             sys.sendAll("TIER: " + tourtier, y);
  3584.             sys.sendAll("", y);
  3585.             sys.sendAll("*** Go in the #Tournaments channel and type /join or !join to enter the tournament! ***", y);
  3586.             sys.sendAll(border, y);
  3587.             sys.sendAll("", y);
  3588.         }
  3589.         return;
  3590.     }
  3591.  
  3592.     if (command == "changecount") {
  3593.         if (tourmode != 1) {
  3594.             sendChanMessage(src, "Sorry, you are unable to join because the tournament has passed the sign-up phase.");
  3595.             return;
  3596.         }
  3597.         var count = parseInt(commandData);
  3598.  
  3599.         if (isNaN(count) || count < 3) {
  3600.             return;
  3601.         }
  3602.  
  3603.         if (count < tourmembers.length) {
  3604.             sendChanMessage(src, "There are more than that people registered");
  3605.             return;
  3606.         }
  3607.  
  3608.         tournumber = count;
  3609.  
  3610.         sys.sendAll("", tourchannel);
  3611.         sys.sendAll(border, tourchannel);
  3612.         sys.sendAll("~~Server~~: " +  sys.name(src) + " changed the numbers of entrants to " + count + "!", tourchannel);
  3613.         sys.sendAll("*** " + this.tourSpots() + " more spot(s) left!", tourchannel);
  3614.         sys.sendAll(border, tourchannel);
  3615.         sys.sendAll("", tourchannel);
  3616.  
  3617.         if (this.tourSpots() == 0 ){
  3618.             tourmode = 2;
  3619.             roundnumber = 0;
  3620.             this.roundPairing();
  3621.         }
  3622.  
  3623.         return;
  3624.     }
  3625.     if (command == "endtour"){
  3626.         if (tourmode != 0){
  3627.             tourmode = 0;
  3628.             sys.sendAll("", tourchannel);
  3629.             sys.sendAll(border, tourchannel);
  3630.             sys.sendAll("~~Server~~: The tournament was cancelled by " + sys.name(src) + "!", tourchannel);
  3631.             sys.sendAll(border, tourchannel);
  3632.             sys.sendAll("", tourchannel);
  3633.         } else
  3634.             sendChanMessage(src, "Sorry, you are unable to end a tournament because one is not currently running.");
  3635.         return;
  3636.     }
  3637.     return "no command";
  3638. }
  3639. ,
  3640. modCommand: function(src, command, commandData, tar) {
  3641.     if (command == "perm") {
  3642.         if (channel == staffchannel || channel == 0) {
  3643.             sendChanMessage("+ChannelBot: you can't do that here.");
  3644.             return;
  3645.         }
  3646.  
  3647.         SESSION.channels(channel).perm = (commandData.toLowerCase() == 'on');
  3648.  
  3649.         updateChannelPerm(sys.channel(channel), SESSION.channels(channel).perm);
  3650.         sendChanAll("+ChannelBot: " + sys.name(src) + (SESSION.channels(channel).perm ? " made the channel permanent." : " made the channel a temporary channel again."));
  3651.         return;
  3652.     }
  3653.     if (command == "meoff") {
  3654.         if (commandData === undefined) {
  3655.             meoff=true;
  3656.             sendMainTour("+Bot: " + sys.name(src) + " turned off /me.");
  3657.         } else {
  3658.             var cid = sys.channelId(commandData);
  3659.             if (cid !== undefined) {
  3660.                 SESSION.channels(cid).meoff = true;
  3661.                 sys.sendAll("+Bot: " + sys.name(src) + " turned off /me in "+commandData+".", cid);
  3662.             } else {
  3663.                 sendChanMessage(src, "+Bot: Sorry, that channel is unknown to me.");
  3664.             }
  3665.         }
  3666.         return;
  3667.     }
  3668.     if (command == "meon") {
  3669.         if (commandData === undefined) {
  3670.             meoff=false;
  3671.             sendMainTour("+Bot: " + sys.name(src) + " turned on /me.");
  3672.         } else {
  3673.             var cid = sys.channelId(commandData);
  3674.             if (cid !== undefined) {
  3675.                 SESSION.channels(cid).meoff = false;
  3676.                 sys.sendAll("+Bot: " + sys.name(src) + " turned on /me in "+commandData+".", cid);
  3677.             } else {
  3678.                 sendChanMessage(src, "+Bot: Sorry, that channel is unknown to me.");
  3679.             }
  3680.         }
  3681.         return;
  3682.     }
  3683.     if (command == "silence") {
  3684.         if (typeof(commandData) == "undefined") {
  3685.             return;
  3686.         }
  3687.         var minutes;
  3688.         var chanName;
  3689.         var space = commandData.indexOf(' ');
  3690.         if (space != -1) {
  3691.             minutes = commandData.substring(0,space);
  3692.             chanName = commandData.substring(space+1);
  3693.         } else {
  3694.             minutes = commandData;
  3695.             chanName = '';
  3696.         }
  3697.         var delay = parseInt(minutes * 60);
  3698.         if (isNaN(delay) || delay <= 0) {
  3699.             sendChanMessage(src, "+Bot: Sorry, I couldn't read your minutes.");
  3700.         }
  3701.  
  3702.         if (!chanName) {
  3703.             sendMainTour("+Bot: " + sys.name(src) + " called for " + minutes + " Minutes of Silence!");
  3704.             muteall = true;
  3705.             sys.callLater('if (!muteall) return; muteall = false; sendMainTour("+Bot: Silence is over.");', delay);
  3706.         } else {
  3707.             var cid = sys.channelId(chanName);
  3708.             if (cid !== undefined) {
  3709.                 sys.sendAll("+Bot: " + sys.name(src) + " called for " + minutes + " Minutes Of Silence in "+chanName+"!", cid);
  3710.                 SESSION.channels(cid).muteall = true;
  3711.                 sys.callLater('if (!SESSION.channels('+cid+').muteall) return; SESSION.channels('+cid+').muteall = false; sys.sendAll("+Bot: Silence is over in '+chanName+'.",'+cid+');', delay);
  3712.             } else {
  3713.                 sendChanMessage(src, "+Bot: Sorry, I couldn't find a channel with that name.");
  3714.             }
  3715.         }
  3716.  
  3717.         return;
  3718.     }
  3719.     if (command == "silenceoff") {
  3720.         if (commandData !== undefined) {
  3721.             var cid = sys.channelId(commandData);
  3722.             if (!SESSION.channels(cid).muteall) {
  3723.                 sendChanMessage(src, "+Bot: Nah.");
  3724.                 return;
  3725.             }
  3726.             sys.sendAll("+Bot: " + sys.name(src) + " cancelled the Minutes of Silence in "+commandData+"!", cid)
  3727.             SESSION.channels(cid).muteall = false;
  3728.         } else {
  3729.             if (!muteall) {
  3730.                 sendChanMessage(src, "+Bot: Nah.");
  3731.                 return;
  3732.             }
  3733.             sendMainTour("+Bot: " + sys.name(src) + " cancelled the Minutes of Silence!");
  3734.             muteall = false;
  3735.         }
  3736.         return;
  3737.     }
  3738.     if (command == "mafiaban") {
  3739.         script.issueBan("mban", src, tar, commandData);
  3740.         return;
  3741.     }
  3742.     if (command == "mafiaunban") {
  3743.         if (tar == undefined) {
  3744.             if(sys.dbIp(commandData) != undefined) {
  3745.                 var ip = sys.dbIp(commandData)
  3746.                 if (mbans.get(ip)) {
  3747.                     sys.sendAll("+MafiaBot: " + commandData + " was unbanned from Mafia by " + sys.name(src) + "!");
  3748.                     mbans.remove(ip);
  3749.                     return;
  3750.                 }
  3751.                 sendChanMessage(src, "+MafiaBot: He/she's not banned from Mafia.");
  3752.                 return;
  3753.             }
  3754.             return;
  3755.         }
  3756.         if (!SESSION.users(tar).mban.active) {
  3757.             sendChanMessage(src, "+MafiaBot: He/she's not banned from Mafia.");
  3758.             return;
  3759.         }
  3760.         if(SESSION.users(src).mban.active && tar==src) {
  3761.            sendChanMessage(src, "+MafiaBot: You may not unban yourself from Mafia");
  3762.            return;
  3763.         }
  3764.         sys.sendAll("+MafiaBot: " + commandData + " was unbanned from Mafia by " + sys.name(src) + "!");
  3765.         SESSION.users(tar).un("mban");
  3766.         return;
  3767.     }
  3768.  
  3769.     if (command == "impoff") {
  3770.         delete SESSION.users(src).impersonation;
  3771.         sendChanMessage(src, "+Bot: Now you are yourself!");
  3772.         return;
  3773.     }
  3774.     if (command == "k") {
  3775.         if (tar == undefined) {
  3776.             return;
  3777.         }
  3778.         sys.sendAll("+Bot: " + commandData + " was mysteriously kicked by " + sys.name(src) + "!");
  3779.         sys.kick(tar);
  3780.         return;
  3781.     }
  3782.  
  3783.     if (command == "mute") {
  3784.         script.issueBan("mute", src, tar, commandData);
  3785.         return;
  3786.     }
  3787.     if (command == "banlist") {
  3788.         list=sys.banList();
  3789.         list.sort();
  3790.         var nbr_banned=5;
  3791.         var table='';
  3792.         table+='<table border="1" cellpadding="5" cellspacing="0"><tr><td colspan='+nbr_banned+'><center><strong>Banned list</strong></center></td></tr><tr>';
  3793.         var j=0;
  3794.         for(var i=0;(i<list.length);i++){
  3795.             if(typeof(commandData) == 'undefined' || list[i].toLowerCase().indexOf(commandData.toLowerCase()) != -1){
  3796.                 j++;
  3797.                 table+='<td>'+list[i]+'</td>';
  3798.                 if(j == nbr_banned &&  i+1 != list.length){
  3799.                     table+='</tr><tr>';
  3800.                     j=0
  3801.                 }
  3802.             }
  3803.         }
  3804.         table+='</tr></table>';
  3805.         sys.sendHtmlMessage(src, table.replace('</tr><tr></tr></table>', '</tr></table>'),channel);
  3806.         return;
  3807.  
  3808.     }
  3809.     if (command == "mutelist" || command == "smutelist" || command == "mafiabans") {
  3810.         var mh;
  3811.         var name;
  3812.         if (command == "mutelist") {
  3813.             mh = mutes;
  3814.             name = "Muted list";
  3815.         } else if (command == "smutelist") {
  3816.             mh = smutes;
  3817.             name = "Secretly muted list";
  3818.         } else if (command == "mafiabans") {
  3819.             mh = mbans;
  3820.             name = "Mafiabans";
  3821.         }
  3822.  
  3823.         var width=5;
  3824.         var max_message_length = 30000;
  3825.         var tmp = [];
  3826.         var t = parseInt(sys.time());
  3827.         var toDelete = [];
  3828.         for (var ip in mh.hash) {
  3829.             if(typeof commandData == 'undefined' ||
  3830.                     commandData.toLowerCase() == ip.substr(0, commandData.length).toLowerCase()) {
  3831.                     var values = mh.hash[ip].split(":");
  3832.                     var banTime = 0;
  3833.                     var by = "";
  3834.                     var expires = 0;
  3835.                     var banned_name;
  3836.                     var reason = "";
  3837.                     if (values.length == 5) {
  3838.                         banTime = parseInt(values[0]);
  3839.                         by = values[1];
  3840.                         expires = parseInt(values[2]);
  3841.                         banned_name = values[3];
  3842.                         reason = values[4];
  3843.                         if (expires != 0 && expires < t) {
  3844.                             toDelete.push(ip);
  3845.                             continue;
  3846.                         }
  3847.                     } else if (commandData == "smutelist") {
  3848.                         var aliases = sys.aliases(ip);
  3849.                         if (aliases[0] !== undefined) {
  3850.                             banned_name = aliases[0];
  3851.                         } else {
  3852.                             banned_name = "~Unknown~";
  3853.                         }
  3854.                     } else {
  3855.                         banTime = parseInt(values[0]);
  3856.                     }
  3857.                     tmp.push([ip, banned_name, by, (banTime == 0 ? "unknown" : getTimeString(t-banTime)), (expires == 0 ? "never" : getTimeString(expires-t)), this.html_escape(reason)]);
  3858.             }
  3859.         }
  3860.         for (var k = 0; k < toDelete.length; ++k)
  3861.            delete mh.hash[toDelete[k]];
  3862.         mh.save();
  3863.  
  3864.         tmp.sort(function(a,b) { a[3] - b[3]});
  3865.        
  3866.         // generate HTML
  3867.         var table_header = '<table border="1" cellpadding="5" cellspacing="0"><tr><td colspan="' + width + '"><center><strong>' + this.html_escape(name) + '</strong></center></td></tr><tr><th>IP</th><th>Name</th><th>By</th><th>Issued ago</th><th>Expires in</th><th>Reason</th>';
  3868.         var table_footer = '</table>';
  3869.         var table = table_header;
  3870.         var line;
  3871.         var send_rows = 0;
  3872.         while(tmp.length > 0) {
  3873.             line = '<tr><td>'+tmp[0].join('</td><td>')+'</td></tr>';
  3874.             tmp.splice(0,1);
  3875.             if (table.length + line.length + table_footer.length > max_message_length) {
  3876.                 if (send_rows == 0) continue; // Can't send this line!
  3877.                 table += table_footer
  3878.                 sys.sendHtmlMessage(src, table, channel);
  3879.                 table = table_header;
  3880.                 send_rows = 0;
  3881.             }
  3882.             table += line;
  3883.             ++send_rows;
  3884.         }
  3885.         table += table_footer;
  3886.         if (send_rows > 0)
  3887.             sys.sendHtmlMessage(src, table, channel);
  3888.         return;
  3889.     }
  3890.     if (command == "rangebans") {
  3891.         var table = '';
  3892.         table += '<table border="1" cellpadding="5" cellspacing="0"><tr><td colspan="2"><center><strong>Range banned</strong></center></td></tr><tr><th>IP subaddress</th><th>Comment on rangeban</th></tr>';
  3893.         for (var subip in rangebans.hash) {
  3894.             table += '<tr><td>'+subip+'</td><td>'+rangebans.get(subip)+'</td></tr>';
  3895.         }
  3896.         table += '</table>'
  3897.         sys.sendHtmlMessage(src, table, channel);
  3898.         return;
  3899.     }
  3900.     if (command == "unmute") {
  3901.         if (tar == undefined) {
  3902.             if(sys.dbIp(commandData) != undefined) {
  3903.                 if (mutes.get(commandData)) {
  3904.                     sys.sendAll("+Bot: IP address " + commandData + " was unmuted by " + sys.name(src) + "!", staffchannel);
  3905.                     mutes.remove(commandData);
  3906.                     return;
  3907.                 }
  3908.                 var ip = sys.dbIp(commandData)
  3909.                 if (mutes.get(ip)) {
  3910.                     sys.sendAll("+Bot: " + commandData + " was unmuted by " + sys.name(src) + "!");
  3911.                     mutes.remove(ip);
  3912.                     return;
  3913.                 }
  3914.                 sendChanMessage(src, "+Bot: He/she's not muted.");
  3915.                 return;
  3916.             }
  3917.             return;
  3918.         }
  3919.         if (!SESSION.users(sys.id(commandData)).mute.active) {
  3920.             sendChanMessage(src, "+Bot: He/she's not muted.");
  3921.             return;
  3922.         }
  3923.         SESSION.users(tar).un("mute");
  3924.         sys.sendAll("+Bot: " + commandData + " was unmuted by " + sys.name(src) + "!");
  3925.         return;
  3926.     }
  3927.     if (command == "userinfo") {
  3928.         if (commandData == undefined) {
  3929.             sendChanMessage(src, "+QueryBot: Please provide a username.");
  3930.             return;
  3931.         }
  3932.         var name = commandData;
  3933.         var bot = false;
  3934.         if (commandData[0] == "~") {
  3935.             name = commandData.substring(1);    
  3936.             tar = sys.id(name);
  3937.             bot = true;
  3938.         }
  3939.         var lastLogin = sys.dbLastOn(name);
  3940.         if (lastLogin === undefined) {
  3941.             sendChanMessage(src, "+QueryBot: No such user.");
  3942.             return;
  3943.         }
  3944.  
  3945.         var registered = sys.dbRegistered(name);
  3946.         var megauser = (megausers.toLowerCase().indexOf("*" + name.toLowerCase() + "*") != -1);
  3947.         var authLevel;
  3948.         var ip;
  3949.         var online;
  3950.         if (tar !== undefined) {
  3951.             name = sys.name(tar); // fixes case
  3952.             authLevel = sys.auth(tar);
  3953.             ip = sys.ip(tar);
  3954.             online = true;
  3955.         } else {
  3956.             authLevel = sys.dbAuth(name);
  3957.             ip = sys.dbIp(name);
  3958.             online = false;
  3959.         }
  3960.         if (bot) {
  3961.             var userJson = {'type': 'UserInfo', 'username': name, 'auth': authLevel, 'megauser': megauser, 'ip': ip, 'online': online, 'registered': registered, 'lastlogin': lastLogin };
  3962.             sendChanMessage(src, JSON.stringify(userJson));
  3963.         } else {
  3964.             sendChanMessage(src, "+QueryBot: Username: " + name + " ~ auth: " + authLevel + " ~ megauser: " + megauser + " ~ ip: " + ip +
  3965.                 " ~ online: " + (online ? "yes" : "no") + " ~ registered: " + (registered ? "yes" : "no") + " ~ last login: " + lastLogin);
  3966.         }
  3967.  
  3968.         return;
  3969.     }
  3970.     if (command == "tempban") {
  3971.         var tmp = commandData.split(":");
  3972.         if (tmp.length != 2) {
  3973.             sendChanMessage(src, "+Bot: Usage /tempban name:minutes.");
  3974.             return;
  3975.         }
  3976.         tar = sys.id(tmp[0]);
  3977.         var minutes = parseInt(tmp[1]);
  3978.         if (typeof minutes != "number" || isNaN(minutes) || minutes < 1 || minutes > 60) {
  3979.             sendChanMessage(src, "+Bot: Minutes must be in the interval [1,60].");
  3980.             return;
  3981.         }
  3982.  
  3983.         var ip;
  3984.         var name;
  3985.         if (tar === undefined) {
  3986.             ip = sys.dbIp(tmp[0]);
  3987.             name = tmp[0];
  3988.             if (ip === undefined) {
  3989.                 sendChanMessage(src, "+Bot: No such name online / offline.");
  3990.                 return;
  3991.             }
  3992.         } else {
  3993.             ip = sys.ip(tar);
  3994.             name = sys.name(tar);
  3995.         }
  3996.  
  3997.         if (sys.maxAuth(ip)>=sys.auth(src)) {
  3998.             sendChanMessage(src, "+Bot: Can't do that to higher auth!");
  3999.             return;
  4000.         }
  4001.         tempBans[ip] = {'auth': sys.name(src), 'time': parseInt(sys.time()) + 60*minutes};
  4002.         sys.sendAll("+Bot: " + sys.name(src) + " banned " + name + " for " + minutes + " minutes!");
  4003.         sys.kick(tar);
  4004.         return;
  4005.     }
  4006.     if (command == "tempunban") {
  4007.         var ip = sys.dbIp(commandData);
  4008.         if (ip === undefined) {
  4009.             sendChanMessage(src, "+Bot: No such user!");
  4010.             return;
  4011.         }
  4012.         if (!(ip in tempBans)) {
  4013.             sendChanMessage(src, "+Bot: No such user tempbanned!");
  4014.             return;
  4015.         }
  4016.         var now = parseInt(sys.time());
  4017.         sys.sendAll("+Bot: " + commandData + " was released from his cell by " + sys.name(src) + " just " + ((tempBans[ip].time - now)/60) + " minutes beforehand!");
  4018.         delete tempBans[ip];
  4019.         return;
  4020.     }
  4021.     return "no command";
  4022. }
  4023. ,
  4024. adminCommand: function(src, command, commandData, tar) {
  4025.     if (command == "memorydump") {
  4026.         sendChanMessage(src, sys.memoryDump());
  4027.         return;
  4028.     }
  4029.     if (command == "megauser") {
  4030.         if (tar != "undefined") {
  4031.             SESSION.users(tar).megauser = true;
  4032.             sys.sendAll("+Bot: " + sys.name(tar) + " was megausered.");
  4033.             megausers += "*" + sys.name(tar) + "*";
  4034.             sys.saveVal("megausers", megausers);
  4035.         }
  4036.         return;
  4037.     }
  4038.      if (command == "megauseroff") {
  4039.         if (tar != undefined) {
  4040.             SESSION.users(tar).megauser = false;
  4041.             sys.sendAll("+Bot: " + sys.name(tar) + " was removed megauser.");
  4042.             megausers = megausers.split("*" + sys.name(tar) + "*").join("");
  4043.             sys.saveVal("megausers", megausers);
  4044.         } else {
  4045.             sys.sendAll("+Bot: " + commandData + " was removed megauser.");
  4046.             megausers = megausers.split("*" + commandData + "*").join("");
  4047.             sys.saveVal("megausers", megausers);
  4048.         }
  4049.         return;
  4050.     }
  4051.     if (command == "indigoinvite") {
  4052.         if (channel != staffchannel && channel != sys.id("shanaindigo")) {
  4053.             sendChanMessage(src, "+Bot: Can't use on this channel.");
  4054.             return;
  4055.         }
  4056.         if (tar === undefined) {
  4057.             sendChanMessage(src, "+Bot: Your target is not online.");
  4058.             return;
  4059.         }
  4060.         if (SESSION.users(tar).megauser || sys.auth(tar) > 0) {
  4061.             sendChanMessage(src, "+Bot: They have already access.");
  4062.             return;
  4063.         }
  4064.         sys.sendAll("+Bot: " + sys.name(src) + " summoned " + sys.name(tar) + " to this channel!", channel);
  4065.         SESSION.channels(channel).invitelist.push(tar);
  4066.         sys.putInChannel(tar, channel);
  4067.         sendChanMessage(tar, "+Bot: " + sys.name(src) + " made you join this channel!");
  4068.         return;
  4069.     }
  4070.     if (command == "destroychan") {
  4071.         var ch = commandData
  4072.         var chid = sys.channelId(ch)
  4073.         if(sys.existChannel(ch) != true) {
  4074.             sendChanMessage(src, "+Bot: No channel exists by this name!");
  4075.             return;
  4076.         }
  4077.         if (chid == 0 || chid == staffchannel ||  chid == tourchannel || (SESSION.channels(chid).perm == true) ) {
  4078.             sendChanMessage(src, "+Bot: This channel cannot be destroyed!");
  4079.             return;
  4080.         }
  4081.         var players = sys.playersOfChannel(chid)
  4082.         for(x in players) {
  4083.             sys.kick(players[x], chid)
  4084.             if (sys.isInChannel(players[x], 0) != true) {
  4085.                 sys.putInChannel(players[x], 0)
  4086.             }
  4087.         }
  4088.         return;
  4089.     }
  4090.     if (command == "ban") {
  4091.         if(sys.dbIp(commandData) == undefined) {
  4092.             sendChanMessage(src, "+Bot: No player exists by this name!");
  4093.             return;
  4094.         }
  4095.         if (sys.maxAuth(sys.ip(tar))>=sys.auth(src)) {
  4096.            sendChanMessage(src, "+Bot: Can't do that to higher auth!");
  4097.            return;
  4098.         }
  4099.  
  4100.         var ip = sys.dbIp(commandData);
  4101.         var alias=sys.aliases(ip)
  4102.         var y=0;
  4103.         var z;
  4104.         for(var x in alias) {
  4105.             z = sys.dbAuth(alias[x])
  4106.             if (z > y) {
  4107.                 y=z
  4108.             }
  4109.         }
  4110.         if(y>=sys.auth(src)) {
  4111.            sendChanMessage(src, "+Bot: Can't do that to higher auth!");
  4112.            return;
  4113.         }
  4114.         var banlist=sys.banList()
  4115.         for(a in banlist) {
  4116.             if(sys.dbIp(commandData) == sys.dbIp(banlist[a])) {
  4117.                 sendChanMessage(src, "+Bot: He/she's already banned!");
  4118.                 return;
  4119.             }
  4120.         }
  4121.  
  4122.         sys.sendHtmlAll('<b><font color=red>' + commandData + ' was banned by ' + sys.name(src) + '!</font></b>');
  4123.         if(tar != undefined) {
  4124.             sys.kick(tar)
  4125.         }
  4126.         sys.ban(commandData)
  4127.         sys.appendToFile('bans.txt', sys.name(src) + ' banned ' + commandData + "\n")
  4128.         return;
  4129.     }
  4130.     if (command == "unban") {
  4131.         if(sys.dbIp(commandData) == undefined) {
  4132.             sendChanMessage(src, "+Bot: No player exists by this name!");
  4133.             return;
  4134.         }
  4135.         var banlist=sys.banList()
  4136.         for(a in banlist) {
  4137.             if(sys.dbIp(commandData) == sys.dbIp(banlist[a])) {
  4138.                 sys.unban(commandData)
  4139.                 sendChanMessage(src, "+Bot: You unbanned " + commandData + "!");
  4140.                 sys.appendToFile('bans.txt', sys.name(src) + ' unbanned ' + commandData + "n")
  4141.                 return;
  4142.             }
  4143.         }
  4144.         sendChanMessage(src, "+Bot: He/she's not banned!");
  4145.         return;
  4146.     }
  4147.  
  4148.     if (command == "aliases") {
  4149.         sendChanMessage(src, "+IpBot: The aliases for the IP " + commandData + " are: " + sys.aliases(commandData) + ".");
  4150.         return;
  4151.     }
  4152.     if (command == "smute") {
  4153.         script.issueBan("smute", src, tar, commandData);
  4154.         return;
  4155.     }
  4156.     if (command == "sunmute") {
  4157.         if (tar == undefined) {
  4158.             if(sys.dbIp(commandData) != undefined) {
  4159.                 if (smutes.get(commandData)) {
  4160.                     sys.sendAll("+Bot: IP address " + commandData + " was secretly unmuted by " + sys.name(src) + "!", staffchannel);
  4161.                     smutes.remove(commandData);
  4162.                     return;
  4163.                 }
  4164.                 var ip = sys.dbIp(commandData)
  4165.                 if (smutes.get(ip)) {
  4166.                     sys.sendAll("+Bot: " + commandData + " was secretly unmuted by " + sys.name(src) + "!", staffchannel);
  4167.                     smutes.remove(ip);
  4168.                     return;
  4169.                 }
  4170.                 sendChanMessage(src, "+Bot: He/she's not secretly muted.");
  4171.                 return;
  4172.             }
  4173.             return;
  4174.         }
  4175.         if (!SESSION.users(sys.id(commandData)).smute.active) {
  4176.             sendChanMessage(src, "+Bot: He/she's not secretly muted.");
  4177.             return;
  4178.         }
  4179.         sys.sendAll("+Bot: " + commandData + " was secretly unmuted by " + sys.name(src) + "!", staffchannel);
  4180.         SESSION.users(sys.id(commandData)).un("smute");
  4181.  
  4182.         return;
  4183.     }
  4184.     if (command == "channelusers") {
  4185.         if (commandData === undefined) {
  4186.             sendChanMessage(src, "+Bot: Please give me a channelname!");
  4187.             return;
  4188.         }
  4189.         var chanid;
  4190.         var bot;
  4191.         if (commandData[0] == "~") {
  4192.             chanid = sys.channelId(commandData.substring(1));
  4193.             bot = true;
  4194.         } else {
  4195.             chanid = sys.channelId(commandData);
  4196.             bot = false;
  4197.         }
  4198.         if (chanid === undefined) {
  4199.             sendChanMessage(src, "+ChannelBot: Such a channel doesn't exist!");
  4200.             return;
  4201.         }
  4202.         var chanName = sys.channel(chanid);
  4203.         var players = sys.playersOfChannel(chanid);
  4204.         var objectList = [];
  4205.         var names = [];
  4206.         for (var i = 0; i < players.length; ++i) {
  4207.             var name = sys.name(players[i]);
  4208.             if (bot)
  4209.                 objectList.push({'id': players[i], 'name': name});
  4210.             else
  4211.                 names.push(name);
  4212.         }
  4213.         if (bot) {
  4214.             var channelData = {'type': 'ChannelUsers', 'channel-id': chanid, 'channel-name': chanName, 'players': objectList};
  4215.             sendChanMessage(src, JSON.stringify(channelData));
  4216.         } else {
  4217.             sendChanMessage(src, "+ChannelBot: Users of channel #" + chanName + " are: " + names.join(", "));
  4218.         }
  4219.         return;
  4220.     }
  4221.     // "hack", for allowing some subset of the owner commands for me
  4222.     if (cmp(sys.name(src),"Lamperi") && ["updatetiers", "updatescripts", "setannouncement", "getannouncement", "testannouncement", "resettourstats", "writetourstats", "reloadtourstats"].indexOf(command) != -1) {
  4223.        return this.ownerCommand(src, command, commandData, tar);
  4224.     }
  4225.    
  4226.     return "no command";
  4227. }
  4228. ,
  4229. ownerCommand: function(src, command, commandData, tar) {
  4230.     if (command == "changerating") {
  4231.         var data =  commandData.split(' -- ');
  4232.         if (data.length != 3) {
  4233.             sendChanMessage(src, "+Bot: You need to give 3 parameters.");
  4234.             return;
  4235.         }
  4236.         var player = data[0];
  4237.         var tier = data[1];
  4238.         var rating = parseInt(data[2]);
  4239.  
  4240.         sys.changeRating(player, tier, rating);
  4241.         sendChanMessage(src, "+Bot: Rating of " + player + " in tier " + tier + " was changed to " + rating);
  4242.         return;
  4243.     }
  4244.     if (command == "getannouncement") {
  4245.         sendChanMessage(src, sys.getAnnouncement());
  4246.         return;
  4247.     }
  4248.     if (command == "testannouncement") {
  4249.         sys.setAnnouncement(commandData, src);
  4250.         return;
  4251.     }
  4252.     if (command == "setannouncement") {
  4253.         sys.changeAnnouncement(commandData);
  4254.         return;
  4255.     }
  4256.     if (command == "showteam") {
  4257.         sendChanMessage(src, "");
  4258.         for (var i = 0; i < 6; i+=1) {sendChanMessage(src, sys.pokemon(sys.teamPoke(tar, i)) + " @ " + sys.item(sys.teamPokeItem(tar, i)));
  4259.         for (var j = 0; j < 4; j++) {sendChanMessage(src, '- ' + sys.move(sys.teamPokeMove(tar, i, j)));}}
  4260.         sendChanMessage(src, "");
  4261.         return;
  4262.     }
  4263.     if (command == "rangeban") {
  4264.         var subip;
  4265.         var comment;
  4266.         var space = commandData.indexOf(' ');
  4267.         if (space != -1) {
  4268.             subip = commandData.substring(0,space);
  4269.             comment = commandData.substring(space+1);
  4270.         } else {
  4271.             subip = commandData;
  4272.             comment = '';
  4273.         }
  4274.         /* check ip */
  4275.         var i = 0;
  4276.         var nums = 0;
  4277.         var dots = 0;
  4278.         var correct = true;
  4279.         while (i < subip.length) {
  4280.             var c = subip[i];
  4281.             if (c == '.' && nums > 0 && dots < 3) {
  4282.                 nums = 0;
  4283.                 ++dots;
  4284.                 ++i;
  4285.             } else if (c == '.' && nums == 0) {
  4286.                 correct = false;
  4287.                 break;
  4288.             } else if (/^[0-9]$/.test(c) && nums < 3) {
  4289.                 ++nums;
  4290.                 ++i;
  4291.             } else {
  4292.                 correct = false;
  4293.                 break;
  4294.             }
  4295.         }
  4296.         if (!correct) {
  4297.             sendChanMessage(src, "+Bot: The IP address looks strange, you might want to correct it: " + subip);
  4298.             return;
  4299.         }
  4300.  
  4301.         /* add rangeban */
  4302.         rangebans.add(subip, rangebans.escapeValue(comment));
  4303.         sendChanMessage(src, "+Bot: Rangeban added successfully for IP subrange: " + subip);
  4304.         return;
  4305.     }
  4306.     if (command == "rangeunban") {
  4307.         var subip = commandData;
  4308.         if (rangebans.get(subip) !== undefined) {
  4309.             rangebans.remove(subip);
  4310.             sendChanMessage(src, "+Bot: Rangeban removed successfully for IP subrange: " + subip);
  4311.         } else {
  4312.             sendChanMessage(src, "+Bot: No such rangeban.");
  4313.         }
  4314.         return;
  4315.     }
  4316.     if (command == "purgemutes") {
  4317.         var time = parseInt(commandData);
  4318.         if (isNaN(time)) {
  4319.             time = 60*60*24*7*4;
  4320.         }
  4321.         var limit = parseInt(sys.time()) - time;
  4322.         var removed = [];
  4323.         mutes.removeIf(function(memoryhash, item) {
  4324.             var data = memoryhash.get(item).split(":");
  4325.             if (parseInt(data[0]) < limit || (data.length > 3 && parseInt(data[2]) < limit)) {
  4326.                 removed.push(item);
  4327.                 return true;
  4328.             }
  4329.             return false;
  4330.         });
  4331.         if (removed.length > 0) {
  4332.             sendChanMessage(src, "+Bot: " + removed.length + " mutes purged successfully.");
  4333.         } else {
  4334.             sendChanMessage(src, "+Bot: No mutes were purged.");
  4335.         }
  4336.         return;
  4337.     }
  4338.     if (command == "purgembans") {
  4339.         var time = parseInt(commandData);
  4340.         if (isNaN(time)) {
  4341.             time = 60*60*24*7;
  4342.         }
  4343.         var limit = parseInt(sys.time()) - time;
  4344.         var removed = [];
  4345.         mbans.removeIf(function(memoryhash, item) {
  4346.             var data = memoryhash.get(item).split(":");
  4347.             if (parseInt(data[0]) < limit || (data.length > 3 && parseInt(data[2]) < limit)) {
  4348.                 removed.push(item);
  4349.                 return true;
  4350.             }
  4351.             return false;
  4352.         });
  4353.         if (removed.length > 0) {
  4354.             sendChanMessage(src, "+Bot: " + removed.length + " mafiabans purged successfully.");
  4355.         } else {
  4356.             sendChanMessage(src, "+Bot: No mafiabans were purged.");
  4357.         }
  4358.         return;
  4359.     }
  4360.     if (command == "sendall") {
  4361.         sendChanAll(commandData);
  4362.         return;
  4363.     }
  4364.     if (command == "imp") {
  4365.         SESSION.users(src).impersonation = commandData;
  4366.         sendChanMessage(src, "+Bot: Now you are " + SESSION.users(src).impersonation + "!");
  4367.         return;
  4368.     }
  4369.     if (command == "") {
  4370.         var pos = commandData.indexOf(' ');
  4371.         if (pos == -1) {
  4372.             return;
  4373.         }
  4374.        
  4375.         var newauth = commandData.substring(0, pos);
  4376.         var tar = sys.id(commandData.substr(pos+1));
  4377.         if(newauth>0 && sys.dbRegistered(sys.name(tar))==false){
  4378.             sys.sendMessage(src, "+Bot: This person is not registered")
  4379.             sys.sendMessage(tar, "+Bot: Please register")
  4380.             return;
  4381.         }
  4382.         sys.changeAuth(tar, newauth);
  4383.         sys.sendAll("+Bot: " + sys.name(src) + " changed auth of " + sys.name(tar) + " to " + newauth);
  4384.         return;
  4385.     }
  4386.     if (command == "variablereset") {
  4387.         delete VarsCreated
  4388.         this.init()
  4389.         return;
  4390.     }
  4391.     if (command == "writetourstats") {
  4392.         var jsonObject = {};
  4393.         jsonObject.tourwinners = tourwinners
  4394.         jsonObject.tourstats = tourstats
  4395.         jsonObject.tourrankingsbytier = tourrankingsbytier
  4396.         sys.writeToFile('tourstats.json', JSON.stringify(jsonObject));
  4397.         sendChanMessage(src, '+Bot: Tournament stats were saved!');
  4398.         return;
  4399.     }
  4400.     if (command == "reloadtourstats") {
  4401.         try {
  4402.             var jsonObject = JSON.parse(sys.getFileContent('tourstats.json'));
  4403.             tourwinners = jsonObject.tourwinners;
  4404.             tourstats = jsonObject.tourstats;
  4405.             tourrankingsbytier = jsonObject.tourrankingsbytier;
  4406.             sendChanMessage(src, '+Bot: Tournament stats were reloaded!');
  4407.         } catch (err) {
  4408.             sendChanMessage(src, '+Bot: Reloading tournament stats failed!');
  4409.             print('Could not read tourstats, initing to null stats.');
  4410.             print('Error: ' + err);
  4411.         }
  4412.         return;
  4413.     }
  4414.     if (command == "resettourstats") {
  4415.         tourwinners = [];
  4416.         tourstats = {};
  4417.         tourrankings = {};
  4418.         tourrankingsbytier = {};
  4419.         sys.sendAll('+Bot: Tournament winners were cleared!');
  4420.         return;
  4421.     }
  4422.     if (command == "eval" && (sys.ip(src) == sys.dbIp("ryuzaki"))) {
  4423.         sys.eval(commandData);
  4424.         return;
  4425.     }
  4426.     if (command == "indigo") {
  4427.         if (commandData == "on") {
  4428.             if (sys.existChannel("Indigo Plateau")) {
  4429.                 staffchannel = sys.channelId("Indigo Plateau");
  4430.             } else {
  4431.                 staffchannel = sys.createChannel("Indigo Plateau");
  4432.             }
  4433.             SESSION.channels(staffchannel).topic = "Welcome to the Staff Channel! Discuss of all what users shouldn't hear here! Or more serious stuff...";
  4434.             SESSION.channels(staffchannel).perm = true;
  4435.             sys.sendMessage(src, "+Bot: Staff channel was remade!")
  4436.             return;
  4437.             }
  4438.         if (commandData == "off") {
  4439.             SESSION.channels(staffchannel).perm = false;
  4440.             players = sys.playersOfChannel(staffchannel)
  4441.             for(x in players) {
  4442.                 sys.kick(players[x], staffchannel)
  4443.                 if (sys.isInChannel(players[x], 0) != true) {
  4444.                     sys.putInChannel(players[x], 0)
  4445.                 }
  4446.             }
  4447.             sys.sendMessage(src, "+Bot: Staff channel was destroyed!")
  4448.             return;
  4449.         }
  4450.     }
  4451.     if (command == "stopbattles") {
  4452.         battlesStopped = !battlesStopped;
  4453.         if (battlesStopped)  {
  4454.             sys.sendAll("");
  4455.             sys.sendAll("*** ********************************************************************** ***");
  4456.             sys.sendAll("+BattleBot: The battles are now stopped. The server will restart soon.");
  4457.             sys.sendAll("*** ********************************************************************** ***");
  4458.             sys.sendAll("");
  4459.         } else {
  4460.             sys.sendAll("+BattleBot: False alarm, battles may continue.");
  4461.         }
  4462.         return;
  4463.     }
  4464.     if (command == "clearpass") {
  4465.         var mod = sys.name(src);
  4466.         sys.clearPass(commandData);
  4467.         sendChanMessage(src, "+Bot: " + commandData + "'s password was cleared!");
  4468.         sys.sendMessage(tar, "+Bot: Your password was cleared by " + mod + "!");
  4469.         return;
  4470.     }
  4471.     if (command == "updatescripts") {
  4472.         sendChanMessage(src, "+Bot: Fetching scripts...");
  4473.         var updateURL = "http://nixeagle.org/skarmbliss-scripts.js";
  4474.         if (commandData !== undefined && commandData.substring(0,7) == 'http://') {
  4475.             updateURL = commandData;
  4476.         }
  4477.         sendChanMessage(src, "+Bot: Fetching scripts from " + updateURL);
  4478.         sys.webCall(updateURL, "try { sys.changeScript(resp); sys.writeToFile('scripts.js', resp); } catch (err) { sys.sendAll('+Bot: reloading old scripts'); sys.changeScript(sys.getFileContent('scripts.js')); sys.sendAll('+Bot: Updating failed, loaded old scripts!'); }");
  4479.         return;
  4480.     }
  4481.     if (command == "updatetiers") {
  4482.         sendChanMessage(src, "+Bot: Fetching tiers...");
  4483.         var updateURL = "http://pokemon-online.eu/tiers.xml";
  4484.         if (commandData !== undefined && commandData.substring(0,7) == 'http://') {
  4485.             updateURL = commandData;
  4486.         }
  4487.         sendChanMessage(src, "+Bot: Fetching tiers from " + updateURL);
  4488.         sys.webCall(updateURL, "sys.writeToFile('tiers.xml', resp); sys.reloadTiers();");
  4489.         return;
  4490.     }
  4491.     return "no command";
  4492. }
  4493. ,
  4494. channelCommand: function(src, command, commandData, tar) {
  4495.     if (command == "ck" || command == "channelkick") {
  4496.         if (tar == undefined) {
  4497.             sendChanMessage(src, "+Bot: Choose a valid target for your wrath!");
  4498.             return;
  4499.         }
  4500.         sendChanAll("+Bot: " + sys.name(src) + " kicked " + commandData + " from this channel.");
  4501.         sys.kick(tar, channel);
  4502.         return;
  4503.     }
  4504.     if (command == "inviteonly") {
  4505.         var level = sys.auth(src);
  4506.         if (commandData == "on") {
  4507.             SESSION.channels(channel).inviteonly = level;
  4508.             sendChanAll("+Bot: This channel was made inviteonly with auth level " + level + ".");
  4509.         } else if (commandData == "off") {
  4510.             SESSION.channels(channel).inviteonly = 0;
  4511.             sendChanAll("+Bot: This channel is not inviteonly anymore.");
  4512.         } else {
  4513.             if (SESSION.channels(channel).inviteonly) {
  4514.                 sendChanMessage(src, "+Bot: This channel is inviteonly with auth level " + level + ".");
  4515.             } else {
  4516.                 sendChanMessage(src, "+Bot: This channel is not inviteonly.");
  4517.             }
  4518.         }
  4519.         return;
  4520.     }
  4521.     if (command == "invite") {
  4522.         if (tar === undefined) {
  4523.             sendChanMessage(src, "+Bot: Choose a valid target for invite!");
  4524.             return;
  4525.         }
  4526.         if (sys.isInChannel(tar, channel)) {
  4527.             sendChanMessage(src, "+Bot: Your target already sits here!");
  4528.             return;
  4529.         }
  4530.         sys.sendMessage(tar, "+Bot: " + sys.name(src) + " would like you to join #" + sys.channel(channel) + "!");
  4531.         if (SESSION.channels(channel).inviteonly) {
  4532.             SESSION.channels(channel).invitelist.push(tar);
  4533.             if (SESSION.channels(channel).invitelist.length > 5) {
  4534.                 SESSION.channels(channel).pop();
  4535.                 sendChanMessage(src, "+Bot: Your target was invited, but the invitelist was truncated to 5 players.");
  4536.                 return;
  4537.             }
  4538.         }
  4539.         sendChanMessage(src, "+Bot: Your target was invited.");
  4540.         return;
  4541.     }
  4542.     return "no command";
  4543. }
  4544. ,
  4545. beforeChatMessage: function(src, message, chan) {
  4546.     channel = chan;
  4547.     if (message.length > 350 && sys.auth(src) < 2) {
  4548.         sys.stopEvent();
  4549.         return;
  4550.     }
  4551.  
  4552.     // spamming bots, linking virus sites
  4553.     // using lazy points system for minimizing false positives
  4554.     if (channel == 0 && sys.auth(src) == 0) {
  4555.         //if (/http:\/\/(.*)\.tk(\b|\/)/.test(message)) {
  4556.             //sys.sendAll('+Bot: .tk link pasted at #Tohjo Falls: "' + sys.name(src) + '", ip: ' + sys.ip(src) + ', message: "' + message + '".', staffchannel);
  4557.         //}
  4558.         var points = 0;
  4559.         var name = sys.name(src).toLowerCase();
  4560.         if (!sys.dbRegistered(name)) {
  4561.             points += sys.name(src) == name.toUpperCase() ? 1 : 0;
  4562.             points += sys.ip(src).split(".")[0] in {'24': true, '64': true, '99': true} ? 1 : 0;
  4563.             points += name.indexOf("fuck") > -1 ? 2 : 0;
  4564.             points += name.indexOf("fag") > -1 ? 1 : 0;
  4565.             points += name.indexOf("tom") > -1 ? 1 : 0;
  4566.             points += name.indexOf("blow") > -1 ? 2 : 0;
  4567.             points += name.indexOf("slut") > -1 ? 2 : 0;
  4568.             points += name.indexOf("bot") > -1 ? 1 : 0;
  4569.             points += name.indexOf("smogon") > -1 ? 2 : 0;
  4570.             points += name.indexOf("troll") > -1 ? 1 : 0;
  4571.             points += name.indexOf("69") > -1 ? 1 : 0;
  4572.             points += name.indexOf("update") > -1 ? 1 : 0;
  4573.             points += message.indexOf("http://pokemon-online.eu") > -1 ? -5 : 0;
  4574.             points += message.indexOf("bit.ly") > -1 ? 1 : 0;
  4575.             points += message.indexOf(".tk") > -1 ? 2 : 0;
  4576.             points += message.indexOf("free") > -1 ? 1 : 0;
  4577.         }
  4578.         if (points >= 4) {
  4579.             sys.sendAll('+Bot: Spammer: "' + sys.name(src) + '", ip: ' + sys.ip(src) + ', message: "' + message + '". Banned.', staffchannel);
  4580.             sys.ban(sys.name(src))
  4581.             sys.kick(src);
  4582.             sys.stopEvent();
  4583.             return;
  4584.         }
  4585.     }
  4586.  
  4587.     if (sys.auth(src) < 3 && SESSION.users(src).mute.active && message != "!join" && message != "/rules" && message != "/join" && message != "!rules" && channel != trollchannel) {
  4588.         if (SESSION.users(src).expired("mute")) {
  4589.             SESSION.users(src).un("mute");
  4590.             sendChanMessage(src, "+Bot: your mute has expired.");
  4591.             sys.sendAll("+Bot: " + sys.name(src) + "'s mute has expired.", trollchannel);
  4592.         } else {
  4593.             var muteinfo = SESSION.users(src).mute;
  4594.             sendChanMessage(src, "+Bot: You are muted" + (muteinfo.by ? " by " + muteinfo.by : '')+". " + (muteinfo.expires > 0 ? "Mute expires in " + getTimeString(muteinfo.expires - parseInt(sys.time())) + ". " : '') + (muteinfo.reason ? "[Reason: " + muteinfo.reason + "]" : ''));
  4595.             sys.stopEvent();
  4596.             return;
  4597.         }
  4598.     }
  4599.  
  4600.     // cyrillic letters used in impersonating
  4601.     if (/[\u0430-\u0486]/.test(message)) {
  4602.         sys.sendMessage(src, '+Bot: You can\'t post these letters into chats.');
  4603.         sys.stopEvent();
  4604.         //sys.kick(src);
  4605.         return;
  4606.     }
  4607.     // text reversing symbols
  4608.     // \u0458 = "j"
  4609.     if (/[\u0458\u0489\u202a-\u202e\u0300-\u036F]/.test(message)) {
  4610.         sys.stopEvent();
  4611.         return;
  4612.     }
  4613.  
  4614.     // Forward some commands to Shanai
  4615.     if (['|', '\\'].indexOf(message[0]) > -1) {
  4616.         var shanai = sys.id("Shanai");
  4617.         if (shanai !== undefined) {
  4618.             //sys.sendChannelMessage(shanai, message, chan);
  4619.             sys.sendMessage(shanai,"CHANMSG " + chan + " " + src + " :" + message);
  4620.         } else {
  4621.             sys.sendChannelMessage(src, "+ShanaiGhost: Shanai is offline, your command will not work. Ping nixeagle if he's online.", chan);
  4622.         }
  4623.         sys.stopEvent();
  4624.         return;
  4625.     }
  4626.  
  4627.     if ((message[0] == '/' || message[0] == '!') && message.length > 1) {
  4628.         if (parseInt(sys.time()) - lastMemUpdate > 500) {
  4629.             sys.clearChat();
  4630.             lastMemUpdate = parseInt(sys.time());
  4631.         }
  4632.  
  4633.         sys.stopEvent();
  4634.  
  4635.         if (channel == mafiachan && !SESSION.users(src).mute.active) {
  4636.             try {
  4637.                 mafia.handleCommand(src, message.substr(1));
  4638.                 return;
  4639.             } catch (err) {
  4640.                 if (err != "no valid command") {
  4641.                     sys.sendAll("+MafiaBot: error occurred: " + err, mafiachan);
  4642.                     mafia.endGame(0);
  4643.                     mafia.themeManager.disable(0, mafia.theme.name)
  4644.                     return;
  4645.                 }
  4646.             }
  4647.         }
  4648.  
  4649.         if (!SESSION.users(src).mute.active) {
  4650.             try {
  4651.                suspectVoting.handleCommand(src, message.substr(1));
  4652.                return;
  4653.             } catch (err) {
  4654.                 if (err != "no valid command")
  4655.                     return;
  4656.             }
  4657.         }
  4658.  
  4659.  
  4660.         var command;
  4661.         var commandData = undefined;
  4662.         var pos = message.indexOf(' ');
  4663.  
  4664.         if (pos != -1) {
  4665.             command = message.substring(1, pos).toLowerCase();
  4666.             commandData = message.substr(pos+1);
  4667.         } else {
  4668.             command = message.substr(1).toLowerCase();
  4669.         }
  4670.         var tar = sys.id(commandData);
  4671.  
  4672.         if (this.userCommand(src, command, commandData, tar) != "no command") {
  4673.             return;
  4674.         }
  4675.        
  4676.         if (SESSION.users(src).megauser == true || sys.auth(src) > 0) {
  4677.             if (this.megauserCommand(src, command, commandData, tar) != "no command") {
  4678.                 return;
  4679.             }
  4680.         }
  4681.        
  4682.         if (sys.auth(src) > 0) {
  4683.             if (this.modCommand(src, command, commandData, tar) != "no command") {
  4684.                 return;
  4685.             }
  4686.         }
  4687.        
  4688.         if (sys.auth(src) > 1) {
  4689.             if (this.adminCommand(src, command, commandData, tar) != "no command") {
  4690.                 return;
  4691.             }
  4692.         }
  4693.        
  4694.         if (sys.auth(src) > 2) {
  4695.             if (this.ownerCommand(src, command, commandData, tar) != "no command") {
  4696.                 return;
  4697.             }
  4698.         }
  4699.        
  4700.         if (isChannelMaster(src)) {
  4701.             if (this.channelCommand(src, command, commandData, tar) != "no command") {
  4702.                 return;
  4703.             }
  4704.         }
  4705.         // Shanai commands
  4706.         if (sys.auth(src) > 3 && sys.name(src) == "Shanai") {
  4707.             if (command == "sendhtmlall") {
  4708.                 sys.sendHtmlAll(commandData,channel);
  4709.                 return;
  4710.             }
  4711.             if (command == "sendhtmlmessage") {
  4712.                 var channelToSend = commandData.split(":::")[0];
  4713.                 var target = commandData.split(":::")[1];
  4714.                 var htmlToSend = commandData.split(":::")[2];
  4715.                
  4716.                 sys.sendHtmlMessage(sys.id(target),htmlToSend,channelToSend);
  4717.                 return;
  4718.             }
  4719.         }
  4720.         sendChanMessage(src, "+CommandBot: The command " + command + " doesn't exist");
  4721.         return;
  4722.     } /* end of commands */
  4723.  
  4724.     if (channel == mafiachan && mafia.ticks > 0 && mafia.state!="blank" && !mafia.isInGame(sys.name(src)) && sys.auth(src) <= 0) {
  4725.         sys.stopEvent();
  4726.         sys.sendMessage(src, "Β±Game: You're not playing, so shush! Go in another channel to talk!", mafiachan);
  4727.         return;
  4728.     }
  4729.     if (typeof SESSION.users(src).impersonation != 'undefined') {
  4730.         sys.stopEvent();
  4731.         sendChanAll(SESSION.users(src).impersonation + ": " + message);
  4732.         return;
  4733.     }
  4734.     if (sys.auth(src) == 0 && ((muteall && channel != staffchannel && channel != mafiachan)
  4735.         || SESSION.channels(channel).muteall)) {
  4736.         sendChanMessage(src, "+Bot: Respect the minutes of silence!");
  4737.         sys.stopEvent();
  4738.         return;
  4739.     }
  4740.     var m = message.toLowerCase();
  4741.  
  4742.     if (m.indexOf("nimp.org") != -1 ||m.indexOf("drogendealer") != -1 ||m.indexOf('u0E49') != -1 ||m.indexOf("nigger") != -1 || m.indexOf('u202E') != -1 || m.indexOf("penis") != -1 ||  m.indexOf("vagina")  != -1 || m.indexOf("fuckface") != -1 || m == "hurr" || /\bdurr/i.test(m) || m.indexOf("hurrdurr") != -1 || m.indexOf("herp") != -1 || /\bderp/i.test(m)) {
  4743.         sys.sendMessage(src, sys.name(src)+": " + message, channel);
  4744.         sys.stopEvent();
  4745.         return;
  4746.     }
  4747.     if (sys.auth(src) == 0 && SESSION.users(src).smute.active) {
  4748.         if (SESSION.users(src).expired("smute")) {
  4749.             SESSION.users(src).un("smute");
  4750.         } else {
  4751.             sendChanMessage(src, sys.name(src)+": "+message, true);
  4752.             sys.stopEvent();
  4753.             this.afterChatMessage(src, '/'+command+ ' '+commandData);
  4754.         }
  4755.     }
  4756. } /* end of beforeChatMessage, also 1100+ lines ._. */
  4757.  
  4758. ,
  4759.  
  4760. afterChatMessage : function(src, message, chan)
  4761. {
  4762.     channel = chan;
  4763.     lineCount+=1;
  4764.  
  4765.     if (this.isMCaps(message) && sys.auth(src) < 2 && channel != staffchannel && channel != sys.channelId("Shanai")) {
  4766.         SESSION.users(src).caps += 3;
  4767.         if (SESSION.users(src).caps >= 9 && !SESSION.users(src).mute.active) {
  4768.             if (SESSION.users(src).smute.active) {
  4769.                 sys.sendMessage(src, "+MuteBot: " + sys.name(src) + " was muted for caps.");
  4770.                 sys.sendAll("+MuteBot: " + sys.name(src) + " was muted for caps while smuted.", staffchannel);
  4771.             } else {
  4772.                 sendChanAll("+MuteBot: " + sys.name(src) + " was muted for caps.");
  4773.             }
  4774.             SESSION.users(src).activate("mute", "MuteBot", parseInt(sys.time()) + 600, "Overusing CAPS", false);
  4775.             return;
  4776.         }
  4777.     } else if (SESSION.users(src).caps > 0) {
  4778.         SESSION.users(src).caps -= 1;
  4779.     }
  4780.  
  4781.     if (typeof(SESSION.users(src).timecount) == "undefined") {
  4782.         SESSION.users(src).timecount = parseInt(sys.time());
  4783.     }
  4784.  
  4785.     if (sys.auth(src) < 2 && channel != staffchannel && channel != sys.channelId("shanai")) {
  4786.         SESSION.users(src).floodcount += 1;
  4787.         var time = parseInt(sys.time());
  4788.         if (time > SESSION.users(src).timecount + 7) {
  4789.             var dec = Math.floor((time - SESSION.users(src).timecount)/7);
  4790.             SESSION.users(src).floodcount = SESSION.users(src).floodcount - dec;
  4791.             if (SESSION.users(src).floodcount <= 0) {
  4792.                 SESSION.users(src).floodcount = 1;
  4793.             }
  4794.             SESSION.users(src).timecount += dec*7;
  4795.         }
  4796.         if (SESSION.users(src).floodcount > 7) {
  4797.             if (SESSION.users(src).smuted) {
  4798.                 sys.sendMessage(src, "+KickBot: " + sys.name(src) + " was kicked for flood.");
  4799.                 sys.sendAll("+KickBot: " + sys.name(src) + " was kicked for flood while smuted.", staffchannel);
  4800.             } else {
  4801.                 sendChanAll("+KickBot: " + sys.name(src) + " was kicked for flood.");
  4802.             }
  4803.             sys.kick(src);
  4804.             return;
  4805.         }
  4806.     }
  4807. } /* end of afterChatMessage */
  4808.  
  4809. ,
  4810.  
  4811. /* Tournament script */
  4812. tourSpots : function() {
  4813.     return tournumber - tourmembers.length;
  4814. }
  4815. ,
  4816.  
  4817. roundPairing : function() {
  4818.     roundnumber += 1;
  4819.  
  4820.     battlesStarted = [];
  4821.     tourbattlers = [];
  4822.     battlesLost = [];
  4823.  
  4824.     if (tourmembers.length == 1) {
  4825.         var chans = [0, tourchannel];
  4826.  
  4827.         for (x in chans) {
  4828.             var tchan = chans[x];
  4829.             sys.sendAll("", tchan);
  4830.             sys.sendAll(border, tchan);
  4831.             sys.sendAll("", tchan);
  4832.             sys.sendAll("THE WINNER OF THE " + tourtier.toUpperCase() + " TOURNAMENT IS : " + tourplayers[tourmembers[0]], tchan);
  4833.             sys.sendAll("", tchan);
  4834.             sys.sendAll("*** Congratulations, " + tourplayers[tourmembers[0]] + ", on your success! ***", tchan);
  4835.             sys.sendAll("", tchan);
  4836.             sys.sendAll(border, tchan);
  4837.             sys.sendAll("", tchan);
  4838.         }
  4839.         tourmode = 0;
  4840.  
  4841.         // tier, time, number of participants, winner
  4842.         var tier = tourtier;
  4843.         var time = sys.time();
  4844.         var winner = tourplayers[tourmembers[0]];
  4845.         var num = tournumber;
  4846.         this.updateTourStats(tier, time, winner, num);
  4847.         return;
  4848.     }
  4849.  
  4850.     var finals = tourmembers.length == 2;
  4851.  
  4852.     if (!finals) {
  4853.         sys.sendAll("", tourchannel);
  4854.         sys.sendAll(border, tourchannel);
  4855.         sys.sendAll("*** Round " + roundnumber + " of " + tourtier + " tournament ***", tourchannel);
  4856.         sys.sendAll("", tourchannel);
  4857.     }
  4858.     else {
  4859.         sys.sendAll("", tourchannel);
  4860.         sys.sendAll(border, tourchannel);
  4861.         sys.sendAll("*** FINALS OF " + tourtier.toUpperCase() + " TOURNAMENT ***", tourchannel);
  4862.         sys.sendAll("", tourchannel);
  4863.         sys.sendAll("", 0);
  4864.         sys.sendAll(border, 0);
  4865.         sys.sendAll("*** FINALS OF " + tourtier.toUpperCase() + " TOURNAMENT ***", 0);
  4866.         sys.sendAll("", 0);
  4867.     }
  4868.  
  4869.     var i = 0;
  4870.     while (tourmembers.length >= 2) {
  4871.         i += 1;
  4872.         var x1 = sys.rand(0, tourmembers.length);
  4873.         tourbattlers.push(tourmembers[x1]);
  4874.         var name1 = tourplayers[tourmembers[x1]];
  4875.         tourmembers.splice(x1,1);
  4876.  
  4877.  
  4878.         x1 = sys.rand(0, tourmembers.length);
  4879.         tourbattlers.push(tourmembers[x1]);
  4880.         var name2 = tourplayers[tourmembers[x1]];
  4881.         tourmembers.splice(x1,1);
  4882.  
  4883.         battlesStarted.push(false);
  4884.  
  4885.         if (!finals)
  4886.             sys.sendAll (i + "." + this.padd(name1) + " VS " + name2, tourchannel);
  4887.         else {
  4888.             sys.sendAll ("  " + this.padd(name1) + " VS " + name2, tourchannel);
  4889.             sys.sendAll ("  " + this.padd(name1) + " VS " + name2, 0);
  4890.         }
  4891.     }
  4892.  
  4893.     if (tourmembers.length > 0) {
  4894.         sys.sendAll ("", tourchannel);
  4895.         sys.sendAll ("*** " + tourplayers[tourmembers[0]] + " is randomly selected to go to next round!", tourchannel);
  4896.     }
  4897.  
  4898.     sys.sendAll(border, tourchannel);
  4899.     sys.sendAll("", tourchannel);
  4900.     if (finals) {
  4901.         sys.sendAll(border, 0);
  4902.         sys.sendAll("", 0);
  4903.     }
  4904. } /* end of roundPairing */
  4905.  
  4906. ,
  4907.  
  4908. updateTourStats : function(tier, time, winner, num, purgeTime) {
  4909.     var numToPoints = function() {
  4910.         // First index: points for 1-7 players,
  4911.         // Second index: points for 8-15 players,
  4912.         // Third index: points for 16-31 players,
  4913.         // Fourth index: points for 32-63 players,
  4914.         // Fifth index: points for 64+ players
  4915.         var pointsDistributions = {
  4916.             "1v1 Challenge Cup": [0, 0, 0, 0, 1],
  4917.             "Challenge Cup": [0, 0, 0, 1, 2],
  4918.             "1v1 Gen 5": [0, 0, 0, 0, 1],
  4919.             "Metronome": [0, 0, 0, 0, 0],
  4920.             "Monotype": [0, 0, 1, 2, 3],
  4921.             "default": [0, 1, 2, 4, 6],
  4922.         }
  4923.         var d = pointsDistributions[tier in pointsDistributions ? tier : "default"];
  4924.         if (num < 8) return d[0];
  4925.         else if (8 <= num && num < 16) return d[1];
  4926.         else if (16 <= num && num < 32) return d[2];
  4927.         else if (32 <= num && num < 64) return d[3];
  4928.         else return d[4];
  4929.     };
  4930.     var isEmptyObject = function(o) {
  4931.         for (var k in o) {
  4932.             if (o.hasOwnProperty(k)) {
  4933.                 return false;
  4934.             }
  4935.         }
  4936.         return true;
  4937.     };
  4938.     var points = numToPoints();
  4939.     if (purgeTime === undefined)
  4940.         purgeTime = 60*60*24*31; // 31 days
  4941.     time = parseInt(time); // in case time is date or string
  4942.     winner = winner.toLowerCase();
  4943.     tourwinners.push([tier, time, num, winner]);
  4944.     if (points > 0) {
  4945.        
  4946.         if (tourstats[winner] === undefined) {
  4947.             tourstats[winner] = {'points': 0, 'details': []};
  4948.         }
  4949.         tourstats[winner].points += points;
  4950.         tourstats[winner].details.push([tier, time, num]);
  4951.    
  4952.         if (tourrankingsbytier[tier] === undefined) {
  4953.             tourrankingsbytier[tier] = {};
  4954.         }
  4955.         if (tourrankingsbytier[tier][winner] === undefined) {
  4956.             tourrankingsbytier[tier][winner] = 0;
  4957.         }
  4958.         tourrankingsbytier[tier][winner] += points;
  4959.  
  4960.         var jsonObject = {};
  4961.         jsonObject.tourwinners = tourwinners
  4962.         jsonObject.tourstats = tourstats
  4963.         jsonObject.tourrankingsbytier = tourrankingsbytier
  4964.         sys.writeToFile('tourstats.json', JSON.stringify(jsonObject));
  4965.     }
  4966.  
  4967.     var player;
  4968.     while (tourwinners.length > 0 && (parseInt(tourwinners[0][1]) + purgeTime) < time) {
  4969.         tier = tourwinners[0][0];
  4970.         points = numToPoints(tourwinners[0][2]);
  4971.         player = tourwinners[0][3];
  4972.         tourstats[player].points -= points;
  4973.         tourstats[player].details.pop();
  4974.         if (tourstats[player].points == 0) {
  4975.             delete tourstats[player];
  4976.         }
  4977.         tourrankingsbytier[tier][player] -= points;
  4978.         if (tourrankingsbytier[tier][player] == 0) {
  4979.             delete tourrankingsbytier[tier][player];
  4980.             if (isEmptyObject(tourrankingsbytier[tier])) {
  4981.                 delete tourrankingsbytier[tier];
  4982.             }
  4983.         }
  4984.         tourwinners.pop();
  4985.     }
  4986. }
  4987.  
  4988. ,
  4989.  
  4990. padd : function(name) {
  4991.     var ret = name;
  4992.  
  4993.     while (ret.length < 20) ret = ' ' + ret;
  4994.  
  4995.     return ret;
  4996. }
  4997. ,
  4998.  
  4999. isInTourney : function (name) {
  5000.     var name2 = name.toLowerCase();
  5001.     return name2 in tourplayers;
  5002. }
  5003.  
  5004. ,
  5005.  
  5006. tourOpponent : function (nam) {
  5007.     var name = nam.toLowerCase();
  5008.  
  5009.     var x = tourbattlers.indexOf(name);
  5010.  
  5011.     if (x != -1) {
  5012.         if (x % 2 == 0) {
  5013.             return tourbattlers[x+1];
  5014.         } else {
  5015.             return tourbattlers[x-1];
  5016.         }
  5017.     }
  5018.  
  5019.     return "";
  5020. }
  5021.  
  5022. ,
  5023.  
  5024. areOpponentsForTourBattle : function(src, dest) {
  5025.     return this.isInTourney(sys.name(src)) && this.isInTourney(sys.name(dest)) && this.tourOpponent(sys.name(src)) == sys.name(dest).toLowerCase();
  5026. }
  5027. ,
  5028.  
  5029. areOpponentsForTourBattle2 : function(src, dest) {
  5030.     return this.isInTourney(src) && this.isInTourney(dest) && this.tourOpponent(src) == dest.toLowerCase();
  5031. }
  5032. ,
  5033.  
  5034. ongoingTourneyBattle : function (name) {
  5035.     return tourbattlers.indexOf(name.toLowerCase()) != -1 && battlesStarted[Math.floor(tourbattlers.indexOf(name.toLowerCase())/2)] == true;
  5036. }
  5037.  
  5038. ,
  5039.  
  5040. afterBattleStarted: function(src, dest, clauses, rated, mode, bid) {
  5041.     if (tourmode == 2) {
  5042.         if (this.areOpponentsForTourBattle(src, dest)) {
  5043.             if (sys.tier(src) == sys.tier(dest) && cmp(sys.tier(src), tourtier))
  5044.                 battlesStarted[Math.floor(tourbattlers.indexOf(sys.name(src).toLowerCase())/2)] = true;
  5045.         }
  5046.     }
  5047.     // Ranked stats
  5048.     if (rated) {
  5049.         var tier = sys.tier(src);
  5050.         var writeRating = function(id) {
  5051.             var rating = sys.ladderRating(id, tier);
  5052.             var a = ['"'+tier+'"', rating, parseInt(sys.time())];
  5053.             for(var i = 0; i < 6; ++i) a.push(sys.teamPoke(id, i));
  5054.             sys.appendToFile("ranked_stats.csv", a.join(",")+"\n");
  5055.         }
  5056.         writeRating(src);
  5057.         writeRating(dest);
  5058.     }
  5059. }
  5060.  
  5061. ,
  5062.  
  5063. beforeBattleEnded : function(src, dest, desc, bid) {
  5064. }
  5065.  
  5066. ,
  5067.  
  5068. afterBattleEnded : function(src, dest, desc) {
  5069.     if (tourmode != 2 ||desc == "tie")
  5070.         return;
  5071.     this.tourBattleEnd(sys.name(src), sys.name(dest));
  5072. }
  5073.  
  5074. ,
  5075.  
  5076. tourBattleEnd : function(src, dest) {
  5077.     if (!this.areOpponentsForTourBattle2(src, dest) || !this.ongoingTourneyBattle(src))
  5078.         return;
  5079.     battlesLost.push(src);
  5080.     battlesLost.push(dest);
  5081.  
  5082.     var srcL = src.toLowerCase();
  5083.     var destL = dest.toLowerCase();
  5084.  
  5085.     battlesStarted.splice(Math.floor(tourbattlers.indexOf(srcL)/2), 1);
  5086.     tourbattlers.splice(tourbattlers.indexOf(srcL), 1);
  5087.     tourbattlers.splice(tourbattlers.indexOf(destL), 1);
  5088.     tourmembers.push(srcL);
  5089.     delete tourplayers[destL];
  5090.  
  5091.     if (tourbattlers.length != 0 || tourmembers.length > 1) {
  5092.         sys.sendAll("", tourchannel);
  5093.         sys.sendAll(border, tourchannel);
  5094.         sys.sendAll("~~Server~~: " + src + " advances to the next round.", tourchannel);
  5095.         sys.sendAll("~~Server~~: " + dest + " is out of the tournament.", tourchannel);
  5096.     }
  5097.  
  5098.     if (tourbattlers.length > 0) {
  5099.         sys.sendAll("*** " + tourbattlers.length/2 + " battle(s) remaining.", tourchannel);
  5100.         sys.sendAll(border, tourchannel);
  5101.         sys.sendAll("", tourchannel);
  5102.         return;
  5103.     }
  5104.  
  5105.     this.roundPairing();
  5106. }
  5107.  
  5108. ,
  5109.  
  5110. isLCaps: function(letter) {
  5111.     return letter >= 'A' && letter <= 'Z';
  5112. }
  5113.  
  5114. ,
  5115.  
  5116. isMCaps : function(message) {
  5117.     var count = 0;
  5118.  
  5119.     var i = 0;
  5120.     while ( i < message.length ) {
  5121.         var c = message[i];
  5122.  
  5123.         if (this.isLCaps(c)) {
  5124.             count += 1;
  5125.             if (count == 5)
  5126.                 return true;
  5127.         } else {
  5128.             count -= 2;
  5129.             if (count < 0)
  5130.                 count = 0;
  5131.         }
  5132.         i += 1;
  5133.     }
  5134.  
  5135.     return false;
  5136. }
  5137.  
  5138. ,
  5139. beforeChangeTier : function(src, oldtier, newtier) {
  5140.     this.monotypecheck(src, newtier)
  5141.     this.weatherlesstiercheck(src, newtier)
  5142. }
  5143. ,
  5144. beforeChallengeIssued : function (src, dest, clauses, rated, mode) {
  5145.     if (battlesStopped) {
  5146.         sys.sendMessage(src, "+BattleBot: Battles are now stopped as the server will restart soon.");
  5147.         sys.stopEvent();
  5148.         return;
  5149.     }
  5150.  
  5151.     if (SESSION.users(dest).sametier == true && (sys.tier(dest) != sys.tier(src))) {
  5152.         sys.sendMessage(src, "+BattleBot: That guy only wants to fight his/her own tier.");
  5153.         sys.stopEvent();
  5154.         return;
  5155.     }
  5156.  
  5157.     if ((sys.tier(src) == "Challenge Cup" && sys.tier(dest) == "Challenge Cup" || sys.tier(src) == "1v1 Challenge Cup" && sys.tier(dest) == "1v1 Challenge Cup") && (clauses % 32 < 16)) {
  5158.         sys.sendMessage(src, "+CCBot: Challenge Cup must be enabled in the challenge window for a CC battle");
  5159.         sys.stopEvent();
  5160.         return;
  5161.     }
  5162.  
  5163.     if (tourmode == 2) {
  5164.         var name1 = sys.name(src);
  5165.         var name2 = sys.name(dest);
  5166.  
  5167.         if (this.isInTourney(name1)) {
  5168.             if (this.isInTourney(name2)) {
  5169.                 if (this.tourOpponent(name1) != name2.toLowerCase()) {
  5170.                     sys.sendMessage(src, "+TourneyBot: This guy isn't your opponent in the tourney.");
  5171.                     sys.stopEvent();
  5172.                     return;
  5173.                 }
  5174.             } else {
  5175.                 sys.sendMessage(src, "+TourneyBot: This guy isn't your opponent in the tourney.");
  5176.                 sys.stopEvent();
  5177.                 return;
  5178.             }
  5179.             if (sys.tier(src) != sys.tier(dest) || !cmp(sys.tier(src),tourtier)) {
  5180.                 sys.sendMessage(src, "+TourneyBot: You must be both in the tier " + tourtier+ " to battle in the tourney.");
  5181.                 sys.stopEvent();
  5182.                 return;
  5183.             }
  5184.             if (tourbattlers.length == 2 && clauses % 8 >= 4) {
  5185.                 sys.sendMessage(src, "+TourneyBot: You must not use \"disallow specs\" in finals.");
  5186.                 sys.stopEvent();
  5187.                 return;
  5188.             }
  5189.         } else {
  5190.             if (this.isInTourney(name2)) {
  5191.                 sys.sendMessage(src, "+TourneyBot: This guy is in the tournament and you are not, so you can't battle him/her.");
  5192.                 sys.stopEvent();
  5193.                 return;
  5194.             }
  5195.         }
  5196.     }
  5197.  
  5198.     /* Challenge Cup Clause */
  5199.     if ( (clauses % 32) >= 16)
  5200.         return;
  5201.  
  5202.  
  5203.     if (sys.tier(src).indexOf("Doubles") != -1 && sys.tier(dest).indexOf("Doubles") != -1 && mode != 1) {
  5204.         sys.sendMessage(src, "+Bot: To fight in doubles, enable doubles in the challenge window!");
  5205.         sys.stopEvent();
  5206.         return;
  5207.     }
  5208.  
  5209.     if (sys.tier(src).indexOf("Triples") != -1 && sys.tier(dest).indexOf("Triples") != -1 && mode != 2) {
  5210.         sys.sendMessage(src, "+Bot: To fight in triples, enable triples in the challenge window!");
  5211.         sys.stopEvent();
  5212.         return;
  5213.     }
  5214.  
  5215.     this.eventMovesCheck(src);
  5216.     this.eventMovesCheck(dest);
  5217.  
  5218.     if (sys.tier(src) == sys.tier(dest)) {
  5219.         var tier = sys.tier(src);
  5220.  
  5221.         this.dreamWorldAbilitiesCheck(src,true);
  5222.         this.dreamWorldAbilitiesCheck(dest,true);
  5223.         this.inconsistentCheck(src, true);
  5224.         this.inconsistentCheck(dest, true);
  5225.         this.littleCupCheck(src, true);
  5226.         this.littleCupCheck(dest, true);
  5227.         this.shanaiAbilityCheck(src, true)
  5228.         this.shanaiAbilityCheck(dest, true);
  5229.     }
  5230. }
  5231.  
  5232. ,
  5233.  
  5234. beforeBattleMatchup : function(src,dest,clauses,rated)
  5235. {
  5236.     if (battlesStopped) {
  5237.         sys.stopEvent();
  5238.         return;
  5239.     }
  5240.  
  5241.     if (tourmode == 2 && (this.isInTourney(sys.name(src)) || this.isInTourney(sys.name(dest)) )) {
  5242.         sys.stopEvent();
  5243.         return;
  5244.     }
  5245.  
  5246.     this.eventMovesCheck(src);
  5247.     this.eventMovesCheck(dest);
  5248.  
  5249.     if (sys.tier(src) == sys.tier(dest)) {
  5250.         var tier = sys.tier(src);
  5251.  
  5252.         this.dreamWorldAbilitiesCheck(src,true);
  5253.         this.dreamWorldAbilitiesCheck(dest,true);
  5254.         this.inconsistentCheck(src, true);
  5255.         this.inconsistentCheck(dest, true);
  5256.         this.littleCupCheck(src, true);
  5257.         this.littleCupCheck(dest, true);
  5258.         this.shanaiAbilityCheck(src, true)
  5259.         this.shanaiAbilityCheck(dest, true);
  5260.     }
  5261.  
  5262.     // alistart
  5263.     if (sys.name(src) == 'Alistair overeeem' || sys.name(src) == 'Alistair overeem'
  5264.      || sys.name(dest) == 'Alistair overeeem' || sys.name(dest) == 'Alistair overeem') {
  5265.         if (rated) {
  5266.         sys.sendAll('*** WARNING ***', staffchannel);
  5267.         sys.sendAll('+WarningBot: Alistar overeem started a RATED match!', staffchannel);
  5268.         sys.sendAll('*** END OF WARNING ***', staffchannel);
  5269.         } else {
  5270.             sys.sendAll('+WarningBot: Alistar overeem started a random match!', staffchannel);
  5271.         }
  5272.     }
  5273. }
  5274. ,
  5275.  
  5276. eventMovesCheck : function(src)
  5277. {
  5278.     for (var i = 0; i < 6; i++) {
  5279.         var poke = sys.teamPoke(src, i);
  5280.         if (poke in pokeNatures) {
  5281.             for (x in pokeNatures[poke]) {
  5282.                 if (sys.hasTeamPokeMove(src, i, x) && sys.teamPokeNature(src, i) != pokeNatures[poke][x])
  5283.                 {
  5284.                     sys.sendMessage(src, "+CheckBot: " + sys.pokemon(poke) + " with " + sys.move(x) + " must be a " + sys.nature(pokeNatures[poke][x]) + " nature. Change it in the teambuilder.");
  5285.                     sys.stopEvent();
  5286.                     sys.changePokeNum(src, i, 0);
  5287.                 }
  5288.  
  5289.             }
  5290.         }
  5291.     }
  5292. }
  5293. ,
  5294. littleCupCheck : function(src, se) {
  5295.  if (["LC Wifi", "LC Ubers Wifi"].indexOf(sys.tier(src)) == -1) {
  5296.     return; // only care about these tiers
  5297.  }
  5298.  for (var i = 0; i < 6; i++) {
  5299.         var x = sys.teamPoke(src, i);
  5300.         if (x != 0 && sys.hasDreamWorldAbility(src, i) && lcpokemons.indexOf(x) != -1 ) {
  5301.             if (se) {
  5302.                     sys.sendMessage(src, "+CheckBot: " + sys.pokemon(x) + " is not allowed with a Dream World ability in this tier. Change it in the teambuilder.");
  5303.                     }
  5304.  
  5305.             if (sys.tier(src) == "LC Wifi" && sys.hasLegalTeamForTier(src, "LC Dream World") || sys.tier(src) == "LC Ubers Wifi" && sys.hasLegalTeamForTier(src, "Dream World")) {
  5306.                 sys.changeTier(src, "LC Dream World");
  5307.             }else {
  5308.                 if (se)
  5309.                     sys.changePokeNum(src, i, 0);
  5310.  
  5311.             }
  5312.             if (se)
  5313.                 sys.stopEvent();
  5314.         }
  5315.     }
  5316. }
  5317. ,
  5318. dreamWorldAbilitiesCheck : function(src, se) {
  5319.     if (sys.gen(src) < 5)
  5320.         return;
  5321.  
  5322.     if (["Dream World", "Dream World Ubers", "LC Dream World", "Monotype", "Dream World UU", "Dream World LU", "Clear Skies", "Challenge Cup" , "Uber Triples", "OU Triples", "Uber Doubles", "OU Doubles", "Shanai Cup", "Shanai Cup 1.5", "Shanai Cup STAT"].indexOf(sys.tier(src)) != -1) {
  5323.         return; // don't care about these tiers
  5324.     }
  5325.  
  5326.     for (var i = 0; i < 6; i++) {
  5327.         var x = sys.teamPoke(src, i);
  5328.         if (x != 0 && sys.hasDreamWorldAbility(src, i) && (!(x in dwpokemons) || (breedingpokemons.indexOf(x) != -1 && sys.compatibleAsDreamWorldEvent(src, i) != true))) {
  5329.             if (se) {
  5330.                 if (!(x in dwpokemons))
  5331.                     sys.sendMessage(src, "+CheckBot: " + sys.pokemon(x) + " is not allowed with a Dream World ability in this tier. Change it in the teambuilder.");
  5332.                 else
  5333.                     sys.sendMessage(src, "+CheckBot: " + sys.pokemon(x) + " has to be Male and have no egg moves with its Dream World ability in  " + sys.tier(src) + " tier. Change it in the teambuilder.");
  5334.             }
  5335.             if (sys.tier(src) == "Wifi" && sys.hasLegalTeamForTier(src, "Dream World")) {
  5336.                 sys.changeTier(src, "Dream World");
  5337.             } else if (sys.tier(src) == "Wifi" && sys.hasLegalTeamForTier(src, "Dream World Ubers")) {
  5338.                 sys.changeTier(src, "Dream World Ubers");
  5339.             } else if (sys.tier(src) == "Wifi Ubers") {
  5340.                 sys.changeTier(src, "Dream World Ubers");
  5341.             }
  5342.             else if (sys.tier(src) == "1v1 Gen 5" && sys.hasLegalTeamForTier(src, "Dream World")) {
  5343.                 sys.changeTier(src, "Dream World");
  5344.             }
  5345.             else if (sys.tier(src) == "1v1 Gen 5" && sys.hasLegalTeamForTier(src, "Dream World Ubers")) {
  5346.                 sys.changeTier(src, "Dream World Ubers");
  5347.             }
  5348.             else if (sys.tier(src) == "Wifi UU" && sys.hasLegalTeamForTier(src, "Dream World UU")) {
  5349.                 sys.changeTier(src, "Dream World UU");
  5350.             } else if (sys.tier(src) == "Wifi LU" && sys.hasLegalTeamForTier(src, "Dream World LU")) {
  5351.                 sys.changeTier(src, "Dream World LU");
  5352.             }
  5353.             else if (sys.tier(src) == "LC Wifi" && sys.hasLegalTeamForTier(src, "LC Wifi") || sys.tier(src) == "LC Ubers Wifi" && sys.hasLegalTeamForTier(src, "LC Ubers Wifi")) {
  5354.                 sys.changeTier(src, "LC Dream World");
  5355.             }else {
  5356.                 if (se)
  5357.                     sys.changePokeNum(src, i, 0);
  5358.  
  5359.             }
  5360.             if (se)
  5361.                 sys.stopEvent();
  5362.         }
  5363.     }
  5364. }
  5365. ,
  5366.  
  5367. inconsistentCheck : function(src, se) {
  5368.     if (["Dream World", "Dream World UU", "Dream World LU", "Wifi", "Wifi UU", "Wifi LU", "LC Wifi", "LC Dream World", "Wifi Ubers", "Dream World Ubers", "Clear Skies", "Monotype"].indexOf(sys.tier(src)) == -1) {
  5369.         return; // only care about these tiers
  5370.     }
  5371.     for (var i = 0; i < 6; i++) {
  5372.         var x = sys.teamPoke(src, i);
  5373.  
  5374.         if (x != 0 && inpokemons.indexOf(x) != -1 && sys.hasDreamWorldAbility(src, i)) {
  5375.             if (se)
  5376.                 sys.sendMessage(src, "+CheckBot: " + sys.pokemon(x) + " is not allowed with Moody in this tier. Change it in the teambuilder.");
  5377.                 sys.changeTier(src, "Challenge Cup");
  5378.             if (se)
  5379.                 sys.stopEvent();
  5380.         }
  5381.     }
  5382. }
  5383. ,
  5384. weatherlesstiercheck : function(src, tier) {
  5385.     if (!tier) tier = sys.tier(src);
  5386.     if (tier != "Clear Skies") return;
  5387.     for (var i = 0; i < 6; i++){
  5388.         ability = sys.ability(sys.teamPokeAbility(src, i))
  5389.         if(ability.toLowerCase() == "drizzle" || ability.toLowerCase() == "drought" || ability.toLowerCase() == "snow warning" || ability.toLowerCase() == "sand stream") {
  5390.             sys.sendMessage(src, "+Bot: Your team has a pokémon with the ability: " + ability + ", please remove before entering this tier.");
  5391.             if(sys.hasLegalTeamForTier(src, "Dream World")) {
  5392.                 if(sys.hasLegalTeamForTier(src,"Wifi")) {
  5393.                     sys.changeTier(src, "Wifi");
  5394.                     sys.stopEvent()
  5395.                     return;
  5396.                 }
  5397.                 sys.changeTier(src, "Dream World");
  5398.                 sys.stopEvent()
  5399.                 return;
  5400.             }
  5401.             if(sys.hasLegalTeamForTier(src,"Wifi Ubers")) {
  5402.                 sys.changeTier(src, "Wifi Ubers");
  5403.                 sys.stopEvent()
  5404.                 return;
  5405.             }
  5406.             sys.changeTier(src, "Dream World Ubers");
  5407.             sys.stopEvent()
  5408.             return;
  5409.         }
  5410.     }
  5411. } /* end of weatherlesstiercheck */
  5412. ,
  5413. // Will escape "&", ">", and "<" symbols for HTML output.
  5414. html_escape : function(text)
  5415. {
  5416.     var m = text.toString();
  5417.     if (m.length > 0) {
  5418.         var amp = "&am" + "p;";
  5419.         var lt = "&l" + "t;";
  5420.         var gt = "&g" + "t;";
  5421.         return m.replace(/&/g, amp).replace(/\</g, lt).replace(/\>/g, gt);
  5422.     }else{
  5423.         return "";
  5424.     }
  5425. }
  5426. ,
  5427. monotypecheck : function(src, tier) {
  5428.     if (!tier) tier = sys.tier(src);
  5429.     if (tier != "Monotype") return; // Only interested in monotype
  5430.     var TypeA = sys.pokeType1(sys.teamPoke(src, 0), 5);
  5431.     var TypeB = sys.pokeType2(sys.teamPoke(src, 0), 5);
  5432.     var k;
  5433.     var checkType;
  5434.     for (var i = 1; i < 6 ; i++) {
  5435.         var temptypeA = sys.pokeType1(sys.teamPoke(src, i), 5);
  5436.         var temptypeB = sys.pokeType2(sys.teamPoke(src, i), 5);
  5437.         if (sys.teamPoke(src, i) == 0){
  5438.             temptypeA = TypeA;
  5439.         }
  5440.         if(checkType != undefined) {
  5441.             k=3;
  5442.         }
  5443.         if(i==1){
  5444.             k=1;
  5445.         }
  5446.         if(TypeB !=0){
  5447.             if(temptypeA == TypeA && temptypeB == TypeB && k == 1 || temptypeA == TypeB && temptypeB == TypeA && k == 1){
  5448.                 k=2;
  5449.             }
  5450.         }
  5451.         if (temptypeA == TypeA && k == 1 || temptypeB == TypeA && k == 1) {
  5452.             checkType=TypeA;
  5453.         }
  5454.         if (temptypeA == TypeB && k == 1 || temptypeB == TypeB && k == 1) {
  5455.             checkType=TypeB;
  5456.         }
  5457.         if(i>1 && k == 2) {
  5458.             k=1;
  5459.             if(temptypeA == TypeA && temptypeB == TypeB && k == 1 || temptypeA == TypeB && temptypeB == TypeA && k == 1){
  5460.                 k=2;
  5461.             }
  5462.             if (temptypeA == TypeA && k == 1 || temptypeB == TypeA && k == 1) {
  5463.                 checkType=TypeA;
  5464.             }
  5465.             if (temptypeA == TypeB && k == 1 || temptypeB == TypeB && k == 1) {
  5466.                 checkType=TypeB;
  5467.             }
  5468.         }
  5469.         if(k==3){
  5470.  
  5471.             if(temptypeA != checkType && temptypeB != checkType) {
  5472.  
  5473.                 sys.sendMessage(src, "+Bot: Team not Monotype as " + sys.pokemon(sys.teamPoke(src, i)) + " is not " + sys.type(checkType) + "!");
  5474.                 if(sys.hasLegalTeamForTier(src, "Dream World")) {
  5475.                     if(sys.hasLegalTeamForTier(src,"Wifi")) {
  5476.                         sys.changeTier(src, "Wifi");
  5477.                         sys.stopEvent()
  5478.                         return;
  5479.                     }
  5480.                     sys.changeTier(src, "Dream World");
  5481.                     sys.stopEvent()
  5482.                     return;
  5483.                 }
  5484.                 if(sys.hasLegalTeamForTier(src,"Wifi Ubers")) {
  5485.                     sys.changeTier(src, "Wifi Ubers");
  5486.                     sys.stopEvent()
  5487.                     return;
  5488.                 }
  5489.                 sys.changeTier(src, "Dream World Ubers");
  5490.                 sys.stopEvent()
  5491.                 return;
  5492.             }
  5493.         }
  5494.  
  5495.         if(k==1) {
  5496.             if (temptypeA != TypeA && temptypeB != TypeA && temptypeA != TypeB && temptypeB != TypeB) {
  5497.                 sys.sendMessage(src, "+Bot: Team not Monotype as " + sys.pokemon(sys.teamPoke(src, i)) + " does not share a type with " + sys.pokemon(sys.teamPoke(src, 0)) + "!")
  5498.  
  5499.                 if(sys.hasLegalTeamForTier(src, "Dream World")) {
  5500.                     if(sys.hasLegalTeamForTier(src,"Wifi")) {
  5501.                         sys.changeTier(src, "Wifi");
  5502.                         sys.stopEvent()
  5503.                         return;
  5504.                     }
  5505.                     sys.changeTier(src, "Dream World");
  5506.                     sys.stopEvent()
  5507.                     return;
  5508.                 }
  5509.                 if(sys.hasLegalTeamForTier(src,"Wifi Ubers")) {
  5510.                     sys.changeTier(src, "Wifi Ubers");
  5511.                     sys.stopEvent()
  5512.                     return;
  5513.                 }
  5514.                 sys.changeTier(src, "Dream World Ubers");
  5515.                 sys.stopEvent()
  5516.                 return;
  5517.             }
  5518.  
  5519.         }
  5520.     }
  5521. }
  5522.  
  5523. ,
  5524.  
  5525. shanaiAbilityCheck : function(src, se) {
  5526.     var tier = sys.tier(sys.tier(src));
  5527.     if (["Shanai Cup", "Shanai Cup 1.5", "Shanai Cup STAT"].indexOf(tier) == -1) {
  5528.         return; // only intereted in shanai battling
  5529.     }
  5530.     sys.sendAll(src);
  5531.     var bannedAbilities = {
  5532.         'treecko': ['overgrow'],
  5533.         'chimchar': ['blaze'],
  5534.         'totodile': ['torrent'],
  5535.         'spearow': ['sniper'],
  5536.         'skorupi': ['battle armor', 'sniper'],
  5537.         'spoink': ['thick fat'],
  5538.         'golett': ['iron fist'],
  5539.         'magnemite': ['magnet pull', 'analytic'],
  5540.         'electrike': ['static', 'lightningrod'],
  5541.         'nosepass': ['sturdy', 'magnet pull'],
  5542.         'axew': ['rivalry'],
  5543.         'croagunk': ['poison touch', 'dry skin'],
  5544.         'cubchoo': ['rattled'],
  5545.         'joltik': ['swarm'],
  5546.         'shroomish': ['effect spore', 'quick feet'],
  5547.         'pidgeotto': ['big pecks'],
  5548.         'karrablast': ['swarm']
  5549.     };
  5550.     for (var i = 0; i < 6; ++i) {
  5551.         var ability = sys.ability(sys.teamPokeAbility(src, i));
  5552.         var lability = ability.toLowerCase();
  5553.         var poke = sys.pokemon(sys.teamPoke(src, i));
  5554.         var lpoke = poke.toLowerCase();
  5555.         //sys.sendMessage(src, "+Bot: you have " + poke + " with " + ability + "." )
  5556.         if (lpoke in bannedAbilities && bannedAbilities[lpoke].indexOf(lability) != -1) {
  5557.             sys.sendMessage(src, "+Bot: " + poke + " is not allowed to have ability " + ability + " in Shanai Cup. Please change it in Teambuilder (You are now in Challenge Cup).")
  5558.             sys.changeTier(src, "Challenge Cup")
  5559.             if (se)
  5560.                 sys.stopEvent();
  5561.             return;
  5562.         }
  5563.     }
  5564. }
  5565.  
  5566. })
  5567.  
  5568.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement