diff --git a/docs/api/modules/cryptowalletrpc.rst b/docs/api/modules/cryptowalletrpc.rst index 502eb64..6d947c9 100644 --- a/docs/api/modules/cryptowalletrpc.rst +++ b/docs/api/modules/cryptowalletrpc.rst @@ -3,6 +3,10 @@ Module capable of operating Bitcoind-style RPC. Provided as a service. +.. note:: This module requires installation of some :doc:`optional dependencies `: + + * bitcoinrpc + Class Reference --------------- diff --git a/docs/api/modules/dogerpc.rst b/docs/api/modules/dogerpc.rst index 3781856..ebef9da 100644 --- a/docs/api/modules/dogerpc.rst +++ b/docs/api/modules/dogerpc.rst @@ -1,7 +1,14 @@ :mod:`DogeRPC` --- A dogecoind RPC service ========================================== -This module provides a service for interacting with dogecoind. +This module provides a service called ``dogerpc`` for interacting with dogecoind. + +.. note:: This module requires installation of some :doc:`optional dependencies `: + + * bitcoinrpc + +A dogecoin daemon is required to use this module. It must be configured to +allow RPC connections. Class Reference --------------- @@ -10,3 +17,5 @@ Class Reference :members: :undoc-members: :show-inheritance: + + diff --git a/docs/api/modules/dogescramble.rst b/docs/api/modules/dogescramble.rst index 7fe0f71..c846df8 100644 --- a/docs/api/modules/dogescramble.rst +++ b/docs/api/modules/dogescramble.rst @@ -2,7 +2,67 @@ ========================================================= This module provides a word scrambling game that rewards winners with small -amounts of Dogecoin +amounts of Dogecoin. Requires a ``dogerpc`` service provider such as +:doc:`DogeRPC `. + +Config +------ + +.. code-block:: json + + { + "hintDelay": 15, + "delayNext": 5, + "maxHints": 5, + "abortAfterNoGuesses": 2, + "categoryduration": 10, + "winAmount": 5, + "decreaseFactor": 0.75 + } + +In addition to the json config above, additional categories of words may be +added by adding additional text files to the DogeScramble data dir. + +.. cmdoption:: hintDelay + + Seconds between hints if the word is not guessed + +.. cmdoption:: delayNext + + Delay in seconds between the end of one round and start of the next + +.. cmdoption:: maxHints + + How many letters will be hinted before the word is thrown away + +.. cmdoption:: abortAfterNoGuesses + + How many rounds may pass with no players guessing. Once this count is + passed, the game is automatically stopped. + +.. cmdoption:: categoryduration + + Number of words used from a category before changing the category + +.. cmdoption:: winAmount + + Amount of dogecoin to send the winner + +.. cmdoption:: decreaseFactor + + For subsequent wins by the same player, the reward will be the previous + reward multiplied times this number + +Commands +-------- + +.. cmdoption:: .scramble + + Start the unscramble game + +.. cmdoption:: .scrambleoff + + Stop the unscramble game Class Reference --------------- diff --git a/docs/api/modules/duckhunt.rst b/docs/api/modules/duckhunt.rst index b8bb8c4..593e1bb 100644 --- a/docs/api/modules/duckhunt.rst +++ b/docs/api/modules/duckhunt.rst @@ -1,7 +1,21 @@ :mod:`DuckHunt` --- Duckhunt game ================================= -An animal hunting IRC game +Example usage: + +.. code-block:: none + + 3:15:06 PM \_o< Quack! + 3:15:08 PM <@dave-irccloud> !shoot + 3:15:08 PM dave-irccloud fires after 1.73 seconds and misses! + 3:15:09 PM <@dave-irccloud> !shoot + 3:15:10 PM dave-irccloud fires after 3.83 seconds and misses! + 3:15:11 PM <@dave-irccloud> !shoot + 3:15:11 PM dave-irccloud bags a 2.63 lb Duck in 4.92 seconds! + 3:15:19 PM <@dave-irccloud> !huntscore + << in pm >> + 3:15:19 PM 0 prime catches, 0 runts, 3 bullets used and 2 misses. + 3:15:20 PM You've shot 1 Ducks for a total weight of 2.63 lbs. Class Reference --------------- diff --git a/docs/api/modules/scramble.rst b/docs/api/modules/scramble.rst index 9bb364c..2d1d417 100644 --- a/docs/api/modules/scramble.rst +++ b/docs/api/modules/scramble.rst @@ -1,5 +1,21 @@ -:mod:`Scramble` --- Module to provide a word scramble game -========================================================== +:mod:`Scramble` --- Word scramble game module +============================================= + +Example usage: + +.. code-block:: none + + 3:04:00 PM <@dave-irccloud> .scrambleon + 3:04:00 PM New word - leppa + 3:04:15 PM Hint: - a____ + 3:04:30 PM Hint: - ap___ + 3:04:32 PM <@dave-irccloud> apple + 3:04:32 PM dave-irccloud guessed the word - apple! dave-irccloud now has 3 points. Next word in 5 seconds. + 3:04:35 PM <@dave-irccloud> .scrambleoff + 3:04:39 PM <@dave-irccloud> .scramble top + 3:04:39 PM Top 1: dave-irccloud: 3 + +Requires a dictionary to pull words from, ``words.txt`` should be placed in: ``./datadir/data/Scramble/`` Class Reference --------------- diff --git a/docs/setup/_setup.rst b/docs/setup/_setup.rst index 5907a3c..efe5586 100644 --- a/docs/setup/_setup.rst +++ b/docs/setup/_setup.rst @@ -1,7 +1,7 @@ Setup Tutorial ============== -Installing and runnig PyIRCBot requires installing the needed dependancies and +Installing and runnig PyIRCBot requires installing the needed dependencies and providing some environmental information about where the bot is being run. Contents: @@ -9,6 +9,6 @@ Contents: .. toctree:: :maxdepth: 8 - dependancies.rst + dependencies.rst initial_config.rst running.rst diff --git a/docs/setup/dependancies.rst b/docs/setup/dependencies.rst similarity index 69% rename from docs/setup/dependancies.rst rename to docs/setup/dependencies.rst index 859e39a..8a626fa 100644 --- a/docs/setup/dependancies.rst +++ b/docs/setup/dependencies.rst @@ -1,5 +1,5 @@ ************ -Dependancies +Dependencies ************ PyIRCBot is designed to run on Python 3, and is usually tested with 3.4. Python @@ -23,3 +23,10 @@ them. - **bitcoinrpc** - https://github.com/jgarzik/python-bitcoinrpc - **pymysql** - https://github.com/dpedu/MySQL-for-Python-3 (needs \ libmysqlclient-dev on your system) + +At time of writing there is a bug that will prevent the bitcoinrpc module from +working with Python 3. When pull `#55`_ is merged, the bug will be fixed. +Until then, using my `fork`_ is recommended. + +.. _#55: https://github.com/jgarzik/python-bitcoinrpc/pull/55 +.. _fork: https://github.com/dpedu/python-bitcoinrpc diff --git a/examples/data/config/BitcoinPrice.json b/examples/data/config/BitcoinPrice.json new file mode 100644 index 0000000..f1b46f3 --- /dev/null +++ b/examples/data/config/BitcoinPrice.json @@ -0,0 +1,3 @@ +{ + "cache": 300 +} \ No newline at end of file diff --git a/examples/data/config/BitcoinPrice.yml b/examples/data/config/BitcoinPrice.yml deleted file mode 100644 index d7dc8a8..0000000 --- a/examples/data/config/BitcoinPrice.yml +++ /dev/null @@ -1 +0,0 @@ -cache: 300 \ No newline at end of file diff --git a/examples/data/config/Calc.json b/examples/data/config/Calc.json new file mode 100644 index 0000000..8f113d9 --- /dev/null +++ b/examples/data/config/Calc.json @@ -0,0 +1,16 @@ +{ + "allowDelete": true, + "delaySubmit": 0, + "delayCalc": 0, + "delayCalcSpecific": 0, + "delayMatch": 0, + "cmd_calc": [ + ".calc", + "calc", + ".quote" + ], + "cmd_match": [ + ".match", + "match" + ] +} \ No newline at end of file diff --git a/examples/data/config/Calc.yml b/examples/data/config/Calc.yml deleted file mode 100644 index 1bdb3cc..0000000 --- a/examples/data/config/Calc.yml +++ /dev/null @@ -1,12 +0,0 @@ -allowDelete: true -delaySubmit: 0 -delayCalc: 0 -delayCalcSpecific: 0 -delayMatch: 0 -cmd_calc: - - .calc - - calc - - .quote -cmd_match: - - .match - - match \ No newline at end of file diff --git a/examples/data/config/CryptoWalletRPC.json b/examples/data/config/CryptoWalletRPC.json new file mode 100644 index 0000000..ab74cea --- /dev/null +++ b/examples/data/config/CryptoWalletRPC.json @@ -0,0 +1,26 @@ +{ + "types": { + "LTC": { + "name": "Litecoin", + "abbr": "LTC", + "host": "127.0.0.1", + "username": "user", + "password": "pass", + "port": 12893, + "precision": 8, + "reserve": 0.01, + "link": "https://litecoin.org/" + }, + "BTC": { + "name": "Bitcoin", + "abbr": "BTC", + "host": "127.0.0.1", + "username": "user", + "password": "pass", + "port": 48191, + "precision": 8, + "reserve": 0.001, + "link": "http://bitcoin.org/" + } + } +} \ No newline at end of file diff --git a/examples/data/config/CryptoWalletRPC.yml b/examples/data/config/CryptoWalletRPC.yml deleted file mode 100644 index 54009d6..0000000 --- a/examples/data/config/CryptoWalletRPC.yml +++ /dev/null @@ -1,21 +0,0 @@ -types: - LTC: - name: Litecoin - abbr: LTC - host: 127.0.0.1 - username: user - password: pass - port: 12893 - precision: 8 - reserve: .01 - link: https://litecoin.org/ - BTC: - name: Bitcoin - abbr: BTC - host: 127.0.0.1 - username: user - password: pass - port: 48191 - precision: 8 - reserve: .001 - link: http://bitcoin.org/ \ No newline at end of file diff --git a/examples/data/config/DogeDice.json b/examples/data/config/DogeDice.json new file mode 100644 index 0000000..e548ee4 --- /dev/null +++ b/examples/data/config/DogeDice.json @@ -0,0 +1,9 @@ +{ + "minBet": 0.01, + "lobbyIdleSeconds": 15, + "channelWhitelistOn": true, + "channelWhitelist": [ + "dogegamestest", + "test" + ] +} \ No newline at end of file diff --git a/examples/data/config/DogeDice.yml b/examples/data/config/DogeDice.yml deleted file mode 100644 index 38b7305..0000000 --- a/examples/data/config/DogeDice.yml +++ /dev/null @@ -1,6 +0,0 @@ -minBet: .01 -lobbyIdleSeconds: 15 -channelWhitelistOn: True -channelWhitelist: - - dogegamestest - - test \ No newline at end of file diff --git a/examples/data/config/DogeRPC.json b/examples/data/config/DogeRPC.json new file mode 100644 index 0000000..8510981 --- /dev/null +++ b/examples/data/config/DogeRPC.json @@ -0,0 +1,6 @@ +{ + "host": "127.0.0.1", + "username": "wallet_rpc_user", + "password": "wallet_rpc_pass", + "port": 22555 +} \ No newline at end of file diff --git a/examples/data/config/DogeRPC.yml b/examples/data/config/DogeRPC.yml deleted file mode 100644 index 4264dfa..0000000 --- a/examples/data/config/DogeRPC.yml +++ /dev/null @@ -1,4 +0,0 @@ -host: 127.0.0.1 -username: wallet_rpc_user -password: wallet_rpc_pass -port: 22555 \ No newline at end of file diff --git a/examples/data/config/DogeScramble.json b/examples/data/config/DogeScramble.json new file mode 100644 index 0000000..eb32f1b --- /dev/null +++ b/examples/data/config/DogeScramble.json @@ -0,0 +1,9 @@ +{ + "hintDelay": 15, + "delayNext": 5, + "maxHints": 5, + "abortAfterNoGuesses": 2, + "categoryduration": 10, + "winAmount": 5, + "decreaseFactor": 0.75 +} diff --git a/examples/data/config/DuckHunt.json b/examples/data/config/DuckHunt.json new file mode 100644 index 0000000..00de581 --- /dev/null +++ b/examples/data/config/DuckHunt.json @@ -0,0 +1,17 @@ +{ + "delayMin": 5, + "delayMax": 15, + "missChance": 50, + "animal": "\\_o< Quack!", + "animalSpecies": "Duck", + "animalSpeciesPlural": "Ducks", + "animalNameMale": "Duck", + "animalNameFemale": "Duck", + "runtChance": 10, + "primeChance": 5, + "weightMin": 2.5, + "weightMax": 3.5, + "weightRunt": 1.5, + "weightFat": 5, + "activeChannel": "##xmopx" +} \ No newline at end of file diff --git a/examples/data/config/DuckHunt.yml b/examples/data/config/DuckHunt.yml deleted file mode 100644 index 0eabcdf..0000000 --- a/examples/data/config/DuckHunt.yml +++ /dev/null @@ -1,15 +0,0 @@ -delayMin: 5 -delayMax: 15 -missChance: 50 -animal: "\\_o< Quack!" -animalSpecies: "Duck" -animalSpeciesPlural: "Ducks" -animalNameMale: "Duck" -animalNameFemale: "Duck" -runtChance: 10 -primeChance: 5 -weightMin: 2.5 -weightMax: 3.5 -weightRunt: 1.5 -weightFat: 5.0 -activeChannel: "#xmopx" diff --git a/examples/data/config/GameBase.json b/examples/data/config/GameBase.json new file mode 100644 index 0000000..c8f83ff --- /dev/null +++ b/examples/data/config/GameBase.json @@ -0,0 +1,6 @@ +{ + "channelWhitelistOn": true, + "channelWhitelist": [ + "test" + ] +} \ No newline at end of file diff --git a/examples/data/config/GameBase.yml b/examples/data/config/GameBase.yml deleted file mode 100644 index 9f93ded..0000000 --- a/examples/data/config/GameBase.yml +++ /dev/null @@ -1,3 +0,0 @@ -channelWhitelistOn: True -channelWhitelist: - - test \ No newline at end of file diff --git a/examples/data/config/Inventory.json b/examples/data/config/Inventory.json new file mode 100644 index 0000000..ae25066 --- /dev/null +++ b/examples/data/config/Inventory.json @@ -0,0 +1,13 @@ +{ + "limit": 25, + "recv_msg": "Oh, thanks, I'll keep %(adjective)s%(item)s safe", + "inv_msg": "\u0000\u0001ACTION is carrying %(itemlist)s\u0000\u0001", + "swap_msg": "\u0000\u0001ACTION takes %(adjective)s%(recv_item)s but drops %(drop_item)s\u0000\u0010", + "dupe_msg": "No thanks, I've already got %(item)s", + "adjectives": [ + "some", + "the", + "an", + "these" + ] +} \ No newline at end of file diff --git a/examples/data/config/Inventory.yml b/examples/data/config/Inventory.yml deleted file mode 100644 index 2599f58..0000000 --- a/examples/data/config/Inventory.yml +++ /dev/null @@ -1,10 +0,0 @@ -limit: 25 -recv_msg: "Oh, thanks, I'll keep %(adjective)s%(item)s safe" -inv_msg: "\x01ACTION is carrying %(itemlist)s\x01" -swap_msg: "\x01ACTION takes %(adjective)s%(recv_item)s but drops %(drop_item)s\x10" -dupe_msg: "No thanks, I've already got %(item)s" -adjectives: - - some - - the - - an - - these \ No newline at end of file diff --git a/examples/data/config/MySQL.json b/examples/data/config/MySQL.json new file mode 100644 index 0000000..7c986cd --- /dev/null +++ b/examples/data/config/MySQL.json @@ -0,0 +1,6 @@ +{ + "host": "localhost", + "username": "root", + "password": "root", + "database": "pyircbot" +} \ No newline at end of file diff --git a/examples/data/config/MySQL.yml b/examples/data/config/MySQL.yml deleted file mode 100644 index 37d9ca0..0000000 --- a/examples/data/config/MySQL.yml +++ /dev/null @@ -1,4 +0,0 @@ -host: 10.0.3.14 -username: root -password: root -database: pyircbot_dev diff --git a/examples/data/config/NFLLive.json b/examples/data/config/NFLLive.json new file mode 100644 index 0000000..3dd144d --- /dev/null +++ b/examples/data/config/NFLLive.json @@ -0,0 +1,3 @@ +{ + "cache": 90 +} \ No newline at end of file diff --git a/examples/data/config/NFLLive.yml b/examples/data/config/NFLLive.yml deleted file mode 100644 index f4f0754..0000000 --- a/examples/data/config/NFLLive.yml +++ /dev/null @@ -1 +0,0 @@ -cache: 90 \ No newline at end of file diff --git a/examples/data/config/RandQuote.json b/examples/data/config/RandQuote.json new file mode 100644 index 0000000..5513452 --- /dev/null +++ b/examples/data/config/RandQuote.json @@ -0,0 +1,3 @@ +{ + "limit": 10000 +} \ No newline at end of file diff --git a/examples/data/config/RandQuote.yml b/examples/data/config/RandQuote.yml deleted file mode 100644 index c8b8ec5..0000000 --- a/examples/data/config/RandQuote.yml +++ /dev/null @@ -1 +0,0 @@ -limit: 10000 \ No newline at end of file diff --git a/examples/data/config/Remind.json b/examples/data/config/Remind.json new file mode 100644 index 0000000..32e9088 --- /dev/null +++ b/examples/data/config/Remind.json @@ -0,0 +1,4 @@ +{ + "mytimezone": "US/Pacific", + "precision": 5 +} \ No newline at end of file diff --git a/examples/data/config/Remind.yml b/examples/data/config/Remind.yml deleted file mode 100644 index 4e8f421..0000000 --- a/examples/data/config/Remind.yml +++ /dev/null @@ -1,2 +0,0 @@ -mytimezone: US/Pacific -precision: 5 \ No newline at end of file diff --git a/examples/data/config/Scramble.json b/examples/data/config/Scramble.json new file mode 100644 index 0000000..f1b213d --- /dev/null +++ b/examples/data/config/Scramble.json @@ -0,0 +1,6 @@ +{ + "hintDelay": 15, + "delayNext": 5, + "maxHints": 5, + "abortAfterNoGuesses": 5 +} \ No newline at end of file diff --git a/examples/data/config/Scramble.yml b/examples/data/config/Scramble.yml deleted file mode 100644 index acb369b..0000000 --- a/examples/data/config/Scramble.yml +++ /dev/null @@ -1,4 +0,0 @@ -hintDelay: 15 -delayNext: 5 -maxHints: 5 -abortAfterNoGuesses: 5 \ No newline at end of file diff --git a/examples/data/config/Seen.json b/examples/data/config/Seen.json new file mode 100644 index 0000000..23f620c --- /dev/null +++ b/examples/data/config/Seen.json @@ -0,0 +1,4 @@ +{ + "timezone": "EST", + "add_hours": 0 +} \ No newline at end of file diff --git a/examples/data/config/Seen.yml b/examples/data/config/Seen.yml deleted file mode 100644 index 41fa4e3..0000000 --- a/examples/data/config/Seen.yml +++ /dev/null @@ -1,2 +0,0 @@ -timezone: EST -add_hours: 0 \ No newline at end of file diff --git a/examples/data/config/Services.json b/examples/data/config/Services.json index 425655a..3b735ad 100644 --- a/examples/data/config/Services.json +++ b/examples/data/config/Services.json @@ -19,7 +19,7 @@ "ghost_cmd":"ghost %(nick)s %(password)s" }, "channels":[ - "#xmopx" + "##xmopx" ], "privatechannels":{ "to":"chanserv", diff --git a/examples/data/config/Tell.json b/examples/data/config/Tell.json new file mode 100644 index 0000000..cecf525 --- /dev/null +++ b/examples/data/config/Tell.json @@ -0,0 +1,4 @@ +{ + "max": 10, + "maxage": 2678400 +} \ No newline at end of file diff --git a/examples/data/config/Tell.yml b/examples/data/config/Tell.yml deleted file mode 100644 index 2cf8599..0000000 --- a/examples/data/config/Tell.yml +++ /dev/null @@ -1,2 +0,0 @@ -max: 10 -maxage: 2678400 \ No newline at end of file diff --git a/examples/data/config/Weather.json b/examples/data/config/Weather.json new file mode 100644 index 0000000..a4a4e88 --- /dev/null +++ b/examples/data/config/Weather.json @@ -0,0 +1,4 @@ +{ + "apikey": "get an API key at: http://www.wunderground.com/weather/api/ (choose 'anvil')", + "defaultUnit": "c" +} \ No newline at end of file diff --git a/examples/data/config/Weather.yml b/examples/data/config/Weather.yml deleted file mode 100644 index 0a23982..0000000 --- a/examples/data/config/Weather.yml +++ /dev/null @@ -1,2 +0,0 @@ -apikey: "get an API key at: http://www.wunderground.com/weather/api/ (choose \"anvil\")" -defaultUnit: c \ No newline at end of file diff --git a/examples/data/data/DogeScramble/minecraft_words.txt b/examples/data/data/DogeScramble/minecraft_words.txt new file mode 100644 index 0000000..3241431 --- /dev/null +++ b/examples/data/data/DogeScramble/minecraft_words.txt @@ -0,0 +1,313 @@ +Air +Stone +Grass +Dirt +Cobblestone +Wooden Plank +Sapling +Redwood Sapling +Birch Sapling +Bedrock +Water +Lava +Sand +Gravel +Gold Ore +Iron Ore +Coal Ore +Wood +Redwood +Birchwood +Leaves +Redwood Leaves +Birchwood Leaves +Sponge +Glass +Lapis Lazuli Ore +Lapis Lazuli Block +Dispenser +Sandstone +Note Block +Bed Block +Powered Rail +Detector Rail +Sticky Piston +Web +Dead Shrub +Tall Grass +Live Shrub +Dead Shrub +Piston +Piston Head +White Wool +Orange Wool +Magenta Wool +Light Blue Wool +Yellow Wool +Light Green Wool +Pink Wool +Gray Wool +Light Gray Wool +Cyan Wool +Purple Wool +Blue Wool +Brown Wool +Dark Green Wool +Red Wool +Black Wool +Dandelion +Rose +Brown Mushroom +Red Mushroom +Gold Block +Iron Block +Double Stone Slab +Double Sandstone Slab +Double Wooden Slab +Double Cobblestone Slab +Double Brick Slab +Double Stone Brick Slab +Stone Slab +Sandstone Slab +Wooden Slab +Cobblestone Slab +Brick Slab +Stone Brick Slab +Brick +TNT +Bookshelf +Mossy Cobblestone +Obsidian +Torch +Fire +Monster Spawner +Wooden Stairs +Chest +Redstone Wire +Diamond Ore +Diamond Block +Workbench +Wheat Crops +Soil +Furnace +Sign Post +Wooden Door +Ladder +Rails +Cobblestone Stairs +Wall Sign +Lever +Stone Pressure Plate +Iron Door Block +Wooden Pressure Plate +Redstone Ore +Redstone Torch +Stone Button +Snow +Ice +Snow Block +Cactus +Clay +Sugar Cane +Jukebox +Fence +Pumpkin +Netherrack +Soul Sand +Glowstone +Portal +Jack-O-Lantern +Cake Block +Redstone Repeater Block +Locked Chest +Trapdoor +Stone (Silverfish) +Stone Brick +Mossy Stone Brick +Cracked Stone Brick +Red Mushroom Cap +Brown Mushroom Cap +Iron Bars +Glass Pane +Melon Block +Pumpkin Stem +Melon Stem +Vines +Fence Gate +Brick Stairs +Stone Brick Stairs +Mycelium +Lily Pad +Nether Brick +Nether Brick Fence +Nether Brick Stairs +Nether Wart +Iron Shovel +Iron Pickaxe +Iron Axe +Flint and Steel +Apple +Bow +Arrow +Coal +Charcoal +Diamond +Iron Ingot +Gold Ingot +Iron Sword +Wooden Sword +Wooden Shovel +Wooden Pickaxe +Wooden Axe +Stone Sword +Stone Shovel +Stone Pickaxe +Stone Axe +Diamond Sword +Diamond Shovel +Diamond Pickaxe +Diamond Axe +Stick +Bowl +Mushroom Soup +Gold Sword +Gold Shovel +Gold Pickaxe +Gold Axe +String +Feather +Sulphur +Wooden Hoe +Stone Hoe +Iron Hoe +Diamond Hoe +Gold Hoe +Wheat Seeds +Wheat +Bread +Leather Helmet +Leather Chestplate +Leather Leggings +Leather Boots +Chainmail Helmet +Chainmail Chestplate +Chainmail Leggings +Chainmail Boots +Iron Helmet +Iron Chestplate +Iron Leggings +Iron Boots +Diamond Helmet +Diamond Chestplate +Diamond Leggings +Diamond Boots +Gold Helmet +Gold Chestplate +Gold Leggings +Gold Boots +Flint +Raw Porkchop +Cooked Porkchop +Painting +Golden Apple +Sign +Wooden Door +Bucket +Water Bucket +Lava Bucket +Minecart +Saddle +Iron Door +Redstone +Snowball +Boat +Leather +Milk Bucket +Clay Brick +Clay Balls +Sugarcane +Paper +Book +Slimeball +Storage Minecart +Powered Minecart +Egg +Compass +Fishing Rod +Clock +Glowstone Dust +Raw Fish +Cooked Fish +Ink Sack +Rose Red +Cactus Green +Coco Beans +Lapis Lazuli +Purple Dye +Cyan Dye +Light Gray Dye +Gray Dye +Pink Dye +Lime Dye +Dandelion Yellow +Light Blue Dye +Magenta Dye +Orange Dye +Bone Meal +Bone +Sugar +Cake +Bed +Redstone Repeater +Cookie +Map +Shears +Melon +Pumpkin Seeds +Melon Seeds +Raw Beef +Steak +Raw Chicken +Cooked Chicken +Rotten Flesh +Ender Pearl +Blaze Rod +Ghast Tear +Gold Nugget +Nether Wart Seeds +Potion +Glass Bottle +Spider Eye +Fermented Spider Eye +Blaze Powder +Magma Cream +Gold Music Disc +Green Music Disc +Chicken +Cow +Mooshroom +Ocelot +Pig +Sheep +Squid +Villager +Enderman +Wolf +Zombie Pigman +Wolf +Ocelot +Blaze +Cave Spider +Creeper +Ghast +Magma Cube +Silverfish +Skeleton +Slime +Spider +Spider Jockey +Zombie +Snow Golem +Iron Golem +Ender Dragon +Rana \ No newline at end of file diff --git a/pyircbot/modulebase.py b/pyircbot/modulebase.py index 8c49f0d..29c608a 100644 --- a/pyircbot/modulebase.py +++ b/pyircbot/modulebase.py @@ -34,7 +34,7 @@ class ModuleBase: here""" self.config={} - """Configuration dictionary. Autoloaded from `%(datadir)s/%(modulename)s.yml`""" + """Configuration dictionary. Autoloaded from `%(datadir)s/%(modulename)s.json`""" self.log = logging.getLogger("Module.%s" % self.moduleName) """Logger object for this module""" @@ -57,7 +57,7 @@ class ModuleBase: pass def getConfigPath(self): - """Returns the absolute path of this module's YML config file""" + """Returns the absolute path of this module's json config file""" return self.bot.getConfigPath(self.moduleName) def getFilePath(self, f=None): diff --git a/pyircbot/modules/CardsAgainstHumanity.py b/pyircbot/modules/CardsAgainstHumanity.py old mode 100644 new mode 100755 index b6df955..fb44cdd --- a/pyircbot/modules/CardsAgainstHumanity.py +++ b/pyircbot/modules/CardsAgainstHumanity.py @@ -6,7 +6,6 @@ """ from pyircbot.modulebase import ModuleBase,ModuleHook -import yaml import os import time from threading import Timer @@ -14,243 +13,242 @@ from operator import itemgetter from random import choice class CardsAgainstHumanity(ModuleBase): - def __init__(self, bot, moduleName): - # init the base module - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[ModuleHook("PRIVMSG", self.scramble)] - self.loadConfig() - - # Dictionary - self.whitesFile = open(self.getFilePath("answers.txt"),'r') - self.blacksFile = open(self.getFilePath("questions.txt"),'r') - self.whites = [line.rstrip() for line in self.whitesFile] - self.blacks = [line.rstrip() for line in self.blacksFile] - self.currentBlack = "" - self.whitesFile.close() - self.blacksFile.close() - self.log.info("CAH: Loaded."+str(len(self.whites))+" White Cards "+str(len(self.blacks))+" Black Cards") - # Per channel games - self.games = {} - - - def scramble(self, args, prefix, trailing): - channel = args[0] - if channel[0] == "#": - if not channel in self.games: - self.games[channel]=cardsGame(self, channel,self.whites,self.blacks) - self.games[channel].stuff(args, prefix, trailing) - - - def ondisable(self): - self.log.info("CAH: Unload requested, ending games...") - # for game in self.games: - # self.games[game].gameover() + def __init__(self, bot, moduleName): + # init the base module + ModuleBase.__init__(self, bot, moduleName); + self.hooks=[ModuleHook("PRIVMSG", self.scramble)] + + # Dictionary + self.whitesFile = open(self.getFilePath("answers.txt"),'r') + self.blacksFile = open(self.getFilePath("questions.txt"),'r') + self.whites = [line.rstrip() for line in self.whitesFile] + self.blacks = [line.rstrip() for line in self.blacksFile] + self.currentBlack = "" + self.whitesFile.close() + self.blacksFile.close() + self.log.info("CAH: Loaded."+str(len(self.whites))+" White Cards "+str(len(self.blacks))+" Black Cards") + # Per channel games + self.games = {} + + + def scramble(self, args, prefix, trailing): + channel = args[0] + if channel[0] == "#": + if not channel in self.games: + self.games[channel]=cardsGame(self, channel,self.whites,self.blacks) + self.games[channel].stuff(args, prefix, trailing) + + + def ondisable(self): + self.log.info("CAH: Unload requested, ending games...") + # for game in self.games: + # self.games[game].gameover() class cardsGame: - def __init__(self, master, channel,whites,blacks): - self.master = master - self.channel = channel - # Running? - self.running = False - # Current word - # self.message = 'xmopxshell has downs' - self.players = {} - self.timers = {} - self.whites = whites - self.blacks = blacks - self.lastCzar = -1 - self.czar = "" - self.started = False - self.active = False - self.allowPick = 0 - self.choices = {} - self.czarTimer = None - def stuff(self, args, prefix, trailing): - prefix = self.master.bot.decodePrefix(prefix) - sender = prefix.nick - if self.master.bot.messageHasCommand(".joinGame", trailing): - self.join(sender) - elif self.master.bot.messageHasCommand(".ready",trailing): - result = self.markReady(sender) - if result: - self.started = True - self.master.bot.act_PRIVMSG(self.channel,"All players are ready!") - for player in self.players: - self.master.bot.act_PRIVMSG(player,"ITS TIME TO D-D-D-D-D-DUEL!") - self.players[player]=[] - for player in self.players: - self.deal(player) - self.sendCards(player) - self.active = True - self.makeTurn() - elif self.master.bot.messageHasCommand(".pick",trailing): - if self.active: - if sender != self.czar: - print(sender,self.czar) - print(sender != self.czar) - if self.allowPick > 0: - if sender in self.players: - cards = trailing.split(' ')[1:] - if len(cards)==self.allowPick: - if self.checkBounds(cards): - if sender not in self.choices: - cardChoices = [self.players[sender][int(index)] for index in cards] - print(cardChoices) - self.choices[sender] = cardChoices - self.removeAndReplenishCards(sender, cardChoices) - self.sendCards(sender) - del self.choices[sender] - if sender in timers: - self.timers[sender].cancel() - if self.allDrawn(): - self.readChoices() - self.master.bot.act_PRIVMSG(self.channel,self.czar+"! Please choose the winner!") - czarTimer = Timer(180,self.kick,(self.czar,"taking too long to pick a choice. The next turn iwll be made.")) - self.makeTurn() - - else: - self.master.bot.act_PRIVMSG(self.channel,sender+", you picked a card that was out of the range. Please don't do that.") - else: - self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(cards))+" cards. You were supposed to pick "+str(self.allowPick)) - elif self.master.bot.messageHasCommand(".choose",trailing): - if sender==self.czar: - choice = trailing.split()[1:] - if len(choice)==1: - if self.checkChoiceBounds(int(choice[0])): - self.master.bot.act_PRIVMSG(self.channel,list(self.choices.keys())[int(choice[0])]+", you won the round!") - if self.czarTimer!=None: - self.czarTimer.cancel() - self.makeTurn() - else: - self.master.bot.act_PRIVMSG(self.channel,sender+", your choice was out of the range. Please don't do that.") - else: - self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(choice))+" "+" winners. You were only supposed to pick 1.") - elif self.master.bot.messageHasCommand('.leave',trailing): - if sender in self.players: - self.kick(sender,'choosing to leave the game you dolt') - if sender is self.czar: - self.makeTurn() - - def join(self,nick): - if not self.started: - if nick not in self.players: - self.players[nick]=False - self.master.bot.act_PRIVMSG(self.channel, nick+" has joined the game! | The players currently are "+str(self.players)) - else: - print("the game has already started!") - self.master.bot.act_PRIVMSG(self.channel,"The game has already started!") - def markReady(self,nick): - if not self.started: - if nick in self.players: - self.players[nick]=True - for player in self.players: - print(player) - if not self.players[player]: - print (player+" not ready") - return False - return True - else: - self.master.bot.act_PRIVMSG(self.channel, "You are not in the game! Type .joinGame!") - else: - print("game has already started!") - self.master.bot.act_PRIVMSG(self.channel,"The game has already started!") - def deal(self,nick): - self.players[nick] = [self.pickWhite() for i in range (7)] - def pickWhite(self): - card = choice(self.whites) - self.whites.remove(card) - return card - def pickBlack(self): - card = choice(self.blacks) - self.blacks.remove(card) - return card - def sendCards(self,nick): - cards = "" - for card in self.players[nick]: - cards+=str(self.players[nick].index(card))+". " - cards+=card+" " - self.master.bot.act_PRIVMSG(nick,"Your cards are "+cards) - def readCard(self,card): - count = card.count('_') - if count == 0: - if 'haiku' in card: - count = 3 - else: - count = 1 - self.master.bot.act_PRIVMSG(self.channel,"The black card is \""+card+"\" Pick "+str(count)) - return count - def pickCzar(self): - index = self.lastCzar+1 - if index < len(self.players): - self.lastCzar = index - return index - else: - self.lastCzar = 0 - return 0 - def announceCzar(self): - self.master.bot.act_PRIVMSG(self.channel,"The Czar is "+self.czar+"!") - def checkBounds(self,cards): - for item in cards: - if int(item)>6 or int(item)<0: - return False - return True - def checkChoiceBounds(self,choice): - if choice<0 or choice>len(self.choices)-1: - return False - return True - def makeTurn(self): - self.choices.clear() - card = self.pickBlack() - self.timers.clear() - self.currentBlack = card - self.allowPick = self.readCard(card) - self.lastCzar = self.pickCzar() - self.czar = list(self.players.keys())[self.lastCzar] - print (self.lastCzar,self.czar) - for player in self.players: - if player!=self.czar: - self.timers[player] = Timer(180,self.kick,(player,"taking more than 180 seconds for their turn.")) - self.timers[player].start() - self.announceCzar() - def kick(self,nick,reason): - del self.players[nick] - if nick in self.timers: - self.timers[nick].cancel() - del self.timers[nick] - self.master.bot.act_PRIVMSG(self.channel,nick+" has been kicked due to "+reason) - if len(self.players)<=1: - self.master.bot.act_PRIVMSG(self.channel,"The game is being shut down due to having <=1 players") - self.started = False - self.active = False - for timer in self.timers: - timer.cancel() - self.timers.clear() - self.players.clear() - def removeAndReplenishCards(self,nick,cards): - for card in cards: - self.players[nick].remove(card) - self.players[nick].append(self.pickWhite()) - def readChoices(self): - if '_' in self.currentBlack: - for player in list(self.choices.keys()): - cardInstance = str(list(self.choices.keys()).index(player))+". "+self.currentBlack - cardInstance = list(cardInstance) #do this as opposed to space to preserve spaces - for choice in self.choices[player]: - for char in cardInstance: - if char=='_': - print(char) - choice = choice.replace('.','') - cardInstance[cardInstance.index(char)] = choice - break - self.master.bot.act_PRIVMSG(self.channel,''.join(cardInstance)) - else: - for player in self.choices: - self.master.bot.act_PRIVMSG(self.channel,self.currentBlack+' '+' '.join(self.choices[player])) - - def allDrawn(self): - for player in self.players: - if player not in self.choices: - if player != self.czar: - return False - return True + def __init__(self, master, channel,whites,blacks): + self.master = master + self.channel = channel + # Running? + self.running = False + # Current word + # self.message = 'xmopxshell has downs' + self.players = {} + self.timers = {} + self.whites = whites + self.blacks = blacks + self.lastCzar = -1 + self.czar = "" + self.started = False + self.active = False + self.allowPick = 0 + self.choices = {} + self.czarTimer = None + def stuff(self, args, prefix, trailing): + prefix = self.master.bot.decodePrefix(prefix) + sender = prefix.nick + if self.master.bot.messageHasCommand(".joinGame", trailing): + self.join(sender) + elif self.master.bot.messageHasCommand(".ready",trailing): + result = self.markReady(sender) + if result: + self.started = True + self.master.bot.act_PRIVMSG(self.channel,"All players are ready!") + for player in self.players: + self.master.bot.act_PRIVMSG(player,"ITS TIME TO D-D-D-D-D-DUEL!") + self.players[player]=[] + for player in self.players: + self.deal(player) + self.sendCards(player) + self.active = True + self.makeTurn() + elif self.master.bot.messageHasCommand(".pick",trailing): + if self.active: + if sender != self.czar: + print(sender,self.czar) + print(sender != self.czar) + if self.allowPick > 0: + if sender in self.players: + cards = trailing.split(' ')[1:] + if len(cards)==self.allowPick: + if self.checkBounds(cards): + if sender not in self.choices: + cardChoices = [self.players[sender][int(index)] for index in cards] + print(cardChoices) + self.choices[sender] = cardChoices + self.removeAndReplenishCards(sender, cardChoices) + self.sendCards(sender) + del self.choices[sender] + if sender in timers: + self.timers[sender].cancel() + if self.allDrawn(): + self.readChoices() + self.master.bot.act_PRIVMSG(self.channel,self.czar+"! Please choose the winner!") + czarTimer = Timer(180,self.kick,(self.czar,"taking too long to pick a choice. The next turn iwll be made.")) + self.makeTurn() + + else: + self.master.bot.act_PRIVMSG(self.channel,sender+", you picked a card that was out of the range. Please don't do that.") + else: + self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(cards))+" cards. You were supposed to pick "+str(self.allowPick)) + elif self.master.bot.messageHasCommand(".choose",trailing): + if sender==self.czar: + choice = trailing.split()[1:] + if len(choice)==1: + if self.checkChoiceBounds(int(choice[0])): + self.master.bot.act_PRIVMSG(self.channel,list(self.choices.keys())[int(choice[0])]+", you won the round!") + if self.czarTimer!=None: + self.czarTimer.cancel() + self.makeTurn() + else: + self.master.bot.act_PRIVMSG(self.channel,sender+", your choice was out of the range. Please don't do that.") + else: + self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(choice))+" "+" winners. You were only supposed to pick 1.") + elif self.master.bot.messageHasCommand('.leave',trailing): + if sender in self.players: + self.kick(sender,'choosing to leave the game you dolt') + if sender is self.czar: + self.makeTurn() + + def join(self,nick): + if not self.started: + if nick not in self.players: + self.players[nick]=False + self.master.bot.act_PRIVMSG(self.channel, nick+" has joined the game! | The players currently are "+str(self.players)) + else: + print("the game has already started!") + self.master.bot.act_PRIVMSG(self.channel,"The game has already started!") + def markReady(self,nick): + if not self.started: + if nick in self.players: + self.players[nick]=True + for player in self.players: + print(player) + if not self.players[player]: + print (player+" not ready") + return False + return True + else: + self.master.bot.act_PRIVMSG(self.channel, "You are not in the game! Type .joinGame!") + else: + print("game has already started!") + self.master.bot.act_PRIVMSG(self.channel,"The game has already started!") + def deal(self,nick): + self.players[nick] = [self.pickWhite() for i in range (7)] + def pickWhite(self): + card = choice(self.whites) + self.whites.remove(card) + return card + def pickBlack(self): + card = choice(self.blacks) + self.blacks.remove(card) + return card + def sendCards(self,nick): + cards = "" + for card in self.players[nick]: + cards+=str(self.players[nick].index(card))+". " + cards+=card+" " + self.master.bot.act_PRIVMSG(nick,"Your cards are "+cards) + def readCard(self,card): + count = card.count('_') + if count == 0: + if 'haiku' in card: + count = 3 + else: + count = 1 + self.master.bot.act_PRIVMSG(self.channel,"The black card is \""+card+"\" Pick "+str(count)) + return count + def pickCzar(self): + index = self.lastCzar+1 + if index < len(self.players): + self.lastCzar = index + return index + else: + self.lastCzar = 0 + return 0 + def announceCzar(self): + self.master.bot.act_PRIVMSG(self.channel,"The Czar is "+self.czar+"!") + def checkBounds(self,cards): + for item in cards: + if int(item)>6 or int(item)<0: + return False + return True + def checkChoiceBounds(self,choice): + if choice<0 or choice>len(self.choices)-1: + return False + return True + def makeTurn(self): + self.choices.clear() + card = self.pickBlack() + self.timers.clear() + self.currentBlack = card + self.allowPick = self.readCard(card) + self.lastCzar = self.pickCzar() + self.czar = list(self.players.keys())[self.lastCzar] + print (self.lastCzar,self.czar) + for player in self.players: + if player!=self.czar: + self.timers[player] = Timer(180,self.kick,(player,"taking more than 180 seconds for their turn.")) + self.timers[player].start() + self.announceCzar() + def kick(self,nick,reason): + del self.players[nick] + if nick in self.timers: + self.timers[nick].cancel() + del self.timers[nick] + self.master.bot.act_PRIVMSG(self.channel,nick+" has been kicked due to "+reason) + if len(self.players)<=1: + self.master.bot.act_PRIVMSG(self.channel,"The game is being shut down due to having <=1 players") + self.started = False + self.active = False + for timer in self.timers: + timer.cancel() + self.timers.clear() + self.players.clear() + def removeAndReplenishCards(self,nick,cards): + for card in cards: + self.players[nick].remove(card) + self.players[nick].append(self.pickWhite()) + def readChoices(self): + if '_' in self.currentBlack: + for player in list(self.choices.keys()): + cardInstance = str(list(self.choices.keys()).index(player))+". "+self.currentBlack + cardInstance = list(cardInstance) #do this as opposed to space to preserve spaces + for choice in self.choices[player]: + for char in cardInstance: + if char=='_': + print(char) + choice = choice.replace('.','') + cardInstance[cardInstance.index(char)] = choice + break + self.master.bot.act_PRIVMSG(self.channel,''.join(cardInstance)) + else: + for player in self.choices: + self.master.bot.act_PRIVMSG(self.channel,self.currentBlack+' '+' '.join(self.choices[player])) + + def allDrawn(self): + for player in self.players: + if player not in self.choices: + if player != self.czar: + return False + return True diff --git a/pyircbot/modules/DogeDice.py b/pyircbot/modules/DogeDice.py index 735bb24..5661902 100755 --- a/pyircbot/modules/DogeDice.py +++ b/pyircbot/modules/DogeDice.py @@ -9,7 +9,6 @@ from pyircbot.modulebase import ModuleBase,ModuleHook import random -import yaml import os import time import math diff --git a/pyircbot/modules/DogeRPC.py b/pyircbot/modules/DogeRPC.py index ba78d2d..cca3636 100755 --- a/pyircbot/modules/DogeRPC.py +++ b/pyircbot/modules/DogeRPC.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ .. module:: DogeRPC - :synopsis: Provides a service for interacting with dogecoind. + :synopsis: Provides a service for interacting with dogecoind. .. moduleauthor:: Dave Pedu @@ -11,64 +11,67 @@ from pyircbot.modulebase import ModuleBase,ModuleHook from bitcoinrpc.authproxy import AuthServiceProxy class DogeRPC(ModuleBase): - def __init__(self, bot, moduleName): - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[] - self.services=["dogerpc"] - self.loadConfig() - self.rpc = DogeController(self) - - def getBal(self, acct): - " get a balance of an address or an account " - return self.getAcctBal(acct) - - def getAcctAddr(self, acct): - " returns the address for an account. creates if necessary " - self.rpc.ping() - addrs = self.rpc.con.getaddressesbyaccount(acct) - if len(addrs)==0: - return self.rpc.con.getnewaddress(acct) - return addrs[0] - - def getAcctBal(self, acct): - " returns an account's balance" - self.rpc.ping() - return float(self.rpc.con.getbalance(acct)) - - def canMove(self, fromAcct, toAcct, amount): - " true or false if fromAcct can afford to give toAcct an amount of coins " - balfrom = self.getAcctBal(fromAcct) - return balfrom >= amount - - def move(self, fromAcct, toAcct, amount): - " move coins from one account to another " - self.rpc.ping() - if self.canMove(fromAcct, toAcct, amount): - return self.rpc.con.move(fromAcct, toAcct, amount) - return False - - def send(self, fromAcct, toAddr, amount): - " send coins to an external addr " - self.rpc.ping() - if self.canMove(fromAcct, toAddr, amount): - return self.rpc.con.sendfrom(fromAcct, toAddr, amount) - return False + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName); + self.hooks=[] + self.services=["dogerpc"] + self.loadConfig() + self.rpc = DogeController(self) + + def getBal(self, acct): + "Get a balance of a local address or an account " + return self.getAcctBal(acct) + + def getAcctAddr(self, acct): + "Returns the address for an account. creates if necessary " + self.rpc.ping() + addrs = self.rpc.con.getaddressesbyaccount(acct) + if len(addrs)==0: + return self.rpc.con.getnewaddress(acct) + return addrs[0] + + def getAcctBal(self, acct): + "Returns an account's balance" + self.rpc.ping() + return float(self.rpc.con.getbalance(acct)) + + def canMove(self, fromAcct, toAcct, amount): + "True or false if fromAcct can afford to give toAcct an amount of coins " + balfrom = self.getAcctBal(fromAcct) + return balfrom >= amount + + def move(self, fromAcct, toAcct, amount): + "Move coins from one account to another " + self.rpc.ping() + if self.canMove(fromAcct, toAcct, amount): + return self.rpc.con.move(fromAcct, toAcct, amount) + return False + + def send(self, fromAcct, toAddr, amount): + "Send coins to an external addr " + self.rpc.ping() + if self.canMove(fromAcct, toAddr, amount): + return self.rpc.con.sendfrom(fromAcct, toAddr, amount) + return False class DogeController: - def __init__(self, master): - self.config = master.config - self.log = master.log - self.con = None - self.ping() - - def ping(self): - try: - self.con.getinfo() - except: - self.connect() - - def connect(self): - self.log.debug("DogeRPC: Connecting to dogecoind") - self.con = AuthServiceProxy("http://%s:%s@%s:%s" % (self.config["username"], self.config["password"], self.config["host"], self.config["port"])) - self.con.getinfo() - self.log.debug("DogeRPC: Connected to %s:%s" % (self.config["host"], self.config["port"])) + "RPC instance control class" + def __init__(self, master): + self.config = master.config + self.log = master.log + self.con = None + self.ping() + + def ping(self): + "Test connection and re-establish if necessary" + try: + self.con.getinfo() + except: + self.connect() + + def connect(self): + "Connect to RPC endpoint" + self.log.debug("DogeRPC: Connecting to dogecoind") + self.con = AuthServiceProxy("http://%s:%s@%s:%s" % (self.config["username"], self.config["password"], self.config["host"], self.config["port"])) + self.con.getinfo() + self.log.debug("DogeRPC: Connected to %s:%s" % (self.config["host"], self.config["port"])) diff --git a/pyircbot/modules/DogeScramble.py b/pyircbot/modules/DogeScramble.py index 21c5ffb..406dcea 100755 --- a/pyircbot/modules/DogeScramble.py +++ b/pyircbot/modules/DogeScramble.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ .. module:: DogeScramble - :synopsis: This module provides a word scrambling game that rewards winners with small amounts of Dogecoin + :synopsis: This module provides a word scrambling game that rewards winners with small amounts of Dogecoin .. moduleauthor:: Dave Pedu @@ -9,258 +9,257 @@ from pyircbot.modulebase import ModuleBase,ModuleHook import random -import yaml import os import time from threading import Timer class DogeScramble(ModuleBase): - def __init__(self, bot, moduleName): - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[ModuleHook("PRIVMSG", self.scramble)] - self.loadConfig() - - # Load attribute storage - self.attr = None - serviceProviders = self.bot.getmodulesbyservice("attributes") - if len(serviceProviders)==0: - self.log.error("DogeScramble: Could not find a valid attributes service provider") - else: - self.log.info("DogeScramble: Selecting attributes service provider: %s" % serviceProviders[0]) - self.attr = serviceProviders[0] - - # Load doge RPC - self.doge = self.bot.getBestModuleForService("dogerpc") - - # Per channel games - self.games = {} - - def scramble(self, args, prefix, trailing): - channel = args[0] - if channel[0] == "#": - # Ignore messages from users without a dogewallet password - prefixObj = self.bot.decodePrefix(prefix) - if self.attr.getKey(prefixObj.nick, "password")==None: - return - if not channel in self.games: - self.games[channel]=scrambleGame(self, channel) - self.games[channel].scramble(args, prefix, trailing) - def ondisable(self): - self.log.info("DogeScramble: Unload requested, ending games...") - for game in self.games: - self.games[game].gameover() + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName); + self.hooks=[ModuleHook("PRIVMSG", self.scramble)] + self.loadConfig() + + # Load attribute storage + self.attr = None + serviceProviders = self.bot.getmodulesbyservice("attributes") + if len(serviceProviders)==0: + self.log.error("DogeScramble: Could not find a valid attributes service provider") + else: + self.log.info("DogeScramble: Selecting attributes service provider: %s" % serviceProviders[0]) + self.attr = serviceProviders[0] + + # Load doge RPC + self.doge = self.bot.getBestModuleForService("dogerpc") + + # Per channel games + self.games = {} + + def scramble(self, args, prefix, trailing): + channel = args[0] + if channel[0] == "#": + # Ignore messages from users without a dogewallet password + prefixObj = self.bot.decodePrefix(prefix) + if self.attr.getKey(prefixObj.nick, "password")==None: + return + if not channel in self.games: + self.games[channel]=scrambleGame(self, channel) + self.games[channel].scramble(args, prefix, trailing) + def ondisable(self): + self.log.info("DogeScramble: Unload requested, ending games...") + for game in self.games: + self.games[game].gameover() class scrambleGame: - def __init__(self, master, channel): - self.master = master - self.channel = channel - # Running? - self.running = False - # Current word - self.currentWord = None - # Current word, scrambled - self.scrambled = None - # Online? - self.scrambleOn = False - # Count down to hints - self.hintTimer = None - # of hints given - self.hintsGiven = 0 - # Cooldown between words - self.nextTimer = None - # How many guesses submitted this round - self.guesses = 0; - # How many games in a row where nobody guessed - self.gamesWithoutGuesses = 0; - # What file are we using - self.category_file = None; - # How many words in this category have been used? - self.category_count = 0 - # How long between categories - self.change_category_after_words = self.master.config["categoryduration"] - # Should we change categories at the next pick? - self.should_change_category = True - # Holds the processed category name - self.category_name = None - # list of last picked words - self.lastwords = [] - # name of last winner for decreasing return - self.lastwinner = None - self.lastwinvalue = 0 - - self.delayHint = self.master.config["hintDelay"]; - self.delayNext = self.master.config["delayNext"]; - self.maxHints = self.master.config["maxHints"]; - self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]; - - def gameover(self): - self.clearTimers(); - self.running = False - def clearTimers(self): - self.clearTimer(self.nextTimer) - self.clearTimer(self.hintTimer) - def clearTimer(self, timer): - if timer: - timer.cancel() - def scramble(self, args, prefix, trailing): - prefix = self.master.bot.decodePrefix(prefix) - sender = prefix.nick - - senderIsOp = self.master.attr.getKey(prefix.nick, "op")=="yes" - - cmd = self.master.bot.messageHasCommand(".scramble", trailing) - if cmd and not self.running: - #and senderIsOp - self.running = True - self.startScramble() - return - cmd = self.master.bot.messageHasCommand(".scrambleoff", trailing) - if cmd and senderIsOp and self.running: - self.gameover() - self.running = False - return - - if self.currentWord and trailing.strip().lower() == self.currentWord: - # Get winner withdraw address - useraddr = self.master.attr.getKey(prefix.nick, "dogeaddr") - userwallet = self.master.attr.getKey(prefix.nick, "dogeaccountname") - - self.master.bot.act_PRIVMSG(self.channel, "%s got the word - %s!" % (sender, self.currentWord)) - - if not useraddr: - self.master.bot.act_PRIVMSG(self.channel, "%s: to win DOGE, you must set an wallet address by PMing me \".setdogeaddr\". Next word in %s seconds." % (prefix.nick, self.delayNext)) - else: - winamount = float(self.master.config["winAmount"]) - if self.lastwinner == prefix.nick: - winamount = self.lastwinvalue * self.master.config["decreaseFactor"] - self.lastwinvalue = winamount - self.lastwinner = prefix.nick - - self.master.bot.act_PRIVMSG(self.channel, "%s won %s DOGE! Next word in %s seconds." % (prefix.nick, round(winamount, 8), self.delayNext)) - self.master.doge.move('', userwallet, winamount) - - self.currentWord = None - self.clearTimers() - self.hintsGiven = 0 - self.nextTimer = Timer(self.delayNext, self.startNewWord) - self.nextTimer.start() - self.guesses=0 - self.category_count+=1 - self.master.log.debug("DogeScramble: category_count is: %s" % (self.category_count)) - if self.category_count >= self.change_category_after_words: - self.should_change_category = True - else: - self.guesses+=1 - - def startScramble(self): - self.clearTimer(self.nextTimer) - self.nextTimer = Timer(0, self.startNewWord) - self.nextTimer.start() - - def startNewWord(self): - self.currentWord = self.pickWord() - self.scrambled = self.scrambleWord(self.currentWord) - self.master.bot.act_PRIVMSG(self.channel, "[Category: %s] Unscramble this: %s " % (self.category_name, self.scrambled)) - - self.clearTimer(self.hintTimer) - self.hintTimer = Timer(self.delayHint, self.giveHint) - self.hintTimer.start() - - def giveHint(self): - self.hintsGiven+=1 - - if self.hintsGiven>=len(self.currentWord) or self.hintsGiven > self.maxHints: - self.abortWord() - return - - blanks = "" - for letter in list(self.currentWord): - if letter == " ": - blanks+=" " - else: - blanks+="_" - partFromWord = self.currentWord[0:self.hintsGiven] - partFromBlanks = blanks[self.hintsGiven:] - hintstr = partFromWord+partFromBlanks - - self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr)) - - self.clearTimer(self.hintTimer) - self.hintTimer = Timer(self.delayHint, self.giveHint) - self.hintTimer.start() - - def abortWord(self): - cur = self.currentWord - self.currentWord = None - self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was '%s'. Next word in %s seconds." % (cur, self.delayNext)) - self.hintsGiven = 0 - self.clearTimer(self.nextTimer) - - if self.guesses==0: - self.gamesWithoutGuesses+=1 - if self.gamesWithoutGuesses >= self.abortAfterNoGuesses: - self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scramble to start again.") - self.gameover() - return - else: - self.gamesWithoutGuesses=0 - - self.nextTimer = Timer(self.delayNext, self.startNewWord) - self.nextTimer.start() - - def catFileNameToStr(self, s): - s=s.split(".")[0] - s=s.replace("_", " ") - return s.title() - - def pickWord(self): - if self.should_change_category: - # clear flags - self.should_change_category = False - self.category_count = 0 - # Get the path to word files dir - dirpath = self.master.getFilePath("") - # List dir - files = os.listdir(dirpath) - # choose a random file - random.shuffle(files) - self.category_file = files[0] - self.category_name = self.catFileNameToStr(self.category_file) - # Process the name & announce - self.master.bot.act_PRIVMSG(self.channel, "The category is now: %s " % self.category_name) - # count lines - f = open(self.master.getFilePath(self.category_file), "r") - lines = 0 - while True: - lines+=1 - if f.readline() == "": - break - f.close() - # change category - picked = "" - while picked == "" or picked in self.lastwords: - - skip = random.randint(0, lines) - f = open(self.master.getFilePath(self.category_file), "r") - while skip>=0: - f.readline() - skip-=1 - picked = f.readline().strip().lower() - f.close() - - self.master.log.debug("DogeScramble: picked %s for %s" % (picked, self.channel)) - self.lastwords.append(picked) - if len(self.lastwords) > 5: - self.lastwords.pop(0) - return picked - - def scrambleWord(self, word): - scrambled = "" - for subword in word.split(" "): - scrambled+=self.scrambleIndividualWord(subword)+ " " - return scrambled.strip() - - def scrambleIndividualWord(self, word): - scrambled = list(word) - random.shuffle(scrambled) - return ''.join(scrambled).lower() + def __init__(self, master, channel): + self.master = master + self.channel = channel + # Running? + self.running = False + # Current word + self.currentWord = None + # Current word, scrambled + self.scrambled = None + # Online? + self.scrambleOn = False + # Count down to hints + self.hintTimer = None + # of hints given + self.hintsGiven = 0 + # Cooldown between words + self.nextTimer = None + # How many guesses submitted this round + self.guesses = 0; + # How many games in a row where nobody guessed + self.gamesWithoutGuesses = 0; + # What file are we using + self.category_file = None; + # How many words in this category have been used? + self.category_count = 0 + # How long between categories + self.change_category_after_words = self.master.config["categoryduration"] + # Should we change categories at the next pick? + self.should_change_category = True + # Holds the processed category name + self.category_name = None + # list of last picked words + self.lastwords = [] + # name of last winner for decreasing return + self.lastwinner = None + self.lastwinvalue = 0 + + self.delayHint = self.master.config["hintDelay"]; + self.delayNext = self.master.config["delayNext"]; + self.maxHints = self.master.config["maxHints"]; + self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]; + + def gameover(self): + self.clearTimers(); + self.running = False + def clearTimers(self): + self.clearTimer(self.nextTimer) + self.clearTimer(self.hintTimer) + def clearTimer(self, timer): + if timer: + timer.cancel() + def scramble(self, args, prefix, trailing): + prefix = self.master.bot.decodePrefix(prefix) + sender = prefix.nick + + senderIsOp = self.master.attr.getKey(prefix.nick, "op")=="yes" + + cmd = self.master.bot.messageHasCommand(".scramble", trailing) + if cmd and not self.running: + #and senderIsOp + self.running = True + self.startScramble() + return + cmd = self.master.bot.messageHasCommand(".scrambleoff", trailing) + if cmd and senderIsOp and self.running: + self.gameover() + self.running = False + return + + if self.currentWord and trailing.strip().lower() == self.currentWord: + # Get winner withdraw address + useraddr = self.master.attr.getKey(prefix.nick, "dogeaddr") + userwallet = self.master.attr.getKey(prefix.nick, "dogeaccountname") + + self.master.bot.act_PRIVMSG(self.channel, "%s got the word - %s!" % (sender, self.currentWord)) + + if not useraddr: + self.master.bot.act_PRIVMSG(self.channel, "%s: to win DOGE, you must set an wallet address by PMing me \".setdogeaddr\". Next word in %s seconds." % (prefix.nick, self.delayNext)) + else: + winamount = float(self.master.config["winAmount"]) + if self.lastwinner == prefix.nick: + winamount = self.lastwinvalue * self.master.config["decreaseFactor"] + self.lastwinvalue = winamount + self.lastwinner = prefix.nick + + self.master.bot.act_PRIVMSG(self.channel, "%s won %s DOGE! Next word in %s seconds." % (prefix.nick, round(winamount, 8), self.delayNext)) + self.master.doge.move('', userwallet, winamount) + + self.currentWord = None + self.clearTimers() + self.hintsGiven = 0 + self.nextTimer = Timer(self.delayNext, self.startNewWord) + self.nextTimer.start() + self.guesses=0 + self.category_count+=1 + self.master.log.debug("DogeScramble: category_count is: %s" % (self.category_count)) + if self.category_count >= self.change_category_after_words: + self.should_change_category = True + else: + self.guesses+=1 + + def startScramble(self): + self.clearTimer(self.nextTimer) + self.nextTimer = Timer(0, self.startNewWord) + self.nextTimer.start() + + def startNewWord(self): + self.currentWord = self.pickWord() + self.scrambled = self.scrambleWord(self.currentWord) + self.master.bot.act_PRIVMSG(self.channel, "[Category: %s] Unscramble this: %s " % (self.category_name, self.scrambled)) + + self.clearTimer(self.hintTimer) + self.hintTimer = Timer(self.delayHint, self.giveHint) + self.hintTimer.start() + + def giveHint(self): + self.hintsGiven+=1 + + if self.hintsGiven>=len(self.currentWord) or self.hintsGiven > self.maxHints: + self.abortWord() + return + + blanks = "" + for letter in list(self.currentWord): + if letter == " ": + blanks+=" " + else: + blanks+="_" + partFromWord = self.currentWord[0:self.hintsGiven] + partFromBlanks = blanks[self.hintsGiven:] + hintstr = partFromWord+partFromBlanks + + self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr)) + + self.clearTimer(self.hintTimer) + self.hintTimer = Timer(self.delayHint, self.giveHint) + self.hintTimer.start() + + def abortWord(self): + cur = self.currentWord + self.currentWord = None + self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was '%s'. Next word in %s seconds." % (cur, self.delayNext)) + self.hintsGiven = 0 + self.clearTimer(self.nextTimer) + + if self.guesses==0: + self.gamesWithoutGuesses+=1 + if self.gamesWithoutGuesses >= self.abortAfterNoGuesses: + self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scramble to start again.") + self.gameover() + return + else: + self.gamesWithoutGuesses=0 + + self.nextTimer = Timer(self.delayNext, self.startNewWord) + self.nextTimer.start() + + def catFileNameToStr(self, s): + s=s.split(".")[0] + s=s.replace("_", " ") + return s.title() + + def pickWord(self): + if self.should_change_category: + # clear flags + self.should_change_category = False + self.category_count = 0 + # Get the path to word files dir + dirpath = self.master.getFilePath("") + # List dir + files = os.listdir(dirpath) + # choose a random file + random.shuffle(files) + self.category_file = files[0] + self.category_name = self.catFileNameToStr(self.category_file) + # Process the name & announce + self.master.bot.act_PRIVMSG(self.channel, "The category is now: %s " % self.category_name) + # count lines + f = open(self.master.getFilePath(self.category_file), "r") + lines = 0 + while True: + lines+=1 + if f.readline() == "": + break + f.close() + # change category + picked = "" + while picked == "" or picked in self.lastwords: + + skip = random.randint(0, lines) + f = open(self.master.getFilePath(self.category_file), "r") + while skip>=0: + f.readline() + skip-=1 + picked = f.readline().strip().lower() + f.close() + + self.master.log.debug("DogeScramble: picked %s for %s" % (picked, self.channel)) + self.lastwords.append(picked) + if len(self.lastwords) > 5: + self.lastwords.pop(0) + return picked + + def scrambleWord(self, word): + scrambled = "" + for subword in word.split(" "): + scrambled+=self.scrambleIndividualWord(subword)+ " " + return scrambled.strip() + + def scrambleIndividualWord(self, word): + scrambled = list(word) + random.shuffle(scrambled) + return ''.join(scrambled).lower() diff --git a/pyircbot/modules/DuckHunt.py b/pyircbot/modules/DuckHunt.py index 358622a..78bbc97 100755 --- a/pyircbot/modules/DuckHunt.py +++ b/pyircbot/modules/DuckHunt.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ .. module:: DuckHunt - :synopsis: An animal hunting IRC game + :synopsis: An animal hunting IRC game .. moduleauthor:: Dave Pedu @@ -9,160 +9,160 @@ from pyircbot.modulebase import ModuleBase,ModuleHook import time -import yaml +import json import random from threading import Timer import os class DuckHunt(ModuleBase): - def __init__(self, bot, moduleName): - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[ModuleHook("PRIVMSG", self.hunt)] - self.loadConfig() - - self.ymlPath = self.getFilePath("scores.yml") - - self.timer = None - self.isDuckOut = False - self.outStart = 0 - self.misses = {} - - self.startHunt() - - def hunt(self, args, prefix, trailing): - prefixObj = self.bot.decodePrefix(prefix) - fromWho = prefixObj.nick - - cmd = self.bot.messageHasCommand("!huntscore", trailing, False) - if cmd: - scores = self.loadScores() - if not fromWho in scores: - self.bot.act_PRIVMSG(fromWho, "You have no points :(") - else: - scores = scores[fromWho] - kills = 0 - runts = 0 - prime = 0 - weight = 0.0 - shots = 0 - misses = 0 - for kill in scores: - if kill["prime"]: - prime+=1 - if kill["runt"]: - runts+=1 - kills+=1 - weight+=kill["weight"] - shots+=1 - shots+=kill["misses"] - misses+=kill["misses"] - - self.bot.act_PRIVMSG(fromWho, "You've shot %s %s for a total weight of %s lbs." % (kills, self.config["animalSpeciesPlural"], weight)) - self.bot.act_PRIVMSG(fromWho, "%s prime catches, %s runts, %s bullets used and %s misses." % (prime, runts, shots, misses)) - #self.bot.act_PRIVMSG(fromWho, "More info & highscores: http://duckhunt.xmopx.net/") - self.log.info("DuckHunt: %s used !huntscore" % fromWho) - return - - # Channel only - if not args[0][0]=="#": - return - - cmd = self.bot.messageHasCommand("!shoot", trailing, False) - if cmd: - if self.isDuckOut: - - if not fromWho in self.misses: - self.misses[fromWho]=0 - - shotIn = round(time.time() - self.outStart, 2) - - if random.randint(0, 100) <= self.config["missChance"]: - self.bot.act_PRIVMSG(self.config["activeChannel"], "%s fires after %s seconds and misses!" % (fromWho, shotIn)) - self.misses[fromWho]+=1 - return - - self.isDuckOut = False - - bagged = { - "species":self.config["animalSpecies"], - "gender":"M" if random.randint(0,1)==1 else "F", - "time":shotIn, - "prime":False, - "runt":False, - "weight":0.0, - "date":time.time(), - "misses":self.misses[fromWho] - } - - message = "%s %s " % (fromWho, "bags") - - if random.randint(0, 100) <= self.config["primeChance"]: - bagged["prime"]=True - bagged["weight"]=self.getRandWeight(self.config["weightMax"], self.config["weightFat"]) - message += "a prime catch, a " - elif random.randint(0, 100) <= self.config["runtChance"]: - bagged["runt"]=True - bagged["weight"]=self.getRandWeight(self.config["weightRunt"], self.config["weightMin"]) - message += "a runt of a catch, a " - else: - bagged["weight"]=self.getRandWeight(self.config["weightMin"], self.config["weightMax"]) - message += "a " - - message += "%s lb " % (bagged["weight"]) - if bagged["gender"]=="M": - message += self.config["animalNameMale"]+" " - else: - message += self.config["animalNameFemale"]+" " - - message += "in %s seconds!" % shotIn - self.bot.act_PRIVMSG(self.config["activeChannel"], message) - - self.addKillFor(fromWho, bagged) - - self.misses = {} - - self.startHunt(); - - - def startHunt(self): - " Creates a timer that waits a certain amount of time then sends out a bird \_o< quack" - delay = self.config["delayMin"] + random.randint(0, self.config["delayMax"]-self.config["delayMin"]) - self.timer = Timer(delay, self.duckOut) - self.timer.start() - print("DuckHunt: Sending out animal in %s seconds" % delay) - - def duckOut(self): - self.isDuckOut = True - self.bot.act_PRIVMSG(self.config["activeChannel"], self.config["animal"]) - self.outStart = time.time() - - def getRandWeight(self, minW, maxW): - weight = maxW-minW; - weight = float(weight)*random.random() - return round(weight+minW, 2) - - def getScoreFor(self, playername): - return 1 - - def getScoresFor(self, playername): - return 1 - - def addKillFor(self, playername, kill): - scores = self.loadScores() - if scores==None: - scores = {} - if not playername in scores: - scores[playername]=[] - scores[playername].append(kill) - self.saveScores(scores) - - def loadScores(self): - if not os.path.exists(self.ymlPath): - yaml.dump({}, open(self.ymlPath, 'w')) - return yaml.load(open(self.ymlPath, 'r')) - - def saveScores(self, scores): - yaml.dump(scores, open(self.ymlPath, 'w')) - - def ondisable(self): - self.timer.cancel() + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName); + self.hooks=[ModuleHook("PRIVMSG", self.hunt)] + self.loadConfig() + + self.jsonPath = self.getFilePath("scores.json") + + self.timer = None + self.isDuckOut = False + self.outStart = 0 + self.misses = {} + + self.startHunt() + + def hunt(self, args, prefix, trailing): + prefixObj = self.bot.decodePrefix(prefix) + fromWho = prefixObj.nick + + cmd = self.bot.messageHasCommand("!huntscore", trailing, False) + if cmd: + scores = self.loadScores() + if not fromWho in scores: + self.bot.act_PRIVMSG(fromWho, "You have no points :(") + else: + scores = scores[fromWho] + kills = 0 + runts = 0 + prime = 0 + weight = 0.0 + shots = 0 + misses = 0 + for kill in scores: + if kill["prime"]: + prime+=1 + if kill["runt"]: + runts+=1 + kills+=1 + weight+=kill["weight"] + shots+=1 + shots+=kill["misses"] + misses+=kill["misses"] + + self.bot.act_PRIVMSG(fromWho, "You've shot %s %s for a total weight of %s lbs." % (kills, self.config["animalSpeciesPlural"], weight)) + self.bot.act_PRIVMSG(fromWho, "%s prime catches, %s runts, %s bullets used and %s misses." % (prime, runts, shots, misses)) + #self.bot.act_PRIVMSG(fromWho, "More info & highscores: http://duckhunt.xmopx.net/") + self.log.info("DuckHunt: %s used !huntscore" % fromWho) + return + + # Channel only + if not args[0][0]=="#": + return + + cmd = self.bot.messageHasCommand("!shoot", trailing, False) + if cmd: + if self.isDuckOut: + + if not fromWho in self.misses: + self.misses[fromWho]=0 + + shotIn = round(time.time() - self.outStart, 2) + + if random.randint(0, 100) <= self.config["missChance"]: + self.bot.act_PRIVMSG(self.config["activeChannel"], "%s fires after %s seconds and misses!" % (fromWho, shotIn)) + self.misses[fromWho]+=1 + return + + self.isDuckOut = False + + bagged = { + "species":self.config["animalSpecies"], + "gender":"M" if random.randint(0,1)==1 else "F", + "time":shotIn, + "prime":False, + "runt":False, + "weight":0.0, + "date":time.time(), + "misses":self.misses[fromWho] + } + + message = "%s %s " % (fromWho, "bags") + + if random.randint(0, 100) <= self.config["primeChance"]: + bagged["prime"]=True + bagged["weight"]=self.getRandWeight(self.config["weightMax"], self.config["weightFat"]) + message += "a prime catch, a " + elif random.randint(0, 100) <= self.config["runtChance"]: + bagged["runt"]=True + bagged["weight"]=self.getRandWeight(self.config["weightRunt"], self.config["weightMin"]) + message += "a runt of a catch, a " + else: + bagged["weight"]=self.getRandWeight(self.config["weightMin"], self.config["weightMax"]) + message += "a " + + message += "%s lb " % (bagged["weight"]) + if bagged["gender"]=="M": + message += self.config["animalNameMale"]+" " + else: + message += self.config["animalNameFemale"]+" " + + message += "in %s seconds!" % shotIn + self.bot.act_PRIVMSG(self.config["activeChannel"], message) + + self.addKillFor(fromWho, bagged) + + self.misses = {} + + self.startHunt(); + + + def startHunt(self): + " Creates a timer that waits a certain amount of time then sends out a bird \\_o< quack" + delay = self.config["delayMin"] + random.randint(0, self.config["delayMax"]-self.config["delayMin"]) + self.timer = Timer(delay, self.duckOut) + self.timer.start() + print("DuckHunt: Sending out animal in %s seconds" % delay) + + def duckOut(self): + self.isDuckOut = True + self.bot.act_PRIVMSG(self.config["activeChannel"], self.config["animal"]) + self.outStart = time.time() + + def getRandWeight(self, minW, maxW): + weight = maxW-minW; + weight = float(weight)*random.random() + return round(weight+minW, 2) + + def getScoreFor(self, playername): + return 1 + + def getScoresFor(self, playername): + return 1 + + def addKillFor(self, playername, kill): + scores = self.loadScores() + if scores==None: + scores = {} + if not playername in scores: + scores[playername]=[] + scores[playername].append(kill) + self.saveScores(scores) + + def loadScores(self): + if not os.path.exists(self.jsonPath): + json.dump({}, open(self.jsonPath, 'w')) + return json.load(open(self.jsonPath, 'r')) + + def saveScores(self, scores): + json.dump(scores, open(self.jsonPath, 'w')) + + def ondisable(self): + self.timer.cancel() diff --git a/pyircbot/modules/GameBase.py b/pyircbot/modules/GameBase.py index 389e6f2..d026186 100755 --- a/pyircbot/modules/GameBase.py +++ b/pyircbot/modules/GameBase.py @@ -9,7 +9,6 @@ from pyircbot.modulebase import ModuleBase,ModuleHook import random -import yaml import os import time from threading import Timer diff --git a/pyircbot/modules/Scramble.py b/pyircbot/modules/Scramble.py index c9f64b1..340eb94 100644 --- a/pyircbot/modules/Scramble.py +++ b/pyircbot/modules/Scramble.py @@ -1,6 +1,6 @@ """ .. module:: Scramble - :synopsis: Module to provide a word scramble game + :synopsis: Module to provide a word scramble game .. moduleauthor:: Dave Pedu @@ -8,232 +8,232 @@ from pyircbot.modulebase import ModuleBase,ModuleHook import random -import yaml +import json import os import time from threading import Timer from operator import itemgetter class Scramble(ModuleBase): - def __init__(self, bot, moduleName): - # init the base module - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[ModuleHook("PRIVMSG", self.scramble)] - self.loadConfig() - - # Dictionary - self.wordsCount=0; - self.wordsFile = self.getFilePath("words.txt") - print(self.wordsFile) - wordsF = open(self.wordsFile, "r") - while True: - word = wordsF.readline() - if word=="": - break - self.wordsCount+=1 - wordsF.close - self.log.info("Scramble: Loaded %s words" % str(self.wordsCount)) - # Load scores - self.scoresFile = self.getFilePath("scores.yml") - if not os.path.exists(self.scoresFile): - yaml.dump({}, file(self.scoresFile, 'w')) - self.scores = yaml.load(file(self.scoresFile, 'r')) - # Per channel games - self.games = {} - # Hook in - self.hooks=[ModuleBase.ModuleHook("PRIVMSG", self.scramble)] - - def scramble(self, args, prefix, trailing): - channel = args[0] - if channel[0] == "#": - if not channel in self.games: - self.games[channel]=scrambleGame(self, channel) - self.games[channel].scramble(args, prefix, trailing) - - def saveScores(self): - yaml.dump(self.scores, file(self.scoresFile, 'w')) - - def getScore(self, player, add=0): - player = player.lower() - if not player in self.scores: - self.scores[player] = 0 - if not add == 0: - self.scores[player]+=add - self.saveScores() - - return self.scores[player] - - def getScoreNoWrite(self, player): - if not player.lower() in self.scores: - return 0 - else: - return self.getScore(player) - - def ondisable(self): - self.log.info("Scramble: Unload requested, ending games...") - for game in self.games: - self.games[game].gameover() - self.saveScores() + def __init__(self, bot, moduleName): + # init the base module + ModuleBase.__init__(self, bot, moduleName); + self.hooks=[ModuleHook("PRIVMSG", self.scramble)] + self.loadConfig() + + # Dictionary + self.wordsCount=0; + self.wordsFile = self.getFilePath("words.txt") + print(self.wordsFile) + wordsF = open(self.wordsFile, "r") + while True: + word = wordsF.readline() + if word=="": + break + self.wordsCount+=1 + wordsF.close + self.log.info("Scramble: Loaded %s words" % str(self.wordsCount)) + # Load scores + self.scoresFile = self.getFilePath("scores.json") + if not os.path.exists(self.scoresFile): + json.dump({}, open(self.scoresFile, 'w')) + self.scores = json.load(open(self.scoresFile, 'r')) + # Per channel games + self.games = {} + # Hook in + self.hooks=[ModuleHook("PRIVMSG", self.scramble)] + + def scramble(self, args, prefix, trailing): + channel = args[0] + if channel[0] == "#": + if not channel in self.games: + self.games[channel]=scrambleGame(self, channel) + self.games[channel].scramble(args, prefix, trailing) + + def saveScores(self): + json.dump(self.scores, open(self.scoresFile, 'w')) + + def getScore(self, player, add=0): + player = player.lower() + if not player in self.scores: + self.scores[player] = 0 + if not add == 0: + self.scores[player]+=add + self.saveScores() + + return self.scores[player] + + def getScoreNoWrite(self, player): + if not player.lower() in self.scores: + return 0 + else: + return self.getScore(player) + + def ondisable(self): + self.log.info("Scramble: Unload requested, ending games...") + for game in self.games: + self.games[game].gameover() + self.saveScores() class scrambleGame: - def __init__(self, master, channel): - self.master = master - self.channel = channel - # Running? - self.running = False - # Current word - self.currentWord = None - # Current word, scrambled - self.scrambled = None - # Online? - self.scrambleOn = False - # Count down to hints - self.hintTimer = None - # of hints given - self.hintsGiven = 0 - # Cooldown between words - self.nextTimer = None - # How many guesses submitted this round - self.guesses = 0; - # How many games in a row where nobody guessed - self.gamesWithoutGuesses = 0; - - self.delayHint = self.master.config["hintDelay"]; - self.delayNext = self.master.config["delayNext"]; - self.maxHints = self.master.config["maxHints"]; - self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]; - - def gameover(self): - self.clearTimers(); - self.running = False - def clearTimers(self): - self.clearTimer(self.nextTimer) - self.clearTimer(self.hintTimer) - def clearTimer(self, timer): - if timer: - timer.cancel() - def scramble(self, args, prefix, trailing): - prefix = self.master.bot.decodePrefix(prefix) - sender = prefix.nick - cmd = self.master.bot.messageHasCommand(".scrambleon", trailing) - if cmd and not self.running: - self.running = True - self.startScramble() - return - cmd = self.master.bot.messageHasCommand(".scrambleoff", trailing) - if cmd and self.running: - self.gameover() - self.running = False - return - cmd = self.master.bot.messageHasCommand(".scramble top", trailing) - if cmd: - sortedscores = [] - for player in self.master.scores: - sortedscores.append({'name':player, 'score':self.master.scores[player]}) - sortedscores = sorted(sortedscores, key=itemgetter('score')) - sortedscores.reverse() - numScores = len(sortedscores) - if numScores>3: - numScores=3 - resp = "Top %s: " % str(numScores) - which = 1 - while which<=numScores: - resp+="%s: %s, " % (sortedscores[which-1]["name"], sortedscores[which-1]["score"]) - which+=1 - self.master.bot.act_PRIVMSG(self.channel, resp[:-2]) - cmd = self.master.bot.messageHasCommand(".scramble score", trailing) - if cmd: - someone = cmd.args.strip() - if len(someone) > 0: - self.master.bot.act_PRIVMSG(self.channel, "%s: %s has a score of %s" % (sender, someone, self.master.getScoreNoWrite(someone))) - else: - self.master.bot.act_PRIVMSG(self.channel, "%s: %s" % (sender, self.master.getScore(sender))) - if self.currentWord and trailing.strip().lower() == self.currentWord: - playerScore = self.master.getScore(sender, 1) - self.master.bot.act_PRIVMSG(self.channel, "%s guessed the word - %s! %s now has %s points. Next word in %s seconds." % (sender, self.currentWord, sender, playerScore, self.delayNext)) - self.currentWord = None - self.clearTimers() - self.hintsGiven = 0 - self.nextTimer = Timer(self.delayNext, self.startNewWord) - self.nextTimer.start() - self.guesses=0 - else: - self.guesses+=1 - - def startScramble(self): - self.clearTimer(self.nextTimer) - self.nextTimer = Timer(0, self.startNewWord) - self.nextTimer.start() - - def startNewWord(self): - self.currentWord = self.pickWord() - self.master.log.info("Scramble: New word for %s: %s" % (self.channel, self.currentWord)) - self.scrambled = self.scrambleWord(self.currentWord) - self.master.bot.act_PRIVMSG(self.channel, "New word - %s " % (self.scrambled)) - - self.clearTimer(self.hintTimer) - self.hintTimer = Timer(self.delayHint, self.giveHint) - self.hintTimer.start() - - def giveHint(self): - self.hintsGiven+=1 - - if self.hintsGiven>=len(self.currentWord) or self.hintsGiven > self.maxHints: - self.abortWord() - return - - blanks = "" - for letter in list(self.currentWord): - if letter == " ": - blanks+=" " - else: - blanks+="_" - partFromWord = self.currentWord[0:self.hintsGiven] - partFromBlanks = blanks[self.hintsGiven:] - hintstr = partFromWord+partFromBlanks - - self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr)) - - self.clearTimer(self.hintTimer) - self.hintTimer = Timer(self.delayHint, self.giveHint) - self.hintTimer.start() - - def abortWord(self): - cur = self.currentWord - self.currentWord = None - self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was %s. Next word in %s seconds." % (cur, self.delayNext)) - self.hintsGiven = 0 - self.clearTimer(self.nextTimer) - - if self.guesses==0: - self.gamesWithoutGuesses+=1 - if self.gamesWithoutGuesses >= self.abortAfterNoGuesses: - self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scrambleon to start again.") - self.gameover() - return - else: - self.gamesWithoutGuesses=0 - - self.nextTimer = Timer(self.delayNext, self.startNewWord) - self.nextTimer.start() - - def pickWord(self): - f = open(self.master.wordsFile, "r") - skip = random.randint(0, self.master.wordsCount) - while skip>=0: - f.readline() - skip-=1 - picked = f.readline().strip().lower() - f.close() - return picked - - def scrambleWord(self, word): - scrambled = "" - for subword in word.split(" "): - scrambled+=self.scrambleIndividualWord(subword)+ " " - return scrambled.strip() - - def scrambleIndividualWord(self, word): - scrambled = list(word) - random.shuffle(scrambled) - return ''.join(scrambled).lower() \ No newline at end of file + def __init__(self, master, channel): + self.master = master + self.channel = channel + # Running? + self.running = False + # Current word + self.currentWord = None + # Current word, scrambled + self.scrambled = None + # Online? + self.scrambleOn = False + # Count down to hints + self.hintTimer = None + # of hints given + self.hintsGiven = 0 + # Cooldown between words + self.nextTimer = None + # How many gamesWithoutGuesses submitted this round + self.guesses = 0; + # How many games in a row where nobody guessed + self.gamesWithoutGuesses = 0; + + self.delayHint = self.master.config["hintDelay"]; + self.delayNext = self.master.config["delayNext"]; + self.maxHints = self.master.config["maxHints"]; + self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]; + + def gameover(self): + self.clearTimers(); + self.running = False + def clearTimers(self): + self.clearTimer(self.nextTimer) + self.clearTimer(self.hintTimer) + def clearTimer(self, timer): + if timer: + timer.cancel() + def scramble(self, args, prefix, trailing): + prefix = self.master.bot.decodePrefix(prefix) + sender = prefix.nick + cmd = self.master.bot.messageHasCommand(".scrambleon", trailing) + if cmd and not self.running: + self.running = True + self.startScramble() + return + cmd = self.master.bot.messageHasCommand(".scrambleoff", trailing) + if cmd and self.running: + self.gameover() + self.running = False + return + cmd = self.master.bot.messageHasCommand(".scramble top", trailing) + if cmd: + sortedscores = [] + for player in self.master.scores: + sortedscores.append({'name':player, 'score':self.master.scores[player]}) + sortedscores = sorted(sortedscores, key=itemgetter('score')) + sortedscores.reverse() + numScores = len(sortedscores) + if numScores>3: + numScores=3 + resp = "Top %s: " % str(numScores) + which = 1 + while which<=numScores: + resp+="%s: %s, " % (sortedscores[which-1]["name"], sortedscores[which-1]["score"]) + which+=1 + self.master.bot.act_PRIVMSG(self.channel, resp[:-2]) + cmd = self.master.bot.messageHasCommand(".scramble score", trailing) + if cmd: + someone = cmd.args.strip() + if len(someone) > 0: + self.master.bot.act_PRIVMSG(self.channel, "%s: %s has a score of %s" % (sender, someone, self.master.getScoreNoWrite(someone))) + else: + self.master.bot.act_PRIVMSG(self.channel, "%s: %s" % (sender, self.master.getScore(sender))) + if self.currentWord and trailing.strip().lower() == self.currentWord: + playerScore = self.master.getScore(sender, 1) + self.master.bot.act_PRIVMSG(self.channel, "%s guessed the word - %s! %s now has %s points. Next word in %s seconds." % (sender, self.currentWord, sender, playerScore, self.delayNext)) + self.currentWord = None + self.clearTimers() + self.hintsGiven = 0 + self.nextTimer = Timer(self.delayNext, self.startNewWord) + self.nextTimer.start() + self.guesses=0 + else: + self.guesses+=1 + + def startScramble(self): + self.clearTimer(self.nextTimer) + self.nextTimer = Timer(0, self.startNewWord) + self.nextTimer.start() + + def startNewWord(self): + self.currentWord = self.pickWord() + self.master.log.info("Scramble: New word for %s: %s" % (self.channel, self.currentWord)) + self.scrambled = self.scrambleWord(self.currentWord) + self.master.bot.act_PRIVMSG(self.channel, "New word - %s " % (self.scrambled)) + + self.clearTimer(self.hintTimer) + self.hintTimer = Timer(self.delayHint, self.giveHint) + self.hintTimer.start() + + def giveHint(self): + self.hintsGiven+=1 + + if self.hintsGiven>=len(self.currentWord) or self.hintsGiven > self.maxHints: + self.abortWord() + return + + blanks = "" + for letter in list(self.currentWord): + if letter == " ": + blanks+=" " + else: + blanks+="_" + partFromWord = self.currentWord[0:self.hintsGiven] + partFromBlanks = blanks[self.hintsGiven:] + hintstr = partFromWord+partFromBlanks + + self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr)) + + self.clearTimer(self.hintTimer) + self.hintTimer = Timer(self.delayHint, self.giveHint) + self.hintTimer.start() + + def abortWord(self): + cur = self.currentWord + self.currentWord = None + self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was %s. Next word in %s seconds." % (cur, self.delayNext)) + self.hintsGiven = 0 + self.clearTimer(self.nextTimer) + + if self.guesses==0: + self.gamesWithoutGuesses+=1 + if self.gamesWithoutGuesses >= self.abortAfterNoGuesses: + self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scrambleon to start again.") + self.gameover() + return + else: + self.gamesWithoutGuesses=0 + + self.nextTimer = Timer(self.delayNext, self.startNewWord) + self.nextTimer.start() + + def pickWord(self): + f = open(self.master.wordsFile, "r") + skip = random.randint(0, self.master.wordsCount) + while skip>=0: + f.readline() + skip-=1 + picked = f.readline().strip().lower() + f.close() + return picked + + def scrambleWord(self, word): + scrambled = "" + for subword in word.split(" "): + scrambled+=self.scrambleIndividualWord(subword)+ " " + return scrambled.strip() + + def scrambleIndividualWord(self, word): + scrambled = list(word) + random.shuffle(scrambled) + return ''.join(scrambled).lower() \ No newline at end of file diff --git a/pyircbot/modules/Test.py b/pyircbot/modules/Test.py new file mode 100755 index 0000000..01983ca --- /dev/null +++ b/pyircbot/modules/Test.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +""" +.. module:: Test + :synopsis: For testing code + +.. moduleauthor:: Dave Pedu + +""" + +from pyircbot.modulebase import ModuleBase,ModuleHook + +class Test(ModuleBase): + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName) + self.hooks=[ModuleHook("PRIVMSG", self.dotest)] + + def dotest(self, args): + print("DOTEST(%s)"%(args,)) diff --git a/pyircbot/pyircbot.py b/pyircbot/pyircbot.py index 78d63f1..1d49054 100644 --- a/pyircbot/pyircbot.py +++ b/pyircbot/pyircbot.py @@ -301,9 +301,7 @@ class PyIRCBot: basepath = "%s/config/%s" % (self.botconfig["bot"]["datadir"], moduleName) - if os.path.exists("%s.yml"%basepath): - return "%s.yml"%basepath - elif os.path.exists("%s.json"%basepath): + if os.path.exists("%s.json"%basepath): return "%s.json"%basepath return None @@ -360,15 +358,12 @@ class PyIRCBot: def load(filepath): """Return an object from the passed filepath - :param filepath: path to a file of json or yaml format. filename must end with .json or .yml + :param filepath: path to a json file. filename must end with .json :type filepath: str :Returns: | dict """ - if filepath.endswith(".yml"): - from yaml import load - return load(open(filepath, 'r')) - - elif filepath.endswith(".json"): + + if filepath.endswith(".json"): from json import load return load(open(filepath, 'r')) else: