This commit is contained in:
oddluck 2019-02-19 12:27:08 -05:00
commit ce7df7a774
55 changed files with 521 additions and 15 deletions

29
Frotz/README.md Normal file
View File

@ -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.

43
Frotz/__init__.py Normal file
View File

@ -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

28
Frotz/config.py Normal file
View File

@ -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')

BIN
Frotz/frotz/dfrotz Normal file

Binary file not shown.

Binary file not shown.

BIN
Frotz/games/adventure.z5 Normal file

Binary file not shown.

BIN
Frotz/games/ballyhoo.z3 Normal file

Binary file not shown.

BIN
Frotz/games/beyond_zork.z5 Normal file

Binary file not shown.

BIN
Frotz/games/border_zone.z5 Normal file

Binary file not shown.

BIN
Frotz/games/cutthroats.z3 Normal file

Binary file not shown.

BIN
Frotz/games/deadline.z3 Normal file

Binary file not shown.

BIN
Frotz/games/enchanter.z3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Frotz/games/infidel.z3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Frotz/games/moonmist.z3 Normal file

Binary file not shown.

Binary file not shown.

BIN
Frotz/games/planetfall.z5 Normal file

Binary file not shown.

Binary file not shown.

BIN
Frotz/games/sampler1.z3 Normal file

Binary file not shown.

BIN
Frotz/games/sampler2.z3 Normal file

Binary file not shown.

BIN
Frotz/games/seastalker.z3 Normal file

Binary file not shown.

Binary file not shown.

BIN
Frotz/games/sorcery.z3 Normal file

Binary file not shown.

BIN
Frotz/games/spellbreaker.z3 Normal file

Binary file not shown.

BIN
Frotz/games/starcross.z3 Normal file

Binary file not shown.

BIN
Frotz/games/stationfall.z3 Normal file

Binary file not shown.

BIN
Frotz/games/suspect.z3 Normal file

Binary file not shown.

BIN
Frotz/games/suspended.z3 Normal file

Binary file not shown.

BIN
Frotz/games/trinity.z4 Normal file

Binary file not shown.

BIN
Frotz/games/wishbringer.z5 Normal file

Binary file not shown.

BIN
Frotz/games/witness.z3 Normal file

Binary file not shown.

BIN
Frotz/games/zork1.z5 Normal file

Binary file not shown.

BIN
Frotz/games/zork2.z3 Normal file

Binary file not shown.

BIN
Frotz/games/zork3.z3 Normal file

Binary file not shown.

121
Frotz/plugin.py Normal file
View File

@ -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

1
Frotz/requirements.txt Normal file
View File

@ -0,0 +1 @@
pexpect

17
Frotz/test.py Normal file
View File

@ -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:

View File

@ -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

View File

@ -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

2
Fun/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
requests
html

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,2 @@
requests
unidecode

2
Lyrics/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
requests
html

14
MUD/README.md Normal file
View File

@ -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)

42
MUD/__init__.py Normal file
View File

@ -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

33
MUD/config.py Normal file
View File

@ -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""")))

103
MUD/plugin.py Normal file
View File

@ -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

18
MUD/test.py Normal file
View File

@ -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:

View File

@ -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

2
Uno/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
pickle
time

1
Weed/requirements.txt Normal file
View File

@ -0,0 +1 @@
requests