Merge branch 'master' of https://github.com/oddluck/limnoria-plugins
This commit is contained in:
commit
ce7df7a774
|
|
@ -0,0 +1,29 @@
|
|||
Play interactive fiction Z-Machine games like the Infocom classic Zork.
|
||||
|
||||
Requires limnoria, python 3, pexpect
|
||||
|
||||
Uses the dfrotz (dumb frotz) interpreter https://github.com/DavidGriffith/frotz
|
||||
|
||||
Looks for games in ./games/ directory
|
||||
and for the binary at ./frotz/dfrotz
|
||||
|
||||
usage:
|
||||
frotz load <game name> ex. frotz load zork1.z5 - loads game
|
||||
z <command> ex. z open mailbox, z look - send command
|
||||
z <no input> - sends a blank line equivalent to [RETURN]/[ENTER] when needed
|
||||
frotz stop - ends the game
|
||||
frotz games - lists contents of ./games/ directory
|
||||
|
||||
one game allowed to run per channel/pm. will prompt you to stop running games before allowing a new one to be started.
|
||||
this limits the number of potential child dfrotz processes and keeps this simpler in terms of routing the right game data
|
||||
to the right place.
|
||||
|
||||
game text reformatted to eliminate line/by line output and for easier reading on various screen sizes.
|
||||
|
||||
Some games and a frotz binary included, may need to build your own depending on your system.
|
||||
https://github.com/DavidGriffith/frotz/blob/master/DUMB
|
||||
|
||||
python3 -m pip install pexpect
|
||||
|
||||
Games included here are easily found and freely available all over the net, their owners are their respective owners
|
||||
and if you believe a game should not be here contact me and I will remove it immediately.
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
###
|
||||
# Copyright (c) 2019 oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
"""
|
||||
Frotz: Play interactive fiction games
|
||||
"""
|
||||
|
||||
import supybot
|
||||
import supybot.world as world
|
||||
|
||||
# Use this for the version of this plugin. You may wish to put a CVS keyword
|
||||
# in here if you're keeping the plugin in CVS or some similar system.
|
||||
__version__ = ""
|
||||
|
||||
# XXX Replace this with an appropriate author or supybot.Author instance.
|
||||
__author__ = supybot.authors.unknown
|
||||
|
||||
# This is a dictionary mapping supybot.Author instances to lists of
|
||||
# contributions.
|
||||
__contributors__ = {}
|
||||
|
||||
# This is a url where the most recent plugin package can be downloaded.
|
||||
__url__ = ''
|
||||
|
||||
from . import config
|
||||
from . import plugin
|
||||
from imp import reload
|
||||
# In case we're being reloaded.
|
||||
reload(config)
|
||||
reload(plugin)
|
||||
# Add more reloads here if you add third-party modules and want them to be
|
||||
# reloaded when this plugin is reloaded. Don't forget to import them as well!
|
||||
|
||||
if world.testing:
|
||||
from . import test
|
||||
|
||||
Class = plugin.Class
|
||||
Frotz = config.Frotz
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
###
|
||||
# Copyright (c) 2019, oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.registry as registry
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
_ = PluginInternationalization('Frotz')
|
||||
except:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x: x
|
||||
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by supybot to configure this module. advanced is
|
||||
# a bool that specifies whether the user identified themself as an advanced
|
||||
# user or not. You should effect your configuration by manipulating the
|
||||
# registry as appropriate.
|
||||
from supybot.questions import expect, anything, something, yn
|
||||
conf.registerPlugin('Frotz', True)
|
||||
|
||||
|
||||
Frotz = conf.registerPlugin('Frotz')
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,121 @@
|
|||
###
|
||||
# Copyright (c) 2019 oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.callbacks as callbacks
|
||||
import supybot.ircmsgs as ircmsgs
|
||||
import os
|
||||
import pexpect
|
||||
import re
|
||||
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
_ = PluginInternationalization('Infocom')
|
||||
except ImportError:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x: x
|
||||
|
||||
class Frotz(callbacks.Plugin):
|
||||
"""
|
||||
Play Infocom (Interactive Fiction, Z_machine) Games.
|
||||
"""
|
||||
threaded = True
|
||||
|
||||
def __init__(self, irc):
|
||||
self.__parent = super(Frotz, self)
|
||||
self.__parent.__init__(irc)
|
||||
self.game = {}
|
||||
self.game_path = "{0}/games/".format(os.path.dirname(os.path.abspath(__file__)))
|
||||
self.binary = '{0}/frotz/dfrotz'.format(os.path.dirname(os.path.abspath(__file__)))
|
||||
#self.prompts = [">", "***MORE***", pexpect.TIMEOUT, pexpect.EOF]
|
||||
|
||||
def load(self, irc, msg, args, input):
|
||||
"""<game_name>
|
||||
Load <game_name.z*>.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
game_name = input
|
||||
try:
|
||||
if self.game[channel]:
|
||||
irc.reply("There is a game already in progress on {0}. Please end that game first.".format(channel))
|
||||
except:
|
||||
irc.reply("Starting {0} on {1}. Please wait...".format(game_name, channel))
|
||||
self.game.setdefault(channel, None)
|
||||
game_file= "{0}{1}".format(self.game_path, game_name)
|
||||
self.game[channel] = pexpect.spawn("{0} -S 0 {1}".format(self.binary, game_file))
|
||||
response = self.output(self.game[channel])
|
||||
if len(response) > 2:
|
||||
irc.reply(re.sub(' +', ' ', response[0]), prefixNick=False)
|
||||
irc.reply(" ".join(response[1:]).replace(' .', '.'), prefixNick=False)
|
||||
else:
|
||||
irc.reply(" ".join(response).replace(' .', '.'), prefixNick=False)
|
||||
load = wrap(load, ['text'])
|
||||
|
||||
|
||||
def output(self, output):
|
||||
response = []
|
||||
prompts = ["\n>", "\n> >", "to begin]", "\n\*\*\*MORE\*\*\*", pexpect.TIMEOUT]
|
||||
output.expect(prompts, timeout=5)
|
||||
for line in output.before.splitlines():
|
||||
if line.strip():
|
||||
response.append(line.decode().strip())
|
||||
return response
|
||||
|
||||
def stop(self, irc, msg, args):
|
||||
"""
|
||||
Stop game.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
try:
|
||||
if self.game[channel].isalive() is True:
|
||||
irc.reply("Stopping Game. Thanks for playing.")
|
||||
self.game[channel].close()
|
||||
self.game[channel].terminate()
|
||||
del self.game[channel]
|
||||
else:
|
||||
irc.reply("No game running in {0}".format(channel))
|
||||
except:
|
||||
irc.reply("No game started in {0}".format(channel))
|
||||
stop = wrap(stop)
|
||||
|
||||
def z(self, irc, msg, args, input):
|
||||
"""[<input>]
|
||||
Send user input or blank line (ENTER/RETURN) to the game.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
if input:
|
||||
command = input.strip()
|
||||
else:
|
||||
command = None
|
||||
try:
|
||||
if command:
|
||||
self.game[channel].sendline(command)
|
||||
else:
|
||||
self.game[channel].sendline()
|
||||
response = self.output(self.game[channel])
|
||||
if len(response) > 2:
|
||||
irc.reply(re.sub(' +', ' ', response[1]), prefixNick=False)
|
||||
irc.reply(" ".join(response[2:].replace(' .', '.')), prefixNick=False)
|
||||
else:
|
||||
irc.reply(" ".join(response).replace(' .', '.'), prefixNick=False)
|
||||
except:
|
||||
irc.reply("No game running in {0}?".format(channel))
|
||||
z = wrap(z, [additional('text')])
|
||||
|
||||
def games(self, irc, msg, args):
|
||||
"""
|
||||
List files in the game directory.
|
||||
"""
|
||||
reply = ", ".join(os.listdir(self.game_path))
|
||||
irc.reply(reply, prefixNick=False)
|
||||
games = wrap(games)
|
||||
|
||||
Class = Frotz
|
||||
|
|
@ -0,0 +1 @@
|
|||
pexpect
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
###
|
||||
# Copyright (c) 2019, oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
from supybot.test import *
|
||||
|
||||
|
||||
class InfocomTestCase(PluginTestCase):
|
||||
plugins = ('Frotz',)
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,18 @@
|
|||
# Fun
|
||||
Limnoria plugin to return a random joke, cat fact, useless fact, corporate buzzwords, startup idea, or advice from various APIs
|
||||
Limnoria plugin to return ascii art, random: joke, insult, cat fact, useless fact, corporate buzzwords, startup idea, or advice from various APIs
|
||||
|
||||
commands: advice, buzz, cat fact, joke, startup, useless, insult
|
||||
requirements: limnoria (obviously) python 3, requests, html
|
||||
|
||||
requires limnoria, python 3, requests
|
||||
|
||||
python3 -m pip install requests
|
||||
python3 -m pip install html
|
||||
|
||||
|
||||
commands: advice, ascii buzz, cat fact, joke, startup, useless, insult
|
||||
|
||||
|
||||
ascii --fontlist to get list of fonts
|
||||
ascii --font (font) (text) to use chosen font
|
||||
|
||||
|
||||
insult (target) optionally target the randomly generated insult at a nick in channel
|
||||
|
|
|
|||
|
|
@ -96,14 +96,42 @@ class Fun(callbacks.Plugin):
|
|||
irc.reply(response)
|
||||
startup = wrap(startup)
|
||||
|
||||
def insult(self, irc, msg, args):
|
||||
"""
|
||||
Insult generator.
|
||||
def insult(self, irc, msg, args, nick):
|
||||
"""[<nick>]
|
||||
Insult generator. Optionally send insult to <nick> (<nick> must be in channel).
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
data = requests.get("https://insult.mattbas.org/api/en/insult.json").json()
|
||||
irc.reply(data['insult'])
|
||||
insult = wrap(insult)
|
||||
if nick:
|
||||
response = "{0}: {1}".format(nick, data['insult'])
|
||||
irc.reply(response, prefixNick=False)
|
||||
else:
|
||||
irc.reply(data['insult'])
|
||||
insult = wrap(insult, [additional('nickInChannel')])
|
||||
|
||||
def ascii(self, irc, msg, args, optlist, text):
|
||||
"""[--font <font>] [--fontlist] [<text>]
|
||||
text to ASCII art
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
optlist = dict(optlist)
|
||||
if text:
|
||||
text = text.upper().strip()
|
||||
if 'font' in optlist:
|
||||
font = optlist.get('font')
|
||||
data = requests.get("https://artii.herokuapp.com/make?text={0}&font={1}".format(text, font))
|
||||
for line in data.text.splitlines():
|
||||
if line.strip():
|
||||
irc.reply(line, prefixNick=False)
|
||||
elif 'fontlist' in optlist:
|
||||
fontlist = requests.get("https://artii.herokuapp.com/fonts_list")
|
||||
response = sorted(fontlist.text.split('\n'))
|
||||
irc.reply(str(response).replace('\'', '').replace('[', '').replace(']', ''))
|
||||
elif 'font' not in optlist:
|
||||
data = requests.get("https://artii.herokuapp.com/make?text={0}&font=univers".format(text))
|
||||
for line in data.text.splitlines():
|
||||
if line.strip():
|
||||
irc.reply(line, prefixNick=False)
|
||||
ascii = wrap(ascii, [getopts({'font':'something', 'fontlist':''}), additional('text')])
|
||||
|
||||
Class = Fun
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
requests
|
||||
html
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
This branch uses the jservice.io api to supply questions.
|
||||
This plugin, a modification of TriviaTime, uses the jservice.io api to supply questions.
|
||||
|
||||
This no longer uses the internal question database, rendering question reporting, editing, etc. obsolete. Consider this a hack, though a fully functional one. Previous user stats are not affected by the change.
|
||||
This no longer uses the internal question database, rendering question reporting, editing, etc. obsolete. Consider this a hack, though a fully functional one. Previous user stats are not affected by the change. At some point I will break this out into its own plugin with options to choose category/value, but for now it works well enough as is.
|
||||
|
||||
#Configuration
|
||||
|
||||
|
|
|
|||
|
|
@ -550,9 +550,9 @@ class Game:
|
|||
answers = []
|
||||
questionType = 'regular'
|
||||
answers.append(re.sub('<[^<]+?>', '', unidecode(rawData[0]['answer'])).replace('\\', '').strip())
|
||||
points = float(rawData[0]['value'])
|
||||
if points is None:
|
||||
points = float(500)
|
||||
points = float(500)
|
||||
if rawData[0]['value']:
|
||||
points = float(rawData[0]['value'])
|
||||
question = "({0}) [${1}] {2}: {3}".format(airdate[0], int(points), rawData[0]['category']['title'].title(), re.sub('<[^<]+?>', '', rawData[0]['question']).replace('\\', ''))
|
||||
# Calculate additional points
|
||||
#addPoints = -5 * netTimesAnswered
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
requests
|
||||
unidecode
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
requests
|
||||
html
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
MUD Client
|
||||
|
||||
Connect to a MUD over telnet and play over channel/PM. Allows one telnet session per nick so you can play with your IRC friends.
|
||||
MUD not included, there are plenty out there, there is just a client to allow playing them over IRC.
|
||||
|
||||
config plugins.MUD.server (server address)
|
||||
|
||||
config plugins.MUD.port (port)
|
||||
|
||||
MUD join (connect to server/port and print output to current channel)
|
||||
|
||||
MUD m (send text to MUD or newline if blank and return output)
|
||||
|
||||
MUD stop (disconnect the telnet session)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
###
|
||||
# Copyright (c) 2019 oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
"""
|
||||
MUD: Play interactive fiction games
|
||||
"""
|
||||
|
||||
import supybot
|
||||
import supybot.world as world
|
||||
|
||||
# Use this for the version of this plugin. You may wish to put a CVS keyword
|
||||
# in here if you're keeping the plugin in CVS or some similar system.
|
||||
__version__ = ""
|
||||
|
||||
# XXX Replace this with an appropriate author or supybot.Author instance.
|
||||
__author__ = supybot.authors.unknown
|
||||
|
||||
# This is a dictionary mapping supybot.Author instances to lists of
|
||||
# contributions.
|
||||
__contributors__ = {}
|
||||
|
||||
# This is a url where the most recent plugin package can be downloaded.
|
||||
__url__ = ''
|
||||
|
||||
from . import config
|
||||
from . import plugin
|
||||
from imp import reload
|
||||
# In case we're being reloaded.
|
||||
reload(config)
|
||||
reload(plugin)
|
||||
# Add more reloads here if you add third-party modules and want them to be
|
||||
# reloaded when this plugin is reloaded. Don't forget to import them as well!
|
||||
|
||||
if world.testing:
|
||||
from . import test
|
||||
|
||||
Class = plugin.Class
|
||||
MUD = config.MUD
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
###
|
||||
# Copyright (c) 2019, oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.registry as registry
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
_ = PluginInternationalization('MUD')
|
||||
except:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x: x
|
||||
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by supybot to configure this module. advanced is
|
||||
# a bool that specifies whether the user identified themself as an advanced
|
||||
# user or not. You should effect your configuration by manipulating the
|
||||
# registry as appropriate.
|
||||
from supybot.questions import expect, anything, something, yn
|
||||
conf.registerPlugin('MUD', True)
|
||||
|
||||
MUD = conf.registerPlugin('MUD')
|
||||
|
||||
conf.registerGlobalValue(MUD, 'server',
|
||||
registry.String('', _("""Server Address""")))
|
||||
|
||||
conf.registerGlobalValue(MUD, 'port',
|
||||
registry.Integer('', _("""Port""")))
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
###
|
||||
# Copyright (c) 2019 oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.callbacks as callbacks
|
||||
import supybot.ircmsgs as ircmsgs
|
||||
from telnetlib import Telnet
|
||||
import re
|
||||
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
_ = PluginInternationalization('MUD')
|
||||
except ImportError:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x: x
|
||||
|
||||
class MUD(callbacks.Plugin):
|
||||
"""
|
||||
Play Infocom (Interactive Fiction, Z_machine) Games.
|
||||
"""
|
||||
threaded = True
|
||||
|
||||
def __init__(self, irc):
|
||||
self.__parent = super(MUD, self)
|
||||
self.__parent.__init__(irc)
|
||||
self.tn = {}
|
||||
self.ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
|
||||
|
||||
def join(self, irc, msg, args):
|
||||
"""
|
||||
Join the MUD
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
nick = msg.nick
|
||||
try:
|
||||
if self.tn[nick]:
|
||||
irc.reply("You already have an open connection. Please stop that connection first.")
|
||||
except:
|
||||
self.tn[nick] = Telnet(self.registryValue('server'), self.registryValue('port'))
|
||||
response = self.output(self.tn[nick])
|
||||
for line in response:
|
||||
if line.strip():
|
||||
irc.reply(line, prefixNick=False)
|
||||
join = wrap(join)
|
||||
|
||||
def m(self, irc, msg, args, input):
|
||||
"""[<input>]
|
||||
Send user input or blank line (ENTER/RETURN) to the game.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
nick = msg.nick
|
||||
if input:
|
||||
command = input.strip()
|
||||
else:
|
||||
command = None
|
||||
if self.tn[nick]:
|
||||
if command:
|
||||
self.tn[nick].write(command.encode() + b"\r\n")
|
||||
else:
|
||||
self.tn[nick].write(b"\r\n")
|
||||
response = self.output(self.tn[nick])
|
||||
for line in response:
|
||||
if line.strip():
|
||||
irc.reply(line, prefixNick=False)
|
||||
else:
|
||||
irc.reply("Nick not connected?")
|
||||
m = wrap(m, [additional('text')])
|
||||
|
||||
def stop(self, irc, msg, args):
|
||||
"""
|
||||
Stop game.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
nick = msg.nick
|
||||
try:
|
||||
if self.tn[nick]:
|
||||
irc.reply("Closing connection.")
|
||||
self.tn[nick].close()
|
||||
del self.tn[nick]
|
||||
else:
|
||||
irc.reply("No connection opened.")
|
||||
except:
|
||||
irc.reply("No connection opened.")
|
||||
stop = wrap(stop)
|
||||
|
||||
def output(self, output):
|
||||
response = []
|
||||
response = output.read_until(b"\a", timeout=2)
|
||||
clean = []
|
||||
for line in response.splitlines():
|
||||
clean.append(self.ansi_escape.sub('', line.decode()))
|
||||
return clean
|
||||
|
||||
Class = MUD
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
###
|
||||
# Copyright (c) 2019, oddluck
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
###
|
||||
|
||||
from supybot.test import *
|
||||
|
||||
|
||||
class InfocomTestCase(PluginTestCase):
|
||||
plugins = ('MUD',)
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||
|
||||
|
||||
|
||||
12
README.md
12
README.md
|
|
@ -1,12 +1,20 @@
|
|||
Plugins I wrote or forked. All working under Python 3.
|
||||
|
||||
repolist oddluck / install oddluck (Plugin) (testing Limnoria branch)
|
||||
repolist oddluck / install oddluck Plugin_Name (testing Limnoria branch)
|
||||
|
||||
Requires Limnoria, obviously. Additional requirements in readmes or requirements.txt files
|
||||
|
||||
MUD
|
||||
|
||||
MUD client. Play Multi User Dungeon text games with others over IRC. Multi-user support, play with IRC friends.
|
||||
|
||||
Frotz
|
||||
|
||||
Play interactive fiction games such as the Infocom classics Zork, The Hitchhiker's Guide to the Galaxy, Leather Goddesses of Phobos, etc. multiplayer and multi-channel/pm supported.
|
||||
|
||||
Fun
|
||||
|
||||
return a random joke, cat fact, useless fact, corporate buzzwords, startup idea, insult, or advice from various APIs
|
||||
return text-to-ascii-art, a random; joke, cat fact, useless fact, corporate buzzwords, startup idea, insult, or advice from various APIs
|
||||
|
||||
|
||||
Lyrics
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
pickle
|
||||
time
|
||||
|
|
@ -0,0 +1 @@
|
|||
requests
|
||||
Loading…
Reference in New Issue