This was a program I wrote to enter in the "16k Mud Competition" back in 2000. I didn't win. This was also by and large my first exposure to network programming. I've tweaked it a tiny bit to work with the new versions of Python.
#Eli Fulkerson, 2000
#I unfortunately had to do some minor gymnastics to come in under the limit,
# I was some 500 bytes over when I had completed my feature list, and have
# been forced to compress some verbose variable names as a result.
# conn --> is now co
# room --> is now rm
# socket --> is now sk
#see sparse.htm for verbose documentation
from socket import *
from select import *
from string import *
from whrandom import *
from time import clock
HOST = ''
PORT = 4000
#color constants
endl = chr(27) + "[37m\n\r"
#color implementation
def c(color):
return chr(27) + "[" + `color` + "m"
def sellOre(args,curr, rate, co):
args = int(args)
if args > curr:
co.sk.send("You don't have that much.\n\r")
return curr
else:
co.sk.send("You sell " + `args` + "units for " + `args * .01 * rate` + "credits.\n\r")
co.ship.cash = co.ship.cash + (args * .01 * rate)
return curr - args
def buyOre(args,curr, rate, co):
invalid = 0
for x in args[:]:
if not x in ["1","2","3","4","5","6","7","8","9","0"]:
invalid = 1
if invalid == 0:
args = int(args)
else:
args = 0
if co.ship.cash < 1:
co.sk.send("Your credit isnt that good.\n\r")
return curr
else:
if curr + args > 100:
co.sk.send("You can't hold that much. Purchasing " + `(100 - curr)` + " units for " + `(100 - curr) * .01 * rate` + " credits.\n\r")
co.ship.cash = co.ship.cash - ((100 - curr) * .01 * rate)
return 100
else:
co.sk.send("Purchasing " + `args` + " units for " + `args * .01 * rate` + "credits.\n\r")
co.ship.cash = co.ship.cash - (args * .01 * rate)
return curr + args
class Universe:
def __init__(self):
#room generator
self.rm = []
#create rooms
for x in range(1,1000):
newRoom = Room(x)
self.rm.append(newRoom)
#core
for x in range(1,250):
self.addExit(x, x+1)
if (x+1) % 5 == 0:
self.addExit(x, x+5)
if (x +1) % 10 == 0:
self.addExit(x, x+10)
if (x+1) % 50 == 0:
self.addExit(x, x+50)
#near worlds
for x in range(251,505):
self.addExit(x, x + 1)
self.addExit(x, x+ 2)
#nebula
for x in range(500,999):
rand = randint(501,998)
self.addExit(x, rand)
rand = randint(501,998)
self.addExit(x,rand)
#chaos
for x in range(1,40):
rand1 = randint(2,998)
rand2 = randint(2,998)
if not rand1 == rand2:
self.addExit(rand1,rand2)
print("The Universe Flickers into Being.")
def addExit(self, side1,side2):
newExit = Exit()
newExit.right = self.rm[side1]
self.rm[side2].exit.append(newExit)
newExit = Exit()
newExit.right = self.rm[side2]
self.rm[side1].exit.append(newExit)
class Exit:
def __init__(self):
self.right = Room(-1)
self.mined = 0
class Room:
def __init__(self, sector):
self.name = `sector`
self.exit = []
if sector < 251:
self.desc = "Somewhere Near the Galactic Core"
self.sun = randint(7,13)
elif sector < 501:
self.desc = "Somewhere In the Outer Worlds"
self.sun = randint(5,13)
elif sector < 751:
self.desc = "Somewhere In the Nebula"
self.sun = randint(0,12)
else:
self.desc = "Somewhere Beyond the Nebula"
self.sun = randint(0,9)
if self.sun > 7 and randint(1,2) < 2 and not sector == -1:
self.planet = Planet()
else:
self.planet = -1
def sundesc(self):
if self.sun == 0:
return "A spiral of rock and gas is being drawn carefully into a black hole."
elif self.sun < 8:
return "There is no star nearby."
elif self.sun < 10:
return "This system is lit by a dim dwarf star."
elif self.sun < 12:
return "This system is lit by an average yellow sun."
else:
return "This system is lit by a supergiant."
class Ship:
def __init__(self):
self.time = 0
self.second = 0
self.docked = 0
self.name = "unnamed"
self.rm = Room(-1)
self.fuel = 1000
self.hp = 1000
self.max = 1000
self.ore1 = 0
self.ore2 = 0
self.ore3 = 0
self.cash = 100
def damage(self,num):
self.hp = self.hp - num
def useFuel(self, fuel):
temp = self.fuel - fuel
if temp< 0:
return 0
else:
self.fuel = self.fuel - fuel
return 1
def regen(self):
#regen 1 point of hp and 1 point of fuel per second.
if not self.second == int(clock()) % 60:
if self.fuel < self.max:
self.fuel = self.fuel + 1
if self.hp < self.max:
self.hp = self.hp + 1
self.second = int(clock()) % 60
def rename(self, args, co, players):
args = split(args)
if len(args) > 1 :
old = self.name
self.name = args[1]
co.act(players, c(32) + "Info: " + old + " has been renamed to " + self.name + "." + endl)
else:
co.sk.send("You must specify a new name.\n\r")
class Planet:
def __init__(self):
self.rm = Room(-1)
self.ore1 = randint(25,250)
self.ore2 = randint(25,250)
self.ore3 = randint(25,250)
self.name = choice(["Kra", "A", "E", "I", "O", "U", "Thie", "Mar", "Bel", "Ji", "Li", "Hra", "Fra", "Dra"]) + choice(["ll", "lb", "lod", "b", "c", "d", "fr", "m", "v", "r", "rout", "t", "sil", "em"]) + choice(["eth", "son", "tes", "las", "mis", "nos", "al", "is", "oth", "och", "in", "ir", "er", "ud", "ik"])
class Connection:
def __init__(self, sk, address):
self.sk = sk
self.ip = address[0]
self.dataqueue = ""
def actRoom(self, player, playerlist, message):
for co in playerlist:
if player.ship.rm == co.ship.rm and not player.ship == co.ship:
co.sk.send(message)
def act(self, playerlist, message):
for co in playerlist:
co.sk.send(message)
def enqueue(self, string):
self.dataqueue = self.dataqueue + string
def queue(self):
return self.dataqueue
def resetqueue(self):
self.dataqueue = ""
def fileno(self):
return self.sk.fileno()
def receive(self):
return self.sk.recv(1024)
def showRoom(self, players):
#What area of space is this?
self.sk.send(self.ship.rm.desc + endl)
#What sector are we in?
self.sk.send("Sector: " + self.ship.rm.name + endl)
#What wormgates leave from here?
self.sk.send("Wormgates: ")
temp = self.ship.rm.exit
for a in range(len(temp)):
self.sk.send(temp[a].right.name)
#Is there a planet there?
if not temp[a].right.planet == -1:
self.sk.send("p")
#Is there a black hole there?
if temp[a].right.sun == 0:
self.sk.send("x")
self.sk.send(" ")
self.sk.send(endl)
#What does this sector look like?
temp = self.ship.rm.sundesc()
self.sk.send(temp + endl)
#Is there a planet here?
if not self.ship.rm.planet == -1:
self.sk.send("The planet " + self.ship.rm.planet.name + " is here.\n\r")
#Are there other ships here?
for co in players:
if co.ship.rm == self.ship.rm and not co.ship == self.ship:
self.sk.send("Another ship, the '"+ co.ship.name + "', is here")
if co.ship.docked == 1:
self.sk.send(", docked.\n\r")
else:
self.sk.send(".\n\r")
#Anything else?
#prompt
self.sk.send("\n\rFuel: " + `self.ship.fuel` + " Hp: " + `self.ship.hp` + ">")
self.sk.send(endl)
#if var == 1, then turn mine on. if var == 0, then turn mine off.
def mine(self,side1,side2, uni,var):
temp = uni.rm[int(side1) - 1].exit
temp2 = uni.rm[int(side2) - 1].exit
foundGate = 0
for a in range(len(temp)):
if temp[a].right.name == side2:
temp[a].mined = var
foundGate = 1
for b in range(len(temp2)):
if temp2[b].right.name == side1:
temp2[b].mined = var
return foundGate
def mineExit(self,args,uni,players):
args = split(args)
if len(args) > 1:
gate = args[1]
if self.mine(gate, self.ship.rm.name, uni, 1) == 1:
self.sk.send("You launch a subspace mine, which is quickly swallowed by the wormgate that leads to sector " + gate + ".\n\r")
self.actRoom(self, players, "The " + self.ship.name + " fires a subspace mine into the wormgate that leads to sector " + gate + ".\n\r")
else:
self.sk.send("Not a valid gate.\n\r")
def torpedo(self,args,uni,players):
args = split(args)
foundship = 0
if len(args) > 1:
target = args[1]
for player in players:
if player.ship.rm.name == self.ship.rm.name and target == player.ship.name:
if self.ship.useFuel(500) == 1:
self.sk.send("You target the '" + player.ship.name + "' and launch a torpedo. It impacts milliseconds later.\n\r")
self.actRoom(player, players, "The '" + player.ship.name + "' rocks as a torpedo strikes it.\n\r")
player.sk.send(c(31) + "Your ship rocks violently as the '" + self.ship.name + "' fires upon you!" + endl)
player.ship.damage(randint(200,500))
foundship = 1
else:
self.sk.send("You don't have enough fuel.\n\r")
if foundship == 0:
self.sk.send("Invalid target.\n\r")
else:
self.sk.send("You must specify a target.\n\r")
def enterGate(self,args,uni, players):
args = split(args)
foundGate = -1
if len(args) > 1 :
gate = args[1]
temp = self.ship.rm.exit
for a in range(len(temp)):
if temp[a].right.name == gate:
foundGate = temp[a].right
mined = temp[a].mined
if mined > 0:
self.mine(gate, self.ship.rm.name, uni, 0)
if foundGate == -1:
self.sk.send("Not a valid gate.\n\r")
else:
self.actRoom(self, players, "The '" + self.ship.name + "' falls toward the wormgate to sector " + gate + " and is swallowed by darkness.\n\r")
self.sk.send("Space ripples as your vessel falls through the wormgate to sector " + gate + ".\n\r")
if not mined == 0:
self.sk.send(c(31) + "Your vessel is rocked as a subspace mine explodes within the wormhole!" + endl)
self.actRoom(self,players, "There is a flash of light deep within the wormhole's maw as it winks shut.\n\r")
self.ship.damage(randint(50,300))
self.ship.rm = uni.rm[int(gate) - 1]
if not mined == 0:
self.actRoom(self,players, "A small shockwave rocks your vessel as a wormgate winks open\n\r")
self.actRoom(self, players, "A pulsing wormgate opens briefly, disgorging a vessel, the '" + self.ship.name + "'.\n\r")
self.showRoom(players)
#if black hole!
if self.ship.rm.sun == 0:
self.sk.send("Your entire ship screams and strains as it emerges from the wormgate within the grasp of a fearsome black hole! The wormgate twists upon itself and pulls you back, perhaps to safety...\n\r")
self.ship.damage(randint(200, 600))
self.ship.rm = uni.rm[randint(2,998)]
self.actRoom(self, players, "A pulsing wormgate opens briefly, disgorging a vessel, the '" + self.ship.name + "'.\n\r")
else:
self.sk.send("Enter what wormgate?\n\r")
class Handler:
def __init__(self):
self.clist = [ ]
self.listener = socket(AF_INET, SOCK_STREAM)
self.listener.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self.listener.bind((HOST, PORT))
self.listener.listen(32)
print "Ready on port " + `PORT` + "."
def run(self, uni):
ready = self.clist[:]
#regen and death check
for co in ready:
#if you are dead
if co.ship.hp < 1:
co.sk.send("It is over.\n\r")
co.actRoom(co, self.clist[:], "With a flash of white light, the " + co.ship.name + "'s shielding finally gives way. Your scanners are momentarily blinded as the energy of the explosion washes over your vessel.\n\r")
self.clist.remove(co)
print "Connection closed to " + co.ip + " (" + co.ship.name + ")."
co.act(self.clist, c(32) + "Info: The vessel '" + co.ship.name + "' has been destroyed." + endl)
co.ship.regen()
#process input
ready.append(self.listener)
ready = select(ready, [], [], 0.1)[0]
for co in ready:
if co is self.listener:
sk, address = self.listener.accept()
co = Connection(sk, address)
self.clist.append(co)
print "Connection accepted from " + co.ip + "."
co.sk.send("Welcome Aboard.\n\r")
co.sk.send(c(33)+ "Please see http://www.crosswinds.net/~forcharity/sparse.htm for documentation." + endl)
co.act(self.clist, c(32) + "Info: Someone has entered the game." + endl)
co.ship = Ship()
co.ship.time = int(clock())
co.ship.rm = uni.rm[501]
co.showRoom(self.clist[:])
else:
co.ship.regen()
data = co.receive()
if not data:
print "Connection closed to " + co.ip + "."
self.clist.remove(co)
else:
if not data[-1] == '\n':
co.enqueue(data)
else:
co.enqueue(data)
temp = co.queue()
#'look' command
if temp[0]== "l":
co.showRoom(self.clist[:])
#'enter' command
elif temp[0] == "e":
if co.ship.useFuel(15):
if co.ship.docked == 0:
co.enterGate(temp, uni, self.clist[:])
else:
co.sk.send("Not while docked.\n\r")
else:
co.sk.send("You don't have enough fuel.\n\r")
#'radio' command
elif temp[0] == "r":
temp = join(split(temp)[1:])
if temp:
#fizpop converter
co.act(self.clist[:], c(33) + "The '" + co.ship.name + "' radios, '" + temp + "'"+ endl)
else:
co.sk.send("Radio what?\n\r")
#'?help' command
elif temp[0] == "?":
co.sk.send("Your info:\n\r")
co.sk.send("\n\rFuel: " + `co.ship.fuel` + "(" + `co.ship.max` + ")\n\r")
co.sk.send("Hp: " + `co.ship.hp` + "(" + `co.ship.max` + ")\n\r")
co.sk.send("Ore1: " + `co.ship.ore1` + "\n\r")
co.sk.send("Ore2: " + `co.ship.ore2` + "\n\r")
co.sk.send("Ore3: " + `co.ship.ore3` + "\n\r")
co.sk.send("$" + `co.ship.cash ` + "\n\r")
#'name' command
elif temp[0] == "n":
co.ship.rename(temp, co, self.clist[:])
#'dock' command
elif temp[0] == "d":
if co.ship.useFuel(10):
if co.ship.docked == 1:
co.sk.send("You release your docking clamp, and gently slip away from the station.\n\r")
co.actRoom(co,self.clist[:], "The " + co.ship.name + " disengages its docking clamp and slowly drifts away from the station.\n\r")
co.ship.docked = 0
else:
pl = co.ship.rm.planet
if pl == -1:
co.sk.send("There is no station here to dock with.\n\r")
else:
co.sk.send("You engage your docking clamp, securing your hull against " + pl.name + "'s spacedock.\n\r")
co.sk.send("Trade rates: " + `pl.ore1 * .01` + "% for ore1, "+ `pl.ore2 * .01` + "% for ore2, "+ `pl.ore3 * .01` + "% for ore3.\n\r")
co.actRoom(co,self.clist[:], "The " + co.ship.name + " engages its docking clamp and links with " + pl.name + "'s spacedock.\n\r")
co.ship.docked = 1
else:
co.sk.send("You don't have enough fuel to use your docking clamp.\n\r")
#'quit' command
elif temp[0] == "q":
co.ship.damage(1000000)
#'viewer' command
elif temp[0] == "v":
if co.ship.useFuel(50):
co.sk.send(ljust("Name:", 15) + ljust("Fuel:", 10)+ ljust("Damage:", 10)+"Sector:\n\r")
for player in self.clist[:]:
co.sk.send(ljust(player.ship.name, 15) + ljust(`player.ship.fuel`, 10) + ljust(`player.ship.hp`, 10)+ player.ship.rm.name + "\n\r")
co.act(self.clist, "Your sensors pick up a subspace ping. Someone knows your location.\n\r")
else:
co.sk.send("You don't have enough fuel.\n\r")
#'who' command
elif temp[0] == "w":
co.sk.send(ljust("Name:", 15) + ljust("Seconds Online:", 25)+"IP:\n\r")
for player in self.clist[:]:
co.sk.send(ljust(player.ship.name, 15) + ljust(`int(clock()) - player.ship.time`, 25)+ player.ip + "\n\r")
#'buy' command. purchase upgrade, ore1,ore2,ore3
elif temp[0] == "b":
if co.ship.docked == 0:
co.sk.send("You aren't docked at a planet.\n\r")
else:
args = split(temp)
if len(args) < 2:
co.sk.send("Buy what?\n\r")
else:
found = 0
if len(args) > 2:
if args[1] == "ore1":
co.ship.ore1 = buyOre(args[2], co.ship.ore1, co.ship.rm.planet.ore1, co)
if args[1] == "ore2":
co.ship.ore2 = buyOre(args[2], co.ship.ore2, co.ship.rm.planet.ore2,co)
if args[1] == "ore3":
co.ship.ore3 = buyOre(args[2], co.ship.ore3, co.ship.rm.planet.ore3, co)
elif args[1] == "ship":
if co.ship.cash > co.ship.max:
co.ship.cash = co.ship.cash - 1000
co.ship.max = co.ship.max + 100
co.sk.send("Your max hp and fuel have been increased by 100!\n\r")
else:
co.sk.send("You need " + `co.ship.max` + " credits for an upgrade.\n\r")
else:
co.sk.send("But how many?\n\r")
#'sell' command. sell ore1,ore2,ore3
elif temp[0] == "s":
if co.ship.docked == 0:
co.sk.send("You aren't docked at a planet.\n\r")
else:
args = split(temp)
if len(args) < 2:
co.sk.send("Sell what?\n\r")
else:
if len(args) > 2:
if args[1] == "ore1":
co.ship.ore1 = sellOre(args[2], co.ship.ore1, co.ship.rm.planet.ore1, co)
if args[1] == "ore2":
co.ship.ore2 = sellOre(args[2], co.ship.ore2, co.ship.rm.planet.ore2,co)
if args[1] == "ore3":
co.ship.ore3 = sellOre(args[2], co.ship.ore3, co.ship.rm.planet.ore3, co)
else:
co.sk.send("But how many?\n\r")
#'torpedo' command
elif temp[0] == "t":
if co.ship.docked == 0:
co.torpedo(temp, uni,self.clist[:])
else:
co.sk.send("Not while docked.\n\r")
#'mine' command
elif temp[0] == "m":
if co.ship.useFuel(200):
if co.ship.docked == 0:
co.mineExit(temp, uni, self.clist[:])
else:
co.sk.send("Not while docked.\n\r")
else:
co.sk.send("You don't have enough fuel.\n\r")
else:
co.sk.send("Huh?\n\r")
temp = ""
co.resetqueue()
#Main loop
connections = Handler()
uni = Universe()
while 1:
connections.run(uni)