# Game commands and socials
from util import *
import gzip,event,core
cmds = []
helpd = {}
def D(**data): # register command with data/flags
def d(f): cmds.append((f.func_name,f,data)); return f
return d
C = lambda f: D()(f) # short form for no args
# if this decorator is used, l is parsed into v
def arg(f,req=1,w=0):
def z(S,l):
v = 0
if l or req:
if req and not l: return S.sendl(cap(f.func_name) + " what?")
v = S.find(l,w)
if not v: return S.sendl("You don't see that here.")
f(S,v)
z.orig = f
z.func_name = f.func_name
return z
optarg = lambda f: arg(f,0)
warg = lambda w: lambda f: arg(f,1,w) # ugly, eh?
# handle a command
def do(a,l):
if not l: return
if l[0] == ",": # special handling for abbreviated form of say
if a.foe: l = "say %s, %s" % (a.foe.name,l[1:].lstrip())
else: l = "say %s" % l[1:].lstrip()
x = l.split(" ", 1)
for c,f,d in cmds:
if c.startswith(x[0]):
if "nabbr" in d and c != x[0]:
if "hide" in d: continue
return a.sendl("Must spell out %s." % c)
if "admin" in d and not a.admin:
return a.sendl("Must be admin.")
f(a, (len(x) > 1 and x[1]) or "")
return
else: a.sendl("Huh?")
# commands
@C
def help(S,l):
if l:
if l in helpd: S.write(helpd[l])
else: S.sendl("No such topic.")
else:
S.sendl('Also try typing "commands".\r\n\r\nHelp topics:')
for t in sorted(helpd): S.sendl(" "+t)
# soc = if true, show socials, otherwise show commands
def clist(S,soc):
i=0
for c,f,d in sorted(cmds):
if soc ^ ("soc" in d) or "hide" in d: continue
x = "%s%s" % (c, ("admin" in d and "*" or ""))
S.write("%-18s" % x)
if i % 4 == 3: S.sendl()
i += 1
S.sendl()
@C
def north(S,l): S.go("north")
@C
def south(S,l): S.go("south")
@C
def west(S,l): S.go("west")
@C
def east(S,l): S.go("east")
@C
def up(S,l): S.go("up")
@C
def down(S,l): S.go("down")
@D(nabbr=1)
def quit(S,l):
if S.foe: return S.sendl("Not during combat.")
else: S.c.handle_close()
@C
def commands(S,l): clist(S, 0)
@C
def socials(S,l): clist(S, 1)
@C
@optarg
def look(S,v):
if v: examine.orig(S,v)
else:
S.sendl(S.room.descTo(S))
S.sendl("{GExits{x: "+', '.join(S.room.ex))
@C
@arg
def examine(S,v):
Act(S,v).subj("You look at $VN.").vict("$SN looks at you.")
S.sendl(v.desc)
if is_a(v,core.Actor):
S.sendl("\r\n"+v.status())
if v.worn:
S.sendl("%s is wearing %s."%(cap(v.SE)," and ".join([x.name for x in v.worn.values()])))
@C
@warg(1) # room only
def get(S,v): v.on_get(S)
@C
@warg(2) # inv only
def drop(S,v): v.on_drop(S)
@C
@warg(2) # inv only
def wear(S,v):
v.on_wear(S)
@C
@warg(2) # inv only
def remove(S,v):
v.on_remove(S)
@C
def give(S,l):
lv,lto = fit(xarg(l))
if not lv or not lto or lto=="to": return S.sendl("Syntax: give <item> <person>")
v,to = S.find(lv),S.find(lto)
if not v: S.sendl("No such item here.")
elif not to: S.sendl("No such person here.")
else: v.on_give(S,to)
@C
def lists(S,l):
ss = S.room.shops
if not ss: S.sendl("No shops here.")
for s in ss: s.show(S)
@C
def buy(S,l):
if not l: return lists(S,l)
for s in S.room.shops:
z = s.find(l)
if z: break
else: return S.sendl("Not for sale here.")
S.buy(s,z)
@C
@arg
def drink(S,v):
v.on_drink(S)
@C # throw something
def throw(S,l):
lv,lat = fit(xarg(l))
if not lv or lat=="at": return S.sendl("Syntax: throw <item> [victim]")
v,at = S.find(lv,2),S.find(lat)
if not v: S.sendl("No such item.")
elif lat and not at: S.sendl("No such person here.")
else:
if not S.foe: S.ks = 1
if not S.fight(at): return
if not S.ks: return S.sendl("You're not ready to attack yet.")
v.on_throw(S,S.foe)
@C
def who(S,l):
S.sendl("{YOnline players:{x")
for p in cplayers():
ip = (S.admin and p.c.addr[0]) or ""
S.sendl(" %-15s %s" % (p.name,ip))
@C
def say(S,l):
if not l: return S.sendl("Say what?")
Act(S, 0, cap(l)).subj('You say, "{m$OT{x"').room('$SN says, "{m$OT{x"')
# battle insults
if S.foe and find(l.split(',')[0].lower(),[S.foe]): # UGLY but safer
if not S.ks:
Act(S).subj("{BYou botched the insult due to bad timing.{x").room(
"$SN botched the insult to bad timing.")
return
# This would be a good place to check for lame/awesome insults
# namely, check for shortness, repeats, or unpronounceable nonsense
# conversely, would it be a good idea to reward rhyming insults?
S.rhit(8,'insult')
@C
def ooc(S,l):
Act(S, 0, l).subj('You OOC: {M$OT{x').world('$SN OOCs: {M$OT{x')
@C
def mydesc(S,l):
def cb(t): S.desc = t
from mud import EditUI
S.c.ui = EditUI(S.c, S.desc, cb)
@C
def tell(S,l):
lv,l = fit(l.split(None,1))
if not lv: return S.sendl("Tell whom what?")
for p in cplayers():
if p.name.startswith(fcap(lv)): break
else: return S.sendl("No such player online.")
Act(S,p,l).subj("You tell $VN: {c$OT{x").vict("$SN tells you: {c$OT{x")
@C
@arg
def fight(S,v):
S.fight(v)
@C
@optarg
def hit(S,v):
if not S.foe: S.ks = 1 # one free attack
if not S.fight(v): return
if not v and S.foe: v = S.foe
if not S.ks: return S.sendl("You're not ready to attack yet.")
x = S.worn.get("in grasp",S.FISTS) # weapon (if available) or fists
Act(S,x,v).subj("You swing $VN at $ON.").vict("$SN swings $VN at you.").room("$SN swings $VN at $ON.")
S.hit(x.dam)
@C
def flee(S,l):
Act(S).subj("You try to flee!").room("$SN tries to flee!")
if S.foe:
S.rpc -= S.rpm/10
S.checklose()
if randint(0,5) < 3: S.flee()
@C
def rname(S,l):
if not S.room.try_edit(S): return
if not l: return S.sendl("Set room name to what?")
S.room.name = l
S.sendl("Room name changed to " + l)
@C
def rdesc(S,l):
if not S.room.try_edit(S): return
def cb(t): S.room.desc = t
from mud import EditUI
S.c.ui = EditUI(S.c, S.room.desc, cb)
ztypes = {"smbiz":["lemonade"],"biz":["coffee"],"night":["beer"],"res-high":["apartment"]}
@C
def rent(S,l):
b = S.room.biz
if b.owner: return S.sendl("Not available for rent.")
dep = b.rent * 3 + 10
if not l:
S.sendl('Land for rent (type "rent apply <type>" to rent)'+
"\r\nZoning: %s (valid types: %s)" % (b.zone,ztypes[b.zone])+
"\r\nDeposit+fee: $%d" % dep+
"\r\nHourly rent: $%d" % b.rent)
return
la,l = xarg(l)
if not l or la != "apply": return S.sendl("rent apply <type>")
if dep > S.cash: return S.sendl("Not enough cash.")
if l not in ztypes[b.zone]: return S.sendl("Wrong type.")
S.cash -= dep
b.owner = S.name
b.type = l
S.sendl("You rent the property. Rent will be taken from your cash hourly.")
@C
def shop(S,l):
biz = S.room.biz
if biz.owner != S.name:
return S.sendl("Not your property.")
o,l = fit(xarg(l))
if not o: return S.sendl("Options: new, add <flavors>, sample <flavor>, price '<item>' <price>, restock")
shop = S.room.shop
if o == "new":
if shop: S.sendl("Already got one.")
else: S.room.shop = core.BevShop(biz.type); S.sendl("Created. Sales revenue paid hourly.")
return
if not shop: return S.sendl('Create a shop first.')
if o == "add":
import world
fls = sorted(sxarg(l))
if not l or not set(fls) <= set(shop.fls): # shop has chosen flavors?
return S.sendl("Valid flavors: "+' '.join(shop.fls))
x = world.Drink()
x.fls = fls+[shop.type]
x.name = "a glass of "+l+" "+shop.type
shop.inv += [[x,1,10]]
S.sendl("Added %s." % x.name)
if o == "sample":
x = S.find(l,2)
if not x: return S.sendl("You don't have that.")
if not is_a(x,core.Sample): return S.sendl("Not a flavor sample.")
shop.fls += [x.fl]
S.sendl("Sampled %s." % x.fl)
x.goto(0)
if o == "restock":
S.sendl("Restocked at a cost of $%s." % shop.restock())
if o == "price":
l,tpr = fit(l.rsplit(None,1))
x = shop.find(l)
if not x: return S.sendl("No such item in shop.")
if not tpr.isdigit() or int(tpr) <= 0: return S.sendl("Price must be a positive number.")
x[2] = int(tpr)
S.sendl("Price set.")
@C
def inventory(S,l):
S.sendl("You're carrying:")
for x in S.inv:
w = (x.wloc and x.worn and " (worn %s)" % x.wloc) or ""
S.sendl(" %s%s" % (x.name, w))
@C
def prompt(S,l):
if l == "reset": del S.pro
elif l: S.pro = l; S.sendl("Prompt set.")
else:
S.sendl("{cCurrent prompt{x: "+S.pro.replace("{","{{"))
S.sendl('Type "{Wprompt reset{x" to restore the default.')
@C
def save(S,l): S.save(); S.sendl("Saved.")
@D(admin=1)
def rdig(S,l):
if not l in core.dirs: return S.sendl("Bad dir.")
r = core.Room()
S.room.ex[l] = r
r.ex[core.rdirs[core.dirs.index(l)]] = S.room
S.sendl("Dug.")
@D(admin=1)
def rlink(S,l):
sr = S.room
rd = core.rdirs[core.dirs.index(d)] # reverse direction
d,l = fit(xarg(l))
if not l or not d in core.dirs: return S.sendl("rlink <dir> [<dest>|none]")
if l == "none": # DOES NOT REMOVE OTHER EXIT
if d in sr.ex: del sr.ex[d]; return
dest = find(l,[r for r in core.Thing.all if is_a(r,core.Room)])
if not dest: return S.sendl("Room not found.")
sr.ex[d] = dest
dest.ex[core.rdirs[rd]] = sr
S.sendl("Linked.")
# reloads this module, updating commands and socials
@D(admin=1)
def creload(S,l):
import cmd
reload(cmd)
S.sendl("cmd.py reloaded.")
@D(admin=1)
def goto(S,l):
v = find(l,core.Thing.all)
if not v: S.sendl("Not found.")
elif not v.room: S.sendl("Goes nowhere.")
else:
if S.foe: S.unfight()
Act(S).room("{W$SN{x vanishes in a *{Wfoop{x*.")
S.goto(v.room)
Act(S).subj("{WPoof{x.").room("{W$SN{x appears in a *{Wpoof{x*.")
look(S,"")
@D(admin=1)
def lease(S,l):
o,l = fit(xarg(l))
if not o: return S.sendl("Options: new, evict, condemn, rent <$>, zone <type>")
if o == "new": S.room.biz = core.Biz(); return
biz = S.room.biz
if biz == core.CITY: return S.sendl("No. City property.")
if o == "rent": # Set hourly rent
if not l.isdigit(): S.sendl("In dollars.")
else: biz.rent = int(l)
elif o == "zone": # Set room zoning
if l not in ztypes: S.sendl("Valid zones: "+' '.join(ztypes))
else: biz.zone = l
elif o == "evict": biz.owner = "" # kick out owner and make rentable again
elif o == "condemn": biz.owner = "CITY" # return property to city ownership
else: S.sendl("Bad option.")
# Another admin command for misc things
@D(admin=1)
def frotz(S,l):
if l == '$': S.cash += 5000 # gives you money
elif l == "wsave": core.wsave() # save the world
else: S.sendl("Options: $, wsave")
@D(nabbr=1,hide=1)
@optarg
def xyzzy(S,v): # makes you an admin
if not S.admin and S.c.addr[0] != '127.0.0.1':
return S.sendl("Nothing happens.")
if v and v.npc: return S.sendl("Players only.")
x = v or S
x.admin ^= 1
t = x.admin and "now" or "no longer"
if v: S.sendl("%s is %s an admin." % (x.name,t))
x.sendl("You are %s an admin." % t)
# quick and dirty shutdown!
@D(nabbr=1,admin=1)
def shutdown(S, l):
Act().world("{RSHUTTING DOWN.{x")
for p in cplayers(): p.save()
frotz(S,'wsave')
import asyncore; asyncore.loop(0.1, 1, count=1); asyncore.close_all()
import sys; sys.exit(1)
# adds a social to the command table
# args: subj sans target, room sans target, subj/room/vict with a target
def addsoc(n,ts,tr,tds,tdv,tdr):
def f(S, l):
v = 0
if l:
v = S.find(l)
if not v: return S.sendl("No such person.")
if not v and S.foe: v = S.foe # in combat, auto-target foe
if v and v == S.foe and not S.ks:
return S.sendl("You're not ready yet.")
a = Act(S,v)
if v: a.subj(tds); a.vict(tdv); a.room(tdr)
else: a.subj(ts); a.room(tr)
if v and v == S.foe: # a (potentially) insulting attack
S.rhit(6,n)
cmds.append((n,f,{"soc":1}))
def load_soc():
x = []
for l in gzip.open("socials.txt.gz", "r"):
l = l.strip()
if l == '~': # end of a social
addsoc(*fit(x,6,'')); x = []
else: x += [l]
def load_help():
x = n = ""
f = gzip.open("help.txt.gz","r")
for l in f:
l = l.rstrip()
if not n: n = l; continue
if l == "~":
helpd[n] = x
x = ""; n = 0
else: x += l+"\r\n"
load_soc()
load_help()