1
0
mirror of https://github.com/abakh/nbsdgames.git synced 2025-02-02 15:07:27 -05:00

effort to make it py3

This commit is contained in:
me 2022-02-03 13:46:22 +03:30
parent dd6e6354e4
commit 3381c4df1a
113 changed files with 22045 additions and 768 deletions

View File

@ -9,7 +9,7 @@
# __________
import os, sys
print 'Running on Python', sys.version
print('Running on Python', sys.version)
if __name__ == '__main__':
LOCALDIR = sys.argv[0]
else:
@ -61,12 +61,12 @@ def look_for_local_server():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('127.0.0.1', port))
except socket.error, e:
except socket.error as e:
return None
try:
s.shutdown(2)
s.close()
except Exception, e:
except Exception as e:
pass
url2, port2 = load_url_file()
if port2 != port:
@ -93,9 +93,9 @@ def start_local_server():
else:
httppages.main(None, TAGFILENAME, 0)
if logfile:
print >> logfile
print(file=logfile)
if logfile:
print "Logging to", logfile.filename
print("Logging to", logfile.filename)
fd = logfile.f.fileno()
try:
# detach from parent
@ -130,35 +130,35 @@ if not url:
if url:
break
else:
print >> sys.stderr, 'The local server is not starting, giving up.'
print('The local server is not starting, giving up.', file=sys.stderr)
sys.exit(1)
try:
import webbrowser
browser = webbrowser.get()
name = getattr(browser, 'name', browser.__class__.__name__)
print "Trying to open '%s' with '%s'..." % (url, name)
print("Trying to open '%s' with '%s'..." % (url, name))
browser.open(url)
except:
exc, val, tb = sys.exc_info()
print '-'*60
print >> sys.stderr, "Failed to launch the web browser:"
print >> sys.stderr, " %s: %s" % (exc.__name__, val)
print
print "Sorry, I guess you have to go to the following URL manually:"
print('-'*60)
print("Failed to launch the web browser:", file=sys.stderr)
print(" %s: %s" % (exc.__name__, val), file=sys.stderr)
print()
print("Sorry, I guess you have to go to the following URL manually:")
else:
print "Done running '%s'." % name
print("Done running '%s'." % name)
if look_for_local_server() != url:
# assume that browser.open() waited for the browser to finish
# and that the server has been closed from the browser.
raise SystemExit
print
print '-'*60
print "If the browser fails to open the page automatically,"
print "you will have to manually go to the following URL:"
print ' ', url
print '-'*60
print "Note that the server runs in the background. You have to use"
print "the 'Stop this program' link to cleanly stop it."
print "Normally, however, running this script multiple times should"
print "not create multiple servers in the background."
print()
print('-'*60)
print("If the browser fails to open the page automatically,")
print("you will have to manually go to the following URL:")
print(' ', url)
print('-'*60)
print("Note that the server runs in the background. You have to use")
print("the 'Stop this program' link to cleanly stop it.")
print("Normally, however, running this script multiple times should")
print("not create multiple servers in the background.")

164
BubBob.py.bak Executable file
View File

@ -0,0 +1,164 @@
#! /usr/bin/env python
#
# This script is used to start the server.
# For command-line usage please run
#
# python bubbob/bb.py --help
#
# __________
import os, sys
print 'Running on Python', sys.version
if __name__ == '__main__':
LOCALDIR = sys.argv[0]
else:
LOCALDIR = __file__
try:
LOCALDIR = os.readlink(LOCALDIR)
except:
pass
sys.argv[0] = os.path.abspath(LOCALDIR)
LOCALDIR = os.path.dirname(sys.argv[0])
# ----------
import socket, tempfile
sys.path.insert(0, LOCALDIR)
os.chdir(LOCALDIR)
try:
username = '-'+os.getlogin()
except:
try:
import pwd
username = '-'+pwd.getpwuid(os.getuid())[0]
except:
username = ''
TAGFILENAME = 'BubBob-%s%s.url' % (socket.gethostname(), username)
TAGFILENAME = os.path.join(tempfile.gettempdir(), TAGFILENAME)
def load_url_file():
try:
url = open(TAGFILENAME, 'r').readline().strip()
except (OSError, IOError):
return None, None
if not url.startswith('http://127.0.0.1:'):
return None, None
url1 = url[len('http://127.0.0.1:'):]
try:
port = int(url1[:url1.index('/')])
except ValueError:
return None, None
return url, port
def look_for_local_server():
# Look for a running local web server
url, port = load_url_file()
if port is None:
return None
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('127.0.0.1', port))
except socket.error, e:
return None
try:
s.shutdown(2)
s.close()
except Exception, e:
pass
url2, port2 = load_url_file()
if port2 != port:
return None
return url2
def start_local_server():
MAINSCRIPT = os.path.join('bubbob', 'bb.py')
has_server = os.path.exists(MAINSCRIPT)
if hasattr(os, 'fork') and hasattr(os, 'dup2'):
if os.fork() == 0:
# in the child process
if has_server:
sys.path.insert(0, os.path.join(LOCALDIR, 'bubbob'))
import bb
bb.BubBobGame.Quiet = 1
else:
sys.path.insert(0, os.path.join(LOCALDIR, 'http2'))
import httppages
import gamesrv, stdlog
logfile = stdlog.LogFile()
if has_server:
bb.start_metaserver(TAGFILENAME, 0)
else:
httppages.main(None, TAGFILENAME, 0)
if logfile:
print >> logfile
if logfile:
print "Logging to", logfile.filename
fd = logfile.f.fileno()
try:
# detach from parent
os.dup2(fd, 1)
os.dup2(fd, 2)
os.dup2(fd, 0)
except OSError:
pass
logfile.close()
gamesrv.mainloop()
sys.exit(0)
else:
if not has_server:
MAINSCRIPT = os.path.join('http2', 'httppages.py')
args = [sys.executable, MAINSCRIPT, '--quiet',
'--saveurlto=%s' % TAGFILENAME]
# (quoting sucks on Windows) ** 42
if sys.platform == 'win32':
args[0] = '"%s"' % (args[0],)
os.spawnv(os.P_NOWAITO, sys.executable, args)
# main
url = look_for_local_server()
if not url:
start_local_server()
# wait for up to 5 seconds for the server to start
for i in range(10):
import time
time.sleep(0.5)
url = look_for_local_server()
if url:
break
else:
print >> sys.stderr, 'The local server is not starting, giving up.'
sys.exit(1)
try:
import webbrowser
browser = webbrowser.get()
name = getattr(browser, 'name', browser.__class__.__name__)
print "Trying to open '%s' with '%s'..." % (url, name)
browser.open(url)
except:
exc, val, tb = sys.exc_info()
print '-'*60
print >> sys.stderr, "Failed to launch the web browser:"
print >> sys.stderr, " %s: %s" % (exc.__name__, val)
print
print "Sorry, I guess you have to go to the following URL manually:"
else:
print "Done running '%s'." % name
if look_for_local_server() != url:
# assume that browser.open() waited for the browser to finish
# and that the server has been closed from the browser.
raise SystemExit
print
print '-'*60
print "If the browser fails to open the page automatically,"
print "you will have to manually go to the following URL:"
print ' ', url
print '-'*60
print "Note that the server runs in the background. You have to use"
print "the 'Stop this program' link to cleanly stop it."
print "Normally, however, running this script multiple times should"
print "not create multiple servers in the background."

Binary file not shown.

View File

@ -1,6 +1,6 @@
#! /usr/bin/env python
from __future__ import generators
# __________
import os, sys
@ -89,11 +89,11 @@ class BubBobGame(gamesrv.Game):
if self.metaregister:
self.do_updatemetaserver()
frametime = 0.0
for i in xrange(500):
for i in range(500):
import boards
for gen in boards.BoardGen[:]:
try:
frametime += gen.next()
frametime += next(gen)
except StopIteration:
try:
boards.BoardGen.remove(gen)
@ -110,7 +110,7 @@ class BubBobGame(gamesrv.Game):
self.game_reset_gen = boards.game_reset()
else:
try:
self.game_reset_gen.next()
next(self.game_reset_gen)
except StopIteration:
self.game_reset_gen = None
return frametime * boards.FRAME_TIME
@ -132,9 +132,9 @@ class BubBobGame(gamesrv.Game):
if kbd and not [p for p in BubPlayer.PlayerList if p.isplaying()]:
return 0
import traceback
print "-"*60
print("-"*60)
traceback.print_exc()
print "-"*60
print("-"*60)
if not kbd:
try:
if self.metaserver:
@ -145,15 +145,15 @@ class BubBobGame(gamesrv.Game):
else:
if metaclient.metaclisrv:
metaclient.metaclisrv.send_traceback()
except Exception, e:
print '! %s: %s' % (e.__class__.__name__, e)
except Exception as e:
print('! %s: %s' % (e.__class__.__name__, e))
import boards
num = getattr(boards.curboard, 'num', None)
if self.Quiet:
print "Crash recovery! Automatically restarting board %s" % num
print("Crash recovery! Automatically restarting board %s" % num)
import time; time.sleep(2)
else:
print "Correct the problem and leave pdb to restart board %s..."%num
print("Correct the problem and leave pdb to restart board %s..."%num)
import pdb; pdb.post_mortem(sys.exc_info()[2])
self.openboard(num)
return 1
@ -183,7 +183,7 @@ class BubBobGame(gamesrv.Game):
setuppath('metaserver')
import metaclient
metaclient.meta_register(self)
print '.'
print('.')
else:
try:
import metaclient
@ -201,8 +201,8 @@ class BubBobGame(gamesrv.Game):
def setuppath(dirname):
dir = os.path.abspath(os.path.join(LOCALDIR, os.pardir, dirname))
if not os.path.isdir(dir):
print >> sys.stderr, (
'../%s: directory not found ("cvs update -d" ?)' % dirname)
print((
'../%s: directory not found ("cvs update -d" ?)' % dirname), file=sys.stderr)
sys.exit(1)
if dir not in sys.path:
sys.path.insert(0, dir)
@ -210,28 +210,28 @@ def setuppath(dirname):
def parse_cmdline(argv):
# parse command-line
def usage():
print >> sys.stderr, 'usage:'
print >> sys.stderr, ' python bb.py'
print('usage:', file=sys.stderr)
print(' python bb.py', file=sys.stderr)
## print >> sys.stderr, ' python bb.py [-w/--webbrowser=no]'
## print >> sys.stderr, 'where:'
## print >> sys.stderr, ' -w --webbrowser=no don''t automatically start web browser'
print >> sys.stderr, 'or:'
print >> sys.stderr, ' python bb.py [level-file.bin] [-m] [-b#] [-s#] [-l#] [-M#]'
print >> sys.stderr, 'with options:'
print >> sys.stderr, ' -m --metaserver register the server on the Metaserver so anyone can join'
print >> sys.stderr, ' -b# --begin # start at board number # (default 1)'
print >> sys.stderr, ' --start # synonym for --begin'
print >> sys.stderr, ' --final # end at board number # (default 100)'
print >> sys.stderr, ' -s# --step # advance board number by steps of # (default 1)'
print >> sys.stderr, ' -l# --lives # limit the number of lives to #'
print >> sys.stderr, ' --extralife # gain extra life every # points'
print >> sys.stderr, ' --limitlives # max # of lives player can gain in one board'
print >> sys.stderr, ' -M# --monsters # multiply the number of monsters by #'
print >> sys.stderr, ' (default between 1.0 and 2.0 depending on # of players)'
print >> sys.stderr, ' -i --infinite restart the server at the end of the game'
print >> sys.stderr, ' --port LISTEN=# set fixed tcp port for game server'
print >> sys.stderr, ' --port HTTP=# set fixed tcp port for http server'
print >> sys.stderr, ' -h --help display this text'
print('or:', file=sys.stderr)
print(' python bb.py [level-file.bin] [-m] [-b#] [-s#] [-l#] [-M#]', file=sys.stderr)
print('with options:', file=sys.stderr)
print(' -m --metaserver register the server on the Metaserver so anyone can join', file=sys.stderr)
print(' -b# --begin # start at board number # (default 1)', file=sys.stderr)
print(' --start # synonym for --begin', file=sys.stderr)
print(' --final # end at board number # (default 100)', file=sys.stderr)
print(' -s# --step # advance board number by steps of # (default 1)', file=sys.stderr)
print(' -l# --lives # limit the number of lives to #', file=sys.stderr)
print(' --extralife # gain extra life every # points', file=sys.stderr)
print(' --limitlives # max # of lives player can gain in one board', file=sys.stderr)
print(' -M# --monsters # multiply the number of monsters by #', file=sys.stderr)
print(' (default between 1.0 and 2.0 depending on # of players)', file=sys.stderr)
print(' -i --infinite restart the server at the end of the game', file=sys.stderr)
print(' --port LISTEN=# set fixed tcp port for game server', file=sys.stderr)
print(' --port HTTP=# set fixed tcp port for http server', file=sys.stderr)
print(' -h --help display this text', file=sys.stderr)
#print >> sys.stderr, ' -rxxx record the game in file xxx'
sys.exit(1)
@ -246,9 +246,9 @@ def parse_cmdline(argv):
'lives=', 'monsters=', 'infinite', 'help',
'extralife=', 'limitlives=', 'final=',
'saveurlto=', 'quiet', 'port=', 'makeimages'])
except error, e:
print >> sys.stderr, 'bb.py: %s' % str(e)
print >> sys.stderr
except error as e:
print('bb.py: %s' % str(e), file=sys.stderr)
print(file=sys.stderr)
usage()
options = {}
@ -269,7 +269,7 @@ def parse_cmdline(argv):
elif key in ('--final'):
options['finalboard'] = int(value)
if options['finalboard'] < options['beginboard']:
print >> sys.stderr, 'bb.py: final board value must be larger than begin board.'
print('bb.py: final board value must be larger than begin board.', file=sys.stderr)
sys.exit(1)
elif key in ('--extralife'):
options['extralife'] = int(value)
@ -295,14 +295,14 @@ def parse_cmdline(argv):
# webbrowser = value.startswith('y')
if args:
if len(args) > 1:
print >> sys.stderr, 'bb.py: multiple level files specified'
print('bb.py: multiple level files specified', file=sys.stderr)
sys.exit(1)
levelfile = os.path.abspath(args[0])
os.chdir(LOCALDIR)
BubBobGame(levelfile, **options)
else:
if options:
print >> sys.stderr, 'bb.py: command-line options ignored'
print('bb.py: command-line options ignored', file=sys.stderr)
start_metaserver(save_url_to, quiet)
def start_metaserver(save_url_to, quiet):

345
bubbob/bb.py.bak Executable file
View File

@ -0,0 +1,345 @@
#! /usr/bin/env python
from __future__ import generators
# __________
import os, sys
if __name__ == '__main__':
LOCALDIR = sys.argv[0]
else:
LOCALDIR = __file__
try:
LOCALDIR = os.readlink(LOCALDIR)
except:
pass
LOCALDIR = os.path.dirname(os.path.abspath(LOCALDIR))
# ----------
import random, time
sys.path.insert(0, os.path.join(os.path.dirname(LOCALDIR), 'common'))
sys.path.insert(0, LOCALDIR)
import gamesrv
PROFILE = 0
class BubBobGame(gamesrv.Game):
FnDesc = "Bub & Bob"
FnBasePath = "bubbob"
Quiet = 0
End = 0
def __init__(self, levelfile,
beginboard = 1,
stepboard = 1,
finalboard = 100,
limitlives = None,
extralife = 50000,
lifegainlimit = None,
autoreset = 0,
metaserver = 0,
monsters = 0):
gamesrv.Game.__init__(self)
self.game_reset_gen = None
self.levelfile = levelfile
self.beginboard = beginboard
self.finalboard = finalboard
self.stepboard = stepboard
self.limitlives = limitlives
self.lifegainlimit = lifegainlimit
self.extralife = extralife
self.autoreset = autoreset
self.metaserver = metaserver
self.f_monsters = monsters
self.updatemetaserver()
levelsname, ext = os.path.splitext(os.path.basename(levelfile))
self.FnDesc = BubBobGame.FnDesc + ' ' + levelsname
self.reset()
self.openserver()
def openboard(self, num=None):
self.End = 0
if num is None:
num = self.beginboard-1
import boards
boards.loadmodules(force=1)
import boards # possibly re-import
self.width = boards.bwidth + 9*boards.CELL
self.height = boards.bheight
boards.curboard = None
boards.BoardGen = [boards.next_board(num)]
self.updatemetaserver()
def reset(self):
import player
self.openboard()
for p in player.BubPlayer.PlayerList:
p.reset()
def FnPlayers(self):
from player import BubPlayer
result = {}
for p in BubPlayer.PlayerList:
result[p.pn] = p
return result
def FnFrame(self):
if self.metaregister:
self.do_updatemetaserver()
frametime = 0.0
for i in xrange(500):
import boards
for gen in boards.BoardGen[:]:
try:
frametime += gen.next()
except StopIteration:
try:
boards.BoardGen.remove(gen)
except ValueError:
pass
if frametime >= 1.1:
break
else:
# should normally never occur
boards.BoardGen[:] = [boards.next_board()]
frametime = 1.0
if self.game_reset_gen is None:
if self.End and self.autoreset:
self.game_reset_gen = boards.game_reset()
else:
try:
self.game_reset_gen.next()
except StopIteration:
self.game_reset_gen = None
return frametime * boards.FRAME_TIME
def FnServerInfo(self, msg):
try:
from images import writestr
writestr(50, 50, msg)
self.sendudpdata()
except:
pass
def FnExcHandler(self, kbd):
if kbd:
self.FnServerInfo("Server was Ctrl-C'ed!")
else:
self.FnServerInfo('Ooops -- server crash!')
from player import BubPlayer
if kbd and not [p for p in BubPlayer.PlayerList if p.isplaying()]:
return 0
import traceback
print "-"*60
traceback.print_exc()
print "-"*60
if not kbd:
try:
if self.metaserver:
try:
import metaclient
except ImportError:
pass
else:
if metaclient.metaclisrv:
metaclient.metaclisrv.send_traceback()
except Exception, e:
print '! %s: %s' % (e.__class__.__name__, e)
import boards
num = getattr(boards.curboard, 'num', None)
if self.Quiet:
print "Crash recovery! Automatically restarting board %s" % num
import time; time.sleep(2)
else:
print "Correct the problem and leave pdb to restart board %s..."%num
import pdb; pdb.post_mortem(sys.exc_info()[2])
self.openboard(num)
return 1
def FnListBoards():
import boards
result = []
for fn in os.listdir('levels'):
base, ext = os.path.splitext(fn)
if ext in ('.py', '.bin'):
result.append((base, os.path.join('levels', fn)))
return result
FnListBoards = staticmethod(FnListBoards)
def FnExtraDesc(self):
import boards
s = gamesrv.Game.FnExtraDesc(self)
if boards.curboard and self.End != 'gameover':
s = '%s, board %d' % (s, boards.curboard.num+1)
return s
def do_updatemetaserver(self):
self.metaregister -= 1
if self.metaregister > 0:
return
if self.metaserver and (self.autoreset or self.End != 'gameover'):
setuppath('metaserver')
import metaclient
metaclient.meta_register(self)
print '.'
else:
try:
import metaclient
except ImportError:
pass
else:
metaclient.meta_unregister(self)
def updatemetaserver(self):
self.metaregister = 2
updateboard = updateplayers = updatemetaserver
def setuppath(dirname):
dir = os.path.abspath(os.path.join(LOCALDIR, os.pardir, dirname))
if not os.path.isdir(dir):
print >> sys.stderr, (
'../%s: directory not found ("cvs update -d" ?)' % dirname)
sys.exit(1)
if dir not in sys.path:
sys.path.insert(0, dir)
def parse_cmdline(argv):
# parse command-line
def usage():
print >> sys.stderr, 'usage:'
print >> sys.stderr, ' python bb.py'
## print >> sys.stderr, ' python bb.py [-w/--webbrowser=no]'
## print >> sys.stderr, 'where:'
## print >> sys.stderr, ' -w --webbrowser=no don''t automatically start web browser'
print >> sys.stderr, 'or:'
print >> sys.stderr, ' python bb.py [level-file.bin] [-m] [-b#] [-s#] [-l#] [-M#]'
print >> sys.stderr, 'with options:'
print >> sys.stderr, ' -m --metaserver register the server on the Metaserver so anyone can join'
print >> sys.stderr, ' -b# --begin # start at board number # (default 1)'
print >> sys.stderr, ' --start # synonym for --begin'
print >> sys.stderr, ' --final # end at board number # (default 100)'
print >> sys.stderr, ' -s# --step # advance board number by steps of # (default 1)'
print >> sys.stderr, ' -l# --lives # limit the number of lives to #'
print >> sys.stderr, ' --extralife # gain extra life every # points'
print >> sys.stderr, ' --limitlives # max # of lives player can gain in one board'
print >> sys.stderr, ' -M# --monsters # multiply the number of monsters by #'
print >> sys.stderr, ' (default between 1.0 and 2.0 depending on # of players)'
print >> sys.stderr, ' -i --infinite restart the server at the end of the game'
print >> sys.stderr, ' --port LISTEN=# set fixed tcp port for game server'
print >> sys.stderr, ' --port HTTP=# set fixed tcp port for http server'
print >> sys.stderr, ' -h --help display this text'
#print >> sys.stderr, ' -rxxx record the game in file xxx'
sys.exit(1)
try:
from getopt import gnu_getopt as getopt
except ImportError:
from getopt import getopt
from getopt import error
try:
opts, args = getopt(argv, 'mb:s:l:M:ih',
['metaserver', 'start=', 'step=',
'lives=', 'monsters=', 'infinite', 'help',
'extralife=', 'limitlives=', 'final=',
'saveurlto=', 'quiet', 'port=', 'makeimages'])
except error, e:
print >> sys.stderr, 'bb.py: %s' % str(e)
print >> sys.stderr
usage()
options = {}
#webbrowser = 1
save_url_to = None
quiet = 0
for key, value in opts:
if key in ('-m', '--metaserver'):
options['metaserver'] = 1
elif key in ('-b', '--start', '--begin'):
options['beginboard'] = int(value)
elif key in ('-s', '--step'):
options['stepboard'] = int(value)
elif key in ('-l', '--lives'):
options['limitlives'] = int(value)
elif key in ('--limitlives'):
options['lifegainlimit'] = int(value)
elif key in ('--final'):
options['finalboard'] = int(value)
if options['finalboard'] < options['beginboard']:
print >> sys.stderr, 'bb.py: final board value must be larger than begin board.'
sys.exit(1)
elif key in ('--extralife'):
options['extralife'] = int(value)
elif key in ('-M', '--monsters'):
options['monsters'] = float(value)
elif key in ('-i', '--infinite'):
options['autoreset'] = 1
elif key in ('-h', '--help'):
usage()
elif key == '--saveurlto':
save_url_to = value
elif key == '--quiet':
quiet = 1
elif key == '--port':
portname, portvalue = value.split('=')
portvalue = int(portvalue)
import msgstruct
msgstruct.PORTS[portname] = portvalue
elif key == '--makeimages':
import images
sys.exit(0)
#elif key in ('-w', '--webbrowser'):
# webbrowser = value.startswith('y')
if args:
if len(args) > 1:
print >> sys.stderr, 'bb.py: multiple level files specified'
sys.exit(1)
levelfile = os.path.abspath(args[0])
os.chdir(LOCALDIR)
BubBobGame(levelfile, **options)
else:
if options:
print >> sys.stderr, 'bb.py: command-line options ignored'
start_metaserver(save_url_to, quiet)
def start_metaserver(save_url_to, quiet):
os.chdir(LOCALDIR)
setuppath('http2')
import httppages
httppages.main(BubBobGame, save_url_to, quiet)
def setup():
keybmp = gamesrv.getbitmap(os.path.join('images', 'keys.ppm'))
def keybmplist(x):
return [keybmp.geticon(x, y, 32, 32) for y in range(0, 128, 32)]
BubBobGame.FnKeys = [
("right", keybmplist(0), "kRight"),
("left", keybmplist(32), "kLeft"),
("jump", keybmplist(64), "kJump"),
("fire", keybmplist(96), "kFire"),
("-right", [], "kmRight"),
("-left", [], "kmLeft"),
("-jump", [], "kmJump"),
("-fire", [], "kmFire"),
]
setup()
def main():
parse_cmdline(sys.argv[1:])
if not PROFILE:
gamesrv.mainloop()
else:
import profile
prof = profile.Profile()
try:
prof = prof.run('gamesrv.mainloop()')
finally:
prof.dump_stats('profbb')
if __name__ == '__main__':
main()

View File

@ -20,7 +20,8 @@ def meancolor(img):
b1 += b
return r1/count, g1/count, b1/count
def addshadow(img, (r1, g1, b1), depth=8):
def addshadow(img, xxx_todo_changeme, depth=8):
(r1, g1, b1) = xxx_todo_changeme
w = len(img[0])
h = len(img)
pad = depth * [keycol]
@ -35,7 +36,8 @@ def addshadow(img, (r1, g1, b1), depth=8):
result[1+d+i][w+d] = color
return result
def addrshadow(img, (r1, g1, b1), depth=8):
def addrshadow(img, xxx_todo_changeme1, depth=8):
(r1, g1, b1) = xxx_todo_changeme1
w = len(img[0])
h = len(img)
pad = depth * [keycol]
@ -49,17 +51,17 @@ def addrshadow(img, (r1, g1, b1), depth=8):
def load(filename):
print "Loading %s..." % filename
print("Loading %s..." % filename)
Bin = macbinary.MacBinary(filename)
levels = {}
mnstrlist = [Nasty, Monky, Ghosty, Flappy,
Springy, Orcy, Gramy, Blitzy]
for key, lvl in Bin['LEVL'].items():
for key, lvl in list(Bin['LEVL'].items()):
d = lvl.getlevel(mnstrlist)
class BinBoard(boards.Board):
pass
for key1, value1 in d.items():
for key1, value1 in list(d.items()):
setattr(BinBoard, key1, value1)
levels[key] = BinBoard

122
bubbob/binboards.py.bak Normal file
View File

@ -0,0 +1,122 @@
import macbinary
import boards
import gamesrv
from mnstrmap import Nasty, Monky, Ghosty, Flappy
from mnstrmap import Springy, Orcy, Gramy, Blitzy
from images import KEYCOL
keycol = (KEYCOL & 0xFF,
(KEYCOL>>8) & 0xFF,
(KEYCOL>>16) & 0xFF)
def meancolor(img):
r1 = g1 = b1 = 0
count = float(len(img) * len(img[0]))
for line in img:
for r, g, b in line:
r1 += r
g1 += g
b1 += b
return r1/count, g1/count, b1/count
def addshadow(img, (r1, g1, b1), depth=8):
w = len(img[0])
h = len(img)
pad = depth * [keycol]
result = [line + pad for line in img] + [
(w+depth) * [keycol] for d in range(depth)]
for d in range(depth):
f = 1.0 - float(d)/depth
color = (r1 * f, g1 * f, b1 * f)
for i in range(w):
result[h+d][1+d+i] = color
for i in range(h):
result[1+d+i][w+d] = color
return result
def addrshadow(img, (r1, g1, b1), depth=8):
w = len(img[0])
h = len(img)
pad = depth * [keycol]
result = [line + pad for line in img]
for d in range(depth):
f = 1.0 - float(d)/depth
color = (r1 * f, g1 * f, b1 * f)
for i in range(h):
result[i][w+d] = color
return result
def load(filename):
print "Loading %s..." % filename
Bin = macbinary.MacBinary(filename)
levels = {}
mnstrlist = [Nasty, Monky, Ghosty, Flappy,
Springy, Orcy, Gramy, Blitzy]
for key, lvl in Bin['LEVL'].items():
d = lvl.getlevel(mnstrlist)
class BinBoard(boards.Board):
pass
for key1, value1 in d.items():
setattr(BinBoard, key1, value1)
levels[key] = BinBoard
def loader(code, rsrc=Bin['ppat'], cache={}):
try:
return cache[code]
except KeyError:
pass
keycol1 = None
bid = code[0]
result = None
if code[1] == 'l':
# left border wall
img = rsrc[bid + 228].getimage()
color = meancolor(img)
img = [line[:32] for line in img]
result = addrshadow(img, color)
elif code[1] == 'r':
# right border wall
img = rsrc[bid + 228].getimage()
w = len(img[0])
assert w in (32, 64), bid
if w == 64:
color = meancolor(img)
img = [line[32:64] for line in img]
result = addrshadow(img, color)
else:
# normal wall
dx, dy = code[1:]
img = rsrc[bid + 128].getimage()
w = len(img[0])
h = len(img)
assert w & 15 == h & 15 == 0, bid
dx *= 16
dy *= 16
if dx < w and dy < h:
color = meancolor(img)
img = [line[dx:dx+16] for line in img[dy:dy+16]]
result = addshadow(img, color)
keycol1 = KEYCOL
if result is not None:
w, h, data = macbinary.image2rgb(result)
ppmdata = "P6\n%d %d\n255\n%s" % (w, h, data)
result = gamesrv.newbitmap(ppmdata, keycol1), (0, 0, w, h)
cache[code] = result
return result
def bin_haspat(code, loader=loader):
try:
return loader(code) is not None
except KeyError:
return 0
def bin_loadpattern(code, keycol=None, loader=loader):
result = loader(code)
assert result is not None, code
return result
boards.haspat = bin_haspat
boards.loadpattern = bin_loadpattern
return levels

View File

@ -1,4 +1,4 @@
from __future__ import generators
import random, os, sys, math
import gamesrv
import images
@ -72,8 +72,8 @@ class Board(Copyable):
def enter(self, complete=1, inplace=0, fastreenter=False):
global curboard
if inplace:
print "Re -",
print "Entering board", self.num+1
print("Re -", end=' ')
print("Entering board", self.num+1)
self.set_musics()
# add board walls
l = self.sprites.setdefault('walls', [])
@ -96,9 +96,9 @@ class Board(Copyable):
righticon = patget((self.num, 'r'))
else:
righticon = lefticon
xrange = range(2, self.width-2)
xrange = list(range(2, self.width-2))
else:
xrange = range(self.width)
xrange = list(range(self.width))
lefticon = righticon = None
if BOARD_BKGND == 1:
@ -255,7 +255,7 @@ class Board(Copyable):
def reorder_walls(self):
walls_by_pos = self.walls_by_pos
items = [(yx, w1.ico) for yx, w1 in walls_by_pos.items()]
items = [(yx, w1.ico) for yx, w1 in list(walls_by_pos.items())]
if not items:
return # otherwise self.sprites['walls'] would be emptied
items.sort()
@ -289,7 +289,7 @@ class Board(Copyable):
yield 0.9
i = 0
sprites = []
for l in self.sprites.values():
for l in list(self.sprites.values()):
sprites += l
self.sprites.clear()
self.walls_by_pos.clear()
@ -440,7 +440,7 @@ def loadmodules(force=0):
elif os.path.isfile(os.path.join(m, '__init__.py')):
modulefiles[m] = os.path.join(m, '__init__.py')
mtimes = {}
for m, mfile in modulefiles.items():
for m, mfile in list(modulefiles.items()):
mtimes[m] = os.stat(mfile).st_mtime
reload = force or (mtimes != getattr(sys, 'ST_MTIMES', None))
import player
@ -449,8 +449,8 @@ def loadmodules(force=0):
delete = hasattr(sys, 'ST_MTIMES')
sys.ST_MTIMES = mtimes
if delete:
print "Reloading modules."
for m, mfile in modulefiles.items():
print("Reloading modules.")
for m, mfile in list(modulefiles.items()):
if m is not None and m in sys.modules:
del sys.modules[m]
@ -471,12 +471,12 @@ def loadmodules(force=0):
del boards.BoardList[:]
if levelfilename.lower().endswith('.py'):
levels = {}
print 'Source level file:', levelfilename
execfile(levelfilename, levels)
print('Source level file:', levelfilename)
exec(compile(open(levelfilename, "rb").read(), levelfilename, 'exec'), levels)
if 'GenerateLevels' in levels:
levels = levels['GenerateLevels']()
if isinstance(levels, list):
levels = dict(zip(range(len(levels)), levels))
levels = dict(list(zip(list(range(len(levels))), levels)))
else:
import binboards
levels = binboards.load(levelfilename)
@ -555,7 +555,7 @@ def wait_for_one_player():
if random.random() > 0.4321:
try:
key, (filename, (x, y, w, h)) = random.choice(
images.sprmap.items())
list(images.sprmap.items()))
except:
w = h = 0
if w == h == 32:
@ -1116,7 +1116,7 @@ def extra_aquarium():
for s in waves_sprites:
s.kill()
BubPlayer.SuperFish = True
fishplayers(-sys.maxint)
fishplayers(-sys.maxsize)
def extra_walls_falling():
walls_by_pos = curboard.walls_by_pos
@ -1156,7 +1156,7 @@ def single_blocks_falling(xylist):
def extra_display_repulse(cx, cy, dlimit=5000, dfactor=1000):
offsets = {}
for s in gamesrv.sprites_by_n.values():
for s in list(gamesrv.sprites_by_n.values()):
x, y = s.getdisplaypos()
if x is not None:
dx = x - cx
@ -1172,7 +1172,7 @@ def extra_display_repulse(cx, cy, dlimit=5000, dfactor=1000):
while offsets:
prevoffsets = offsets
offsets = {}
for s, (dx, dy) in prevoffsets.items():
for s, (dx, dy) in list(prevoffsets.items()):
if s.alive:
if dx < 0:
dx += max(1, (-dx)//5)
@ -1212,7 +1212,7 @@ def extra_light_off(timeout, icocache={}):
for bubber in playerlist:
for dragon in bubber.dragons:
dragons[dragon] = True
for s in gamesrv.sprites_by_n.values():
for s in list(gamesrv.sprites_by_n.values()):
try:
ico = icocache[s.ico, s in dragons]
except KeyError:
@ -1220,12 +1220,12 @@ def extra_light_off(timeout, icocache={}):
icocache[s.ico, s in dragons] = ico
s.setdisplayicon(ico)
yield 0
for s in gamesrv.sprites_by_n.values():
for s in list(gamesrv.sprites_by_n.values()):
s.setdisplayicon(s.ico)
def extra_swap_up_down(N=27):
# unregister all walls
walls = curboard.walls_by_pos.items()
walls = list(curboard.walls_by_pos.items())
walls.sort()
if not walls:
return
@ -1317,7 +1317,7 @@ def extra_make_random_level(cx=None, cy=None, repeat_delay=200):
localdir = os.path.dirname(__file__)
filename = os.path.join(localdir, 'levels', 'RandomLevels.py')
d = {}
execfile(filename, d)
exec(compile(open(filename, "rb").read(), filename, 'exec'), d)
Level = d['GenerateSingleLevel'](curboard.width, curboard.height)
lvl = Level(curboard.num)
walllist = []
@ -1413,7 +1413,7 @@ def initsubgame(music, displaypoints):
def register(dict):
global width, height, bwidth, bheight, bheightmod
items = dict.items()
items = list(dict.items())
items.sort()
for name, board in items:
try:
@ -1433,8 +1433,8 @@ def register(dict):
test = B(-1)
assert test.width == width, "some boards have a different width"
assert test.height == height, "some boards have a different height"
except Exception, e:
print 'Caught "%s" in level "%s":' % (e, B.__name__)
except Exception as e:
print('Caught "%s" in level "%s":' % (e, B.__name__))
raise e
bwidth = width*CELL
bheight = height*CELL

1470
bubbob/boards.py.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
from __future__ import generators
import random, os, math
import random as random_module
import gamesrv
@ -646,13 +646,13 @@ class Megabonus(Bonus):
return self.y == boards.bheight - CELL - self.ico.h
def kill(self):
for bubble in self.bubbles.values():
for bubble in list(self.bubbles.values()):
bubble.pop()
Bonus.kill(self)
def taken(self, dragon):
poplist = [dragon]
for bubble in self.bubbles.values():
for bubble in list(self.bubbles.values()):
bubble.pop(poplist)
def bubbles_position(self):
@ -712,7 +712,7 @@ class Megabonus(Bonus):
while 1:
for t in range(2):
yield None
bubbles = [dxy for dxy, b in self.bubbles.items()
bubbles = [dxy for dxy, b in list(self.bubbles.items())
if b.bubber is bubber]
if not bubbles:
break
@ -776,7 +776,7 @@ class Megabonus(Bonus):
while 1:
for cycle in [1]*8 + [2]*10 + [1]*8 + [0]*10:
yield None
for (dx, dy), bubble in bubbles.items():
for (dx, dy), bubble in list(bubbles.items()):
if not hasattr(bubble, 'poplist'):
if 0: # disabled clipping
if (dx, north[dy]) in bubbles:
@ -822,7 +822,7 @@ class Megabonus(Bonus):
yield None
bubble.pop(poplist)
for bubble in self.bubbles.values():
for bubble in list(self.bubbles.values()):
bubble.gen.append(bubble_timeout(bubble, self.vspeed))
self.bubbles.clear()
self.kill()
@ -1249,7 +1249,7 @@ class Lollipop(TemporaryBonus):
def taken(self, dragon):
dragon.dcap['left2right'] = -dragon.dcap['left2right']
if self.big:
perm = range(4)
perm = list(range(4))
while perm[0] == 0 or perm[1] == 1 or perm[2] == 2 or perm[3] == 3:
random.shuffle(perm)
names = ('key_left', 'key_right', 'key_jump', 'key_fire')
@ -1589,7 +1589,7 @@ class Egg(RandomBonus):
d1 = dragons[0]
d1.move(x, y)
d1.dcap['shield'] = 50
for d1, bubber2 in xchg.items():
for d1, bubber2 in list(xchg.items()):
d1.bubber.dragons.remove(d1)
d1.bubber = bubber2
bubber2.dragons.append(d1)
@ -1705,7 +1705,7 @@ class Chestnut(RandomBonus):
try:
import statesaver
except ImportError:
print "'statesaver' module not compiled, no clock bonus"
print("'statesaver' module not compiled, no clock bonus")
Clock = None
else:
import new
@ -1734,11 +1734,11 @@ else:
boards.curboard,
images.ActiveSprites,
images.SpritesByLoc,
BubPlayer.__dict__.items(),
list(BubPlayer.__dict__.items()),
gamesrv.sprites,
gamesrv.sprites_by_n,
ps,
images.Snd.__dict__.items(),
list(images.Snd.__dict__.items()),
)
#import pdb; pdb.set_trace()
return statesaver.copy(topstate)
@ -1938,8 +1938,8 @@ else:
random = random_module.Random()
localrandom = DustStar.localrandom
self.state = 'pre'
self.randombase1 = hash(localrandom.random()) * 914971L
self.randombase2 = hash(localrandom.random()) * 914971L
self.randombase1 = hash(localrandom.random()) * 914971
self.randombase2 = hash(localrandom.random()) * 914971
self.saved_next = None
self.saved_last = self
random.seed(self.randombase1)
@ -2019,7 +2019,7 @@ else:
for s in touching:
if isinstance(s, interact):
s.touched(ghost)
for d, ghost in self.ghosts.items():
for d, ghost in list(self.ghosts.items()):
if d not in new_ghosts:
ghost.kill()
self.ghosts = new_ghosts
@ -2036,12 +2036,12 @@ else:
DragonBubble(*args)
if self.state == 'restoring' and self.ghosts:
self.state = 'post'
for ghost in self.ghosts.values():
for ghost in list(self.ghosts.values()):
ghost.integrate()
def flush_ghosts(self):
if self.latest_entries:
for ghost in self.ghosts.values():
for ghost in list(self.ghosts.values()):
ghost.disintegrate()
self.latest_entries.clear()
self.dragonlist = None
@ -2282,7 +2282,7 @@ class Sheep(RandomBonus):
vy = 0
while delta or slist:
ndelta = {}
for p, dp in delta.items():
for p, dp in list(delta.items()):
if dp:
d1 = max(-250, min(250, dp))
p.givepoints(d1)
@ -2379,7 +2379,7 @@ class Donut(RandomBonus):
b.kill()
Classes = [c for c in globals().values()
Classes = [c for c in list(globals().values())
if type(c)==type(RandomBonus) and issubclass(c, RandomBonus)]
Classes.remove(RandomBonus)
Classes.remove(TemporaryBonus)
@ -2500,5 +2500,5 @@ def __cheat(c):
c[0] = globals()[c[0]]
assert issubclass(c[0], Bonus)
Cheat.append(tuple(c))
import __builtin__
__builtin__.__cheat = __cheat
import builtins
builtins.__cheat = __cheat

2504
bubbob/bonuses.py.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
from __future__ import generators
import random, math
import gamesrv
import images
@ -19,7 +19,7 @@ bubble_wind = {
class Bubble(ActiveSprite):
exploding_bubbles = range(131,136)
exploding_bubbles = list(range(131,136))
red_bubbles = [156, 157, 156, 155]
white_bubbles = [164, 165, 164, 163]
pink_bubbles = [172, 173, 172, 171]
@ -233,7 +233,7 @@ class Bubble(ActiveSprite):
ico = icons[1]
yfrac = 0.0
self.dragon_jumped = False
for i in xrange(timeout):
for i in range(timeout):
hspeed = random.randrange(2, 4)
if ico is not icons[1]:
icotimeout += 1
@ -410,7 +410,8 @@ class DragonBubble(Bubble):
hspeed = -hspeed
self.gen.append(self.throw_bubble(hspeed, special_bubble, (acos,asin)))
def throw_bubble(self, hspeed, special_bubble=None, (acos,asin)=(1,0)):
def throw_bubble(self, hspeed, special_bubble=None, xxx_todo_changeme=(1,0)):
(acos,asin) = xxx_todo_changeme
from monsters import Monster
nx = self.x
ny = self.y
@ -680,7 +681,7 @@ class BonusBubble(Bubble):
def findhole(self, testline):
holes = [x for x in range(len(testline)-1) if testline[x:x+2]==' ']
if not holes:
holes = range(2, len(testline)-3)
holes = list(range(2, len(testline)-3))
return random.choice(holes) * CELL
def thrown_bubble(self, x, y, hspeed, acossin):
@ -688,7 +689,8 @@ class BonusBubble(Bubble):
self.move(x, y)
self.gen = [self.throwing_bubble(hspeed, acossin, self.imgsetter)]
def throwing_bubble(self, hspeed, (acos,asin), restore_img):
def throwing_bubble(self, hspeed, xxx_todo_changeme1, restore_img):
(acos,asin) = xxx_todo_changeme1
nx = self.x
ny = self.y
while abs(hspeed) >= 4.0:
@ -962,7 +964,7 @@ class WaterCell(ActiveSprite):
ActiveSprite.kill(self)
if not self.watercells[None].alive:
del self.watercells[None]
for s in self.watercells.values():
for s in list(self.watercells.values()):
if s.alive:
s.in_charge()
break
@ -974,7 +976,7 @@ class WaterCell(ActiveSprite):
new = []
nwatercells = {None: self}
for key, s in watercells.items():
for key, s in list(watercells.items()):
if key:
x, y, dir = key
if s.repeat:
@ -1012,7 +1014,7 @@ class WaterCell(ActiveSprite):
for args in new:
WaterCell(*args)
for key, s in watercells.items():
for key, s in list(watercells.items()):
if key:
x, y, dir = key
flag = 0

1284
bubbob/bubbles.py.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,4 +7,4 @@ for ext in ['.py', '.bin']:
break
sys.argv[1] = levelfile
execfile('bb.py')
exec(compile(open('bb.py', "rb").read(), 'bb.py', 'exec'))

10
bubbob/command.py.bak Normal file
View File

@ -0,0 +1,10 @@
import os, sys
levels, ext = os.path.splitext(os.path.basename(sys.argv[1]))
for ext in ['.py', '.bin']:
levelfile = 'levels/%s%s' % (levels, ext)
if os.path.exists(levelfile):
break
sys.argv[1] = levelfile
execfile('bb.py')

View File

@ -16,7 +16,7 @@ except ImportError:
def create_image(name,source,extralines=0,alt=''):
if len(sys.argv) == 2 and sys.argv[1] == '-i':
return
print name, source
print(name, source)
src = open(source[0],'r')
assert src.readline().strip() == 'P6'
line = src.readline()
@ -29,9 +29,9 @@ def create_image(name,source,extralines=0,alt=''):
data = src.read()
src.close()
img = os.popen("convert PPM:- doc/images/"+name+'.png','w')
print >> img, 'P6'
print >> img, source[1][2], source[1][3]+extralines
print >> img, c
print('P6', file=img)
print(source[1][2], source[1][3]+extralines, file=img)
print(c, file=img)
cx = source[1][0]+source[1][2]//2
cy = source[1][1]+source[1][3]*6//7
for y in range(source[1][1],source[1][1]+source[1][3]):
@ -74,7 +74,7 @@ def split_name(name):
return words
dfile = open('doc/bonuses.html','w')
print >> dfile, """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
print("""<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
@ -97,7 +97,7 @@ print >> dfile, """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<I>big bonus</I>
</TD>
</TR>
"""
""", file=dfile)
#" A stupid comment to stop emacs from mis-fontifying.
class Potion4:
@ -109,7 +109,7 @@ class Potion4:
processed = {}
for bonus in bonuses.Classes:
if processed.has_key(bonus):
if bonus in processed:
continue
name = split_name(bonus.__name__)
name.reverse()
@ -125,25 +125,25 @@ def sorter(a,b):
else:
return 1
sorted_classes = processed.items()
sorted_classes = list(processed.items())
sorted_classes.sort(sorter)
for clasindex, clas in enumerate(sorted_classes):
bonus = clas[0]
images = ''
name = bonus.__name__
if bonus.__dict__.has_key('nimages'):
if 'nimages' in bonus.__dict__:
# A multi image entry.
i = 0
l = len(bonus.nimages)
for image in bonus.nimages:
if image == 'potion4':
continue
images += create_image(name+`i`, sprmap[image], alt=name)
images += create_image(name+repr(i), sprmap[image], alt=name)
i += 1
if (l-3*(i/3) >= 3) and (i % 3) == 0:
images += '<br>'
elif bonus.__dict__.has_key('nimage'):
elif 'nimage' in bonus.__dict__:
images = create_image(name, sprmap[bonus.nimage], alt=name)
doc = bonus.__doc__
if doc == None:
@ -155,16 +155,16 @@ for clasindex, clas in enumerate(sorted_classes):
bgcolor = '"#E0FFE0"'
else:
bgcolor = 'white'
print >> dfile, '<TR><TD width=132 align=right>',
print >> dfile, images,
print >> dfile, '</TD><TD width=20></TD>',
print >> dfile, '<TD bgcolor=%s>%s</TD>' % (bgcolor, doc),
print >> dfile, '</TD><TD width=20 bgcolor=%s></TD>' % bgcolor,
print >> dfile, '<TD bgcolor=%s>%s</TD></TR>' % (bgcolor, bigdoc)
print('<TR><TD width=132 align=right>', end=' ', file=dfile)
print(images, end=' ', file=dfile)
print('</TD><TD width=20></TD>', end=' ', file=dfile)
print('<TD bgcolor=%s>%s</TD>' % (bgcolor, doc), end=' ', file=dfile)
print('</TD><TD width=20 bgcolor=%s></TD>' % bgcolor, end=' ', file=dfile)
print('<TD bgcolor=%s>%s</TD></TR>' % (bgcolor, bigdoc), file=dfile)
print >> dfile, """ </TABLE>
print(""" </TABLE>
</BODY>
</HTML>
"""
""", file=dfile)
dfile.close()

170
bubbob/doc/bonus-doc.py.bak Executable file
View File

@ -0,0 +1,170 @@
#!/usr/bin/env python
import os, sys, string, struct
os.chdir(os.pardir)
sys.path.insert(0, os.getcwd())
sys.path.insert(1, os.path.abspath(os.path.join(os.pardir, 'common')))
from images import sprmap
import bonuses, images
try:
import psyco; psyco.full()
except ImportError:
pass
def create_image(name,source,extralines=0,alt=''):
if len(sys.argv) == 2 and sys.argv[1] == '-i':
return
print name, source
src = open(source[0],'r')
assert src.readline().strip() == 'P6'
line = src.readline()
while line[0] == '#':
line = src.readline()
size = string.split(line)
w = string.atoi(size[0])
h = string.atoi(size[1])
c = src.readline().strip()
data = src.read()
src.close()
img = os.popen("convert PPM:- doc/images/"+name+'.png','w')
print >> img, 'P6'
print >> img, source[1][2], source[1][3]+extralines
print >> img, c
cx = source[1][0]+source[1][2]//2
cy = source[1][1]+source[1][3]*6//7
for y in range(source[1][1],source[1][1]+source[1][3]):
for x in range(source[1][0],source[1][0]+source[1][2]):
rgb = data[y*3*w+3*x:y*3*w+3*x+3]
if rgb == '\x01\x01\x01':
d = (x-cx)*(x-cx)+(y-cy)*(y-cy)*6
if d > 255: d = 255
rgb = chr(d)*3
img.write(rgb)
for y in range(y+1, y+1+extralines):
for x in range(source[1][0],source[1][0]+source[1][2]):
d = (x-cx)*(x-cx)+(y-cy)*(y-cy)*6
if d > 255: d = 255
rgb = chr(d)*3
img.write(rgb)
img.close()
return html_tag(name, alt)
def html_tag(name, alt):
url = 'images/%s.png' % (name,)
f = open('doc/'+url, 'rb')
alldata = f.read()
f.close()
url = 'data:image/png;base64,' + alldata.encode('base64').replace('\n','')
return '<IMG SRC="%s" ALT="%s">' % (url, alt)
def split_name(name):
"Split a name into its words based on capitalisation."
words = []
word = ''
for c in name:
if c.isupper() and word != '':
words.append(word)
word = c
else:
word += c
words.append(word)
return words
dfile = open('doc/bonuses.html','w')
print >> dfile, """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Author" CONTENT="The Bub's Brothers">
<TITLE>The Bub's Brothers Bonuses</TITLE>
</HEAD>
<BODY bgcolor=white text=black>
<TABLE cellspacing=0 border=0>
<TR>
<TD width=132 align=right>
</TD>
<TD width=20>
</TD>
<TD bgcolor="#80FF80" align=center>
<I>regular bonus</I>
</TD>
<TD bgcolor="#80FF80" width=20>
</TD>
<TD bgcolor="#80FF80" align=center>
<I>big bonus</I>
</TD>
</TR>
"""
#" A stupid comment to stop emacs from mis-fontifying.
class Potion4:
"Subgame! For a while, let's play one of the seven mini-games."
nimage = 'potion4'
# Some classes exists in more than one example just to increase their
# probability. Removes the duplicate with the help of this dict.
processed = {}
for bonus in bonuses.Classes:
if processed.has_key(bonus):
continue
name = split_name(bonus.__name__)
name.reverse()
processed[bonus] = string.join(name)
if bonus is bonuses.Potion:
processed[Potion4] = string.join(name) + '.'
def sorter(a,b):
if a[1] == b[1]:
return 0
elif a[1] < b[1]:
return -1
else:
return 1
sorted_classes = processed.items()
sorted_classes.sort(sorter)
for clasindex, clas in enumerate(sorted_classes):
bonus = clas[0]
images = ''
name = bonus.__name__
if bonus.__dict__.has_key('nimages'):
# A multi image entry.
i = 0
l = len(bonus.nimages)
for image in bonus.nimages:
if image == 'potion4':
continue
images += create_image(name+`i`, sprmap[image], alt=name)
i += 1
if (l-3*(i/3) >= 3) and (i % 3) == 0:
images += '<br>'
elif bonus.__dict__.has_key('nimage'):
images = create_image(name, sprmap[bonus.nimage], alt=name)
doc = bonus.__doc__
if doc == None:
doc = ''
bigdoc = getattr(bonus, 'bigdoc', None) or ''
if hasattr(bonus, 'bigbonus'):
assert bigdoc, "missing 'bigdoc' on %r" % (bonus,)
if clasindex % 2 == 1:
bgcolor = '"#E0FFE0"'
else:
bgcolor = 'white'
print >> dfile, '<TR><TD width=132 align=right>',
print >> dfile, images,
print >> dfile, '</TD><TD width=20></TD>',
print >> dfile, '<TD bgcolor=%s>%s</TD>' % (bgcolor, doc),
print >> dfile, '</TD><TD width=20 bgcolor=%s></TD>' % bgcolor,
print >> dfile, '<TD bgcolor=%s>%s</TD></TR>' % (bgcolor, bigdoc)
print >> dfile, """ </TABLE>
</BODY>
</HTML>
"""
dfile.close()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
@ -393,7 +393,7 @@ def run():
def setup():
from player import BubPlayer
for key, (filename, rect) in localmap.items():
for key, (filename, rect) in list(localmap.items()):
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:

403
bubbob/ext1/__init__.py.bak Normal file
View File

@ -0,0 +1,403 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
from boards import CELL, HALFCELL
from mnstrmap import GreenAndBlue
from bubbles import BubblingEyes, Bubble
from bonuses import Bonus
LocalDir = os.path.basename(os.path.dirname(__file__))
localmap = {
'ark-paddle': ('image1-%d.ppm', (0, 0, 80, 32)),
}
music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav'))
snd_wall = gamesrv.getsample(os.path.join(LocalDir, 'wall.wav'))
snd_brick = gamesrv.getsample(os.path.join(LocalDir, 'brick.wav'))
def aget(x, y):
if 0 <= x < curboard.width and y >= 0:
if y >= curboard.height:
return ' '
return curboard.walls[y][x]
else:
return '#'
def sign(x):
if x >= 0.0:
return 1
else:
return -1
class PaddleEyes(BubblingEyes):
def __init__(self, bubber, saved_caps, paddle):
BubblingEyes.__init__(self, bubber, saved_caps, paddle)
self.deltax = (paddle.ico.w - self.ico.w) // 2
self.deltay = (paddle.ico.h - self.ico.h) // 2
self.step(self.deltax, self.deltay)
def playing_bubble(self, paddle, accel=0.75, vmax=4.5):
import boards
dx = self.deltax
dy = self.deltay
bubber = paddle.bubber
vx = 0.0
fx = paddle.x
while paddle.alive:
wannago = bubber.wannago(self.dcap)
if paddle.timeleft is None:
keydy = 0
else:
keydy = -1
key = ('eyes', wannago, keydy)
if fx < 2*CELL:
if vx < 0.0:
vx = -vx * 0.45
wannago = 1
elif fx + paddle.ico.w > boards.bwidth - 2*CELL:
if vx > 0.0:
vx = -vx * 0.45
wannago = -1
if not wannago:
if -accel <= vx <= accel:
vx = 0
elif vx < 0.0:
wannago = 0.7
else:
wannago = -0.7
vx += accel * wannago
if vx < -vmax:
vx = -vmax
elif vx > vmax:
vx = vmax
fx += vx
paddle.move(int(fx), paddle.y)
self.move(paddle.x+dx, paddle.y+dy, images.sprget(key))
yield None
self.kill()
def bottom_up(self):
return 0
class Paddle(ActiveSprite):
def __init__(self, arkanoid, bubber, px, py):
ico = images.sprget(('ark-paddle', bubber.pn))
ActiveSprite.__init__(self, ico, px - (ico.w-2*CELL)//2,
py - (ico.h-2*CELL)//2)
self.arkanoid = arkanoid
self.bubber = bubber
self.timeleft = None
self.gen.append(self.bounce_down())
self.gen.append(self.bkgndstuff())
self.arkanoid.paddles.append(self)
def bounce_down(self):
import boards
target_y = boards.bheight - self.ico.h
fy = self.y
vy = 0.0
while fy < target_y or abs(vy) > 0.3:
if fy < target_y:
vy += 0.3
elif vy > 0.0:
vy = -vy / 3.0
fy += vy
self.move(self.x, int(fy))
yield None
while self.y > target_y:
self.step(0, -2)
yield None
self.move(self.x, target_y)
self.gen.append(self.wait_and_shoot())
def wait_and_shoot(self):
timeout = 30
while timeout > 0:
timeout -= self.arkanoid.ready
yield None
self.gen.append(self.catch(Ball(self)))
def catch(self, ball):
import boards
while ball.alive:
if ball.y > boards.bheight//2+1 and ball.vy > 0.0:
deltay = self.y - Ball.Y_MARGIN - ball.y
self.timeleft = deltay / ball.vy
#if -1.25 <= self.timeleft <= 0.5:
if -12 <= deltay <= 1:
ball.bouncepad(self.arkanoid.paddles)
yield None
self.timeleft = None
if ball.missed:
self.kill()
def kill(self):
images.Snd.Pop.play(1.0, pad=0.0)
images.Snd.Pop.play(1.0, pad=1.0)
ico = images.sprget(Bubble.exploding_bubbles[0])
for i in range(11):
s = ActiveSprite(ico,
self.x + random.randrange(self.ico.w) - CELL,
self.y + random.randrange(self.ico.h) - CELL)
s.gen.append(s.die(Bubble.exploding_bubbles))
try:
self.arkanoid.paddles.remove(self)
except ValueError:
pass
ActiveSprite.kill(self)
def bkgndstuff(self):
while 1:
if self.timeleft is not None:
self.arkanoid.order.append((self.timeleft, self))
yield None
touching = images.touching(self.x+1, self.y+1,
self.ico.w-2, self.ico.h-2)
touching.reverse()
for s in touching:
if isinstance(s, Bonus):
s.touched(self)
def score(self, hits):
bricks = self.arkanoid.bricks
bricks[self.bubber] = bricks.get(self.bubber, 0) + hits
self.bubber.givepoints(125*(2**hits))
class Ball(ActiveSprite):
Y_MARGIN = 20
SPEED = 5.8
def __init__(self, paddle):
self.paddle = paddle
imglist1 = GreenAndBlue.new_bubbles[paddle.bubber.pn]
ActiveSprite.__init__(self, images.sprget(imglist1[0]),
paddle.x + paddle.ico.w//2,
paddle.y - Ball.Y_MARGIN)
self.missed = 0
self.setimages(self.imgseq(imglist1[1:], 6))
self.bounceangle(0.2)
self.gen.append(self.flying())
def bouncepad(self, paddles):
for paddle in paddles:
dx = (self.x + self.ico.w//2) - (paddle.x + paddle.ico.w//2)
dxmax = paddle.ico.w//2
angle = float(dx) / dxmax
if 0.0 <= angle <= 1.0:
angle = angle * 1.111 + 0.07
elif -1.0 <= angle <= 0.0:
angle = angle * 1.111 - 0.07
else:
continue
self.bounceangle(angle)
self.play(snd_wall)
break
def bounceangle(self, angle):
self.vx = math.sin(angle) * self.SPEED
self.vy = - math.cos(angle) * self.SPEED
def flying(self):
import boards
fx = self.x
fy = self.y
while self.y < boards.bheight:
fx += self.vx
fy += self.vy
self.move(int(fx), int(fy))
yield None
cx = self.x // CELL + 1
cy = self.y // CELL + 1
dx = sign(self.vx)
dy = sign(self.vy)
hits = 0.0
if aget(cx, cy) == '#':
hits += self.ahit(cx, cy, 0, 0)
if aget(cx+dx, cy) == '#':
hits += self.ahit(cx+dx, cy, 0, dy)
self.vx = -self.vx
if aget(cx, cy+dy) == '#':
hits += self.ahit(cx, cy+dy, dx, 0)
self.vy = -self.vy
if hits:
hits = int(hits)
if hits:
self.paddle.score(hits)
self.play(snd_brick)
else:
self.play(snd_wall)
self.missed = 1
self.kill()
def ahit(self, cx, cy, dx, dy):
total = 0.01
for i in (-1, 0, 1):
x = cx + i*dx
y = cy + i*dy
if (2 <= x < curboard.width - 2 and 0 <= y < curboard.height and
aget(x, y) == '#'):
curboard.killwall(x, y)
self.paddle.arkanoid.killedbricks += 1
total += 1.0
return total
def pop(self):
self.play(images.Snd.Pop)
self.gen = [self.die(Bubble.exploding_bubbles)]
class Arkanoid:
def bgen(self, limittime = 60.1): # 0:60
import boards
from player import BubPlayer
self.bricks = {}
for t in boards.initsubgame(music, self.displaypoints):
yield t
tc = boards.TimeCounter(limittime)
self.ready = 0
self.builddelay = {}
self.nbbricks = 0
self.order = []
self.paddles = []
#finish = 0
for t in self.frame():
self.order_paddles()
t = boards.normal_frame()
self.build_paddles()
yield t
#if len(self.paddles) == 0:
# finish += 1
# if finish == 20:
# break
#else:
# finish = 0
tc.update(t)
if tc.time == 0.0:
break
if (BubPlayer.FrameCounter & 15) == 7:
for s in images.ActiveSprites:
if isinstance(s, Bonus):
s.timeout = 0 # bonuses stay
elif isinstance(s, Bubble):
s.pop()
tc.restore()
self.ready = 0
for s in images.ActiveSprites[:]:
if isinstance(s, Ball):
s.pop()
for t in boards.result_ranking(self.bricks, self.nbbricks):
self.build_paddles()
yield t
self.remove_paddles()
self.unframe()
def displaypoints(self, bubber):
return self.bricks.get(bubber, 0)
def frame(self):
for y in range(curboard.height-1, curboard.height//2, -1):
yield None
yield None
for x in range(2, curboard.width-2):
if aget(x, y) == '#':
curboard.killwall(x, y)
brickline = curboard.width-4
expected = (brickline * curboard.height) // 5
y = curboard.height//2
nbbricks = 0
while y>=0 and nbbricks + (y+1)*brickline >= expected:
yield None
for x in range(2, curboard.width-2):
if aget(x, y) == '#':
nbbricks += 1
y -= 1
while y >= -1:
yield None
yield None
for x in range(2, curboard.width-2):
if y < 0 or aget(x, y) == ' ':
curboard.putwall(x, y)
nbbricks += brickline
curboard.reorder_walls()
y -= 1
nbbricks -= brickline
self.ready = 1
self.nbbricks = nbbricks
self.killedbricks = 0
while self.killedbricks < self.nbbricks:
yield None
def unframe(self):
for x in range(2, curboard.width-2):
curboard.killwall(x, -1)
def build_paddles(self):
from player import BubPlayer
for p in BubPlayer.PlayerList:
dragons = [d for d in p.dragons if not isinstance(d, PaddleEyes)]
if dragons and len(p.dragons) == len(dragons):
if self.builddelay.get(p):
self.builddelay[p] -= 1
else:
self.builddelay[p] = 53
dragon = random.choice(dragons)
paddle = Paddle(self, p, dragon.x, dragon.y)
eyes = PaddleEyes(p, dragon.dcap, paddle)
p.dragons.append(eyes)
p.emotic(dragon, 4)
for d in dragons:
d.kill()
def order_paddles(self):
self.order.sort()
self.order.reverse()
for timeleft, paddle in self.order:
try:
self.paddles.remove(paddle)
except ValueError:
pass
else:
self.paddles.insert(0, paddle)
paddle.to_front()
del self.order[:]
def remove_paddles(self):
killclasses = (Paddle, PaddleEyes, Ball, Bonus)
for s in images.ActiveSprites[:]:
if isinstance(s, killclasses):
s.kill()
# This game is suitable for at least min_players players
min_players = 1
def run():
global curboard
import boards
from boards import curboard
boards.replace_boardgen(Arkanoid().bgen())
def setup():
from player import BubPlayer
for key, (filename, rect) in localmap.items():
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:
images.sprmap[key, p.pn] = (filename % p.pn, rect)
else:
images.sprmap[key] = (filename, rect)
setup()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
@ -397,8 +397,8 @@ class Pacman:
# digs the rectangle (x1,y1,x2,y2) and marks it as
# processed. Also recursively mark as processed all existing
# holes that are pacman-connected to the rectangle.
xrange = range(x1,x2)
yrange = range(y1,y2)
xrange = list(range(x1,x2))
yrange = list(range(y1,y2))
if not reversed:
xrange.reverse()
yrange.reverse()
@ -479,7 +479,7 @@ class Pacman:
if not holes:
holes[boards.width//2, boards.height//2] = 0
holeslist = holes.keys()
holeslist = list(holes.keys())
random.shuffle(holeslist)
startx, starty = holeslist.pop()
# make the hole larger (2x2) towards the center of the board
@ -572,7 +572,7 @@ def run():
boards.replace_boardgen(Pacman().bgen())
def setup():
for key, (filename, rect) in localmap.items():
for key, (filename, rect) in list(localmap.items()):
filename = os.path.join(LocalDir, filename)
images.sprmap[key] = (filename, rect)
setup()

578
bubbob/ext2/__init__.py.bak Normal file
View File

@ -0,0 +1,578 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
from boards import CELL, HALFCELL, bget
from mnstrmap import GreenAndBlue, Ghost
from bonuses import Bonus
from bubbles import Bubble
LocalDir = os.path.basename(os.path.dirname(__file__))
localmap = {
('pac-lg', -1,0) : ('image1.ppm', ( 0, 0, 32, 32)),
('pac-sm', -1,0) : ('image1.ppm', (32, 0, 32, 32)),
('pac-lg', 0,-1) : ('image1.ppm', ( 0, 32, 32, 32)),
('pac-sm', 0,-1) : ('image1.ppm', (32, 32, 32, 32)),
('pac-lg', 1,0) : ('image1.ppm', ( 0, 64, 32, 32)),
('pac-sm', 1,0) : ('image1.ppm', (32, 64, 32, 32)),
('pac-lg', 0,1) : ('image1.ppm', ( 0, 96, 32, 32)),
('pac-sm', 0,1) : ('image1.ppm', (32, 96, 32, 32)),
'pac-black' : ('image2.ppm', ( 0, 0, 32, 32)),
'pac-dot' : ('image2.ppm', ( 0, 32, 8, 8)),
}
music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav'))
class PacSprite(ActiveSprite):
def __init__(self, ico, x, y):
import boards
if y < -2*CELL:
y = -2*CELL
elif y > boards.bheight:
y = boards.bheight
x = (x+HALFCELL) & -CELL
y = (y+HALFCELL) & -CELL
ActiveSprite.__init__(self, ico, x, y)
self.wannadx = self.wannady = 0
def moving(self):
import boards
dx = dy = 0
turned = None
was_clear = 0
while 1:
if dx or dy:
frontx = self.x+CELL+dx*(CELL+1)
fronty = self.y+CELL+dy*(CELL+1)
clear = (bget((frontx+dy)//CELL, (fronty-dx)//CELL) == ' ' and
bget((frontx-dy)//CELL, (fronty+dx)//CELL) == ' ')
if clear:
blocked = 0
else:
blocked = (was_clear or (self.x<=2*CELL and dx<0) or
(self.x>=boards.bwidth-4*CELL and dx>0))
else:
blocked = 1
if blocked:
if turned:
dx, dy = turned
turned = None
continue
self.lastmove = None
else:
if turned:
self.resetimages(dx, dy)
turned = None
self.lastmove = dx, dy
self.step(2*dx, 2*dy)
self.vertical_warp()
was_clear = clear
yield None
if self.wannadx != dx or self.wannady != dy:
if ((self.wannadx and not (self.y % CELL)) or
(self.wannady and not (self.x % CELL))):
turned = dx, dy
dx = self.wannadx
dy = self.wannady
class Pac(PacSprite):
no_hat = 1
def __init__(self, pacman, bubber, x, y, dcap):
ico = GreenAndBlue.normal_bubbles[bubber.pn][1]
PacSprite.__init__(self, images.sprget(('eyes', 0, 0)), x, y)
self.bubble = ActiveSprite(images.sprget(ico), x, y)
self.bubber = bubber
self.pacman = pacman
self.ready = 0
self.gen.append(self.playing())
self.pacman.pacs.append(self)
self.dcap = dcap
def resetimages(self, dx, dy):
self.ready = 1
self.setimages(self.cyclic([('pac-lg', dx, dy),
'pac-black',
('pac-sm', dx, dy)], 5))
def to_front(self):
self.bubble.to_front()
ActiveSprite.to_front(self)
def kill(self):
self.play(images.Snd.Pop)
self.bubble.gen = [self.bubble.die(Bubble.exploding_bubbles)]
self.pacman.latestposition[self.bubber] = self.x, self.y
try:
self.bubber.dragons.remove(self)
except ValueError:
pass
try:
self.pacman.pacs.remove(self)
except ValueError:
pass
ActiveSprite.kill(self)
def playing(self):
bubber = self.bubber
for t in self.moving():
if self.pacman.ready:
d = [(bubber.key_left, -1, 0),
(bubber.key_right, 1, 0),
(bubber.key_jump, 0,-1),
(bubber.key_fire, 0, 1)]
d.sort()
if d[-1][0] > d[-2][0]:
self.wannadx, self.wannady = d[-1][1:]
self.bubble.move(self.x, self.y)
yield None
if self.ready:
touching = images.touching(self.x+CELL-3, self.y+CELL-3, 6, 6)
touching.reverse()
for s in touching:
if isinstance(s, Bonus):
s.touched(self)
elif isinstance(s, PacGhost):
self.kill()
return
class PacGhost(PacSprite):
def __init__(self, pacman, x, y):
left = random.random() < 0.5
if left:
ico = Ghost.left[0]
else:
ico = Ghost.right[0]
PacSprite.__init__(self, images.sprget(ico), x, y)
self.pacman = pacman
self.gen.append(self.waiting())
if left:
self.wannadx = -1
else:
self.wannadx = 1
self.resetimages(self.wannadx, self.wannady)
def resetimages(self, dx, dy):
if dx > 0:
self.setimages(self.cyclic(Ghost.right, 3))
elif dx < 0:
self.setimages(self.cyclic(Ghost.left, 3))
#else: don't change image
def waiting(self, delay=45):
while not self.pacman.ready:
yield None
for i in range(delay):
yield None
self.gen.append(self.walking())
def walking(self):
round = 0
self.touchable = 1
lastmove_x = 0
for t in self.moving():
if random.random() < 0.1:
lastmove_x = self.wannadx
if self.lastmove is None and random.random() < 0.75:
round = 0 # try to move again immediately
if self.lastmove is None or random.random() < 0.01:
dragons = self.pacman.pacs or images.ActiveSprites
distances = [(abs(dragon.x-self.x)+abs(dragon.y-self.y),
dragon) for dragon in dragons]
distance, dragon = min(distances)
if lastmove_x:
self.wannadx = 0
if (dragon.y < self.y) ^ (random.random() < 0.3):
self.wannady = -1
else:
self.wannady = 1
else:
self.wannady = 0
if (dragon.x < self.x) ^ (random.random() < 0.3):
self.wannadx = -1
else:
self.wannadx = 1
else:
lastmove_x = self.lastmove[0]
## for i in range(10):
## dragon = random.choice(dragons)
## dx = dragon.x - self.x
## dy = dragon.y - self.y
## if dx or dy:
## dist = math.sqrt(dx*dx+dy*dy)
## dx /= dist
## dy /= dist
## wx, wy = random.choice([(-1,0), (1,0), (0,-1), (0,1)])
## ex = wx-dx
## ey = wy-dy
## if ex*ex + ey*ey < random.random()*3.14:
## break
## self.wannadx = wx
## self.wannady = wy
if round == 0: # go just a bit faster than the players
round = 6
else:
round -= 1
yield None
class FruitBonus(Bonus):
pass
class Pacman:
def bgen(self, limittime = 45.1): # 0:45
import boards
from player import BubPlayer
self.ready = 0
self.dots = []
monsters = BubPlayer.MonsterList[:]
random.shuffle(monsters)
keep = len([p for p in BubPlayer.PlayerList if p.isplaying()])
monsters = monsters[:2 + keep//2]
for d in monsters:
PacGhost(self, d.x, d.y)
for t in boards.initsubgame(music, self.displaypoints):
yield t
tc = boards.TimeCounter(limittime)
self.builddelay = {}
self.latestposition = {}
self.pacs = []
#finish = 0
for t in self.frame():
t = boards.normal_frame()
self.build_pacs()
yield t
#if len(self.pacs) == 0:
# finish += 1
# if finish == 20:
# break
#else:
# finish = 0
tc.update(t)
if tc.time == 0.0:
break
if (BubPlayer.FrameCounter & 15) == 7:
for s in images.ActiveSprites:
if isinstance(s, Bubble):
s.pop()
tc.restore()
self.ready = 0
results = {}
for b in self.dots:
for d in b.taken_by:
bubber = d.bubber
results[bubber] = results.get(bubber, 0) + 1
for t in boards.result_ranking(results, len(self.dots)):
self.remove_pacs()
yield t
for s in images.ActiveSprites[:]:
if isinstance(s, Bonus):
s.kill()
def displaypoints(self, bubber):
result = 0
for b in self.dots:
for d in b.taken_by:
if d.bubber is bubber:
result += 1
return result
def frame(self):
import boards
from bonuses import Fruits
for t in self.digwalls():
yield t
def anywall(x1,y1,x2,y2):
for tx in range(x1, x2):
for ty in range(y1, y2):
if bget(tx, ty) == '#':
return 1
return 0
def give_one_point(dragon):
dragon.bubber.displaypoints += 1
scoreboard()
dots = self.dots
ico = images.sprget('pac-dot')
for x in range(boards.width):
for y in range(boards.height):
if not anywall(x, y, x+2, y+2):
if anywall(x-1, y-1, x+3, y+3):
b = Bonus((x+1)*CELL - ico.w//2,
(y+1)*CELL - ico.h//2,
'pac-dot', points=-100, falling=0)
b.sound = 'Extra'
b.timeout = 0
b.taken = give_one_point
dots.append(b)
for s in images.ActiveSprites:
if isinstance(s, PacGhost):
s.to_front()
yield None
self.ready = 1
for i in range(len([s for s in images.ActiveSprites
if isinstance(s, PacGhost)])):
for j in range(32):
yield None
for j in range(100):
x = random.randrange(4, boards.width-6)
y = random.randrange(3, boards.height-5)
if not anywall(x-2, y-2, x+4, y+4):
nimage, points = random.choice(Fruits.Fruits)
points += 650 # boost to the range 750-1000
b = FruitBonus(x*CELL, y*CELL,
nimage, points, falling=0)
b.timeout = 0
break
while dots:
dots = [b for b in dots if b.alive]
yield None
def build_pacs(self):
from player import BubPlayer
for p in BubPlayer.PlayerList:
dragons = [d for d in p.dragons if not isinstance(d, Pac)]
if dragons and len(p.dragons) == len(dragons):
if self.builddelay.get(p):
self.builddelay[p] -= 1
else:
self.builddelay[p] = 109
dragon = random.choice(dragons)
if p in self.latestposition:
dragon.move(*self.latestposition[p])
pac = Pac(self, p, dragon.x, dragon.y, dragon.dcap)
p.dragons.append(pac)
p.emotic(dragon, 4)
for d in dragons:
d.kill()
def remove_pacs(self):
from player import Dragon
killclasses = (PacSprite, FruitBonus, Dragon)
for s in images.ActiveSprites[:]:
if isinstance(s, killclasses):
s.kill()
def digwalls(self):
import boards
holes = {}
for x in range(2, boards.width-2):
y = boards.height-1
if bget(x, 0) == '#' or bget(x, y) == '#':
if bget(x, 0) == ' ': curboard.putwall(x, 0)
if bget(x, y) == ' ': curboard.putwall(x, y)
curboard.reorder_walls()
for y in range(1, boards.height-1):
if bget(x, y) == ' ':
holes[x, y] = 0
if x % 7 == 0:
yield None
# 'holes' maps coordinates (x,y) to 0 (not processed)
# or 1 (processed).
# All processed holes are pacman-connected.
def rdig(x1,y1,x2,y2, reversed, holes=holes):
# digs the rectangle (x1,y1,x2,y2) and marks it as
# processed. Also recursively mark as processed all existing
# holes that are pacman-connected to the rectangle.
xrange = range(x1,x2)
yrange = range(y1,y2)
if not reversed:
xrange.reverse()
yrange.reverse()
if len(xrange) > len(yrange):
xylist = [(x, y) for x in xrange for y in yrange]
else:
xylist = [(x, y) for y in yrange for x in xrange]
t = 0
for x, y in xylist:
if bget(x, y) == '#':
curboard.killwall(x, y)
if t == 0:
yield None
t = 2
else:
t -= 1
holes.setdefault((x, y), 0)
fill = []
for x in range(x1,x2-1):
for y in range(y1,y2-1):
fill.append((x, y))
for x, y in fill:
if ((x, y) in holes and
(x, y+1) in holes and
(x+1, y) in holes and
(x+1, y+1) in holes):
if (holes[x, y] == 0 or
holes[x, y+1] == 0 or
holes[x+1, y] == 0 or
holes[x+1, y+1] == 0):
holes[x, y] = 1
holes[x, y+1] = 1
holes[x+1, y] = 1
holes[x+1, y+1] = 1
fill.append((x+1,y))
fill.append((x-1,y))
fill.append((x,y+1))
fill.append((x,y-1))
def joined(x1,y1,x2,y2, holes=holes, boards=boards):
# returns
# 1 if the rectangle (x1,y1,x2,y2) is pac-connected to
# some already-processed holes
# 0 if it is not
# -1 if (x1,y1,x2,y2) is out of the screen
if x1<2 or y1<1 or x2>boards.width-2 or y2>boards.height-1:
return -1
accum1 = accum2 = 0
for x in range(x1,x2):
if holes.get((x,y1-1)):
accum1 += 1
if accum1 == 2:
return 1
else:
accum1 = 0
if holes.get((x,y2)):
accum2 += 1
if accum2 == 2:
return 1
else:
accum2 = 0
accum1 = accum2 = 0
for y in range(y1,y2):
if holes.get((x1-1,y)):
accum1 += 1
if accum1 == 2:
return 1
else:
accum1 = 0
if holes.get((x2,y)):
accum2 += 1
if accum2 == 2:
return 1
else:
accum2 = 0
return 0
if not holes:
holes[boards.width//2, boards.height//2] = 0
holeslist = holes.keys()
random.shuffle(holeslist)
startx, starty = holeslist.pop()
# make the hole larger (2x2) towards the center of the board
if startx > boards.width//2:
startx -= 1
if starty > boards.height//2:
starty -= 1
# initial 2x2 hole
for t in rdig(startx, starty, startx+2, starty+2, 0):
yield t
dlist = [
(0,0,1,0, 0,-1), (0,0,1,0, 0,0), # right
(0,0,0,1, -1,0), (0,0,0,1, 0,0), # bottom
(-1,0,0,0, -1,-1), (-1,0,0,0, -1,0), # left
(0,-1,0,0, -1,-1), (0,-1,0,0, 0,-1), # top
]
while holeslist:
random.shuffle(dlist)
pending = holeslist
holeslist = []
progress = 0
for x, y in pending:
if holes[x, y] != 0:
continue
for dx1, dy1, dx2, dy2, dx, dy in dlist:
x1 = x + dx
y1 = y + dy
x2 = x1 + 2
y2 = y1 + 2
result = 0
while result == 0:
result = joined(x1,y1,x2,y2)
if result == 1:
# rectangle (x1,y1,x2,y2) is good
for t in rdig(x1, y1, x2, y2,
dx1<0 or dy1<0 or dx2<0 or dy2<0):
yield t
progress = 1
break
x1 += dx1
y1 += dy1
x2 += dx2
y2 += dy2
else:
# rectangle (x1,y1,x2,y2) is too large for the screen
# failure
continue
break
else:
# no successful direction found from this point
holeslist.append((x, y)) # try again later
if not progress:
# deadlocked situation, add a new random hole
x = random.randrange(2, boards.width-2)
y = random.randrange(1, boards.height-1)
holeslist.insert(0, (x, y))
holes.setdefault((x, y), 0)
yield None
# pattern transformation:
# X. ..
# ... --> ...
# .X .X
progress = 1
while progress:
progress = 0
for y in range(1, boards.height-1):
for x in range(3, boards.width-3):
if (' ' == bget(x, y)
== bget(x+1, y)
== bget(x-1, y)
== bget(x, y+1)
== bget(x, y-1)):
if '#' == bget(x-1, y-1) == bget(x+1, y+1):
curboard.killwall(x-1, y-1)
progress = 1
elif '#' == bget(x+1, y-1) == bget(x-1, y+1):
curboard.killwall(x+1, y-1)
progress = 1
yield None
# This game is suitable for at least min_players players
min_players = 1
def run():
global curboard
import boards
from boards import curboard
boards.replace_boardgen(Pacman().bgen())
def setup():
for key, (filename, rect) in localmap.items():
filename = os.path.join(LocalDir, filename)
images.sprmap[key] = (filename, rect)
setup()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
@ -292,7 +292,7 @@ class Galaga:
if in_place[1]:
xbounds = [s.x for s in in_place[1]]
self.alien_bounds = min(xbounds), max(xbounds)
shifter.next()
next(shifter)
elif toohigh:
self.globaly += 1
squadtime -= 1
@ -357,7 +357,7 @@ def run():
boards.replace_boardgen(Galaga().bgen())
def setup():
for key, (filename, rect) in localmap.items():
for key, (filename, rect) in list(localmap.items()):
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:

367
bubbob/ext3/__init__.py.bak Normal file
View File

@ -0,0 +1,367 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
import boards
from boards import CELL, HALFCELL, bget
from mnstrmap import GreenAndBlue, Fire
from bonuses import Bonus
from player import Dragon, BubPlayer
import monsters
from bubbles import Bubble
LocalDir = os.path.basename(os.path.dirname(__file__))
localmap = {
'gala': ('image1-%d.ppm', (0, 0, 32, 32)),
}
music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav'))
snd_shoot = gamesrv.getsample(os.path.join(LocalDir, 'shoot.wav'))
class Ship(ActiveSprite):
def __init__(self, galaga, bubber, x, y):
ico = images.sprget(('gala', bubber.pn))
ActiveSprite.__init__(self, ico, x, y)
self.galaga = galaga
self.bubber = bubber
self.gen.append(self.movedown())
self.gen.append(self.playing_ship())
self.gen.append(self.doomed())
self.galaga.ships.append(self)
def movedown(self):
import boards
target_y = boards.bheight - self.ico.h
while self.y < target_y:
yield None
self.move(self.x, self.y + 3)
self.move(self.x, target_y)
def playing_ship(self):
import boards
bubber = self.bubber
xmin = HALFCELL
xmax = boards.bwidth - HALFCELL - self.ico.w
fire = 0
while 1:
wannago = bubber.wannago(self.dcap)
nx = self.x + 2*wannago
if nx < xmin:
nx = xmin
elif nx > xmax:
nx = xmax
self.move(nx, self.y)
if fire:
fire -= 1
elif bubber.key_fire:
self.firenow()
fire = 28
yield None
def firenow(self):
ico = images.sprget(GreenAndBlue.new_bubbles[self.bubber.pn][0])
s = Shot(ico, self.x, self.y)
s.d = self
s.gen = [s.straightup(self)]
self.play(snd_shoot)
def doomed(self):
dangerous = Alien, monsters.MonsterShot
while 1:
touching = images.touching(self.x+3, self.y+3, 26, 26)
for s in touching:
if isinstance(s, dangerous):
self.kill()
return
yield None
yield None
def kill(self):
try:
self.bubber.dragons.remove(self)
except ValueError:
pass
images.Snd.Pop.play(1.0, pad=0.0)
images.Snd.Pop.play(1.0, pad=1.0)
ico = images.sprget(Bubble.exploding_bubbles[0])
for i in range(11):
s = ActiveSprite(ico,
self.x + random.randrange(self.ico.w) - CELL,
self.y + random.randrange(self.ico.h) - CELL)
s.gen.append(s.die(Bubble.exploding_bubbles))
try:
self.galaga.ships.remove(self)
except ValueError:
pass
ActiveSprite.kill(self)
class Shot(Bubble):
touchable = 0
def straightup(self, ship):
ymin = -self.ico.h
while self.y > ymin:
self.step(0, -10)
touching = images.touching(self.x+CELL-1, self.y+CELL-1, 2, 2)
touching = [s for s in touching if isinstance(s, Alien)]
if touching:
alien = random.choice(touching)
self.gen = []
self.touchable = 1
self.move(alien.x, alien.y)
self.pop([ship])
alien.kill()
scores = ship.galaga.scores
scores[ship.bubber] = scores.get(ship.bubber, 0) + 1
ship.bubber.givepoints(100)
return
yield None
def popped(self, dragon):
return 200
class Alien(monsters.Monster):
ANGLES = 32
SPEED = 5
ANGLE_TABLE = [(SPEED * math.cos(a*2.0*math.pi/ANGLES),
-SPEED * math.sin(a*2.0*math.pi/ANGLES))
for a in range(ANGLES)]
touchable = 0
def __init__(self, galaga, squadron, rank, relativey):
centerx = boards.bwidth // 2
go_left = squadron % 2
dx = (1,-1)[go_left]
halfspan = centerx*7//12
relativex = - halfspan + 4*CELL*rank
if relativex > halfspan:
raise StopIteration
if squadron % 3 == 2:
from mnstrmap import Ghosty as mcls
else:
from mnstrmap import Flappy as mcls
mdef = mcls(centerx // CELL - 1, -7, go_left)
mdef.left_weapon = mdef.right_weapon = [Fire.drop]
monsters.Monster.__init__(self, mdef)
self.path = [(None, centerx + (dx*centerx)*2//3, boards.bheight//3),
(None, centerx - (dx*centerx)*4//5, boards.bheight//6),
(galaga, -dx*relativex, -relativey)]
self.gen = [self.waiting(rank * 20)]
self.in_place = 0
galaga.nbmonsters += 1
def default_mode(self, angle=ANGLES//4):
self.touchable = 1
speed = self.SPEED
relative, tx, ty = self.path[0]
fx = self.x
fy = self.y
ymax = boards.bheight - self.ico.h
cont = 1
if relative:
shoot_prob = 0.0085
else:
shoot_prob = 0.021
while cont:
if self.angry:
self.kill() # never getting out of a bubble
return
if relative:
dx = relative.globalx + tx
dy = relative.globaly + ty
else:
dx = tx
dy = ty
dx -= self.x
dy -= self.y
tests = []
for a1 in (-1, 0, 1):
a1 = (angle+a1) % self.ANGLES
testx, testy = self.ANGLE_TABLE[a1]
testx -= dx
testy -= dy
tests.append((testx*testx+testy*testy, a1))
ignored, angle = min(tests)
if dx*dx+dy*dy > speed*speed:
dx, dy = self.ANGLE_TABLE[angle]
elif relative:
self.in_place = 1
if self.y > ymax and relative.ships:
for ship in relative.ships[:]:
ship.kill()
relative.builddelay[ship.bubber] = 9999
relative.gameover = 1
#x0 = self.x//CELL + 1
#if x0 < 2: x0 = 0
#if x0 >= boards.width-2: x0 = boards.width-3
#bubbles.FireFlame(x0, boards.height-2, None, [-1, 1],
# boards.width)
else:
self.path.pop(0)
self.gen.append(self.default_mode(angle))
cont = 0
fx += dx
fy += dy
self.move(int(fx), int(fy))
if dx and (self.dir > 0) != (dx > 0):
self.dir = -self.dir
self.resetimages()
if random.random() < shoot_prob and self.y >= 0:
monsters.DownShot(self)
yield None
class Galaga:
gameover = 0
def bgen(self):
self.scores = {}
for t in boards.initsubgame(music, self.displaypoints):
yield t
self.ships = []
self.builddelay = {}
self.nbmonsters = 0
#finish = 0
for t in self.frame():
t = boards.normal_frame()
self.build_ships()
yield t
#if len(self.ships) == 0:
# finish += 1
# if finish == 50:
# break
#else:
# finish = 0
if (BubPlayer.FrameCounter & 15) == 7:
for s in images.ActiveSprites:
if isinstance(s, Bubble) and not isinstance(s, Shot):
s.pop()
for t in boards.result_ranking(self.scores, self.nbmonsters):
self.build_ships()
yield t
for s in images.ActiveSprites[:]:
if isinstance(s, (Alien, Ship)):
s.kill()
def displaypoints(self, bubber):
return self.scores.get(bubber, 0)
def frame(self):
curboard.walls_by_pos.clear()
curboard.winds = ['v' * curboard.width] * curboard.height
for y in range(len(curboard.walls)):
curboard.walls[y] = ' ' * len(curboard.walls[y])
l1 = curboard.sprites['walls']
l2 = curboard.sprites['borderwalls']
while l1 or l2:
for l in [l1, l2]:
for w in l[:]:
w.step(0, 5)
if w.y >= boards.bheight:
l.remove(w)
w.kill()
yield None
self.globalx = boards.bwidth // 2
self.globaly = 0
shifter = self.shifter()
squadrons = len([p for p in BubPlayer.PlayerList if p.isplaying()])
squadrons = 3 + (squadrons+1)//3
nextsquad = 0
relativey = 0
squadtime = 0
while not self.gameover:
yield None
#if random.random() < 0.015:
# bubbles.sendbubble(bubbles.PlainBubble, top=0)
in_place = {0: [], 1: [], 2: []}
for s in BubPlayer.MonsterList:
if isinstance(s, Alien):
in_place[s.in_place].append(s)
toohigh = self.globaly - relativey < -3*CELL
if in_place[1]:
xbounds = [s.x for s in in_place[1]]
self.alien_bounds = min(xbounds), max(xbounds)
shifter.next()
elif toohigh:
self.globaly += 1
squadtime -= 1
if nextsquad >= squadrons:
if not (in_place[0] or in_place[1]):
break
elif squadtime < 0 and not toohigh:
squadtime = 200
try:
rank = 0
while 1:
Alien(self, nextsquad, rank, relativey)
rank += 1
except StopIteration:
pass
nextsquad += 1
relativey += 4*CELL
for t in range(20):
yield None
def shifter(self):
while 1:
# go right
while self.alien_bounds[1] < boards.bwidth-5*CELL:
self.globalx += 2
yield None
# go down
for i in range(3*CELL):
self.globaly += 1
yield None
# go left
while self.alien_bounds[0] > 3*CELL:
self.globalx -= 2
yield None
# go down
for i in range(3*CELL):
self.globaly += 1
yield None
def build_ships(self):
for p in BubPlayer.PlayerList:
dragons = [d for d in p.dragons if not isinstance(d, Ship)]
if dragons and len(p.dragons) == len(dragons):
if self.builddelay.get(p):
self.builddelay[p] -= 1
else:
self.builddelay[p] = 75
dragon = random.choice(dragons)
ship = Ship(self, p, dragon.x, dragon.y)
ship.dcap = dragon.dcap
p.dragons.append(ship)
p.emotic(dragon, 4)
for d in dragons:
d.kill()
# This game is suitable for at least min_players players
min_players = 1
def run():
global curboard
from boards import curboard
boards.replace_boardgen(Galaga().bgen())
def setup():
for key, (filename, rect) in localmap.items():
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:
images.sprmap[key, p.pn] = (filename % p.pn, rect)
else:
images.sprmap[key] = (filename, rect)
setup()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
@ -179,7 +179,7 @@ class BrickEyes(BubblingEyes):
ico = images.sprget(Bubble.exploding_bubbles[0])
self.tetris.score[self.bubber] = self.tetris.score.get(
self.bubber, 0) + 1
xlist = range(x1, x2)
xlist = list(range(x1, x2))
for x in xlist:
s = ActiveSprite(ico,
x*CELL + random.randrange(CELL) - CELL,
@ -317,7 +317,7 @@ class Tetris:
for t in boards.result_ranking(self.score):
self.remove_eyes()
yield t
for s in self.staticbricks.values():
for s in list(self.staticbricks.values()):
s.remove()
def displaypoints(self, bubber):
@ -339,7 +339,7 @@ class Tetris:
else:
height += 1
heights[x] = height
xlist = range(2, curboard.width-2)
xlist = list(range(2, curboard.width-2))
random.shuffle(xlist)
for x in xlist:
h = heights[x]
@ -430,7 +430,7 @@ def run():
def setup():
from player import BubPlayer
for key, (filename, rect) in localmap.items():
for key, (filename, rect) in list(localmap.items()):
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:

440
bubbob/ext4/__init__.py.bak Normal file
View File

@ -0,0 +1,440 @@
from __future__ import generators
import os, math, random
import images, gamesrv
from images import ActiveSprite
from boards import CELL, HALFCELL, bget
from mnstrmap import GreenAndBlue
from bubbles import BubblingEyes, Bubble
from bonuses import Bonus, points
LocalDir = os.path.basename(os.path.dirname(__file__))
localmap = {
't-brick1': ('image1-%d.ppm', (0, 0, 16, 16)),
't-brick2': ('image1-%d.ppm', (16, 0, 16, 16)),
}
music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav'))
class BrickEyes(BubblingEyes):
Patterns = [[(-2,0), (-1,0), (0,0), (1,0)],
[(-2,0), (-1,0), (0,0), (0,-1)],
[(-1,-1), (-1,0), (0,0), (1,0)],
[(-1,0), (0,0), (0,-1), (1,0)],
[(-1,-1), (0,-1), (0,0), (1,0)],
[(-2,0), (-1,0), (-1,-1), (0,-1)],
[(-1,-1), (-1,0), (0,-1), (0,0)]]
def __init__(self, tetris, bubber, saved_caps, olddragon):
BubblingEyes.__init__(self, bubber, saved_caps, olddragon)
self.tetris = tetris
self.bricks = []
def playing_bubble(self, oldsprite):
import boards
self.pat = random.choice(self.Patterns)
self.orientation = 1,0
xmin = 2 - min([x for x,y in self.pat])
xmax = boards.width-3 - max([x for x,y in self.pat])
x = int(random.normalvariate(oldsprite.x, boards.bwidth/4))
x = (x+HALFCELL) // CELL
if x<xmin: x=xmin
if x>xmax: x=xmax
y = -1
self.tx = x
self.ty = y
self.move((x-1)*CELL, (y-1)*CELL)
for i in range(5):
yield None
self.bricks = [Brick(self.bubber, px, py)
for px, py in self.brick_positions()]
self.gen.append(self.step_control())
self.gen.append(self.rotate_control())
self.gen.append(self.fall_control())
self.gen.append(self.move_eyes())
def bottom_up(self):
return 0
def kill(self):
for b in self.bricks:
b.stop(self.tetris)
b.remove()
self.bricks = []
BubblingEyes.kill(self)
def brick_positions(self):
ox, oy = self.orientation
result = []
cx = self.tx*CELL - HALFCELL
cy = self.ty*CELL - HALFCELL
for px, py in self.pat:
px = px*CELL + HALFCELL
py = py*CELL + HALFCELL
result.append((cx+px*ox-py*oy, cy+px*oy+py*ox))
return result
def save_position(self):
return self.tx, self.ty, self.orientation
def restore_position(self, p):
self.tx, self.ty, self.orientation = p
def moved(self, old_position):
for b in self.bricks:
b.set(' ')
try:
for px, py in self.brick_positions():
if bget(px//CELL, py//CELL) != ' ':
self.restore_position(old_position)
return 0
for b, (px, py) in zip(self.bricks, self.brick_positions()):
b.follow(px, py)
finally:
for b in self.bricks:
b.set('!') # note: we need '!' < '#'
return 1
def onground(self):
for b in self.bricks:
if b.gen: # brick still moving
return 0
for px, py in self.brick_positions():
if bget(px//CELL, py//CELL+1) >= '#':
return 1
return 0
def step_control(self):
while 1:
while not self.bubber.wannago(self.dcap):
yield None
pos = self.save_position()
self.tx += self.bubber.wannago(self.dcap)
if self.moved(pos):
for i in range(4):
yield None
yield None
def fall_control(self):
delay = 1
while 1:
for i in range(delay and 14):
if self.bubber.key_fire:
break
yield None
pos = self.save_position()
self.ty += 1
delay = self.moved(pos)
if delay:
for i in range(3):
yield None
elif self.onground() and self.tetris.ready:
self.gen = [self.stopping()]
yield None
def rotate_control(self):
while 1:
while not self.bubber.key_jump:
yield None
pos = self.save_position()
ox, oy = self.orientation
self.orientation = oy, -ox
if self.moved(pos):
for i in range(7):
yield None
yield None
def stopping(self):
self.move(self.x, -self.ico.h)
positions = [(py//CELL, px//CELL) for px, py in self.brick_positions()
if py >= 0]
positions.sort()
positions = [(px, py) for py, px in positions]
for b in self.bricks:
b.stop(self.tetris)
if b.ty < 0:
b.remove()
self.bricks = []
staticbricks = self.tetris.staticbricks
pts = 500
while 1:
for px, py in positions:
y = py
x1 = px
while (x1-1, y) in staticbricks:
x1 -= 1
if bget(x1-1, y) != '#':
continue
x2 = px
while (x2, y) in staticbricks:
x2 += 1
if bget(x2, y) != '#':
continue
if x2-x1 < 2:
continue
# full line
ico = images.sprget(Bubble.exploding_bubbles[0])
self.tetris.score[self.bubber] = self.tetris.score.get(
self.bubber, 0) + 1
xlist = range(x1, x2)
for x in xlist:
s = ActiveSprite(ico,
x*CELL + random.randrange(CELL) - CELL,
y*CELL + random.randrange(CELL) - CELL)
s.gen.append(s.die(Bubble.exploding_bubbles))
s = staticbricks[x, y]
points(x*CELL + HALFCELL, y*CELL + HALFCELL, s, pts)
s.remove()
if pts == 500:
self.play(images.Snd.Fruit)
elif pts == 4000:
self.play(images.Snd.Extralife)
else:
self.play(images.Snd.Extra)
pts *= 2
for y in range(py-1, -1, -1):
if not [x for x in xlist if (x, y) in staticbricks]:
break
for t in range(4):
yield None
if [x for x in xlist if (x, y+1) in staticbricks]:
break
for x in xlist:
if (x, y) in staticbricks:
staticbricks[x, y].shiftdown()
yield None
break
else:
break
if self.tetris.ready < 2:
self.gen.append(self.playing_bubble(self))
def move_eyes(self):
while 1:
tx = (self.tx-1) * CELL
ty = (self.ty-1) * CELL
for i in range(3):
if tx < self.x:
dx = -1
elif tx > self.x:
dx = +1
else:
dx = 0
if ty > self.y:
dy = +1
else:
dy = 0
self.step(2*dx, 2*dy)
key = ('eyes', dx, 0)
self.seticon(images.sprget(key))
yield None
class Brick(ActiveSprite):
def __init__(self, bubber, x, y):
ico = images.sprget(('t-brick1', bubber.pn))
ActiveSprite.__init__(self, ico, x, y)
self.tx = x//CELL
self.ty = y//CELL
self.bubber = bubber
def follow(self, x, y):
self.tx = x//CELL
self.ty = y//CELL
self.gen = [self.following(x, y)]
def following(self, nx, ny):
dx = (nx - self.x) / 7.0
dy = (ny - self.y) / 7.0
for i in range(6, 0, -1):
self.move(nx - int(i*dx), ny - int(i*dy))
yield None
self.move(nx, ny)
def set(self, c):
x, y = self.tx, self.ty
if 0 <= x < curboard.width and 0 <= y < curboard.height:
line = curboard.walls[y]
curboard.walls[y] = line[:x] + c + line[x+1:]
def stop(self, tetris):
self.set('X')
self.seticon(images.sprget(('t-brick2', self.bubber.pn)))
images.ActiveSprites.remove(self)
tetris.staticbricks[self.tx, self.ty] = self
self.staticbricks = tetris.staticbricks
def remove(self):
del self.staticbricks[self.tx, self.ty]
self.set(' ')
gamesrv.Sprite.kill(self)
def shiftdown(self):
del self.staticbricks[self.tx, self.ty]
self.set(' ')
self.ty += 1
self.set('X')
self.staticbricks[self.tx, self.ty] = self
self.step(0, CELL)
class Tetris:
def bgen(self, limittime = 90.1): # 1:30
import boards
from player import BubPlayer
self.score = {}
for t in boards.initsubgame(music, self.displaypoints):
yield t
tc = boards.TimeCounter(limittime)
self.ready = 0
self.staticbricks = {}
finished = 0
for t in self.frame():
t = boards.normal_frame()
self.build_eyes()
yield t
tc.update(t)
if tc.time == 0.0:
self.ready = 2
finished += not self.still_playing()
if finished > 16:
break
if (BubPlayer.FrameCounter & 15) == 7:
for s in images.ActiveSprites:
if isinstance(s, Bubble):
s.pop()
elif isinstance(s, Bonus):
s.kill()
tc.restore()
for t in boards.result_ranking(self.score):
self.remove_eyes()
yield t
for s in self.staticbricks.values():
s.remove()
def displaypoints(self, bubber):
return self.score.get(bubber, 0)
def frame(self):
heights = {1: curboard.height,
curboard.width-2: curboard.height}
ymax = curboard.height-1
maxheight = curboard.height*3//4
for x in range(2, curboard.width-2):
if bget(x, ymax) == ' ':
curboard.putwall(x, ymax)
height = 1
for y in range(ymax-1, -1, -1):
if bget(x, y) == '#':
if height == maxheight:
curboard.killwall(x, y)
else:
height += 1
heights[x] = height
xlist = range(2, curboard.width-2)
random.shuffle(xlist)
for x in xlist:
h = heights[x]
x1 = x2 = x
while heights[x1-1] == h:
x1 -= 1
while heights[x2] == h:
x2 += 1
parts = (x2-x1) // 8
if not parts:
continue
left = 0
if heights[x1-1] > h:
x1 -= 1
left += 1
right = parts+1
if heights[x2] > h:
x2 += 1
right -= 1
for p in range(left, right):
x = x1 + ((x2-x1-1)*p+parts//2)//parts
y = ymax
for i in range(2):
while bget(x, y) == '#':
y -= 1
if y >= 3:
curboard.putwall(x, y)
heights[x] += 1
curboard.reorder_walls()
walls_by_pos = curboard.walls_by_pos
moves = 1
s = 8.0
while moves:
moves = 0
for y in range(curboard.height-3, -1, -1):
for x in range(2, curboard.width-2):
if ((y,x) in walls_by_pos and
(y+1,x) not in walls_by_pos):
y0 = y
while (y0-1,x) in walls_by_pos:
y0 -= 1
w = curboard.killwall(x, y0, 0)
curboard.putwall(x, y+1, w)
moves = 1
curboard.reorder_walls()
for i in range(int(s)+2):
yield None
s *= 0.95
self.ready = 1
while 1:
yield None
def build_eyes(self):
from player import BubPlayer
for p in BubPlayer.PlayerList:
dragons = [d for d in p.dragons if not isinstance(d, BrickEyes)]
if dragons and len(p.dragons) == len(dragons):
dragon = random.choice(dragons)
eyes = BrickEyes(self, p, dragon.dcap, dragon)
p.dragons.append(eyes)
#p.emotic(dragon, 4)
for d in dragons:
d.kill()
def still_playing(self):
from player import BubPlayer
for p in BubPlayer.PlayerList:
for d in p.dragons:
if d.gen:
return 1
return 0
def remove_eyes(self):
from player import BubPlayer
for p in BubPlayer.PlayerList:
for d in p.dragons:
d.kill()
# This game is suitable for at least min_players players
min_players = 1
def run():
global curboard
import boards
from boards import curboard
boards.replace_boardgen(Tetris().bgen())
def setup():
from player import BubPlayer
for key, (filename, rect) in localmap.items():
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:
images.sprmap[key, p.pn] = (filename % p.pn, rect)
else:
images.sprmap[key] = (filename, rect)
setup()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, random
import images, gamesrv
from images import ActiveSprite
@ -251,7 +251,7 @@ class Lemmings:
testing = {}
def addlemming():
for x, y in testing.items():
for x, y in list(testing.items()):
if bget(x, y) != ' ' == bget(x, y-1):
if x <= curboard.width//2:
dir = 1
@ -283,7 +283,7 @@ def run():
boards.replace_boardgen(Lemmings().bgen())
def setup():
for key, (filename, rect) in localmap.items():
for key, (filename, rect) in list(localmap.items()):
filename = os.path.join(LocalDir, filename)
images.sprmap[key] = (filename, rect)
setup()

289
bubbob/ext5/__init__.py.bak Normal file
View File

@ -0,0 +1,289 @@
from __future__ import generators
import os, random
import images, gamesrv
from images import ActiveSprite
import boards
from boards import CELL, HALFCELL, bget
from monsters import Monster
from player import Dragon, BubPlayer
from bubbles import Bubble
import bonuses
LocalDir = os.path.basename(os.path.dirname(__file__))
localmap = {
('lem-walk', 1,0) : ('image1.ppm', ( 0, 0, 32, 32)),
('lem-walk', 1,1) : ('image1.ppm', ( 32, 0, 32, 32)),
('lem-walk', 1,2) : ('image1.ppm', ( 64, 0, 32, 32)),
('lem-walk', 1,3) : ('image1.ppm', ( 96, 0, 32, 32)),
('lem-walk', 1,4) : ('image1.ppm', (128, 0, 32, 32)),
('lem-walk', 1,5) : ('image1.ppm', (160, 0, 32, 32)),
('lem-walk', 1,6) : ('image1.ppm', (192, 0, 32, 32)),
('lem-walk', 1,7) : ('image1.ppm', (224, 0, 32, 32)),
('lem-fall', 1,0) : ('image1.ppm', (256, 0, 32, 32)),
('lem-fall', 1,1) : ('image1.ppm', (288, 0, 32, 32)),
('lem-fall', 1,2) : ('image1.ppm', (320, 0, 32, 32)),
('lem-fall', 1,3) : ('image1.ppm', (352, 0, 32, 32)),
('lem-fall',-1,3) : ('image2.ppm', ( 0, 0, 32, 32)),
('lem-fall',-1,2) : ('image2.ppm', ( 32, 0, 32, 32)),
('lem-fall',-1,1) : ('image2.ppm', ( 64, 0, 32, 32)),
('lem-fall',-1,0) : ('image2.ppm', ( 96, 0, 32, 32)),
('lem-walk',-1,7) : ('image2.ppm', (128, 0, 32, 32)),
('lem-walk',-1,6) : ('image2.ppm', (160, 0, 32, 32)),
('lem-walk',-1,5) : ('image2.ppm', (192, 0, 32, 32)),
('lem-walk',-1,4) : ('image2.ppm', (224, 0, 32, 32)),
('lem-walk',-1,3) : ('image2.ppm', (256, 0, 32, 32)),
('lem-walk',-1,2) : ('image2.ppm', (288, 0, 32, 32)),
('lem-walk',-1,1) : ('image2.ppm', (320, 0, 32, 32)),
('lem-walk',-1,0) : ('image2.ppm', (352, 0, 32, 32)),
('lem-jail', 0) : ('image4.ppm', ( 0, 0, 32, 32)),
('lem-jail', 1) : ('image4.ppm', ( 0, 32, 32, 32)),
('lem-jail', 2) : ('image4.ppm', ( 0, 64, 32, 32)),
}
for n in range(16):
localmap[('lem-crash', n)] = ('image3.ppm', (32*n, 0, 32, 32))
music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav'))
snd_ouch = gamesrv.getsample(os.path.join(LocalDir, 'ouch.wav'))
class Lemmy:
right = [('lem-walk', 1,n) for n in range(8)]
left = [('lem-walk',-1,n) for n in range(8)]
jailed = [('lem-jail', n) for n in range(3)]
class Lemming(Monster):
def __init__(self, lemmings, x, y, dir):
Monster.__init__(self, Lemmy, x, y, dir, in_list=lemmings.lemlist)
self.lemmings = lemmings
def argh(self, *args, **kwds):
self.untouchable()
self.gen = [self.jumpout()]
def resetimages(self):
pass
def touched(self, dragon):
if 20 >= abs(self.x - dragon.x) >= 14:
if self.x < dragon.x:
self.dir = -1
else:
self.dir = 1
def in_bubble(self, bubble):
self.move(bubble.x, bubble.y)
Monster.in_bubble(self, bubble)
return -1
def bubbling(self, bubble):
dx = random.randrange(-3, 4)
dy = random.randrange(-4, 2)
counter = 0
while not hasattr(bubble, 'poplist'):
if self.y < -CELL and bubble.y > CELL: # bubble wrapped
self.leaveboard(bubble)
return
self.move(bubble.x+dx, bubble.y+dy)
yield None
if bubble.poplist is None and bubble.y <= -2*CELL+1:
self.leaveboard(bubble)
return
self.setimages(None)
self.gen = [self.jumpout()]
def jumpout(self):
# jumping out of the bubble
self.seticon(images.sprget(self.mdef.jailed[1]))
dxy = [(random.random()-0.5) * 9.0,
(random.random()+0.5) * (-5.0)]
for n in self.parabolic(dxy):
yield n
if dxy[1] >= 2.0:
break
if dxy[0] < 0:
self.dir = -1
else:
self.dir = 1
self.touchable = 1
self.gen.append(self.falling())
def falling(self):
self.setimages(None)
n = 0
lemmap = self.lemmings.lemmap
while not self.onground():
yield None
self.move(self.x, (self.y + 4) & ~3,
lemmap['lem-fall', self.dir, n&3])
n += 1
if self.y >= boards.bheight:
self.kill()
return
yield None
if n <= 33:
self.gen.append(self.walking())
else:
self.play(snd_ouch)
self.untouchable()
self.to_front()
self.gen = [self.die([('lem-crash', n) for n in range(16)], 2)]
def walking(self):
self.setimages(None)
n = 0
lemmap = self.lemmings.lemmap
y0 = self.y // 16
while self.y == y0*16:
yield None
nx = self.x + self.dir*2
x0 = (nx+15) // 16
if bget(x0, y0+1) == ' ':
if bget(x0, y0+2) == ' ':
y0 += 1 # fall
elif bget(x0, y0) != ' ':
self.dir = -self.dir
self.resetimages()
continue
else: # climb
y0 -= 1
n2 = 0
while self.y > y0*16:
self.step(0, -2)
if n2:
n2 -= 1
else:
self.seticon(lemmap['lem-walk', self.dir, n&7])
n += 1
n2 = 2
yield None
self.move(nx, self.y, lemmap['lem-walk', self.dir, n&7])
n += 1
yield None
yield None
self.gen.append(self.falling())
def onground(self):
if self.y & 15:
return 0
x0 = (self.x+15) // 16
y0 = self.y // 16 + 2
return bget(x0, y0) != ' ' == bget(x0, y0-1)
def leaveboard(self, bubble):
if hasattr(bubble, 'd'):
bubble.play(images.Snd.Extra)
score = self.lemmings.score
bubber = bubble.d.bubber
score[bubber] = score.get(bubber, 0) + 1
bonuses.points(bubble.x, bubble.y, bubble.d, 500)
self.kill()
default_mode = walking
class Lemmings:
def bgen(self, limittime = 60.1): # 0:60
self.score = {}
for t in boards.initsubgame(music, self.displaypoints):
yield t
self.lemmap = {}
for key in localmap:
self.lemmap[key] = images.sprget(key)
tc = boards.TimeCounter(limittime)
self.lemlist = []
self.lemtotal = 0
for t in self.frame():
t = boards.normal_frame()
yield t
tc.update(t)
if tc.time == 0.0:
break
tc.restore()
for s in self.lemlist[:]:
if s.alive:
s.kill()
for s in images.ActiveSprites[:]:
if isinstance(s, Bubble):
s.pop()
for t in boards.result_ranking(self.score.copy(), self.lemtotal):
yield t
def displaypoints(self, bubber):
return self.score.get(bubber, 0)
def frame(self):
windline = '>>' + '^'*(curboard.width-4) + '<<'
curboard.winds = [windline] * curboard.height
countholes = 0
ymax = curboard.height-1
for x in range(2, curboard.width-2):
if bget(x, ymax) == ' ':
countholes += 1
xrange = []
try:
for delta in range(2, curboard.width):
for x in [delta, curboard.width-delta-1]:
if x in xrange: raise StopIteration
xrange.append(x)
except StopIteration:
pass
for x in xrange:
if countholes > curboard.width//6 and bget(x, ymax) == ' ':
curboard.putwall(x, ymax)
curboard.reorder_walls()
countholes -= 1
for y in range(0, ymax):
if bget(x, y) == ' ':
break
curboard.killwall(x, y)
yield None
testing = {}
def addlemming():
for x, y in testing.items():
if bget(x, y) != ' ' == bget(x, y-1):
if x <= curboard.width//2:
dir = 1
else:
dir = -1
s = Lemming(self, x*CELL-HALFCELL, (y-2)*CELL, dir)
self.lemtotal += 1
if y < ymax:
testing[x] = y+1
else:
del testing[x]
for x in xrange:
testing[x] = 1
addlemming()
yield None
while testing:
addlemming()
yield None
while self.lemlist:
yield None
# This game is suitable for at least min_players players
min_players = 1
def run():
global curboard
from boards import curboard
boards.replace_boardgen(Lemmings().bgen())
def setup():
for key, (filename, rect) in localmap.items():
filename = os.path.join(LocalDir, filename)
images.sprmap[key] = (filename, rect)
setup()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, random
import images, gamesrv
from images import ActiveSprite
@ -258,7 +258,7 @@ def run():
boards.replace_boardgen(Tron().bgen())
def setup():
for key, (filename, rect) in localmap.items():
for key, (filename, rect) in list(localmap.items()):
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:

268
bubbob/ext6/__init__.py.bak Normal file
View File

@ -0,0 +1,268 @@
from __future__ import generators
import os, random
import images, gamesrv
from images import ActiveSprite
import boards
from boards import CELL, HALFCELL, bget
from player import Dragon, BubPlayer
from mnstrmap import Monky
from bubbles import Bubble
from bonuses import Bonus
LocalDir = os.path.basename(os.path.dirname(__file__))
localmap = {
('trn-head', 0,-1): ('image1-%d.ppm', (0, 0, 8, 8)),
('trn-head',-1, 0): ('image1-%d.ppm', (0, 8, 8, 8)),
('trn-head', 0, 1): ('image1-%d.ppm', (0,16, 8, 8)),
('trn-head', 1, 0): ('image1-%d.ppm', (0,24, 8, 8)),
('trn', 0,-1, 1, 0): ('image1-%d.ppm', (0,32, 8, 8)),
('trn', 0, 1, 1, 0): ('image1-%d.ppm', (0,40, 8, 8)),
('trn', 1, 0, 0,-1): ('image1-%d.ppm', (0,48, 8, 8)),
('trn', 1, 0, 0, 1): ('image1-%d.ppm', (0,56, 8, 8)),
('trn', 1, 0, 1, 0): ('image1-%d.ppm', (0,64, 8, 8)),
('trn', 0, 1, 0, 1): ('image1-%d.ppm', (0,72, 8, 8)),
}
music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav'))
snd_crash = gamesrv.getsample(os.path.join(LocalDir, 'crash.wav'))
class TronHead(ActiveSprite):
def __init__(self, tron, bubber, dcap, cx, cy, dir):
self.tron = tron
self.bubber = bubber
self.dcap = dcap
self.cx = cx
self.cy = cy
self.dir = dir
self.icons = {}
for key in localmap:
ico = images.sprget((key, bubber.pn))
key = key[1:]
self.icons[key] = ico
if len(key) == 4:
dx1, dy1, dx2, dy2 = key
key = -dx2, -dy2, -dx1, -dy1
self.icons[key] = ico
ActiveSprite.__init__(self, self.icons[self.dir],
self.cx*8-2, self.cy*8-2)
self.gen.append(self.trailing())
def forward_step(self, dir):
s = gamesrv.Sprite(self.icons[self.dir + dir], self.x, self.y)
self.tron.trailsprites.append(s)
self.dir = dir
self.cx += dir[0]
self.cy += dir[1]
self.move(self.cx*8-2, self.cy*8-2, self.icons[dir])
def trailing(self):
unoccupied = self.tron.unoccupied
bubber = self.bubber
# first go straight forward until we enter the playing board itself
while (self.cx, self.cy) not in unoccupied:
self.forward_step(self.dir)
yield None
yield None
# playing!
unoccupied[self.cx, self.cy] = False
while True:
# turn
d = [(bubber.key_left, -1, 0),
(bubber.key_right, 1, 0),
(bubber.key_jump, 0,-1),
(bubber.key_fire, 0, 1)]
d.sort()
newdir = self.dir
if d[-1][0] > d[-2][0]:
newdir = d[-1][1:]
if (self.dir + newdir) not in self.icons:
newdir = self.dir # forbidden 180-degree turn
# move one step forward
self.forward_step(newdir)
# crash?
if not unoccupied.get((self.cx, self.cy)):
self.crash()
return
unoccupied[self.cx, self.cy] = False
yield None
yield None
def to_front(self):
if self.gen:
ActiveSprite.to_front(self)
def crash(self):
self.move(self.x - self.dir[0], self.y - self.dir[1],
self.icons[self.dir+self.dir])
self.to_back()
self.play(snd_crash)
ico = images.sprget(Monky.decay_weapon[1])
s = ActiveSprite(ico, self.x + self.ico.w//2 - CELL,
self.y + self.ico.h//2 - CELL)
s.gen.append(s.die(Monky.decay_weapon[1:], 4))
self.stop()
def stop(self):
del self.gen[:]
try:
self.tron.trons.remove(self)
except ValueError:
pass
def kill(self):
self.stop()
try:
self.bubber.dragons.remove(self)
except ValueError:
pass
ActiveSprite.kill(self)
class Tron:
def bgen(self, limittime = 60.1): # 1:00
self.score = {}
for t in boards.initsubgame(music, self.displaypoints):
yield t
self.ready = 0
self.trons = []
self.trailsprites = []
self.playerlist = BubPlayer.PlayerList[:]
tc = boards.TimeCounter(limittime)
for t in self.frame(tc):
t = boards.normal_frame()
self.build_trons()
yield t
tc.update(t)
if (BubPlayer.FrameCounter & 15) == 7:
for s in images.ActiveSprites:
if isinstance(s, Bubble):
s.pop()
elif isinstance(s, Bonus):
s.kill()
self.ready = 0
tc.restore()
for t in boards.result_ranking(self.score):
for p in BubPlayer.PlayerList:
for d in p.dragons[:]:
d.kill()
yield t
self.remove_trons()
def displaypoints(self, bubber):
return self.score.get(bubber, 0)
def build_trons(self):
if self.ready == 0:
self.remove_trons()
return
for p in self.playerlist:
dragons = [d for d in p.dragons if not isinstance(d, TronHead)]
if self.ready < 10 and dragons and len(p.dragons) == len(dragons):
self.score.setdefault(p, 0)
dragon = random.choice(dragons)
x, y, dir = self.select_start_point()
head = TronHead(self, p, dragon.dcap, x, y, dir)
self.trons.append(head)
p.dragons.append(head)
#p.emotic(head, 4)
for d in dragons:
d.kill()
def remove_trons(self):
for p in BubPlayer.PlayerList:
for d in p.dragons[:]:
d.kill()
for s in self.trailsprites:
s.kill()
del self.trailsprites[:]
def select_start_point(self):
distmin = 12
while True:
x, y, dir = random.choice(self.start_points)
for head in self.trons:
if abs(x-head.cx//2) + abs(y-head.cy//2) < distmin:
break
else:
break
distmin *= 0.95
if (y, x) in curboard.walls_by_pos:
curboard.killwall(x, y)
x = 2*x+1
y = 2*y - dir[1]
if dir[1] < 0:
y += 2
return x, y, dir
def frame(self, tc):
y1 = 1
y2 = curboard.height-2
while y1 <= y2:
for y in [y1, y2]:
for x in range(2, curboard.width-2):
if (y, x) in curboard.walls_by_pos:
curboard.killwall(x, y)
yield None
y1 += 1
y2 -= 1
self.start_points = []
for x in range(4, curboard.width-3):
self.start_points.append((x, 0, (0, 1)))
self.start_points.append((x, curboard.height-1, (0, -1)))
while tc.time != 0.0:
for y in [0, curboard.height-1]:
for x in range(2, curboard.width-2):
if (y, x) not in curboard.walls_by_pos:
curboard.putwall(x, y)
curboard.reorder_walls()
self.unoccupied = {}
for x in range(5, 2*curboard.width-4):
for y in range(3, 2*curboard.height-2):
self.unoccupied[x, y] = True
random.shuffle(self.playerlist)
for i in range(5):
yield None
min_players = 1
while self.ready < 20 or len(self.trons) >= min_players:
if len(self.trons) >= 2:
min_players = 2
self.ready += 1
yield None
if len(self.trons) == 1:
bubber = self.trons[0].bubber
self.score[bubber] += 1
bubber.givepoints(100)
self.trons[0].stop()
self.ready = 99
for i in range(28):
yield None
self.ready = 0
# This game is suitable for at least min_players players
min_players = 2
def run():
global curboard
from boards import curboard
boards.replace_boardgen(Tron().bgen())
def setup():
for key, (filename, rect) in localmap.items():
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:
images.sprmap[key, p.pn] = (filename % p.pn, rect)
else:
images.sprmap[key] = (filename, rect)
setup()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, random, math
import images, gamesrv
from images import ActiveSprite
@ -312,7 +312,7 @@ class Camel:
tc.restore()
score = {}
for player, shotlist in self.score.items():
for player, shotlist in list(self.score.items()):
score[player] = len(shotlist)
for t in boards.result_ranking(score):
for p in BubPlayer.PlayerList:
@ -389,7 +389,7 @@ def run():
boards.replace_boardgen(Camel().bgen())
def setup():
for key, (filename, rect) in localmap.items():
for key, (filename, rect) in list(localmap.items()):
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:

399
bubbob/ext7/__init__.py.bak Normal file
View File

@ -0,0 +1,399 @@
from __future__ import generators
import os, random, math
import images, gamesrv
from images import ActiveSprite
import boards
from boards import CELL
from player import Dragon, BubPlayer, scoreboard
from bubbles import Bubble
from bonuses import Bonus
from mnstrmap import PlayerBubbles
from mnstrmap import Monky
import bonuses
from ext6 import snd_crash
LocalDir = os.path.basename(os.path.dirname(__file__))
ANGLE_COUNT = 24
ANGLE_STEP = 360 / ANGLE_COUNT
ANGLE_TABLE = {}
for i in range(ANGLE_COUNT):
a = i*ANGLE_STEP*math.pi/180.0
ANGLE_TABLE[i*ANGLE_STEP] = (math.cos(a), math.sin(a))
localmap = {}
for i in range(ANGLE_COUNT):
localmap['camel', i] = ('image1-%d.ppm', (0, i*36, 36, 36))
music = gamesrv.getmusic(os.path.join(LocalDir, 'music.wav'))
snd_fire = gamesrv.getsample(os.path.join(LocalDir, 'fire.wav'))
snd_hit = gamesrv.getsample(os.path.join(LocalDir, 'hit.wav'))
class Plane(ActiveSprite):
lock = None
def __init__(self, camel, bubber, dcap, x, y, dirhint=None):
self.bubber = bubber
self.dcap = dcap
self.camel = camel
self.shotlist = camel.score.setdefault(bubber, {})
if x < x_min:
x = x_min
elif x > x_max:
x = x_max
if y < 4*CELL:
y = 4*CELL
elif y > (curboard.height-4)*CELL - 36:
y = (curboard.height-4)*CELL - 36
if dirhint not in (1, -1):
controldelay = 5
if x < boards.bwidth//2:
dir = 1
else:
dir = -1
else:
controldelay = 20
if x < boards.bwidth//3:
dir = 1
elif x >= boards.bwidth*2//3:
dir = -1
else:
dir = dirhint
if dir > 0:
self.angle = 0
self.flipped = False
else:
self.angle = 180
self.flipped = True
ActiveSprite.__init__(self, self.getico(), x, y)
self.fx = self.x
self.fy = self.y
self.controlgen = self.control(delay=controldelay)
self.gen.append(self.fly())
self.gen.append(self.controlgen)
self.gen.append(self.blink())
self.gen.append(self.bob())
def controlled(self):
return self.controlgen in self.gen
def getico(self):
a = self.angle // ANGLE_STEP
if self.flipped:
if a:
a = ANGLE_COUNT-a
key = 'vflip', ('camel', a, self.bubber.pn)
else:
key = 'camel', a, self.bubber.pn
return images.sprget(key)
def blink(self):
for i in range(10):
yield None
yield None
self.setdisplaypos(-256, -256)
yield None
self.setdisplaypos(-256, -256)
yield None
self.touchable = 1
def bob(self):
f = 3.0
for i in range(0, 1080, ANGLE_STEP):
self.fy += f * ANGLE_TABLE[i % 360][1]
f *= 0.98
yield None
## def loosealtitude(self, y0, angle0):
## if 90 <= angle0 < 270 or (angle0 == 270 and not self.flipped):
## angledir = -1
## else:
## angledir = 1
## for i in range(0, 180, ANGLE_STEP):
## if i % (4*ANGLE_STEP) == 0 and not (45 <= angle0 <= 135):
## angle0 += ANGLE_STEP * angledir
## angle0 = (angle0 + 360) % 360
## y0 += 4.0 * ANGLE_TABLE[i][1]
## if y0 > self.fy:
## self.fy = y0
## self.angle = angle0
## yield None
def turn(self, dir):
self.angle += ANGLE_STEP * dir
self.angle = (self.angle + 360) % 360
def control(self, delay=0):
bubber = self.bubber
prev_key_jump = 0
for i in range(delay):
yield None
shootdelay = 0
while True:
wannago = bubber.wannago(self.dcap)
self.turn(wannago)
if shootdelay:
shootdelay -= 1
elif bubber.key_fire:
x = self.x + self.ico.w//2
y = self.y + self.ico.h//2
acos, asin = ANGLE_TABLE[self.angle]
x += acos * 20
y += asin * 20
if self.flipped:
acos = -acos
asin = -asin
x -= asin * 5
y += acos * 5
self.play(snd_fire)
Shot(self, int(x), int(y), self.angle, 2)
Shot(self, int(x), int(y), self.angle)
shootdelay = 7
for i in range(2):
if bubber.key_jump > prev_key_jump:
self.flipped = not self.flipped
prev_key_jump = bubber.key_jump
yield None
for s in self.touching(12):
if isinstance(s, Plane) and s is not self:
ico = images.sprget(Monky.decay_weapon[1])
s1 = ActiveSprite(ico,
(self.x+s.x)//2 + self.ico.w//2 - CELL,
(self.y+s.y)//2 + self.ico.h//2 - CELL)
s1.gen.append(s1.die(Monky.decay_weapon[1:], 4))
s1.play(snd_crash)
self.gen = [self.godowninflames(s)]
s.gen = [s.godowninflames(self)]
def fly(self, speed=3.3):
while True:
if (self.y < 0 and not (0 < self.angle < 180) and
((abs(270 - self.angle) < -4*self.y) or random.random() < 0.2)):
if (90 <= self.angle < 270 or
(self.angle == 270 and not self.flipped)):
self.turn(-1)
else:
self.turn(1)
ico = self.getico()
acos, asin = ANGLE_TABLE[self.angle]
self.fx += acos * speed
self.fy += asin * speed
self.move(int(self.fx), int(self.fy), ico)
if self.x < x_min:
self.angle = 2 * ANGLE_STEP
self.flipped = not self.flipped
self.gen = [self.godowninflames()]
self.play(images.Snd.Pop)
elif self.x > x_max:
self.angle = 180 - 2 * ANGLE_STEP
self.flipped = not self.flipped
self.gen = [self.godowninflames()]
self.play(images.Snd.Pop)
elif self.y > y_max:
self.gen = [self.crashed()]
yield None
def godowninflames(self, hit_by_plane=None):
if hit_by_plane and hit_by_plane in self.shotlist:
hittime = self.shotlist[hit_by_plane]
if BubPlayer.FrameCounter < hittime + 60:
del self.shotlist[hit_by_plane]
scoreboard()
self.seticon(self.getico())
self.gen.append(self.fly())
trail = [(self.x, self.y)] * 7
ico = images.sprget(PlayerBubbles.explosion[0])
s = ActiveSprite(ico, self.x + self.ico.w//2 - CELL,
self.y + self.ico.h//2 - CELL)
s.gen.append(s.die(PlayerBubbles.explosion))
self.bubber.emotic(self, 4)
while True:
yield None
if random.random() < 0.37:
ico = images.sprget(Bubble.exploding_bubbles[0])
x, y = random.choice(trail)
x += random.randint(-10, 10)
y += random.randint(-10, 10)
s = ActiveSprite(ico, x+2, y+2)
s.gen.append(s.die(Bubble.exploding_bubbles))
if random.random() < 0.5:
yield None
if 90 <= self.angle < 270:
lst = [0, 0, 0, 0, -1, -1, -1, 1, 1]
else:
lst = [0, 0, 0, 0, -1, -1, 1, 1, 1]
self.turn(random.choice(lst))
trail.pop(0)
trail.append((self.x, self.y))
def crashed(self):
self.untouchable()
self.play(snd_crash)
ico = images.sprget(Monky.decay_weapon[1])
self.seticon(ico)
self.step(self.ico.w//2 - CELL,
self.ico.h//2 - CELL)
self.gen.append(self.die(Monky.decay_weapon[1:], 4))
yield None
def kill(self):
try:
self.bubber.dragons.remove(self)
except ValueError:
pass
ActiveSprite.kill(self)
class Shot(ActiveSprite):
def __init__(self, plane, x, y, angle, steps=0):
ico = images.sprcharacterget('.')
ActiveSprite.__init__(self, ico, x-4, y-12)
self.plane = plane
self.angle = angle
self.gen.append(self.moving(steps))
def moving(self, steps=0):
minx = 2*CELL - 4
maxx = (curboard.width-2)*CELL - 4
maxy = (curboard.height-1)*CELL - 12
fx = self.x
fy = self.y
dx, dy = ANGLE_TABLE[self.angle]
dx *= 7.6
dy *= 7.6
fx += dx * steps
fy += dy * steps
for i in range(22-steps):
for s in images.touching(self.x+3, self.y+11, 2, 2):
if isinstance(s, Plane) and s is not self.plane:
self.play(snd_hit)
self.kill()
if s.controlled():
s.gen = [s.godowninflames(self.plane)]
self.plane.shotlist[s] = BubPlayer.FrameCounter
bonuses.points(self.x + 4 - CELL, self.y + 12 - CELL,
self.plane, 100)
return
fx += dx
fy += dy
self.move(int(fx), int(fy))
if self.x < minx or self.x > maxx or self.y > maxy:
break
yield None
self.kill()
class Camel:
def bgen(self, limittime = 90.1): # 1:30
self.score = {}
for t in boards.initsubgame(music, self.displaypoints):
yield t
tc = boards.TimeCounter(limittime)
for t in self.frame(tc):
t = boards.normal_frame()
self.build_planes()
yield t
tc.update(t)
if (BubPlayer.FrameCounter & 15) == 7:
for s in images.ActiveSprites:
if isinstance(s, Bubble):
s.pop()
elif isinstance(s, Bonus):
s.kill()
tc.restore()
score = {}
for player, shotlist in self.score.items():
score[player] = len(shotlist)
for t in boards.result_ranking(score):
for p in BubPlayer.PlayerList:
for d in p.dragons[:]:
d.kill()
yield t
self.remove_planes()
def displaypoints(self, bubber):
return len(self.score.get(bubber, ()))
def build_planes(self):
for p in BubPlayer.PlayerList:
dragons = [d for d in p.dragons if not isinstance(d, Plane)]
if dragons and len(p.dragons) == len(dragons):
dragon = random.choice(dragons)
if dragon.dcap['infinite_shield']:
start_position = self.select_start_position()
dirhint = None
else:
start_position = dragon.x-2, dragon.y-2
dirhint = getattr(dragon, 'dir', None)
plane = Plane(self, p, dragon.dcap,
start_position[0], start_position[1], dirhint)
p.dragons.append(plane)
p.emotic(plane, 4)
for d in dragons:
d.kill()
def remove_planes(self):
for p in BubPlayer.PlayerList:
for d in p.dragons[:]:
d.kill()
def select_start_position(self):
planes = [d for p in BubPlayer.PlayerList
for d in p.dragons
if isinstance(d, Plane)]
distmin = 180
while True:
x = random.choice([x_min, x_max])
y = random.randint(2*CELL, (curboard.height-4)*CELL - 36)
for d in planes:
dist = (x-d.x)*(x-d.x) + (y-d.y)*(y-d.y)
if dist < distmin*distmin:
break
else:
return x, y
distmin = int(distmin * 0.94)
def frame(self, tc):
y = curboard.height-1
for x in range(2, curboard.width-2):
if (y, x) not in curboard.walls_by_pos:
curboard.putwall(x, y)
curboard.reorder_walls()
for y in range(0, curboard.height-1):
yield None
for x in range(2, curboard.width-2):
if (y, x) in curboard.walls_by_pos:
curboard.killwall(x, y)
while tc.time != 0.0:
yield None
# This game is suitable for at least min_players players
min_players = 2
def run():
global curboard, x_min, x_max, y_max
from boards import curboard
x_min = 2*CELL - 3
x_max = (curboard.width-2)*CELL - 36 + 3
y_max = (curboard.height-1)*CELL - 36 + 7
boards.replace_boardgen(Camel().bgen())
def setup():
for key, (filename, rect) in localmap.items():
filename = os.path.join(LocalDir, filename)
if filename.find('%d') >= 0:
for p in BubPlayer.PlayerList:
images.sprmap[key + (p.pn,)] = (filename % p.pn, rect)
else:
images.sprmap[key] = (filename, rect)
setup()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import gamesrv, os
from sprmap import sprmap as original_sprmap
from patmap import patmap
@ -69,7 +69,7 @@ class ActiveSprite(gamesrv.Sprite):
# common generators
def cyclic(self, nimages, speed=5):
images = [sprget(n) for n in nimages]
speed = range(speed)
speed = list(range(speed))
while 1:
for img in images:
self.seticon(img)
@ -148,7 +148,7 @@ class ActiveSprite(gamesrv.Sprite):
try:
for g in glist:
if self.alive:
g.next()
next(g)
except StopIteration:
try:
self.gen.remove(g)
@ -157,7 +157,7 @@ class ActiveSprite(gamesrv.Sprite):
for g in glist[glist.index(g)+1:]:
if self.alive:
try:
g.next()
next(g)
except StopIteration:
pass
yield None
@ -166,7 +166,7 @@ def touching(x1, y1, w1, h1, margin=0):
touch = {}
x1 = int(x1)
y1 = int(y1)
xrange = range(x1>>5, (x1+w1+31)>>5)
xrange = list(range(x1>>5, (x1+w1+31)>>5))
for y in range(y1>>4, (y1+h1+15)>>4):
for x in xrange:
touch.update(SpritesByLoc.get((x,y), {}))
@ -181,7 +181,7 @@ def action(sprlist, len=len):
try:
for g in glist:
if self.alive:
g.next()
next(g)
except StopIteration:
try:
self.gen.remove(g)
@ -190,7 +190,7 @@ def action(sprlist, len=len):
for g in glist[glist.index(g)+1:]:
if self.alive:
try:
g.next()
next(g)
except StopIteration:
pass
if self.touchable and self.alive:
@ -202,7 +202,7 @@ def action(sprlist, len=len):
for key in self.ranges:
del key[self]
del self.ranges[:]
xrange = range(x>>5, (x+self.ico.w+38)>>5)
xrange = list(range(x>>5, (x+self.ico.w+38)>>5))
for y in range(y>>4, (y+self.ico.h+22)>>4):
for x in xrange:
key = SpritesByLoc.setdefault((x,y), {})
@ -303,7 +303,8 @@ def loadpattern(n, keycol=None):
bitmap = gamesrv.getbitmap(filename, keycol)
return bitmap, rect
def makebkgndpattern(bitmap, (x,y,w,h), darker={}):
def makebkgndpattern(bitmap, xxx_todo_changeme, darker={}):
(x,y,w,h) = xxx_todo_changeme
from boards import CELL
try:
nbitmap, hscale, vscale = darker[bitmap]
@ -329,7 +330,7 @@ def computebiggericon(ico, bigger={}):
bigger[ico] = None, pixmap.imagezoomer(*ico.getimage())
return None
if computing is not None:
result = computing.next() or computing.next() or computing.next()
result = next(computing) or next(computing) or next(computing)
if not result:
return None # still computing
w, h, data = result
@ -456,12 +457,12 @@ def generate_sprmap():
# check and maybe regenerate the colored image files
file = os.path.join('images', 'buildcolors.py')
g = {'__name__': '__auto__', '__file__': file}
execfile(file, g)
exec(compile(open(file, "rb").read(), file, 'exec'), g)
# replace the entries 'filename_%d.ppm' by a family of entries,
# one for each color
sprmap = {}
for n, (filename, rect) in (original_sprmap.items() +
extramap.items() + hatmap.items()):
for n, (filename, rect) in (list(original_sprmap.items()) +
list(extramap.items()) + list(hatmap.items())):
if filename.find('%d') >= 0:
for i in range(MAX):
sprmap[n+1000*i] = (os.path.join('images',filename % i), rect)

542
bubbob/images.py.bak Normal file
View File

@ -0,0 +1,542 @@
from __future__ import generators
import gamesrv, os
from sprmap import sprmap as original_sprmap
from patmap import patmap
import mnstrmap
import pixmap
KEYCOL = 0x010101
MAX = 10
ActiveSprites = []
SpritesByLoc = {}
class ActiveSprite(gamesrv.Sprite):
touchable = 0
imgsetter = None
angry = []
priority = 0
def __init__(self, *args):
gamesrv.Sprite.__init__(self, *args)
if self.priority:
ActiveSprites.insert(0, self)
else:
ActiveSprites.append(self)
self.ranges = []
self.gen = []
def kill(self):
self.untouchable()
del self.gen[:]
ActiveSprites.remove(self)
gamesrv.Sprite.kill(self)
def untouchable(self):
self.touchable = 0
for key in self.ranges:
del key[self]
del self.ranges[:]
def play(self, snd, volume=0.8):
import boards
xmin = 2*boards.CELL
xmax = boards.bwidth-4*boards.CELL
snd.play(volume, pad=float(self.x-xmin)/(xmax-xmin))
def setimages(self, gen):
if self.imgsetter is not None:
try:
self.gen.remove(self.imgsetter)
except ValueError:
pass
self.imgsetter = gen
if gen is not None:
self.gen.append(gen)
def vertical_warp(self):
# short-cut this method to boards.py
import boards
ActiveSprite.vertical_warp = boards.vertical_warp_sprite
self.vertical_warp()
## if moebius:
## self.moebius()
## return moebius
## def moebius(self):
## pass
# common generators
def cyclic(self, nimages, speed=5):
images = [sprget(n) for n in nimages]
speed = range(speed)
while 1:
for img in images:
self.seticon(img)
for i in speed:
yield None
def imgseq(self, nimages, speed=5, repeat=1):
images = [sprget(n) for n in nimages]
for r in range(repeat):
for img in images:
self.seticon(img)
for i in range(speed):
yield None
def die(self, nimages, speed=1):
for n in nimages:
if n is not None:
self.seticon(sprget(n))
for i in range(speed):
yield None
self.kill()
def straightline(self, dx, dy):
fx = self.x + 0.5
fy = self.y + 0.5
while 1:
fx += dx
fy += dy
self.move(int(fx), int(fy))
yield None
def parabolic(self, dxy, warp=0, gravity=0.3):
import boards
from boards import CELL
nx = self.x
ny = self.y
dx, dy = dxy
xmax = boards.bwidth - 2*CELL - self.ico.w
while ny < boards.bheight:
nx += dx
ny += dy
dy += gravity
if nx < 2*CELL:
nx = 2*CELL
dx = abs(dx)
elif nx >= xmax:
nx = xmax
dx = -abs(dx)
if warp and (ny < -2*CELL or ny >= boards.bheight):
nx, ny = boards.vertical_warp(nx, ny)
## if moebius:
## self.moebius()
## dx = -dx
self.move(int(nx), int(ny))
dxy[:] = [dx, dy]
yield None
def following(self, other, dx=0, dy=0):
while other.alive:
self.move(other.x + dx, other.y + dy)
yield None
self.kill()
def touchdelay(self, delay):
for i in range(delay):
yield None
self.touchable = 1
def touching(self, margin=0):
return touching(self.x, self.y, self.ico.w, self.ico.h, margin)
def genangry(self):
# do one more step throught all generators of self.gen
while 1:
glist = self.gen[:]
try:
for g in glist:
if self.alive:
g.next()
except StopIteration:
try:
self.gen.remove(g)
except ValueError:
pass
for g in glist[glist.index(g)+1:]:
if self.alive:
try:
g.next()
except StopIteration:
pass
yield None
def touching(x1, y1, w1, h1, margin=0):
touch = {}
x1 = int(x1)
y1 = int(y1)
xrange = range(x1>>5, (x1+w1+31)>>5)
for y in range(y1>>4, (y1+h1+15)>>4):
for x in xrange:
touch.update(SpritesByLoc.get((x,y), {}))
return [s for s in touch
if x1+margin < s.x+s.ico.w and y1+margin < s.y+s.ico.h and
s.x+margin < x1+w1 and s.y+margin < y1+h1]
def action(sprlist, len=len):
# Main generator dispatch loop
for self in sprlist:
glist = self.gen + self.angry
try:
for g in glist:
if self.alive:
g.next()
except StopIteration:
try:
self.gen.remove(g)
except ValueError:
pass
for g in glist[glist.index(g)+1:]:
if self.alive:
try:
g.next()
except StopIteration:
pass
if self.touchable and self.alive:
# record position
x = self.x & -8
y = self.y & -8
if self.touchable != (x, y):
self.touchable = x, y
for key in self.ranges:
del key[self]
del self.ranges[:]
xrange = range(x>>5, (x+self.ico.w+38)>>5)
for y in range(y>>4, (y+self.ico.h+22)>>4):
for x in xrange:
key = SpritesByLoc.setdefault((x,y), {})
key[self] = 1
self.ranges.append(key)
def sprget(n, spriconcache={}):
try:
return spriconcache[n]
except KeyError:
key = n
if isinstance(key, tuple) and key[0] in Transformations:
t, n = key
transform = Transformations[t]
else:
transform = transform_noflip
filename, rect = sprmap[n]
bitmap, rect = transform(filename, rect)
if isinstance(n, tuple):
n1 = n[0]
else:
n1 = n
if isinstance(n1, int):
n1 = n1 % 1000
alpha = transparency.get(n1, 255)
ico = bitmap.geticon(alpha=alpha, *rect)
spriconcache[key] = ico
return ico
def transform_noflip(filename, rect):
bitmap = gamesrv.getbitmap(filename, KEYCOL)
return bitmap, rect
def make_transform(datamap, ptmap):
def transform(filename, rect, datamap=datamap, ptmap=ptmap, cache={}):
try:
bitmap, width, height = cache[filename]
except KeyError:
f = open(filename, "rb")
data = f.read()
f.close()
width, height, data = pixmap.decodepixmap(data)
data = datamap(width, height, data)
dummy, dummy, nwidth, nheight = ptmap(0, 0, width, height)
data = pixmap.encodepixmap(nwidth, nheight, data)
bitmap = gamesrv.newbitmap(data, KEYCOL)
cache[filename] = bitmap, width, height
#print 'transformed', filename, 'to', nwidth, nheight
x, y, w, h = rect
x1, y1, dummy, dummy = ptmap(x, y, width, height)
x2, y2, dummy, dummy = ptmap(x+w, y+h, width, height)
rect = min(x1,x2), min(y1,y2), abs(x2-x1), abs(y2-y1)
#print filename, ':', (x,y,w,h), '->', rect
return bitmap, rect
return transform
Transformations = {
'': transform_noflip,
'vflip': make_transform(pixmap.vflip, lambda x,y,w,h: (x,h-y,w,h)),
'hflip': make_transform(pixmap.hflip, lambda x,y,w,h: (w-x,y,w,h)),
'cw': make_transform(pixmap.rotate_cw, lambda x,y,w,h: (h-y,x,h,w)),
'ccw': make_transform(pixmap.rotate_ccw,lambda x,y,w,h: (y,w-x,h,w)),
'rot180': make_transform(pixmap.rotate_180,lambda x,y,w,h: (w-x,h-y,w,h)),
}
if 0: # disabled clipping
def sprget_subrect(n, subrect):
x, y, w, h = subrect
filename, (x0, y0, w0, h0) = sprmap[n]
key = (n, 'subrect', subrect)
sprmap[key] = filename, (x0+x, y0+y, w, h)
return sprget(key)
def make_darker(ico, is_dragon, bmpcache={}):
bmp, rect = ico.getorigin()
try:
darkbmp = bmpcache[bmp, is_dragon]
except KeyError:
image = pixmap.decodepixmap(bmp.read())
if is_dragon:
translation = pixmap.translation_dragon
else:
translation = pixmap.translation_darker
darkimage = pixmap.make_dark(image, translation)
data = pixmap.encodepixmap(*darkimage)
darkbmp = gamesrv.newbitmap(data, bmp.colorkey)
bmpcache[bmp, is_dragon] = darkbmp
return darkbmp.geticon(*rect)
def haspat(n):
return n in patmap
def loadpattern(n, keycol=None):
if not haspat(n):
n = (n[0] % 100,) + n[1:]
filename, rect = patmap[n]
filename = os.path.join('tmp', filename)
bitmap = gamesrv.getbitmap(filename, keycol)
return bitmap, rect
def makebkgndpattern(bitmap, (x,y,w,h), darker={}):
from boards import CELL
try:
nbitmap, hscale, vscale = darker[bitmap]
except KeyError:
data = bitmap.read()
width, height, data = pixmap.decodepixmap(data)
nwidth, nheight, data = pixmap.makebkgnd(width, height, data)
hscale = float(nwidth) / width
vscale = float(nheight) / height
data = pixmap.encodepixmap(nwidth, nheight, data)
nbitmap = gamesrv.newbitmap(data, None)
darker[bitmap] = nbitmap, hscale, vscale
x = int(x*hscale)
y = int(y*vscale)
w = int(CELL*hscale)
h = int(CELL*vscale)
return nbitmap, (x,y,w,h)
def computebiggericon(ico, bigger={}):
try:
result, computing = bigger[ico]
except KeyError:
bigger[ico] = None, pixmap.imagezoomer(*ico.getimage())
return None
if computing is not None:
result = computing.next() or computing.next() or computing.next()
if not result:
return None # still computing
w, h, data = result
data = pixmap.encodepixmap(w, h, data)
result = gamesrv.newbitmap(data, KEYCOL).geticon(0, 0, w, h)
bigger[ico] = result, None
return result
def biggericon(ico):
result = None
while result is None:
result = computebiggericon(ico)
return result
extramap = {
'shield-left': ('extra1.ppm', (0, 0, 32, 32)),
'shield-right': ('extra1.ppm', (0, 32, 32, 32)),
'moebius': ('extra1.ppm', (0, 64, 32, 32)),
'flower': ('extra1.ppm', (0, 96, 32, 32)),
'flower2': ('extra1.ppm', (0, 128, 32, 32)),
'potion4': ('extra1.ppm', (0, 160, 32, 32)),
('glasses', -1):('extra1.ppm', (0, 192, 32, 16)),
('glasses', +1):('extra1.ppm', (0, 208, 32, 16)),
'cactus': ('extra1.ppm', (0, 224, 32, 32)),
'questionmark3':('extra2.ppm', (0, 0, 16, 16)),
'questionmark1':('extra2.ppm', (0, 16, 16, 16)),
'questionmark5':('extra2.ppm', (0, 32, 16, 16)),
'questionmark2':('extra2.ppm', (0, 48, 16, 16)),
'questionmark4':('extra2.ppm', (0, 64, 16, 16)),
'percent': ('extra2.ppm', (0, 80, 16, 16)),
'colon': ('extra2.ppm', (0, 96, 16, 16)),
'gameoverbkgnd':('extra2.ppm', (0, 112, 16, 16)),
('eyes', 0,0): ('extra3.ppm', (0, 0, 32, 32)),
('eyes', 0,-1): ('extra3.ppm', (0, 32, 32, 32)),
('eyes', -1,0): ('extra3.ppm', (0, 64, 32, 32)),
('eyes', -1,-1):('extra3.ppm', (0, 96, 32, 32)),
('eyes', 1,0): ('extra3.ppm', (0, 128, 32, 32)),
('eyes', 1,-1): ('extra3.ppm', (0, 160, 32, 32)),
'eyes-blink': ('extra3.ppm', (0, 192, 32, 32)),
('smstar','blue' ,0): ('extra4.ppm', ( 0, 0, 16, 16)),
('smstar','blue' ,1): ('extra4.ppm', ( 0, 16, 16, 16)),
('smstar','yellow' ,0): ('extra4.ppm', ( 0, 32, 16, 16)),
('smstar','yellow' ,1): ('extra4.ppm', ( 0, 48, 16, 16)),
('smstar','red' ,0): ('extra4.ppm', (16, 0, 16, 16)),
('smstar','red' ,1): ('extra4.ppm', (16, 16, 16, 16)),
('smstar','green' ,0): ('extra4.ppm', (16, 32, 16, 16)),
('smstar','green' ,1): ('extra4.ppm', (16, 48, 16, 16)),
('smstar','magenta',0): ('extra4.ppm', (32, 0, 16, 16)),
('smstar','magenta',1): ('extra4.ppm', (32, 16, 16, 16)),
('smstar','cyan' ,0): ('extra4.ppm', (32, 32, 16, 16)),
('smstar','cyan' ,1): ('extra4.ppm', (32, 48, 16, 16)),
('starbub','blue' ,0): ('extra5.ppm', (0, 0, 32, 32)),
('starbub','blue' ,1): ('extra5.ppm', (0, 32, 32, 32)),
('starbub','blue' ,2): ('extra5.ppm', (0, 64, 32, 32)),
('starbub','yellow' ,0): ('extra5.ppm', (0, 96, 32, 32)),
('starbub','yellow' ,1): ('extra5.ppm', (0,128, 32, 32)),
('starbub','yellow' ,2): ('extra5.ppm', (0,160, 32, 32)),
('starbub','red' ,0): ('extra5.ppm', (0,192, 32, 32)),
('starbub','red' ,1): ('extra5.ppm', (0,224, 32, 32)),
('starbub','red' ,2): ('extra5.ppm', (0,256, 32, 32)),
('starbub','green' ,0): ('extra5.ppm', (0,288, 32, 32)),
('starbub','green' ,1): ('extra5.ppm', (0,320, 32, 32)),
('starbub','green' ,2): ('extra5.ppm', (0,352, 32, 32)),
('starbub','magenta',0): ('extra5.ppm', (0,384, 32, 32)),
('starbub','magenta',1): ('extra5.ppm', (0,416, 32, 32)),
('starbub','magenta',2): ('extra5.ppm', (0,448, 32, 32)),
('starbub','cyan' ,0): ('extra5.ppm', (0,480, 32, 32)),
('starbub','cyan' ,1): ('extra5.ppm', (0,512, 32, 32)),
('starbub','cyan' ,2): ('extra5.ppm', (0,544, 32, 32)),
'sheep-sm': ('extra6.ppm', (0, 0, 32, 32)),
'sheep-big': ('extra6.ppm', (0, 32, 46, 50)),
('emotic', 0): ('extra7.ppm', (0, 0, 8, 8)),
('emotic', 1): ('extra7.ppm', (0, 8, 8, 8)),
('emotic', 2): ('extra7.ppm', (0, 16, 8, 8)),
('emotic', 3): ('extra7.ppm', (0, 24, 8, 8)),
('emotic', 4): ('extra7.ppm', (0, 32, 8, 8)),
('emotic', 5): ('extra7.ppm', (0, 40, 8, 8)),
('emotic', 6): ('extra7.ppm', (0, 48, 8, 8)),
('butterfly', 'jailed', 0): ('butterfly.ppm', (0, 0, 32, 32)),
('butterfly', 'jailed', 1): ('butterfly.ppm', (0, 32, 32, 32)),
('butterfly', 'jailed', 2): ('butterfly.ppm', (0, 64, 32, 32)),
('butterfly', 'dead', 0): ('butterfly.ppm', (0, 96, 32, 32)),
('butterfly', 'dead', 1): ('butterfly.ppm', (0, 128, 32, 32)),
('butterfly', 'dead', 2): ('butterfly.ppm', (0, 160, 32, 32)),
('butterfly', 'dead', 3): ('butterfly.ppm', (0, 192, 32, 32)),
('butterfly', 'fly', 0): ('butterfly.ppm', (0, 224, 32, 32)),
('butterfly', 'fly', 1): ('butterfly.ppm', (0, 256, 32, 32)),
'glue': ('glue.ppm', (0, 0, 32, 32)),
'black': ('black.ppm', (0, 0, 32, 32)),
('sheep',-1, 0): ('sheep.ppm', (0, 0, 32, 32)),
('sheep',-1, 1): ('sheep.ppm', (0, 32, 32, 32)),
('sheep',-1, 2): ('sheep.ppm', (0, 64, 32, 32)),
('sheep',-1, 3): ('sheep.ppm', (0, 96, 32, 32)),
('sheep', 1, 0): ('sheep.ppm', (0, 128, 32, 32)),
('sheep', 1, 1): ('sheep.ppm', (0, 160, 32, 32)),
('sheep', 1, 2): ('sheep.ppm', (0, 192, 32, 32)),
('sheep', 1, 3): ('sheep.ppm', (0, 224, 32, 32)),
('sheep', 'a'): ('sheep.ppm', (2, 263, 7, 8)),
('sheep', 'b'): ('sheep.ppm', (11, 262, 6, 10)),
('sheep', 'c'): ('sheep.ppm', (17, 264, 11, 8)),
('sheep', 'd'): ('sheep.ppm', (18, 272, 11, 7)),
('sheep', 'e'): ('sheep.ppm', (18, 279, 11, 8)),
('sheep', 'f'): ('sheep.ppm', (4, 273, 10, 12)),
('sheep', 'g'): ('sheep.ppm', (19, 257, 11, 8)),
}
hatmap = {
('hat', 0, -1,1):('hat2.ppm',( 0, 0, 32, 48)),
('hat', 0, -1,2):('hat2.ppm',( 32, 0, 32, 48)),
('hat', 0, -1,3):('hat2.ppm',( 64, 0, 32, 48)),
('hat', 0, 1,3):('hat2.ppm',( 96, 0, 32, 48)),
('hat', 0, 1,2):('hat2.ppm',(128, 0, 32, 48)),
('hat', 0, 1,1):('hat2.ppm',(160, 0, 32, 48)),
('hat', 1, -1,1):('hat1.ppm',( 0, 0, 32, 48)),
('hat', 1, -1,2):('hat1.ppm',( 32, 0, 32, 48)),
('hat', 1, -1,3):('hat1.ppm',( 64, 0, 32, 48)),
('hat', 1, 1,3):('hat1.ppm',( 96, 0, 32, 48)),
('hat', 1, 1,2):('hat1.ppm',(128, 0, 32, 48)),
('hat', 1, 1,1):('hat1.ppm',(160, 0, 32, 48)),
('hat', 0) :('hat5.ppm',( 32, 0, 32, 48)),
('hat', 1) :('hat5.ppm',( 0, 0, 32, 48)),
}
def generate_sprmap():
# check and maybe regenerate the colored image files
file = os.path.join('images', 'buildcolors.py')
g = {'__name__': '__auto__', '__file__': file}
execfile(file, g)
# replace the entries 'filename_%d.ppm' by a family of entries,
# one for each color
sprmap = {}
for n, (filename, rect) in (original_sprmap.items() +
extramap.items() + hatmap.items()):
if filename.find('%d') >= 0:
for i in range(MAX):
sprmap[n+1000*i] = (os.path.join('images',filename % i), rect)
else:
sprmap[n] = (os.path.join('images', filename), rect)
return sprmap
sprmap = generate_sprmap()
transparency = {
mnstrmap.GreenAndBlue.new_bubbles[0][0]: 0xA0,
mnstrmap.GreenAndBlue.new_bubbles[0][1]: 0xB0,
mnstrmap.GreenAndBlue.new_bubbles[0][2]: 0xC0,
mnstrmap.GreenAndBlue.new_bubbles[0][3]: 0xD0,
mnstrmap.GreenAndBlue.normal_bubbles[0][0]: 0xE0,
mnstrmap.GreenAndBlue.normal_bubbles[0][1]: 0xE0,
mnstrmap.GreenAndBlue.normal_bubbles[0][2]: 0xE0,
mnstrmap.DyingBubble.first[0]: 0xD0,
mnstrmap.DyingBubble.first[1]: 0xD0,
mnstrmap.DyingBubble.first[2]: 0xD0,
mnstrmap.DyingBubble.medium[0]: 0xC0,
mnstrmap.DyingBubble.medium[1]: 0xC0,
mnstrmap.DyingBubble.medium[2]: 0xC0,
mnstrmap.DyingBubble.last[0]: 0xB0,
mnstrmap.DyingBubble.last[1]: 0xB0,
mnstrmap.DyingBubble.last[2]: 0xB0,
'starbub': 0xE0,
}
def sprcharacterget(c, filename=os.path.join('images', 'extra8.ppm')):
n = ord(c) - 32
if 0 <= n < 95:
return gamesrv.getbitmap(filename, KEYCOL).geticon(n*8, 0, 8, 15)
else:
return None
def writestr(x, y, text):
result = []
for c in text:
ico = sprcharacterget(c)
if ico is not None:
result.append(gamesrv.Sprite(ico, x, y))
x += 7
return result
def writestrlines(lines):
import boards
width = boards.bwidth + 9*boards.CELL
y = 50
for text in lines:
if text:
writestr((width - 7*len(text)) // 2, y, text)
y += 28
else:
y += 14
def getsample(fn, freq):
return gamesrv.getsample(os.path.join('sounds', fn), freq)
SoundList = ['Pop', 'Jump', 'Die', 'LetsGo', 'Extralife',
'Fruit', 'Extra', 'Yippee', 'Hurry', 'Hell', 'Shh']
class Snd:
pass
def loadsounds(freqfactor=1):
for key in SoundList:
setattr(Snd, key, getsample(key.lower()+'.wav', freqfactor))
loadsounds()
music_intro = gamesrv.getmusic('music/Snd1-8.wav')
music_game = gamesrv.getmusic('music/Snd2-8.wav')
music_potion = gamesrv.getmusic('music/Snd3-8.wav')
music_modern = gamesrv.getmusic('music/Snd4-8.wav')
music_old = gamesrv.getmusic('music/Snd5-8.wav')
music_game2 = gamesrv.getmusic('music/Snd6-8.wav')
#gamesrv.set_musics([music_intro, music_game], 1)

View File

@ -62,7 +62,7 @@ def initpalettelut ():
s = "".join ([chr ((v >> shift) & 0xff) for shift in (0,8,16)])
PaletteIndex[s] = i
# invalidate COLORS, but match the length to the number of alt palettes.
COLORS = range ((len (Palettes) / PALETTESIZE) - 1)
COLORS = list(range((len (Palettes) / PALETTESIZE) - 1))
#print 'COLORS',COLORS
COLORMAPS = [{} for n in COLORS]
#print 'COLORMAPS',COLORMAPS
@ -95,12 +95,12 @@ def inputfiles ():
os.path.join (ThisDir, os.pardir, 'ext7', 'image1-%d.ppm'): 1,
}
d = {}
execfile (os.path.join(ThisDir, os.pardir, 'sprmap.py'), d)
exec(compile(open(os.path.join(ThisDir, os.pardir, 'sprmap.py'), "rb").read(), os.path.join(ThisDir, os.pardir, 'sprmap.py'), 'exec'), d)
sprmap = d['sprmap']
for key, (filename, rect) in sprmap.items ():
for key, (filename, rect) in list(sprmap.items ()):
if filename.find('%d') >= 0:
InputFiles[os.path.join (ThisDir, filename)] = 1
return InputFiles.keys ()
return list(InputFiles.keys ())
# ____________________________________________________________
@ -143,7 +143,7 @@ def ppmbreak (f):
if not line.startswith('#'):
break
wh = line.split ()
w, h = map (int, wh)
w, h = list(map (int, wh))
sig = f.readline ().strip()
assert sig == "255"
data = f.read ()
@ -226,15 +226,15 @@ def writeout (imglist, namepattern, paletted = False):
w, h, data = imglist[i]
fn = namepattern % i
f = open (fn, 'wb')
print >> f, 'P6'
print >> f, w, h
print >> f, 255
print('P6', file=f)
print(w, h, file=f)
print(255, file=f)
f.write (data)
f.close ()
def convert (name):
print >> sys.stderr, 'generating colors for %s...' % name
print('generating colors for %s...' % name, file=sys.stderr)
imglist = [ppmbreak (open (name % 0, 'rb'))]
paletted = False
if Palettes:
@ -285,7 +285,7 @@ else:
if __name__ == '__auto__': # when execfile'd from images.py
rebuild = updatecheck ().items ()
rebuild = list(updatecheck ().items ())
rebuild.sort ()
for fn, r in rebuild:
if r:
@ -308,15 +308,15 @@ if __name__ == '__main__':
except OSError:
pass
else:
print 'rm', filename % n
print('rm', filename % n)
sys.exit()
else:
rebuild = updatecheck ()
if 0 in rebuild.values ():
print >> sys.stderr, ('%d images up-to-date. '
if 0 in list(rebuild.values ()):
print(('%d images up-to-date. '
'Use -f to force a rebuild or -c to clean.' %
rebuild.values ().count(0))
files = [fn for fn, r in rebuild.items () if r]
list(rebuild.values ()).count(0)), file=sys.stderr)
files = [fn for fn, r in list(rebuild.items ()) if r]
files.sort ()
for filename in files:

View File

@ -0,0 +1,324 @@
#! /usr/bin/env python
import sys, os
if __name__ == '__main__':
ThisDir = sys.argv[0]
else:
ThisDir = __file__
ThisDir = os.path.dirname(os.path.abspath(ThisDir))
### rotate colors
import colorsys
COLORS = [#(0, 0.0, 1.0, 1, 1), # vert
#(1, 0.0, 1.0, 1, 1), # bleu
(1, -0.7, 1.0, 1, 1), # rose
(0, -0.2, 1.0, 1, 1), # brun
(1, 0.72,1.0,-1, 1), # jaune
(0, -0.35,0.85,1, 1), # rouge
(0, 0, 0.0, 1, 1), # gris
(0, -0.85, 0.9, 1, 1), # cyan (was mauve)
#(0, 0.2, 1.0, 1, 1), # turquoise
(0, 0.925, 0.95,-1, 1), # bleu fonce
#(0, 0.45, 0.5, -0.5, 0.75), # hum
(1, 'specialpixelmap'), # vert fonce
]
MAX = 2 + len (COLORS)
## By ION:
#
# Here's the new palette-based method.
#
# It's an array [N][320] of 24bit unsigned integers
# (where N is the total number of color sets including the original one.)
#
# That is, you access it like
#
# Palettes[(PALETTESIZE * palettenumber)+paletteindex]
#
# Activate it by passing a palette file as a cmdline argument.
#
# The color mapping could be further sped up
# by making Palettes an array of bytes rather than ints,
# at the cost of increased complexity (Palettes [ (PALETTESIZE * 3 * palettenumber) + paletteindex + component])
#
Palettes = None # currently there is no 'internal' palette since this is experimental.
PALETTESIZE = 960
PaletteIndex = None
# generate the string:paletteindex lookup table
def initpalettelut ():
global PaletteIndex
global COLORS, COLORMAPS
# palette 0 is the base palette (green dragon, blue tiger)
#
# Palette 0 must contain NO duplicate colors.
PaletteIndex = {}
for i in range (PALETTESIZE):
v = Palettes[i]
#if v & 0xff == 0 and (v >> 8) & 0xff == 0x87 and (v >> 16) & 0xff == 0:
# print 'FOUND'
s = "".join ([chr ((v >> shift) & 0xff) for shift in (0,8,16)])
PaletteIndex[s] = i
# invalidate COLORS, but match the length to the number of alt palettes.
COLORS = range ((len (Palettes) / PALETTESIZE) - 1)
#print 'COLORS',COLORS
COLORMAPS = [{} for n in COLORS]
#print 'COLORMAPS',COLORMAPS
def loadpalettesets (filename):
global Palettes
#import array
#Palettes = array.array ('I')
Palettes = []
assert ((os.path.getsize (filename) % (PALETTESIZE * 3)) == 0)
#print os.path.getsize (filename)
f = open (filename, 'rb')
for i in range (os.path.getsize(filename) / (PALETTESIZE * 3)):
for j in range (PALETTESIZE):
tmp = f.read (3)
val = ord (tmp[0]) | (ord (tmp[1]) << 8) | (ord (tmp[2]) << 16)
Palettes.append (val)
#debuggest
#print len(Palettes)
#print len(Palettes) % PALETTESIZE
assert (len (Palettes) % PALETTESIZE) == 0
#print "Palettes len:",len (Palettes)
def inputfiles ():
InputFiles = {
os.path.join (ThisDir, os.pardir, 'ext1', 'image1-%d.ppm'): 1,
os.path.join (ThisDir, os.pardir, 'ext3', 'image1-%d.ppm'): 1,
os.path.join (ThisDir, os.pardir, 'ext4', 'image1-%d.ppm'): 1,
os.path.join (ThisDir, os.pardir, 'ext6', 'image1-%d.ppm'): 1,
os.path.join (ThisDir, os.pardir, 'ext7', 'image1-%d.ppm'): 1,
}
d = {}
execfile (os.path.join(ThisDir, os.pardir, 'sprmap.py'), d)
sprmap = d['sprmap']
for key, (filename, rect) in sprmap.items ():
if filename.find('%d') >= 0:
InputFiles[os.path.join (ThisDir, filename)] = 1
return InputFiles.keys ()
# ____________________________________________________________
def pixelmap (r, g, b):
r /= 255.0
g /= 255.0
b /= 255.0
h, s, v = colorsys.rgb_to_hsv(r, g, b)
h = (h*sign + delta) % 1.0
s *= sat
v *= lumen
r, g, b = colorsys.hsv_to_rgb(h, s, v)
return r*255.1, g*255.1, b*255.1
def specialpixelmap (r, g, b):
return r * 0.1, g * 0.7, r * 0.5
usingpalette = 0
def palettepixelmap (r, g, b):
# print max(r,g,b)
packed = chr(r) + chr(g) + chr(b)
try:
index = PaletteIndex[packed]
#print 'index %r' % index
# print 'USING', usingpalette
v = thispalette[index] #Palettes[(PALETTESIZE * (usingpalette + 1)) + index]
# print 'hit! %r' % packed
# print '-> %r' % (chr(v & 0xff) + chr ((v >> 8) & 0xff) + chr((v >> 16) & 0xff))
# print '%r : %r' % (Palettes[index], Palettes[PALETTESIZE + index])
return v & 0xff, (v >> 8) & 0xff, (v >> 16) & 0xff
except KeyError:
return r,g,b
def ppmbreak (f):
sig = f.readline ().strip ()
assert sig == "P6"
while 1:
line = f.readline ().strip ()
if not line.startswith('#'):
break
wh = line.split ()
w, h = map (int, wh)
sig = f.readline ().strip()
assert sig == "255"
data = f.read ()
return w, h, data
COLORMAPS = [{} for n in COLORS]
del n
def paletterotate (imglist, chr=chr, int=int, ord=ord):
global thispalette
gw, gh, green = imglist[0]
# assert bw == gw and bh == gh
n = 0
(_, _, fromimage) = imglist[0]
for reserved in COLORS:
# is not being entered, the fool.
# lut = {}
# for
thispalette = Palettes[(PALETTESIZE * (reserved + 1)):(PALETTESIZE * (reserved + 2))]
# wot is this? _ means unused?
# (_, _, otherimage) = imglist[1-n]
image = []
colormap = COLORMAPS[reserved]
append = image.append
for i in range (0, len(fromimage), 3):
rgb1 = fromimage[i:i+3]
# rgb2 = otherimage[i:i+3]
# if rgb1 == rgb2:
# append (rgb1)
if rgb1 in colormap:
append (colormap[rgb1])
else:
# print 'HI!'
r, g, b = ord(rgb1[0]), ord(rgb1[1]), ord(rgb1[2])
# print '%d,%d,%d ->' % (r,g,b)
r, g, b = palettepixelmap (r, g, b)
# print '%d,%d,%d.' % (r,g,b)
newrgb = chr (int (r))+chr (int (g))+chr (int (b))
append (newrgb)
colormap[rgb1] = newrgb
imglist.append((gw, gh, ''.join (image)))
def rotate (imglist, chr=chr, int=int, ord=ord):
global delta, sat, sign, lumen
(bw, bh, blue), (gw, gh, green) = imglist
assert bw == gw and bh == gh
for reserved in range (len (COLORS)):
if len (COLORS[reserved]) == 2:
n, fn = COLORS[reserved]
fn = globals ()[fn]
else:
n, delta, sat, sign, lumen = COLORS[reserved]
fn = pixelmap
(_, _, fromimage) = imglist[n]
(_, _, otherimage) = imglist[1-n]
image = []
colormap = COLORMAPS[reserved]
append = image.append
for i in range (0, len(fromimage), 3):
rgb1 = fromimage[i:i+3]
rgb2 = otherimage[i:i+3]
if rgb1 == rgb2:
append (rgb1)
elif rgb1 in colormap:
append (colormap[rgb1])
else:
r, g, b = fn(ord(rgb1[0]), ord(rgb1[1]), ord(rgb1[2]))
newrgb = chr(int(r))+chr(int(g))+chr(int(b))
append(newrgb)
colormap[rgb1] = newrgb
imglist.append((bw, bh, ''.join(image)))
def writeout (imglist, namepattern, paletted = False):
start = 2
if paletted:
start = 1
for i in range (start, len (imglist)):
w, h, data = imglist[i]
fn = namepattern % i
f = open (fn, 'wb')
print >> f, 'P6'
print >> f, w, h
print >> f, 255
f.write (data)
f.close ()
def convert (name):
print >> sys.stderr, 'generating colors for %s...' % name
imglist = [ppmbreak (open (name % 0, 'rb'))]
paletted = False
if Palettes:
paletterotate (imglist)
paletted = True
else:
imglist.append(ppmbreak (open (name % 1, 'rb')))
rotate (imglist)
writeout (imglist, name, paletted)
def updatecheck ():
myself = os.path.join (ThisDir, 'buildcolors.py')
def older (list1, list2):
def mtime (name):
try:
st = os.stat (name)
except OSError:
return None
else:
return st.st_mtime
list2 = [mtime (name) for name in list2]
if None in list2:
return 0
else:
list1 = [mtime(name) for name in list1]
list1 = [t for t in list1 if t is not None]
return list1 and list2 and max (list1) < min (list2)
rebuild = {}
for filename in inputfiles ():
distfiles = [myself, filename % 0]
genfiles = [filename % n for n in range (1, MAX)]
rebuild[filename] = not older (distfiles, genfiles)
return rebuild
#try to load palettes first
tmp = os.path.join (ThisDir, os.pardir, 'images', 'palettes.dat')
if os.path.exists (tmp):
#print 'loading palettes'
loadpalettesets (tmp)
initpalettelut ()
else:
# from now on we should always use the palette approach;
# comment out the following line to restore the old color-rotation code.
raise IOError("cannot find the palette file %r" % (tmp,))
if __name__ == '__auto__': # when execfile'd from images.py
rebuild = updatecheck ().items ()
rebuild.sort ()
for fn, r in rebuild:
if r:
convert(fn)
#try:
# import psyco
# psyco.bind(rotate)
#except:
# pass
if __name__ == '__main__':
if sys.argv[1:2] == ['-f']:
files = inputfiles ()
elif sys.argv[1:2] == ['-c']:
for filename in inputfiles ():
for n in range (1, MAX):
try:
os.unlink (filename % n)
except OSError:
pass
else:
print 'rm', filename % n
sys.exit()
else:
rebuild = updatecheck ()
if 0 in rebuild.values ():
print >> sys.stderr, ('%d images up-to-date. '
'Use -f to force a rebuild or -c to clean.' %
rebuild.values ().count(0))
files = [fn for fn, r in rebuild.items () if r]
files.sort ()
for filename in files:
convert (filename)

View File

@ -3,7 +3,7 @@
# a bit more related to each other instead of being completely independent.
#
from __future__ import generators
import sys, random, math
from random import uniform, choice, randrange
@ -50,7 +50,7 @@ MnstrCategory = {
"Orcy": 0,
"Gramy": 0,
"Blitzy": 2}
MnstrNames = MnstrCategory.keys()
MnstrNames = list(MnstrCategory.keys())
Bonuses = ['letter', 'fire', 'lightning', 'water', 'top']
def mnstrclslist(name):
@ -61,7 +61,7 @@ def mnstrclslist(name):
class Shape:
basemnstr = ChoiceParameter('basemnstr', MnstrNames)
extramnstr = ChoiceParameter('extramnstr', range(4))
extramnstr = ChoiceParameter('extramnstr', list(range(4)))
samemnstr = BoolParameter('samemnstr')
baseshape = ChoiceParameter('baseshape', ' ODBGMPRWZS')
rooms = BoolParameter('rooms')
@ -72,15 +72,15 @@ class Shape:
platfull = BoolParameter('platfull')
mess = ChoiceParameter('mess', ' ....!')
closed = BoolParameter('closed', 0.95)
bonuses = ChoiceParameter('bonuses', xrange(3**len(Bonuses)))
smooth = ChoiceParameter('smooth', range(4))
bonuses = ChoiceParameter('bonuses', range(3**len(Bonuses)))
smooth = ChoiceParameter('smooth', list(range(4)))
startplats = BoolParameter('startplats', 0.98)
makespace = BoolParameter('makespace', 0.8)
straightfall = BoolParameter('straightfall', 0.8)
mirrored = BoolParameter('mirrored', 0.4)
enlargeholes = BoolParameter('enlargeholes', 0.9)
all_parameters = [name for name in locals().keys()
all_parameters = [name for name in list(locals().keys())
if not name.startswith('_')]
def __init__(self, shape=None):
@ -141,7 +141,7 @@ class Shape:
if self.mess == '!':
self.holes = 1
all_tests = [value for (name, value) in locals().items()
all_tests = [value for (name, value) in list(locals().items())
if name.startswith('test_')]
def accept(self, lvl):
@ -327,7 +327,7 @@ def GenerateLevels():
HEIGHT = 23
def enter(self, *args, **kw):
result = RandomLevel.enter(self, *args, **kw)
params = self.autogen_shape.__dict__.items()
params = list(self.autogen_shape.__dict__.items())
params.sort()
# for keyvalue in params:
# print '%20s: %s' % keyvalue
@ -355,8 +355,8 @@ def GenerateSingleLevel(width, height):
if __name__ == '__main__':
for s in makeshapes():
print s.__dict__
print(s.__dict__)
else:
rnglevel = {}
execfile('levels/rnglevel', rnglevel)
exec(compile(open('levels/rnglevel', "rb").read(), 'levels/rnglevel', 'exec'), rnglevel)
RandomLevel = rnglevel['RandomLevel']

View File

@ -0,0 +1,362 @@
#
# Second try at automatically generating levels that are
# a bit more related to each other instead of being completely independent.
#
from __future__ import generators
import sys, random, math
from random import uniform, choice, randrange
class Parameter(object):
def __init__(self, name, rng):
self.name = name
self.rng = rng
def __get__(self, instance, cls):
assert self.name not in instance.__dict__
value = self.rng()
setattr(instance, self.name, value)
return value
class ChoiceParameter(Parameter):
def __init__(self, name, list):
Parameter.__init__(self, name, lambda : choice(list))
class BoolParameter(Parameter):
def __init__(self, name, prob=0.5):
Parameter.__init__(self, name, lambda : random.random() < prob)
def flat(mean,var):
return randrange(mean-var,mean+var+1)
def dice(n,sides,orig=1):
result = 0
for i in range(n):
result += orig+randrange(sides)
return result
def fork(choice1, prob, choice2):
if random.random() < prob:
return choice1()
else:
return choice2()
MnstrCategory = {
"Nasty": 0,
"Monky": 0,
"Ghosty": 1,
"Flappy": 1,
"Springy": 2,
"Orcy": 0,
"Gramy": 0,
"Blitzy": 2}
MnstrNames = MnstrCategory.keys()
Bonuses = ['letter', 'fire', 'lightning', 'water', 'top']
def mnstrclslist(name):
import boarddef
classname1 = 'L' + name
classname2 = 'R' + name
return [getattr(boarddef, classname1), getattr(boarddef, classname2)]
class Shape:
basemnstr = ChoiceParameter('basemnstr', MnstrNames)
extramnstr = ChoiceParameter('extramnstr', range(4))
samemnstr = BoolParameter('samemnstr')
baseshape = ChoiceParameter('baseshape', ' ODBGMPRWZS')
rooms = BoolParameter('rooms')
holes = BoolParameter('holes')
lines = ChoiceParameter('lines', ' -/|')
platforms = BoolParameter('platforms')
platholes = BoolParameter('platholes')
platfull = BoolParameter('platfull')
mess = ChoiceParameter('mess', ' ....!')
closed = BoolParameter('closed', 0.95)
bonuses = ChoiceParameter('bonuses', xrange(3**len(Bonuses)))
smooth = ChoiceParameter('smooth', range(4))
startplats = BoolParameter('startplats', 0.98)
makespace = BoolParameter('makespace', 0.8)
straightfall = BoolParameter('straightfall', 0.8)
mirrored = BoolParameter('mirrored', 0.4)
enlargeholes = BoolParameter('enlargeholes', 0.9)
all_parameters = [name for name in locals().keys()
if not name.startswith('_')]
def __init__(self, shape=None):
if shape:
self.__dict__.update(shape.__dict__)
self.modified = 0
def set_gens(self, rooms=0, platforms=0, holes=0, smooth=0, mess=' ', lines=' '):
self.rooms = rooms
self.platforms = platforms
self.holes = holes
self.smooth = smooth
self.mess = mess
self.lines = lines
def reset(self, attrname=None):
if attrname:
try:
del self.__dict__[attrname]
except KeyError:
pass
else:
self.__dict__.clear()
self.modified = 1
def __eq__(self, other):
return (self.__class__ is other.__class__ and
self.__dict__ == other.__dict__)
def test_similar_parameters(self, prevlist):
similarity = 0
rprevlist = prevlist[:]
rprevlist.reverse()
for param in Shape.all_parameters:
accum = 0
for prev in rprevlist:
if getattr(self, param) != getattr(prev, param):
break
else:
accum += 1
similarity += accum
minimum = min(4*len(prevlist), 7)
if not (minimum <= similarity <= 17):
self.reset()
def test_not_too_often(self, prevlist):
for param, bad_value, delay in [
('mess', '.', 2),
('mess', '!', 11),
('holes', 1, 1),
]:
if getattr(self, param) == bad_value:
for prev in prevlist[-delay:]:
if getattr(prev, param) == bad_value:
self.reset(param)
def test_mess_hole(self, prevlist):
if self.mess == '!':
self.holes = 1
all_tests = [value for (name, value) in locals().items()
if name.startswith('test_')]
def accept(self, lvl):
f = lambda d=self.difficulty : randrange(3, 4+int(9*d))
lvl.mlist = [(mnstrclslist(self.basemnstr), f)]
repeat = choice([2,2,3]) - self.extramnstr
if repeat > 1:
lvl.mlist *= repeat
if self.extramnstr:
othermnstr = [name for name in MnstrNames if name!=self.basemnstr]
if self.samemnstr:
othermnstr = [name for name in othermnstr
if MnstrCategory[name]==MnstrCategory[self.basemnstr]]
random.shuffle(othermnstr)
for name in othermnstr[:self.extramnstr]:
lvl.mlist.append((mnstrclslist(name), f))
lvl.genwalls = []
if self.baseshape == 'G':
lvl.genwalls.append((RandomLevel.grids,
uniform(0.7,0.8),
uniform(0.7,0.8)))
self.set_gens()
if self.baseshape == 'P':
lvl.genwalls.append((RandomLevel.pegs,
uniform(0.1,0.2),
uniform(0.45,0.7),
choice([0,1,1,1])))
self.set_gens(smooth=3)
self.closed = random.random() < 0.80
if self.baseshape == 'B':
nr = choice([0,0,1])
lvl.genwalls.append((RandomLevel.bouncers,
dice(1, 100) + 250 - nr*200, # length
uniform(0.7, 1.7),
nr))
self.set_gens(smooth=3)
if self.baseshape == 'W':
nr = dice(1, 3) + 2
lvl.genwalls.append((RandomLevel.walkers,
dice(2, 100) + 100, # length
nr, nr + dice(2, 3),
choice([0,1])))
self.set_gens()
if self.baseshape == 'R':
lvl.genwalls.append((RandomLevel.rivers,
randrange(3,(lvl.WIDTH-4)/4), # the number of rivers
uniform(0.3, 1.4), # the side stepping threshold
10)) # the max side stepping size
self.set_gens()
if self.baseshape == 'Z':
lvl.genwalls.append((RandomLevel.zigzag,))
self.set_gens()
if self.baseshape == 'M':
lvl.genwalls.append((RandomLevel.mondrian,))
self.set_gens()
if self.baseshape == 'O':
lvl.genwalls.append((RandomLevel.remove_joined_blocks,))
self.set_gens()
if self.baseshape == 'S':
lvl.genwalls.append((RandomLevel.platforms_reg,))
self.set_gens()
self.makespace = random.random() < 0.1
if self.closed:
self.startplats = 0
if self.baseshape == 'D':
lvl.genwalls.append((RandomLevel.discrete_blocks,))
self.set_gens()
self.makespace = random.random() < 0.1
if self.closed:
self.startplats = 0
if self.rooms:
nr = dice(2, 6)
lvl.genwalls.append((RandomLevel.rooms,
lambda : flat(9-nr,2), # the half size of the room
lambda : uniform(0.8,1.2), # the excentricity of the room
nr)) # the number of rooms
if self.lines != ' ':
rng_angle = {
'-': lambda : 0,
'/': None, # default
'|': lambda : math.pi/2,
}
lvl.genwalls.append((RandomLevel.lines,
lambda : dice(8,3), # line length
dice(2,4), # number of lines
rng_angle[self.lines]))
if self.platforms:
nplat = dice(2,4,0)
if nplat: space = flat((lvl.HEIGHT-1)/nplat/2,(lvl.HEIGHT-1)/nplat/2-1)
else: space = 1
if self.platholes:
nholes = lambda : dice(1,3)
else:
nholes = lambda : 0
wholes = lambda : dice(2,3)
full = self.platfull
lvl.genwalls.append((RandomLevel.platforms,
(nplat,space), # number of platform and spacing
(nholes,wholes), # number of holes and width
full)) # full width platform
if self.mess != ' ':
threshold = {
'.': 0.02 + 0.08*random.random(), # normal
'!': 0.25 + 0.2 *random.random(), # super-filled
}
lvl.genwalls.append((RandomLevel.mess, threshold[self.mess]))
if self.holes:
nh = choice([1,1,2,2,2,3,3,3,4,5])
lvl.genwalls.append((RandomLevel.holes,
lambda : flat(9-nh,2), # radius of the holes
lambda : uniform(0.9,1.1), # excentricity
nh, # number of holes
lambda : choice([0,0,0,1]))) # circle or rectangle
if self.closed:
lvl.genwalls.append((RandomLevel.close,))
if self.smooth > 0:
# smooth away all lone empty spaces
lvl.genwalls.append((RandomLevel.smooth, 1.0, 1))
# possibly smooth away some lone bricks
if self.smooth == 2:
lvl.genwalls.append((RandomLevel.smooth, 0.25, 0))
elif self.smooth == 3:
lvl.genwalls.append((RandomLevel.smooth, 0.75, 0))
if self.startplats:
lvl.genwalls.append((RandomLevel.startplatform, ))
lvl.genwalls.append((RandomLevel.openstartway, ))
if self.makespace:
lvl.genwalls.append((RandomLevel.make_space, ))
if self.straightfall:
lvl.genwalls.append((RandomLevel.prevent_straight_fall, ))
if self.mirrored:
lvl.genwalls.append((RandomLevel.mirror, ))
if self.enlargeholes:
lvl.genwalls.append((RandomLevel.enlarge_tiny_holes, ))
lvl.genwalls.append((RandomLevel.generate_wind, ))
b = self.bonuses
for name in Bonuses:
setattr(lvl, name, (b % 3) == 1)
b = b // 3
lvl.autogen_shape = self
def generate_shape(prevlist):
tests = Shape.all_tests
s = Shape()
for i in range(100):
s1 = Shape(s)
random.shuffle(tests)
for test in tests:
test(s1, prevlist)
if not s1.modified and s1 == s:
break
s = s1
# else:
# sys.stdout.write('*')
del s.modified
return s
def makeshapes(nblevels=25):
shapelist = []
for i in range(nblevels):
s = generate_shape(shapelist)
s.difficulty = float(i+1)/nblevels
yield s
shapelist.append(s)
if len(shapelist) == 10:
del shapelist[:]
def GenerateLevels():
# print 'generating levels',
Levels = []
for s in makeshapes():
class level(RandomLevel):
WIDTH = 28
HEIGHT = 23
def enter(self, *args, **kw):
result = RandomLevel.enter(self, *args, **kw)
params = self.autogen_shape.__dict__.items()
params.sort()
# for keyvalue in params:
# print '%20s: %s' % keyvalue
return result
s.accept(level)
Levels.append(level)
# sys.stdout.write('.')
# sys.stdout.flush()
# print
class levelfinal(RandomLevel):
WIDTH = level.WIDTH
HEIGHT = level.HEIGHT
genwalls = [(RandomLevel.platforms,(5,3),(lambda:flat(2,1),lambda:flat(6,2)),1),
(RandomLevel.close,)]
Levels.append(levelfinal)
return Levels
def GenerateSingleLevel(width, height):
[s] = makeshapes(1)
class level(RandomLevel):
WIDTH = width
HEIGHT = height
s.accept(level)
return level
if __name__ == '__main__':
for s in makeshapes():
print s.__dict__
else:
rnglevel = {}
execfile('levels/rnglevel', rnglevel)
RandomLevel = rnglevel['RandomLevel']

View File

@ -43,16 +43,16 @@ class TypeList:
return self.resources()[id]
def keys(self):
return self.resources().keys()
return list(self.resources().keys())
def values(self):
return self.resources().values()
return list(self.resources().values())
def items(self):
return self.resources().items()
return list(self.resources().items())
def namedict(self):
return dict([(r.name, r) for r in self.resources().values() if r.name is not None])
return dict([(r.name, r) for r in list(self.resources().values()) if r.name is not None])
class MacBinary:
@ -93,22 +93,22 @@ class MacBinary:
return self.dtypes
def keys(self):
return self.dtypes.keys()
return list(self.dtypes.keys())
def values(self):
return self.dtypes.values()
return list(self.dtypes.values())
def items(self):
return self.dtypes.items()
return list(self.dtypes.items())
class Subfile:
def __init__(self, f, start, length):
if start < 0:
raise ValueError, 'negative position'
raise ValueError('negative position')
if isinstance(f, Subfile):
if start + length > f.length:
raise ValueError, 'subfile out of bounds'
raise ValueError('subfile out of bounds')
f, start = f.f, f.start+start
self.f = f
self.start = start
@ -124,7 +124,7 @@ class Subfile:
return self.f.read(size)
def seek(self, npos):
if npos < 0:
raise ValueError, 'negative position'
raise ValueError('negative position')
self.position = npos
@ -186,7 +186,7 @@ class ppatResource(Resource):
f = self.subfile()
pattype, patmap, patdata = struct.unpack(">Hll", f.read(10))
if pattype != 1:
raise ValueError, 'Pattern type not supported'
raise ValueError('Pattern type not supported')
f.seek(patmap)
(rowBytes, h, w, packType, packSize,
pixelType, pixelSize, cmpCount, cmpSize, pmTable) = (
@ -194,9 +194,9 @@ class ppatResource(Resource):
isBitmap = (rowBytes & 0x8000) != 0
rowBytes &= 0x3FFF
if packType != 0:
raise ValueError, 'packed image not supported'
raise ValueError('packed image not supported')
if pixelType != 0 or cmpCount != 1:
raise ValueError, 'direct RGB image not supported'
raise ValueError('direct RGB image not supported')
assert cmpSize == pixelSize and pixelSize in [1,2,4,8]
f.seek(pmTable)
colormap = loadcolormap(f)

260
bubbob/macbinary.py.bak Normal file
View File

@ -0,0 +1,260 @@
import struct
def padto(n, m):
return (n+m-1) & ~(m-1)
def resourceclass(rtype):
return globals().get(rtype.strip() + 'Resource', Resource)
class TypeList:
def __init__(self, type, fmap, fdata, namebase, start, count):
self.type = type
self.fmap = fmap
self.fdata = fdata
self.namebase = namebase
self.start = start
self.count = count
self.ids = None
def resources(self):
if self.ids is None:
ResourceCls = resourceclass(self.type)
d = {}
self.fmap.seek(self.start)
for resid, resname, resattr, resofshi, resofslo in [
struct.unpack(">HHBBHxxxx", self.fmap.read(12))
for i in range(self.count)]:
if resname == 0xffff:
name = None
else:
self.fmap.seek(self.namebase + resname)
namelen, = struct.unpack(">B", self.fmap.read(1))
name = self.fmap.read(namelen)
assert resid not in d
d[resid] = ResourceCls(self.type, resid, name, resattr,
self.fdata, resofslo + (resofshi<<16))
self.ids = d
return self.ids
def __getitem__(self, id):
return self.resources()[id]
def keys(self):
return self.resources().keys()
def values(self):
return self.resources().values()
def items(self):
return self.resources().items()
def namedict(self):
return dict([(r.name, r) for r in self.resources().values() if r.name is not None])
class MacBinary:
def __init__(self, f):
if type(f) is type(''):
f = open(f, 'rb')
self.f = f
self.f.seek(0x53)
self.dataforksize, self.resforksize = struct.unpack(">ll", self.f.read(8))
self.loadresources()
def getdata(self):
self.f.seek(0x80)
return self.f.read(self.dataforksize)
def loadresources(self):
f = Subfile(self.f, padto(0x80 + self.dataforksize, 0x80), self.resforksize)
ofsdata, ofsmap, lendata, lenmap = struct.unpack(">llll", f.read(16))
fdata = Subfile(f, ofsdata, lendata)
fmap = Subfile(f, ofsmap, lenmap)
fmap.seek(24)
ofstype, ofsname = struct.unpack(">HH", fmap.read(4))
self.dtypes = {}
fmap.seek(ofstype)
numtypes, = struct.unpack(">H", fmap.read(2))
numtypes = numtypes + 1
for rtype, num, ofsref in [struct.unpack(">4sHH", fmap.read(8))
for i in range(numtypes)]:
assert rtype not in self.dtypes
self.dtypes[rtype] = TypeList(rtype, fmap, fdata, ofsname,
ofstype + ofsref, num + 1)
def __getitem__(self, rtype):
return self.dtypes[rtype]
def types(self):
return self.dtypes
def keys(self):
return self.dtypes.keys()
def values(self):
return self.dtypes.values()
def items(self):
return self.dtypes.items()
class Subfile:
def __init__(self, f, start, length):
if start < 0:
raise ValueError, 'negative position'
if isinstance(f, Subfile):
if start + length > f.length:
raise ValueError, 'subfile out of bounds'
f, start = f.f, f.start+start
self.f = f
self.start = start
self.length = length
self.position = 0
def read(self, size=None):
if size is None or self.position + size > self.length:
size = self.length - self.position
if size <= 0:
return ''
self.f.seek(self.start + self.position)
self.position = self.position + size
return self.f.read(size)
def seek(self, npos):
if npos < 0:
raise ValueError, 'negative position'
self.position = npos
class Resource:
def __init__(self, type, id, name, attr, srcfile, srcofs):
self.type = type
self.id = id
self.name = name
self.attr = attr
self.srcfile = srcfile
self.srcofs = srcofs
def subfile(self):
self.srcfile.seek(self.srcofs)
length, = struct.unpack(">l", self.srcfile.read(4))
return Subfile(self.srcfile, self.srcofs + 4, length)
def load(self):
return self.subfile().read()
class RGBImage:
def __init__(self, w, h, data):
assert len(data) == 3*w*h
self.w = w
self.h = h
self.data = data
def loadcolormap(f):
size, = struct.unpack(">xxxxxxH", f.read(8))
size = size + 1
d = {}
for index, r, g, b in [struct.unpack(">HHHH", f.read(8)) for i in range(size)]:
assert index not in d, 'duplicate color index'
d[index] = r/256.0, g/256.0, b/256.0
return d
def image2rgb(image):
# returns (w, h, data)
h = len(image)
result1 = []
for line in image:
for r, g, b in line:
result1.append(chr(int(r)) + chr(int(g)) + chr(int(b)))
return len(image[0]), len(image), ''.join(result1)
class clutResource(Resource):
# a color table
def gettable(self):
return loadcolormap(self.subfile())
class ppatResource(Resource):
# a pattern
def getimage(self):
f = self.subfile()
pattype, patmap, patdata = struct.unpack(">Hll", f.read(10))
if pattype != 1:
raise ValueError, 'Pattern type not supported'
f.seek(patmap)
(rowBytes, h, w, packType, packSize,
pixelType, pixelSize, cmpCount, cmpSize, pmTable) = (
struct.unpack(">xxxxHxxxxHHxxHlxxxxxxxxHHHHxxxxlxxxx", f.read(50)))
isBitmap = (rowBytes & 0x8000) != 0
rowBytes &= 0x3FFF
if packType != 0:
raise ValueError, 'packed image not supported'
if pixelType != 0 or cmpCount != 1:
raise ValueError, 'direct RGB image not supported'
assert cmpSize == pixelSize and pixelSize in [1,2,4,8]
f.seek(pmTable)
colormap = loadcolormap(f)
bits_per_pixel = pixelSize
pixels_per_byte = 8 // bits_per_pixel
image = []
f.seek(patdata)
for y in range(h):
line = f.read(rowBytes)
imgline = []
for x in range(w):
n = x//pixels_per_byte
idx = ((ord(line[n]) >> ((pixels_per_byte - 1 - x%pixels_per_byte) * bits_per_pixel))
& ((1<<bits_per_pixel)-1))
imgline.append(colormap[idx])
image.append(imgline)
return image
class LEVLResource(Resource):
# bub & bob level
WIDTH = 32
HEIGHT = 25
MONSTERS = 30
WALLS = { 1:'#', 0:' '}
WINDS = { 0:' ', 1:'>', 2:'<', 3:'v', 4:'^', 5:'x', 0x66:' '}
FLAGS = ['flag0', 'letter', 'fire', 'lightning', 'water', 'top', 'flag6', 'flag7']
def getlevel(self, mnstrlist):
f = self.subfile()
result = {}
walls = []
for y in range(self.HEIGHT):
line = f.read(self.WIDTH//8)
line = [self.WALLS[(ord(line[x//8]) >> (x%8)) & 1]
for x in range(self.WIDTH)]
walls.append(''.join(line))
result['walls'] = '\n'.join(walls)
winds = []
for y in range(self.HEIGHT):
line = f.read(self.WIDTH)
line = [self.WINDS[ord(v)] for v in line]
winds.append(''.join(line))
result['winds'] = '\n'.join(winds)
monsters = []
for i in range(self.MONSTERS):
x,y,monster_type,f1,f2,f3 = struct.unpack(">BBBBBB", f.read(6))
if monster_type != 0:
assert f1 == 0, f1
cls = mnstrlist[monster_type-1]
monsters.append(cls(x=x, y=y, dir=f2, player=f3))
result['monsters'] = monsters
result['level'], = struct.unpack('>H', f.read(2))
for i in range(8):
result[self.FLAGS[i]] = ord(f.read(1))
return result

View File

@ -7,7 +7,7 @@ class Monster1:
self.player = player
def nrange(start,n):
return range(start,start+n)
return list(range(start,start+n))
class Nasty(Monster1):
right = nrange(239,4)
@ -289,11 +289,11 @@ class birange:
self.a = a
self.n = n
def __getitem__(self, pn):
return range(self.a + 1000*pn, self.a + 1000*pn + self.n)
return list(range(self.a + 1000*pn, self.a + 1000*pn + self.n))
class bidict:
def __init__(self, a,b):
self.a = a.items()
self.a = list(a.items())
def __getitem__(self, pn):
pn *= 1000
d = {}

397
bubbob/mnstrmap.py.bak Normal file
View File

@ -0,0 +1,397 @@
class Monster1:
def __init__(self, x, y, dir, player=0):
self.x = x
self.y = y
self.dir = (1, -1)[dir]
self.player = player
def nrange(start,n):
return range(start,start+n)
class Nasty(Monster1):
right = nrange(239,4)
left = nrange(243,4)
jailed = nrange(247,3)
dead = nrange(253,4)
right_angry = nrange(800,4)
left_angry = nrange(804,4)
class Monky(Monster1):
right = nrange(265,4)
left = nrange(269,4)
jailed = nrange(273,3)
dead = nrange(279,4)
left_weapon = right_weapon = nrange(451,1) # FIXME
decay_weapon = nrange(452,4) # FIXME
right_angry = nrange(808,4)
left_angry = nrange(812,4)
class Ghosty(Monster1):
right = nrange(291,4)
left = nrange(295,4)
jailed = nrange(299,3)
dead = nrange(305,4)
right_angry = nrange(816,4)
left_angry = nrange(820,4)
class Flappy(Monster1):
right = nrange(317,4)
left = nrange(321,4)
jailed = nrange(325,3)
dead = nrange(331,4)
right_angry = nrange(824,4)
left_angry = nrange(828,4)
class Springy(Monster1):
right = nrange(343,4)
left = nrange(347,4)
jailed = nrange(351,3)
dead = nrange(357,4)
right_jump = nrange(369,2)
left_jump = nrange(371,2)
right_angry = nrange(832,4)
left_angry = nrange(836,4)
right_jump_angry = nrange(840,2)
left_jump_angry = nrange(842,2)
class Orcy(Monster1):
right = nrange(373,4)
left = nrange(377,4)
jailed = nrange(381,3)
dead = nrange(387,4)
left_weapon = nrange(456,4)
right_weapon = nrange(460,4)
decay_weapon = nrange(456,0) # FIXME
right_angry = nrange(844,4)
left_angry = nrange(848,4)
class Gramy(Monster1):
right = nrange(399,4)
left = nrange(403,4)
jailed = nrange(407,3)
dead = nrange(413,4)
left_weapon = right_weapon = nrange(472,4) # FIXME
right_angry = nrange(852,4)
left_angry = nrange(856,4)
class Blitzy(Monster1):
right = left = nrange(425,4)
jailed = nrange(429,3)
dead = nrange(435,4)
right_angry = left_angry = nrange(860,4)
left_weapon = right_weapon = nrange(476,1) # FIXME
class Ghost:
left = nrange(443,4)
right = nrange(447,4)
class PlayerBubbles:
appearing = nrange(952,5)
bubble = nrange(910,3)
explosion = nrange(913,3)
left_weapon = nrange(464,4)
right_weapon = nrange(468,4)
decay_weapon = []
class LetterBubbles:
Extend = nrange(128,3) # FIXME
eXtend = nrange(136,3)
exTend = nrange(144,3)
extEnd = nrange(152,3)
exteNd = nrange(160,3)
extenD = nrange(168,3)
class DyingBubble:
first = nrange(163,3)
medium = nrange(171,3)
last = nrange(155,3)
class Fire:
ground = nrange(490,4)
drop = 489
class Lightning:
fired = 488
class Water:
h_flow = 900
v_flow = 901
start_right = 902
start_left = 904
bottom = 903
top = 905
tl_corner = 906
bl_corner = 907
br_corner = 908
tr_corner = 909
class Flood:
waves = nrange(140,4)
fill = 495
class MiscPoints:
pink_100 = 496
class DigitsMisc:
digits_mask = nrange(519,10)
digits_border = nrange(920,10)
digits_white = nrange(930,10)
class PotionBonuses:
coin = 477
flower = 478
trefle = 479
rainbow = 480
green_note = 481
blue_note = 692
class Bonuses:
monster_bonuses = [
(593,1000), # banana
(594,2000), # peach
(595,3000), # quince
(596,4000), # pastec
(597,5000), # wine
(598,6000), # ananas
(599,8000) # diamond
]
door = 139 # Lots of diamonds
red_potion = 637 #\ .
green_potion = 638 # > Clean the level and fill the top 5 lines with one of the PotionBonuses.
yellow_potion = 639 #/
kirsh = 600
icecream1 = 601 # NOT_USED
erdbeer = 602
fish1 = 603
tomato = 604
donut = 605
apple = 606
corn = 607
icecream2 = 608 # NOT_USED
radish = 609
cyan_ice = 610 #\ .
violet_ice = 611 #|
peach2 = 612 # > Produced from the bubbles after a wand.
pastec2 = 613 #|
cream_pie = 614 #|
sugar_pie = 615 #/
brown_wand = 620 #\ .
yellow_wand = 621 #|
green_wand = 622 # > Bubbles turn into bonus of the previous set after
violet_wand = 623 # > the death of the last enemy plus a mega-bonus.
blue_wand = 624 #|
red_wand = 625 #/
violet_chest = 626 #\ .
blue_chest = 627 # > Bubbles turn into diamonds plus after the death
red_chest = 628 # > of the last enemy plus a mega-diamond
yellow_chest = 629 #/
shoe = 631 # speed player movements
grenade = 632 # put fire everywhere
brown_umbrella = 633 # fire rain
grey_umbrella = 634 # water rain
violet_umbrella = 635 # spinning balls rain
clock = 636 # time travel
coffee = 641 # Speed player's movements and fire rate.
book = 642 # Produces stars the middle-top going in any direction which kill the enemy upon contact.
heart_poison = 643 # Froze the enemy and they are now killed on contact.
gold_crux = 644 # become a bubble
red_crux = 645 # become a monster
blue_crux = 646 # become a monster
extend = 647 # Give 100'000 Points to the player and finish the level.
ring = 640 # lord of the ring
green_pepper = 648 # hot stuff!
orange_thing = 649 # slippy
aubergine = 650 # rear gear
carrot = 651 # angry monsters
rape = 652 # auto-fire
white_carrot = 653 # fly
chickpea = 654 # shield
mushroom = 655 # pinball mode
egg = 656 # players permutation
chestnut = 657 # variation of frames per second
green_thing = 658 # sugar bomb
icecream3 = 659 # \ each icecream becomes two of the
icecream4 = 660 # \ next kind, which scores more points
icecream5 = 661 # / that's a lot of points in total
icecream6 = 662 # /
softice1 = 663 # shoot farther
softice2 = 665 # shoot nearer1
french_fries = 664 # shoot 10 lightning bubbles
custard_pie = 666 # shoot faster
lollipop = 667 # invert left and right
cocktail = 668 # short-lived bubbles
ham = 669 # wall builder
bomb = 670 # explodes the structure of the level
beer = 671 # shoot 10 water bubbles
emerald = 672 # mega points
fish2 = 673 # mega blitz
sapphire = 681 # mega points
ruby = 682 # mega points
tin = 674 # angry (double-speed) player
hamburger = 675 # shoot 10 fire bubbles
insect = 676 # walls fall down
blue_necklace = 677 # player ubiquity
violet_necklace = 679 # monster ubiquity
butterfly = 678 # lunar gravity
conch = 680 # complete water flood
yellow_sugar = 630 # from a bonbon bomb
blue_sugar = 691 # from a bonbon bomb
class Diamonds:
# Produced from the bubbles after last enemy is killed and a chest or wand has been caught.
violet = 616
blue = 617
red = 618
yellow = 619
class Stars:
# Effect of the book. Kill monsters on contact.
blue = nrange(940,2)
yellow = nrange(942,2)
red = nrange(944,2)
green = nrange(946,2)
magenta = nrange(948,2)
cyan = nrange(950,2)
COLORS = ['blue', 'yellow', 'red', 'green', 'magenta', 'cyan']
class SpinningBalls:
free = nrange(482,4)
bubbled = nrange(486,2) # NOT_USED
class BigImages:
cyan_ice = 10 # Megabonus produced after a wand
violet_ice = 11
peach2 = 12
pastec2 = 13
cream_pie = 14
sugar_pie = 15
violet = 16
blue = 17
red = 18
yellow = 19
blitz = 30
hurryup = nrange(31,2)
class birange:
def __init__(self, a,b,n):
self.a = a
self.n = n
def __getitem__(self, pn):
return range(self.a + 1000*pn, self.a + 1000*pn + self.n)
class bidict:
def __init__(self, a,b):
self.a = a.items()
def __getitem__(self, pn):
pn *= 1000
d = {}
for key, value in self.a:
d[key] = value + pn
return d
class GreenAndBlue:
water_bubbles = birange(182,185,3)
fire_bubbles = birange(176,554,3)
light_bubbles = birange(179,557,3)
normal_bubbles = birange(188,195,3)
new_bubbles = birange(191,203,4)
players = birange(210,226,13)
jumping_players = birange(683,687,4)
new_players = birange(693,696,3)
numbers = birange(499,509,10) # FIXME: already seen below
comming = birange(693,696,3)
points = bidict({
100: 529,
150: 530,
200: 531,
250: 532,
300: 533,
350: 534,
500: 535,
550: 536,
600: 537,
650: 538,
700: 539,
750: 540,
800: 541,
850: 542,
900: 543,
950: 544,
1000: 545,
2000: 546,
3000: 547,
4000: 548,
5000: 549,
6000: 550,
7000: 551,
8000: 552,
9000: 553,
10000: 20,
20000: 21,
30000: 22,
40000: 23,
50000: 24,
60000: 25,
70000: 26,
},{
100: 561,
150: 562,
200: 563,
250: 564,
300: 565,
350: 566,
500: 567,
550: 568,
600: 569,
650: 570,
700: 571,
750: 572,
800: 573,
850: 574,
900: 575,
950: 576,
1000: 577,
2000: 578,
3000: 579,
4000: 580,
5000: 581,
6000: 582,
7000: 583,
8000: 584,
9000: 585,
10000: 90,
20000: 91,
30000: 92,
40000: 93,
50000: 94,
60000: 95,
70000: 96,
})
gameover = birange(497,498,1)
digits = birange(499,509,10)
fish = birange(700,707,7)
class Butterfly(Monster1):
right = [('butterfly', 'fly', n) for n in range(2)]
left = [Bonuses.insect, Bonuses.butterfly]
jailed = [('butterfly', 'jailed', n) for n in range(3)]
dead = [('butterfly', 'dead', n) for n in range(4)]
class Sheep(Monster1):
right = [('sheep', 1, n) for n in range(4)]
left = [('sheep',-1, n) for n in range(4)]
right_angry = right
left_angry = left

View File

@ -1,4 +1,4 @@
from __future__ import generators
import random
import gamesrv
import images
@ -780,7 +780,7 @@ class Blitzy(Monster):
self.no_shoot_before = BubPlayer.FrameCounter + 29
return 0
MonsterClasses = [c for c in globals().values()
MonsterClasses = [c for c in list(globals().values())
if type(c)==type(Monster) and issubclass(c, Monster)]
MonsterClasses.remove(Monster)

937
bubbob/monsters.py.bak Normal file
View File

@ -0,0 +1,937 @@
from __future__ import generators
import random
import gamesrv
import images
import boards
from boards import *
from images import ActiveSprite
from mnstrmap import GreenAndBlue, Bonuses, Ghost
from player import BubPlayer
import bonuses
class Monster(ActiveSprite):
touchable = 1
special_prob = 0.2
shootcls = None
vx = 2
vy = 0
vdir = -1
is_ghost = 0
MonsterBonus = bonuses.MonsterBonus
def __init__(self, mnstrdef, x=None, y=None, dir=None, in_list=None):
self.mdef = mnstrdef
self.ptag = None
if dir is None: dir = mnstrdef.dir
if x is None: x = mnstrdef.x*CELL
if y is None: y = mnstrdef.y*CELL
self.dir = dir
ActiveSprite.__init__(self, images.sprget(self.imgrange()[0]), x, y)
self.gen.append(self.waiting())
if in_list is None:
in_list = BubPlayer.MonsterList
self.in_list = in_list
self.in_list.append(self)
self.no_shoot_before = 0
#images.ActiveSprites.remove(self)
def unlist(self):
try:
self.in_list.remove(self)
return 1
except ValueError:
return 0
def kill(self):
self.unlist()
ActiveSprite.kill(self)
def tagdragon(self):
lst = bonuses.getvisibledragonlist()
if lst:
return random.choice(lst)
else:
return None
def imgrange(self):
if self.is_ghost:
if self.dir > 0:
return Ghost.right
else:
return Ghost.left
elif self.angry:
if self.dir > 0:
return self.mdef.right_angry
else:
return self.mdef.left_angry
else:
if self.dir > 0:
return self.mdef.right
else:
return self.mdef.left
def imgrange1(self):
# normally this is self.imgrange()[1]
lst = self.imgrange()
return lst[len(lst) > 1]
def resetimages(self, is_ghost=0):
self.is_ghost = is_ghost
if self.gen:
self.setimages(self.cyclic(self.imgrange(), 3))
else: # frozen monster
self.seticon(images.sprget(self.imgrange()[0]))
def blocked(self):
if self.dir < 0:
x0 = (self.x-1)//16
else:
x0 = (self.x+33)//16
y0 = self.y // 16 + 1
y1 = (self.y + 31) // 16
return bget(x0,y0) == '#' or bget(x0,y1) == '#'
def tryhstep(self):
if self.blocked():
self.dir = -self.dir
self.resetimages()
return 0
else:
self.step(self.vx*self.dir, 0)
return 1
def vblocked(self):
if self.vdir < 0:
y0 = self.y//16
else:
y0 = (self.y+1)//16 + 2
x0 = self.x // 16
x1 = self.x // 16 + 1
x2 = (self.x+31) // 16
return bget(x0,y0) == '#' or bget(x1,y0) == '#' or bget(x2,y0) == '#'
def tryvstep(self):
if self.vblocked():
self.vdir = -self.vdir
return 0
else:
self.step(0, self.vy*self.vdir)
self.vertical_warp()
return 1
def waiting(self, delay=20):
for i in range(delay):
yield None
self.resetimages()
self.gen.append(self.default_mode())
def overlapping(self):
if self.in_list is BubPlayer.MonsterList:
for s in self.in_list:
if (-6 <= s.x-self.x <= 6 and -6 <= s.y-self.y < 6 and
#s.dir == self.dir and s.vdir == self.vdir and
s.vx == self.vx and s.vy == self.vy and
(not s.angry) == (not self.angry)):
return s is not self
return 0
def walking(self):
while onground(self.x, self.y):
yield None
if random.random() < 0.2 and self.overlapping():
yield None
x1 = self.x
if self.dir > 0:
x1 += self.vx
if (x1 & 15) < self.vx and random.random() < self.special_prob:
self.move(x1 & -16, self.y)
if self.special():
return
self.tryhstep()
if self.seedragon():
self.gen.append(self.hjumping())
else:
self.gen.append(self.falling())
def seedragon(self, dragon=None):
dragon = dragon or self.tagdragon()
if dragon is None:
return False
return abs(dragon.y - self.y) < 16 and self.dir*(dragon.x-self.x) > 0
def special(self):
dragon = self.tagdragon()
if dragon is None:
return 0
if self.seedragon(dragon) and self.shoot():
return 1
if dragon.y < self.y-CELL:
#and abs(dragon.x-self.x) < 2*(self.y-dragon.y):
for testy in range(self.y-2*CELL, self.y-6*CELL, -CELL):
if onground(self.x, testy):
if random.random() < 0.5:
ndir = self.dir
elif dragon.x < self.x:
ndir = -1
else:
ndir = 1
self.gen.append(self.vjumping(testy, ndir))
return 1
return 0
def shooting(self, pause):
for i in range(pause):
yield None
self.shootcls(self)
yield None
self.gen.append(self.default_mode())
def shoot(self, pause=10):
if (self.shootcls is None or
self.no_shoot_before > BubPlayer.FrameCounter):
return 0
else:
self.gen.append(self.shooting(pause))
self.no_shoot_before = BubPlayer.FrameCounter + 29
return 1
def falling(self):
bubber = getattr(self, 'bubber', None)
while not onground(self.x, self.y):
yield None
ny = self.y + 3
if (ny & 15) > 14:
ny = (ny//16+1)*16
elif (ny & 15) < 3:
ny = (ny//16)*16
nx = self.x
if nx < 32:
nx += 1 + (self.vx-1) * (bubber is not None)
elif nx > boards.bwidth - 64:
nx -= 1 + (self.vx-1) * (bubber is not None)
elif bubber:
dx = bubber.wannago(self.dcap)
if dx and dx != self.dir:
self.dir = dx
self.resetimages()
self.setimages(None)
if dx and not self.blocked():
nx += self.vx*dx
self.seticon(images.sprget(self.imgrange1()))
self.move(nx, ny)
if self.y >= boards.bheight:
self.vertical_warp()
if bubber:
nextgen = self.playing_monster
else:
nextgen = self.walking
self.gen.append(nextgen())
## def moebius(self):
## self.dir = -self.dir
## self.resetimages()
## if hasattr(self, 'dcap'):
## self.dcap['left2right'] *= -1
def hjumping(self):
y0 = self.y
vspeed = -2.2
ny = y0-1
while ny <= y0 and not self.blocked():
self.move(self.x+2*self.dir, int(ny))
yield None
vspeed += 0.19
ny = self.y + vspeed
self.gen.append(self.default_mode())
def vjumping(self, limity, ndir):
self.setimages(None)
yield None
self.dir = -self.dir
self.seticon(images.sprget(self.imgrange()[0]))
for i in range(9):
yield None
self.dir = -self.dir
self.seticon(images.sprget(self.imgrange()[0]))
for i in range(4):
yield None
self.dir = ndir
self.seticon(images.sprget(self.imgrange1()))
for ny in range(self.y-4, limity-4, -4):
self.move(self.x, ny)
if ny < -32:
self.vertical_warp()
yield None
self.resetimages()
self.gen.append(self.default_mode())
def regular(self):
return self.still_playing() and self.touchable and not self.is_ghost
def still_playing(self):
return (self.in_list is BubPlayer.MonsterList and
self in self.in_list)
def touched(self, dragon):
if self.gen:
self.killdragon(dragon)
if self.is_ghost and not hasattr(self, 'bubber'):
self.gen = [self.default_mode()]
self.resetimages()
else:
self.argh(getattr(self, 'poplist', None)) # frozen monster
def killdragon(self, dragon):
dragon.die()
def in_bubble(self, bubble):
if not hasattr(self.mdef, 'jailed'):
return
self.untouchable()
self.angry = []
bubble.move(self.x, self.y)
if not hasattr(bubble, 'withmonster'):
bubble.to_front()
self.to_front()
img = self.mdef.jailed
self.gen = [self.bubbling(bubble)]
self.setimages(self.cyclic([img[1], img[2], img[1], img[0]], 4))
def bubbling(self, bubble):
counter = 0
while not hasattr(bubble, 'poplist'):
self.move(bubble.x, bubble.y)
yield None
counter += 1
if counter == 50 and hasattr(self, 'bubber'):
bubble.setimages(bubble.bubble_red())
if bubble.poplist is None:
self.touchable = 1
self.angry = [self.genangry()]
self.resetimages()
self.gen.append(self.default_mode())
else:
previous_len = len(BubPlayer.MonsterList)
self.argh(bubble.poplist)
dragon = bubble.poplist[0]
if dragon is not None:
if previous_len and not BubPlayer.MonsterList:
points = 990
else:
points = 90
dragon.bubber.givepoints(points)
def argh(self, poplist=None, onplace=0):
if self not in self.in_list:
return
if not poplist:
poplist = [None]
poplist.append(self)
level = len(poplist) - 2
bonuses.BonusMaker(self.x, self.y, self.mdef.dead, onplace=onplace,
outcome=(self.MonsterBonus, level))
self.kill()
def freeze(self, poplist):
# don't freeze monsters largely out of screen, or they'll never come in
if self.regular() and -self.ico.h < self.y < boards.bheight:
self.gen = []
self.poplist = poplist
def flying(self):
blocked = 0
while 1:
if random.random() < 0.2 and self.overlapping():
yield None
hstep = self.tryhstep()
vstep = self.tryvstep()
if hstep or vstep:
blocked = 0
elif blocked:
# blocked! go up or back to the play area
if self.x < 32:
self.step(self.vy, 0)
elif self.x > boards.bwidth - 64:
self.step(-self.vy, 0)
else:
self.step(0, -self.vy)
self.vertical_warp()
else:
blocked = 1
yield None
def becoming_monster(self, big=0, immed=0):
if big:
self.is_ghost = 1
self.seticon(images.sprget(self.imgrange()[0]))
images.Snd.Hell.play()
for i in range(5):
ico = self.ico
self.seticon(self.bubber.icons[11 + immed, self.dir])
yield None
yield None
self.seticon(ico)
yield None
yield None
self.resetimages(is_ghost=big)
self.gen.append(self.playing_monster())
def become_monster(self, bubber, saved_caps, big=0, immed=0):
self.timeoutgen = self.back_to_dragon()
self.default_mode = self.playing_monster
self.bubber = bubber
self.dcap = saved_caps
self.gen = [self.becoming_monster(big, immed)]
def back_to_dragon(self):
for t in range(259):
yield None
if bonuses.getdragonlist():
yield None
yield None
yield None
from player import Dragon
d = Dragon(self.bubber, self.x, self.y, self.dir, self.dcap)
d.dcap['shield'] = 50
self.bubber.dragons.append(d)
self.kill()
def playing_monster(self):
if self.timeoutgen not in self.gen:
self.gen.append(self.timeoutgen)
bubber = self.bubber
while self.is_ghost:
# ghost
self.angry = []
key, dx, dy = max([(bubber.key_left, -1, 0),
(bubber.key_right, 1, 0),
(bubber.key_jump, 0, -1),
(bubber.key_fire, 0, 1)])
if key:
if dx and self.dir != dx:
self.dir = dx
self.resetimages(is_ghost=1)
nx = self.x + 10*dx
ny = self.y + 9*dy
if nx < 0: nx = 0
if nx > boards.bwidth-2*CELL: nx = boards.bwidth-2*CELL
if ny < -CELL: ny = -CELL
if ny > boards.bheight-CELL: ny = boards.bheight-CELL
self.move(nx, ny)
yield None
if self.vy:
# flying monster
while 1:
dx = bubber.wannago(self.dcap)
if dx and dx != self.dir:
self.dir = dx
self.resetimages()
if bubber.key_jump and bubber.key_jump > bubber.key_fire:
dy = self.vdir = -1
elif bubber.key_fire:
dy = self.vdir = 1
else:
dy = 0
hstep = dx and self.tryhstep()
vstep = dy and self.tryvstep()
if dx and dy and not (hstep or vstep):
# blocked?
self.dir = -self.dir
self.vdir = -self.vdir
blocked = self.blocked() and self.vblocked()
self.dir = -self.dir
self.vdir = -self.vdir
if blocked:
# completely blocked! accept move or force back to
# play area
if self.x < 32:
self.step(self.vy, 0)
elif self.x > boards.bwidth - 64:
self.step(-self.vy, 0)
else:
self.step(self.vx*dx, self.vy*dy)
self.vertical_warp()
yield None
elif not isinstance(self, Springy):
# walking monster
jumping_y = 0
imgsetter = self.imgsetter
while onground(self.x, self.y) or jumping_y:
dx = bubber.wannago(self.dcap)
if dx and dx != self.dir:
self.dir = dx
self.resetimages()
imgsetter = self.imgsetter
if dx and not self.blocked():
self.step(self.vx*dx, 0)
if not jumping_y:
self.setimages(imgsetter)
else:
self.seticon(images.sprget(self.imgrange1()))
self.setimages(None)
else:
self.setimages(None)
dx = 0
yield None
if not jumping_y:
wannafire = bubber.key_fire
wannajump = bubber.key_jump
if wannafire and self.shoot(1):
return
if wannajump:
jumping_y = CELL
if jumping_y:
self.step(0, -4)
if self.y < -32:
self.vertical_warp()
if onground(self.x, self.y):
jumping_y = 0
else:
jumping_y -= 1
self.gen.append(self.falling())
else:
# springy
if not onground(self.x, self.y):
self.gen.append(self.falling())
return
prevx = self.x
for t in self.walking():
dx = bubber.wannago(self.dcap)
if dx:
if dx != self.dir:
self.dir = dx
self.resetimages()
if self.blocked() and (self.x-prevx)*dx <= 0:
dx = 0
self.move(prevx + self.vx*dx, self.y)
yield None
prevx = self.x
def become_ghost(self):
self.gen = [self.ghosting()]
self.resetimages(is_ghost=1)
def ghosting(self):
counter = 0
while counter < 5:
for i in range(50):
yield None
dragon = self.tagdragon()
if dragon is None:
counter += 1
else:
counter = 0
px, py = dragon.x, dragon.y
if abs(px-self.x) < abs(py-self.y):
dx = 0
if py > self.y:
dy = 1
else:
dy = -1
else:
dy = 0
if px > self.x:
dx = 1
else:
dx = -1
self.dir = dx
self.resetimages(is_ghost=1)
dx *= 10
dy *= 9
distance = 1E10
while 1:
self.angry = []
self.step(dx, dy)
yield None
dist1 = (px-self.x)*(px-self.x)+(py-self.y)*(py-self.y)
if dist1 > distance:
break
distance = dist1
self.angry = []
self.gen = [self.default_mode()]
self.resetimages()
default_mode = falling
def argh_em_all():
poplist = [None]
for s in images.ActiveSprites[:]:
if isinstance(s, Monster):
s.argh(poplist)
def freeze_em_all():
poplist = [None]
for s in images.ActiveSprites:
if isinstance(s, Monster):
s.freeze(poplist)
class MonsterShot(ActiveSprite):
speed = 6
touchable = 1
def __init__(self, owner, dx=CELL, dy=0):
self.owner = owner
self.speed = owner.dir * self.speed
if owner.dir < 0:
nimages = owner.mdef.left_weapon
else:
nimages = owner.mdef.right_weapon
ActiveSprite.__init__(self, images.sprget(nimages[0]),
owner.x, owner.y + dy)
self.step((owner.ico.w - self.ico.w) // 2,
(owner.ico.h - self.ico.h) // 2)
if not self.blocked():
self.step(dx*owner.dir, 0)
if len(nimages) > 1:
self.setimages(self.cyclic(nimages, 3))
self.gen.append(self.moving())
def blocked(self):
if self.speed < 0:
x0 = (self.x-self.speed-8)//16
else:
x0 = (self.x+self.ico.w+self.speed-8)//16
y0 = (self.y+8) // 16 + 1
return not (' ' == bget(x0,y0) == bget(x0+1,y0))
def moving(self):
while not self.blocked():
yield None
self.step(self.speed, 0)
self.hitwall()
def hitwall(self):
self.untouchable()
self.gen.append(self.die(self.owner.mdef.decay_weapon, 2))
def touched(self, dragon):
dragon.die()
class BoomerangShot(MonsterShot):
speed = 8
def hitwall(self):
self.gen.append(self.moveback())
def moveback(self):
owner = self.owner
if self.speed > 0:
nimages = owner.mdef.left_weapon
else:
nimages = owner.mdef.right_weapon
self.setimages(self.cyclic(nimages, 3))
while (owner.x-self.x) * self.speed < 0:
yield None
self.step(-self.speed, 0)
if self.blocked():
break
self.kill()
class FastShot(MonsterShot):
speed = 15
class DownShot(MonsterShot):
def __init__(self, owner):
MonsterShot.__init__(self, owner, 0, CELL)
def moving(self):
while self.y < boards.bheight:
yield None
self.step(0, 7)
self.kill()
##class DragonShot(MonsterShot):
## speed = 8
## def __init__(self, owner):
## MonsterShot.__init__(self, owner)
## self.untouchable()
## self.gen.append(self.touchdelay(4))
## def touched(self, dragon):
## if dragon is not self.owner:
## if dragon.bubber.bonbons == 0:
## dragon.die()
## else:
## from player import scoreboard
## from bonuses import Sugar1, Sugar2
## from bonuses import BonusMaker
## if random.random() < 0.2345:
## start = 1
## else:
## start = 0
## loose = min(2, dragon.bubber.bonbons)
## for i in range(start, loose):
## cls = random.choice([Sugar1, Sugar2])
## BonusMaker(self.x, self.y, [cls.nimage],
## outcome=(cls,))
## dragon.bubber.bonbons -= loose
## scoreboard()
## dragon.dcap['shield'] = 25
## self.owner.play(images.Snd.Yippee)
## self.kill()
## def blocked(self):
## return self.x < -self.ico.w or self.x >= gamesrv.game.width
## #return self.x < CELL or self.x >= boards.bwidth - 3*CELL
class Nasty(Monster):
pass
class Monky(Monster):
shootcls = MonsterShot
class Ghosty(Monster):
default_mode = Monster.flying
vy = 2
class Flappy(Monster):
default_mode = Monster.flying
vy = 1
class Springy(Monster):
spring_down = 0
def imgrange(self):
if self.spring_down and not self.is_ghost:
if self.angry:
if self.dir > 0:
r = self.mdef.right_jump_angry
else:
r = self.mdef.left_jump_angry
else:
if self.dir > 0:
r = self.mdef.right_jump
else:
r = self.mdef.left_jump
return [r[self.spring_down-1]]
else:
return Monster.imgrange(self)
def walking(self):
self.spring_down = 1
self.resetimages()
for t in range(2+self.overlapping()):
yield None
self.spring_down = 2
self.resetimages()
for t in range(4+2*self.overlapping()):
yield None
self.spring_down = 1
self.resetimages()
for t in range(2+self.overlapping()):
yield None
self.spring_down = 0
self.resetimages()
g = 10.0/43
vy = -20*g
yf = self.y
for t in range(40):
yf += vy
vy += g
if self.blocked():
self.dir = -self.dir
self.resetimages()
nx = self.x + self.dir*self.vx
if self.y//16 < int(yf)//16:
if onground(self.x, (self.y//16+1)*16):
break
if onground(nx, (self.y//16+1)*16):
self.move(nx, self.y)
break
nx, yf = vertical_warp(nx, yf)
self.move(nx, int(yf))
## if moebius:
## self.moebius()
yield None
self.gen.append(self.falling())
class Orcy(Monster):
shootcls = FastShot
class Gramy(Monster):
shootcls = BoomerangShot
vx = 3
class Blitzy(Monster):
shootcls = DownShot
vx = 3
def seedragon(self, dragon=None):
return 0
def special(self):
if random.random() < 0.3:
self.shootcls(self)
return 0
def shoot(self, pause=0):
# no pause (only used when controlled by the player)
if self.no_shoot_before > BubPlayer.FrameCounter:
pass
else:
self.shootcls(self)
self.no_shoot_before = BubPlayer.FrameCounter + 29
return 0
MonsterClasses = [c for c in globals().values()
if type(c)==type(Monster) and issubclass(c, Monster)]
MonsterClasses.remove(Monster)
class Butterfly(Monster):
MonsterBonus = bonuses.IceMonsterBonus
fly_away = False
def waiting(self, delay=0):
return Monster.waiting(self, delay)
def imgrange(self):
self.angry = []
return Monster.imgrange(self)
def killdragon(self, dragon):
if self.is_ghost:
Monster.killdragon(self, dragon)
else:
self.fly_away = True, dragon.x
def flying(self):
repeat = 0
while 1:
r = random.random()
if self.x < 64:
bump = self.dir < 0
elif self.x > boards.bwidth - 64:
bump = self.dir > 0
elif self.fly_away:
wannago = self.x - self.fly_away[1]
if self.x < 100:
wannago = 1
elif self.x > boards.bwidth - 100:
wannago = -1
bump = self.dir * wannago < 0
if repeat:
self.fly_away = False
repeat = 0
else:
repeat = 1
else:
bump = r < 0.07
if bump:
self.dir = -self.dir
self.resetimages()
elif r > 0.92:
self.vdir = -self.vdir
self.step(self.dir * (2 + (r < 0.5)), self.vdir * 2)
self.vertical_warp()
if not repeat:
yield None
default_mode = flying
class Sheep(Monster):
def playing_monster(self):
from bonuses import Bonus
bubber = self.bubber
vy = None
imgsetter = self.imgsetter
poplist = [None]
while 1:
dx = bubber.wannago(self.dcap)
if dx and dx != self.dir:
self.dir = dx
self.resetimages()
imgsetter = self.imgsetter
if dx and vy is None:
self.setimages(imgsetter)
else:
self.setimages(None)
if vy is not None:
if vy < 0:
n = 1
else:
n = 3
self.seticon(images.sprget(self.imgrange()[n]))
if dx and not self.blocked():
self.step(self.vx*dx, 0)
yield None
impulse = 0.0
wannajump = bubber.key_jump
if vy is not None:
vy += 0.33
if vy > 12.0:
vy = 12.0
yf = self.y + yfp + vy
yfp = yf - int(yf)
delta = int(yf) - self.y
if delta > 0:
by_y = {}
for s in images.ActiveSprites:
if isinstance(s, Bonus) and s.touchable:
if abs(s.x - self.x) <= 22:
by_y[s.y] = s
for monster in BubPlayer.MonsterList:
if abs(monster.x - self.x) <= 22:
if monster.regular():
by_y[monster.y] = monster
for ny in range(self.y - 1, self.y + delta + 1):
self.move(self.x, ny)
self.vertical_warp()
if onground(self.x, self.y):
poplist = [None]
impulse = vy
vy = None
break
key = self.y + 29
if key in by_y:
s = by_y[key]
if isinstance(s, Monster):
self.play(images.Snd.Extra)
s.argh(poplist)
elif isinstance(s, Bonus):
s.reallytouched(self)
yfp = 0.0
vy = -3.3
break
else:
self.step(0, delta)
self.vertical_warp()
if vy is None:
if onground(self.x, self.y):
if wannajump:
yfp = 0.0
vy = - max(1.0, impulse) - 2.02
impulse = 0.0
self.play(images.Snd.Jump)
else:
yfp = vy = 0.0
if impulse > 8.1:
break
self.play(images.Snd.Pop)
for n in range(2):
for letter in 'abcdefg':
ico = images.sprget(('sheep', letter))
nx = self.x + random.randrange(-1, self.ico.w - ico.w + 2)
ny = self.y + random.randrange(0, self.ico.h - ico.h + 2)
dxy = [random.random() * 5.3 - 2.65, random.random() * 4 - 4.4]
s = images.ActiveSprite(ico, nx, ny)
s.gen.append(s.parabolic(dxy))
s.gen.append(s.die([None], random.randrange(35, 54)))
self.move(-99, 0)
for t in range(68):
yield None
self.kill()
default_mode = falling = playing_monster
def argh(self, *args, **kwds):
pass

View File

@ -1,4 +1,4 @@
from __future__ import generators
import random, math, time
import gamesrv
import images
@ -123,7 +123,7 @@ class Dragon(ActiveSprite):
outcome=bonus.buildoutcome())
elif self.bubber.letters and random.random() > 0.59 and can_loose_letter:
# loose a letter
lst = range(6)
lst = list(range(6))
random.shuffle(lst)
for l in lst:
lettername = bubbles.extend_name(l)
@ -758,7 +758,7 @@ class BubPlayer(gamesrv.Player):
icons = self.transformedicons[flip]
if flip == 'fish':
for dir in (-1, 1):
for key, value in self.FISH_MODE_MAP.items():
for key, value in list(self.FISH_MODE_MAP.items()):
if value == 'black':
flip = ''
else:
@ -768,7 +768,7 @@ class BubPlayer(gamesrv.Player):
flip = flip or 'hflip'
icons[key, dir] = images.sprget((flip, value))
else:
for key, value in self.iconnames.items():
for key, value in list(self.iconnames.items()):
icons[key] = images.sprget((flip, value))
def setplayername(self, name):
@ -793,9 +793,9 @@ class BubPlayer(gamesrv.Player):
self.loadicons(flip='')
self.keepalive = None
if self.points or self.letters:
print 'New player continues at position #%d.' % n
print('New player continues at position #%d.' % n)
else:
print 'New player is at position #%d.' % n
print('New player is at position #%d.' % n)
self.reset()
self.key_left = 0
self.key_right = 0
@ -810,7 +810,7 @@ class BubPlayer(gamesrv.Player):
#BubPlayer.LatestLetsGo = BubPlayer.FrameCounter
def playerleaves(self):
print 'Closing position #%d.' % self.pn
print('Closing position #%d.' % self.pn)
self.savecaps()
self.zarkoff()
self.keepalive = time.time() + KEEPALIVE
@ -831,7 +831,7 @@ class BubPlayer(gamesrv.Player):
self.pcap = {}
dragons = self.dragons
if dragons:
for key, minimum in Dragon.SAVE_CAP.items():
for key, minimum in list(Dragon.SAVE_CAP.items()):
self.pcap[key] = max(minimum,
max([d.dcap[key] for d in dragons]))
@ -874,7 +874,7 @@ class BubPlayer(gamesrv.Player):
else:
break
self.dragons.append(Dragon(self, x, y, dir))
for key in self.pcap.keys():
for key in list(self.pcap.keys()):
if key not in ('teleport', 'jumpdown'):
del self.pcap[key]
@ -1022,7 +1022,7 @@ def scoreboard(reset=0, inplace=0, compresslimittime=0):
if reset:
for p in BubPlayer.PlayerList:
if inplace:
for s in p.letters.values():
for s in list(p.letters.values()):
if isinstance(s, ActiveSprite):
s.kill()
if len(p.letters) == 6:
@ -1155,7 +1155,7 @@ def scoreboard(reset=0, inplace=0, compresslimittime=0):
lst.append((x0+9*CELL-ico.w, y0-ico.h+16, ico))
y0 -= 5*HALFCELL
for p in BubPlayer.PlayerList:
for name, s in p.letters.items():
for name, s in list(p.letters.items()):
if isinstance(s, ActiveSprite) and s not in bubblesshown:
p.letters[name] = 2
s.kill()
@ -1208,6 +1208,6 @@ def scoreboard(reset=0, inplace=0, compresslimittime=0):
# initialize global board data
def reset_global_board_state():
for key, value in BubPlayer.INIT_BOARD_CAP.items():
for key, value in list(BubPlayer.INIT_BOARD_CAP.items()):
setattr(BubPlayer, key, value)
reset_global_board_state()

1213
bubbob/player.py.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
from __future__ import generators
import random
import boards, images, gamesrv
from boards import CELL, HALFCELL
@ -168,7 +168,7 @@ def display(lines, timeleft, bgen=None, black=0):
t = boards.normal_frame()
else:
try:
t = bgen.next()
t = next(bgen)
except StopIteration:
timeleft = 0.0
break
@ -180,13 +180,13 @@ def display(lines, timeleft, bgen=None, black=0):
def ranking_picture(results, maximum, givepoints):
if maximum is None:
maximum = 0
for n in results.values():
for n in list(results.values()):
maximum += n
maximum = maximum or 1
ranking = []
teamrank = [0, 0]
teamplayers = [[], []]
for p, n in results.items():
for p, n in list(results.items()):
if p.team != -1:
teamrank[p.team] += n
teamplayers[p.team].append((n,p))
@ -205,7 +205,7 @@ def ranking_picture(results, maximum, givepoints):
nbpoints = givepoints and ((len(ranking)+1)//2)*10000
lines = []
for (n, dummy, bubber), i in zip(ranking, range(len(ranking))):
for (n, dummy, bubber), i in zip(ranking, list(range(len(ranking)))):
pic = RPicture()
if isinstance(bubber, list):
fraction = (nbpoints//(10*len(bubber))) * 10
@ -253,7 +253,7 @@ def screen_monster():
pairs = []
for p in BubPlayer.PlayerList:
catch = p.stats.get('monster', {})
for p2, count in catch.items():
for p2, count in list(catch.items()):
if count:
pairs.append((count, p, p2))
random.shuffle(pairs)
@ -277,7 +277,7 @@ def screen_catch():
pairs = []
for p in BubPlayer.PlayerList:
catch = p.stats.get('catch', {})
for p2, count in catch.items():
for p2, count in list(catch.items()):
if count:
pairs.append((count, p, p2))
random.shuffle(pairs)
@ -301,7 +301,7 @@ def screen_bonus():
pairs = []
for p in BubPlayer.PlayerList:
catch = p.stats.get('bonus', {})
for p2, count in catch.items():
for p2, count in list(catch.items()):
if count > 1:
pairs.append((count, p, p2))
random.shuffle(pairs)

391
bubbob/ranking.py.bak Normal file
View File

@ -0,0 +1,391 @@
from __future__ import generators
import random
import boards, images, gamesrv
from boards import CELL, HALFCELL
from mnstrmap import DigitsMisc, Flood, GreenAndBlue
from bubbles import Bubble
from bonuses import Points
from player import BubPlayer
MARGIN = 22
VMARGIN = 12
class RPicture:
def __init__(self):
self.icons = []
def put(self, ico, dx=0, dy=0):
self.icons.append((dx, dy, ico))
def getsize(self):
if self.icons:
return (max([dx+ico.w for dx, dy, ico in self.icons]) + MARGIN,
max([dy+ico.h for dx, dy, ico in self.icons]))
else:
return 0, 0
def render(self, x, y):
return [gamesrv.Sprite(ico, x+dx, y+dy) for dx, dy, ico in self.icons]
class RPoints:
def __init__(self, bubber, nbpoints):
self.bubber = bubber
self.nbpoints = nbpoints
def getsize(self):
return 0, 0
def render(self, x, y):
Points(x, y, self.bubber.pn, self.nbpoints)
return []
class RNumber(RPicture):
map = {'%': 'percent'}
for digit in range(10):
map[str(digit)] = DigitsMisc.digits_white[digit]
def __init__(self, text):
RPicture.__init__(self)
x = 0
for c in text:
ico = images.sprget(self.map[c])
self.put(ico, dx=x)
x += ico.w+1
class RText(RPicture):
def __init__(self, text, margin=VMARGIN):
RPicture.__init__(self)
x = 0
for c in text:
ico = images.sprcharacterget(c)
if ico is not None:
self.put(ico, dx=x)
x += 7
self.margin = margin
def getsize(self):
w, h = RPicture.getsize(self)
h -= (VMARGIN-self.margin)
return w, h
def linesize(line):
width = MARGIN
height = 0
for item in line:
w, h = item.getsize()
width += w
if h > height:
height = h
return width, height
def display(lines, timeleft, bgen=None, black=0):
waves = []
if lines:
totalwidth = 0
totalheight = 0
for line in lines:
w, h = linesize(line)
if w > totalwidth:
totalwidth = w
totalheight += h
heightmargin = (boards.bheight-2*CELL - totalheight) // (len(lines)+1)
if heightmargin > VMARGIN:
heightmargin = VMARGIN
totalheight += heightmargin * (len(lines)+1)
# size in number of CELLs
cwidth = (totalwidth+CELL-1) // CELL
cheight = (totalheight+CELL-1) // CELL
x0 = ((boards.width - cwidth) // 2) * CELL + HALFCELL
y0 = ((boards.height - cheight) // 2) * CELL + HALFCELL
extras = boards.curboard.sprites.setdefault('ranking', [])
#while extras:
# extras.pop().kill()
# yield 0.12
vspeed = -4
while extras:
nextras = []
for s in extras:
s.step(0, vspeed)
if s.y + s.ico.h <= 0:
s.kill()
else:
nextras.append(s)
extras[:] = nextras
yield 1
vspeed -= 1
# draw the box filled with water
original_y0 = y0
wallicon = boards.patget((boards.curboard.num, 0, 0), images.KEYCOL)
if black:
fillicon = images.sprget('gameoverbkgnd')
waveicons = [wallicon]
y0 = boards.bheight+CELL
else:
fillicon = images.sprget(Flood.fill)
waveicons = [images.sprget(n) for n in Flood.waves]
for y in range(y0-CELL, y0+cheight*CELL+CELL, CELL):
w = gamesrv.Sprite(wallicon, x0-CELL, y)
extras.append(w)
for x in range(x0, x0+cwidth*CELL, CELL):
w = gamesrv.Sprite(wallicon, x, y0+cheight*CELL)
extras.append(w)
w = gamesrv.Sprite(waveicons[-1], x, y0-CELL)
extras.append(w)
waves.append(w)
for y in range(y0, y0+cheight*CELL, CELL):
w = gamesrv.Sprite(fillicon, x, y)
extras.append(w)
for y in range(y0-CELL, y0+cheight*CELL+CELL, CELL):
w = gamesrv.Sprite(wallicon, x0+cwidth*CELL, y)
extras.append(w)
# draw the individual items inside
y = y0 + totalheight
lines.reverse()
for line in lines:
linew, lineh = linesize(line)
x = x0 + MARGIN
y -= (lineh + heightmargin)
for item in line:
w, h = item.getsize()
extras += item.render(x, y+(lineh-h)//2)
x += w
vspeed = 0
while y0 > original_y0:
vspeed = max(vspeed-1, original_y0 - y0)
y0 += vspeed
for s in extras:
s.step(0, vspeed)
yield 1
while timeleft > 0.0:
if waves:
ico = waveicons.pop(0)
waveicons.append(ico)
for w in waves:
w.seticon(ico)
for i in range(2):
if bgen is None:
t = boards.normal_frame()
else:
try:
t = bgen.next()
except StopIteration:
timeleft = 0.0
break
timeleft -= t
yield t
# ____________________________________________________________
def ranking_picture(results, maximum, givepoints):
if maximum is None:
maximum = 0
for n in results.values():
maximum += n
maximum = maximum or 1
ranking = []
teamrank = [0, 0]
teamplayers = [[], []]
for p, n in results.items():
if p.team != -1:
teamrank[p.team] += n
teamplayers[p.team].append((n,p))
else:
ranking.append((n, random.random(), p))
teamplayers[0].sort()
teamplayers[0].reverse()
teamplayers[1].sort()
teamplayers[1].reverse()
if teamplayers[0] != []:
ranking.append((teamrank[0], random.random(), teamplayers[0]))
if teamplayers[1] != []:
ranking.append((teamrank[1], random.random(), teamplayers[1]))
ranking.sort()
ranking.reverse()
nbpoints = givepoints and ((len(ranking)+1)//2)*10000
lines = []
for (n, dummy, bubber), i in zip(ranking, range(len(ranking))):
pic = RPicture()
if isinstance(bubber, list):
fraction = (nbpoints//(10*len(bubber))) * 10
total = fraction * len(bubber)
for n, bub in bubber:
bub.givepoints(fraction)
bubber = bubber[0][1]
pic.put(images.sprget(('hat', bubber.team)))
else:
if len(ranking) == 1:
icon = 0
elif i == 0:
icon = 10
elif i == len(ranking) - 1:
icon = 9
else:
icon = 0
pic.put(bubber.icons[icon, +1])
total = 0
line = []
if nbpoints > 0:
line.append(RPoints(bubber, nbpoints))
bubber.givepoints(nbpoints - total)
nbpoints -= 10000
line.append(pic)
line.append(RNumber(str(int(n*100.00001/maximum)) + '%'))
lines.append(line)
return lines
def just_wait():
while 1:
yield 2
def screen_scores():
results = {}
for p in BubPlayer.PlayerList:
if p.points:
results[p] = p.points
lines = ranking_picture(results, None, 0)
lines.insert(0, [RText(" THE END")])
return lines
def screen_monster():
pairs = []
for p in BubPlayer.PlayerList:
catch = p.stats.get('monster', {})
for p2, count in catch.items():
if count:
pairs.append((count, p, p2))
random.shuffle(pairs)
pairs.sort()
pairs.reverse()
del pairs[5:]
lines = []
if pairs:
lines.append([RText('Best Monster Bubblers')])
for count, p, p2 in pairs:
pic = RPicture()
pic.put(p.icons[4,+1], 0, 6)
pic.put(images.sprget(GreenAndBlue.new_bubbles[p.pn][1]), 31, 6)
pic.put(images.sprget(GreenAndBlue.new_bubbles[p.pn][3]), 69, 6)
pic.put(images.sprget(GreenAndBlue.normal_bubbles[p.pn][0]), 101)
pic.put(images.sprget(p2), 101)
lines.append([pic, RNumber(str(count))])
return lines
def screen_catch():
pairs = []
for p in BubPlayer.PlayerList:
catch = p.stats.get('catch', {})
for p2, count in catch.items():
if count:
pairs.append((count, p, p2))
random.shuffle(pairs)
pairs.sort()
pairs.reverse()
del pairs[5:]
lines = []
if pairs:
lines.append([RText('Best Dragon Bubblers')])
for count, p, p2 in pairs:
pic = RPicture()
pic.put(p.icons[4,+1], 0, 6)
pic.put(images.sprget(GreenAndBlue.new_bubbles[p.pn][1]), 31, 6)
pic.put(images.sprget(GreenAndBlue.new_bubbles[p.pn][3]), 69, 6)
pic.put(images.sprget(GreenAndBlue.normal_bubbles[p2.pn][0]), 101)
pic.put(images.sprget(('eyes', 0,0)), 101)
lines.append([pic, RNumber(str(count))])
return lines
def screen_bonus():
pairs = []
for p in BubPlayer.PlayerList:
catch = p.stats.get('bonus', {})
for p2, count in catch.items():
if count > 1:
pairs.append((count, p, p2))
random.shuffle(pairs)
pairs.sort()
pairs.reverse()
seen = {}
npairs = []
for count, p, p2 in pairs:
if p2 not in seen:
npairs.append((count, p, p2))
seen[p2] = 1
pairs = npairs
del pairs[5:]
lines = []
if pairs:
lines.append([RText('Best Bonus Catchers')])
for count, p, p2 in pairs:
pic = RPicture()
pic.put(p.icons[1,+1], 0)
pic.put(images.sprget(p2), 44)
lines.append([pic, RNumber(str(count))])
return lines
def screen_bubble():
pairs = []
for p in BubPlayer.PlayerList:
count = p.stats['bubble']
if count:
pairs.append((count, p))
random.shuffle(pairs)
pairs.sort()
pairs.reverse()
del pairs[5:]
lines = []
if pairs:
lines.append([RText('Best Bubble Exploders')])
for count, p in pairs:
pic = RPicture()
pic.put(p.icons[1,+1], 0)
pic.put(images.sprget(Bubble.exploding_bubbles[1]), 27)
lines.append([pic, RNumber(str(count))])
return lines
def screen_die():
pairs = []
for p in BubPlayer.PlayerList:
count = p.stats['die']
if count:
pairs.append((count, p))
random.shuffle(pairs)
pairs.sort()
pairs.reverse()
del pairs[5:]
lines = []
if pairs:
lines.append([RText('Top Deaths')])
n = 0
for count, p in pairs:
pic = RPicture()
pic.put(p.icons[6+(n%3),+1], 0)
lines.append([pic, RNumber(str(count))])
n += 1
return lines
def screen_authors():
return [
[RText('programming', 6)],
[RText(' Armin & Odie')],
[RText('art', 6)],
[RText(' David Gowers, based on McSebi')],
[RText('levels', 6)],
[RText(' Gio & Odie & MS & Armin')],
[RText('special thanks', 6)],
[RText(' Odie & Brachamutanda')],
[RText('beta-testers', 6)],
[RText(' IMA Connection')],
]
def game_over():
while 1:
for screen in [screen_scores, screen_monster, screen_catch,
screen_bonus, screen_bubble, screen_die,
screen_authors]:
lines = screen()
if lines:
for t in display(lines, 300, just_wait(), 1):
yield t

View File

@ -22,7 +22,7 @@ while idx < len(sys.argv):
if arg == '-seed':
arg = sys.argv[idx]
idx += 1
print "# Using seed: " + arg + "\n"
print("# Using seed: " + arg + "\n")
random.seed(arg)
def printlvl(level):
@ -41,7 +41,7 @@ def printlvl(level):
else:
dir = 'R'
s = dir + m.cls.__name__
if tmpmons.has_key(s):
if s in tmpmons:
tmpmons[s].append(wm)
else:
tmpmons[s] = [wm]
@ -61,7 +61,7 @@ def printlvl(level):
for x in range(0,level.WIDTH):
wm = level.wmap[y][x]
if wm >= 'a':
if monconv.has_key(wm):
if wm in monconv:
walls += monconv[wm]
else:
walls += '?'
@ -84,42 +84,42 @@ def printlvl(level):
winds += "\n"
for m in mons:
print " " + m + " = " + mons[m]
print(" " + m + " = " + mons[m])
if level.letter:
print " letter = 1"
print(" letter = 1")
if level.fire:
print " fire = 1"
print(" fire = 1")
if level.lightning:
print " lightning = 1"
print(" lightning = 1")
if level.water:
print " water = 1"
print(" water = 1")
if level.top:
print " top = 1"
print(" top = 1")
print " walls = \"\"\"\n" + walls + "\"\"\""
print " winds = \"\"\"\n" + winds + "\"\"\""
print(" walls = \"\"\"\n" + walls + "\"\"\"")
print(" winds = \"\"\"\n" + winds + "\"\"\"")
for i in range(n_lvls):
print """
print("""
import boarddef, mnstrmap, random
from boarddef import LNasty, LMonky, LGhosty, LFlappy
from boarddef import LSpringy, LOrcy, LGramy, LBlitzy
from boarddef import RNasty, RMonky, RGhosty, RFlappy
from boarddef import RSpringy, ROrcy, RGramy, RBlitzy
"""
""")
d = {'__name__': 'RandomLevels'}
execfile('levels/RandomLevels.py', d)
exec(compile(open('levels/RandomLevels.py', "rb").read(), 'levels/RandomLevels.py', 'exec'), d)
for i, Lvl in enumerate(d['GenerateLevels']()):
level = Lvl(i)
if level.monsters:
print "\n\nclass level%02d(boarddef.Level):" % (i+1)
print("\n\nclass level%02d(boarddef.Level):" % (i+1))
else:
print "\n\nclass levelFinal(boarddef.Level):"
print("\n\nclass levelFinal(boarddef.Level):")
printlvl(level)
print
print()

125
bubbob/save_rnglevel.py.bak Normal file
View File

@ -0,0 +1,125 @@
#
# This script outputs the random levels in a format you can
# save into a file in the levels-directory and bub'n'bros
# will be able to use it.
#
# this accepts the following parameters:
# -seed N use random seed N for the generation
#
import sys
import random
import string
sys.path.append('..')
sys.path.append('../common')
n_lvls = 1
idx = 0
while idx < len(sys.argv):
arg = sys.argv[idx]
idx += 1
if arg == '-seed':
arg = sys.argv[idx]
idx += 1
print "# Using seed: " + arg + "\n"
random.seed(arg)
def printlvl(level):
mons = {}
monconv = {}
tmpmons = {}
# Populate monster tables
for y in range(0,level.HEIGHT):
for x in range(0,level.WIDTH):
wm = level.wmap[y][x]
if wm >= 'a':
m = getattr(level, wm)
if m.dir == 1:
dir = 'L'
else:
dir = 'R'
s = dir + m.cls.__name__
if tmpmons.has_key(s):
tmpmons[s].append(wm)
else:
tmpmons[s] = [wm]
# Build monster character conversion tables
lettr = 'a'
for m in tmpmons:
for n in tmpmons[m]:
monconv[n] = lettr
mons[lettr] = m
lettr = chr(ord(lettr) + 1)
# Build walls, replacing monsters from mons[]
walls = ""
for y in range(0,level.HEIGHT-1):
walls += "##"
for x in range(0,level.WIDTH):
wm = level.wmap[y][x]
if wm >= 'a':
if monconv.has_key(wm):
walls += monconv[wm]
else:
walls += '?'
else:
walls += wm
walls += "##\n"
walls += "##"
for x in range(0,level.WIDTH):
if level.wmap[0][x] == '#' or level.wmap[level.HEIGHT-1][x] == '#':
walls += "#"
else:
walls += " "
walls += "##\n"
# Build winds
winds = ""
for y in range(0,level.HEIGHT):
for x in range(0,level.WIDTH+4):
winds += level.winds[y][x]
winds += "\n"
for m in mons:
print " " + m + " = " + mons[m]
if level.letter:
print " letter = 1"
if level.fire:
print " fire = 1"
if level.lightning:
print " lightning = 1"
if level.water:
print " water = 1"
if level.top:
print " top = 1"
print " walls = \"\"\"\n" + walls + "\"\"\""
print " winds = \"\"\"\n" + winds + "\"\"\""
for i in range(n_lvls):
print """
import boarddef, mnstrmap, random
from boarddef import LNasty, LMonky, LGhosty, LFlappy
from boarddef import LSpringy, LOrcy, LGramy, LBlitzy
from boarddef import RNasty, RMonky, RGhosty, RFlappy
from boarddef import RSpringy, ROrcy, RGramy, RBlitzy
"""
d = {'__name__': 'RandomLevels'}
execfile('levels/RandomLevels.py', d)
for i, Lvl in enumerate(d['GenerateLevels']()):
level = Lvl(i)
if level.monsters:
print "\n\nclass level%02d(boarddef.Level):" % (i+1)
else:
print "\n\nclass levelFinal(boarddef.Level):"
printlvl(level)
print

View File

@ -27,7 +27,7 @@ def copy_custom_instance(x, memo):
except KeyError:
y = x.inst_build()
memo[id(x)] = y
for key, value in x.__dict__.items():
for key, value in list(x.__dict__.items()):
y.__dict__[key] = copyrec(value, memo)
return y
@ -50,25 +50,25 @@ def copy_dict(x, memo):
except KeyError:
y = {}
memo[id(x)] = y
for key, value in x.items():
for key, value in list(x.items()):
y[copyrec(key, memo)] = copyrec(value, memo)
return y
def copy_function(x, memo):
if not x.func_defaults:
if not x.__defaults__:
return x # not copied
try:
return memo[id(x)]
except KeyError:
y = types.FunctionType(x.func_code, x.func_globals, x.func_name)
y = types.FunctionType(x.__code__, x.__globals__, x.__name__)
memo[id(x)] = y
y.func_defaults = copyrec(x.func_defaults, memo)
y.__defaults__ = copyrec(x.__defaults__, memo)
return y
def copy_method(x, memo):
return types.MethodType(copyrec(x.im_func, memo),
copyrec(x.im_self, memo),
x.im_class)
return types.MethodType(copyrec(x.__func__, memo),
copyrec(x.__self__, memo),
x.__self__.__class__)
def copy_generator(x, memo):
try:

135
bubbob/statesaver.py.bak Normal file
View File

@ -0,0 +1,135 @@
"""
A pure Python implementation of statesaver.c that runs on top of PyPy.
See description in statesaver.c.
Difference: this supports new-style instances too.
Use statesaver.standard_build() as the inst_build() if you want.
"""
from _pickle_support import generator_new
import types
def standard_build(self):
if type(self) is types.InstanceType:
# old-style instance
return types.InstanceType(self.__class__)
else:
# new-style instance
return type(self).__new__(type(self))
# ____________________________________________________________
def not_copied(x, memo):
return x
def copy_custom_instance(x, memo):
try:
return memo[id(x)]
except KeyError:
y = x.inst_build()
memo[id(x)] = y
for key, value in x.__dict__.items():
y.__dict__[key] = copyrec(value, memo)
return y
def copy_tuple(x, memo):
return tuple([copyrec(item, memo) for item in x])
def copy_list(x, memo):
try:
return memo[id(x)]
except KeyError:
y = []
memo[id(x)] = y
for item in x:
y.append(copyrec(item, memo))
return y
def copy_dict(x, memo):
try:
return memo[id(x)]
except KeyError:
y = {}
memo[id(x)] = y
for key, value in x.items():
y[copyrec(key, memo)] = copyrec(value, memo)
return y
def copy_function(x, memo):
if not x.func_defaults:
return x # not copied
try:
return memo[id(x)]
except KeyError:
y = types.FunctionType(x.func_code, x.func_globals, x.func_name)
memo[id(x)] = y
y.func_defaults = copyrec(x.func_defaults, memo)
return y
def copy_method(x, memo):
return types.MethodType(copyrec(x.im_func, memo),
copyrec(x.im_self, memo),
x.im_class)
def copy_generator(x, memo):
try:
return memo[id(x)]
except KeyError:
y = generator_new(copyrec(x.gi_frame, memo), x.gi_running)
memo[id(x)] = y
return y
def copy_frame(x, memo):
try:
return memo[id(x)]
except KeyError:
frame_new, args, state = x.__reduce__()
y = frame_new(*args)
memo[id(x)] = y
newstate = []
for item in state:
if not (item is x.f_globals or item is x.f_builtins):
item = copyrec(item, memo)
newstate.append(item)
y.__setstate__(newstate)
return y
def copy_seqiter(x, memo):
try:
return memo[id(x)]
except KeyError:
# XXX self-recursion is not correctly handled here
seqiter_new, args = x.__reduce__()
args = [copyrec(item, memo) for item in args]
y = seqiter_new(*args)
memo[id(x)] = y
return y
# ____________________________________________________________
type_handlers = {tuple: copy_tuple,
list: copy_list,
dict: copy_dict,
types.FunctionType: copy_function,
types.MethodType: copy_method,
types.GeneratorType: copy_generator,
types.FrameType: copy_frame,
type(iter([])): copy_seqiter,
}
def no_handler_found(x, memo):
if hasattr(x, '__dict__') and hasattr(x.__class__, 'inst_build'):
handler = copy_custom_instance
else:
handler = not_copied
type_handlers[x.__class__] = handler
return handler(x, memo)
def copyrec(x, memo):
try:
cls = x.__class__
except AttributeError:
return x # 'cls' is likely an old-style class object
return type_handlers.get(cls, no_handler_found)(x, memo)
def copy(x):
return copyrec(x, {})

View File

@ -31,12 +31,12 @@ while idx < len(sys.argv):
if arg == '-seed':
arg = sys.argv[idx]
idx += 1
print "Using seed: " + arg + "\n"
print("Using seed: " + arg + "\n")
random.seed(arg)
def printlvl(level):
if show_lvl:
print "\n\n"
print("\n\n")
for y in range(level.HEIGHT):
str = ""
if show_lvl & 1:
@ -45,12 +45,12 @@ def printlvl(level):
if str:
str += " | "
str += level.winds[y]
print str
print(str)
for i in range(n_lvls):
print '%4d:' % i,
print('%4d:' % i, end=' ')
d = {'__name__': 'RandomLevels'}
execfile('levels/RandomLevels.py', d)
exec(compile(open('levels/RandomLevels.py', "rb").read(), 'levels/RandomLevels.py', 'exec'), d)
for i, Lvl in enumerate(d['GenerateLevels']()):
level = Lvl(i)
printlvl(level)
@ -60,5 +60,5 @@ for i in range(n_lvls):
break
else:
for line in level.walls:
print line
print(line)
raise AssertionError("full height wall in column %d" % x)

View File

@ -0,0 +1,64 @@
#
# This test generates 100 times 25 random levels and checks
# that it doesn't crash, and that it gives levels that are
# possible (in the limited sense of not having any full-
# column walls)
#
# this test accepts the following parameters:
# -wall show the level layout
# -wind show the level wind pattern
# -seed N use random seed N for the generation
#
import sys
import random
sys.path.append('..')
sys.path.append('../common')
n_lvls = 100
show_lvl = 0
idx = 0
while idx < len(sys.argv):
arg = sys.argv[idx]
idx += 1
if arg == '-wall':
show_lvl |= 1
n_lvls = 2
if arg == '-wind':
show_lvl |= 2
n_lvls = 2
if arg == '-seed':
arg = sys.argv[idx]
idx += 1
print "Using seed: " + arg + "\n"
random.seed(arg)
def printlvl(level):
if show_lvl:
print "\n\n"
for y in range(level.HEIGHT):
str = ""
if show_lvl & 1:
str = level.walls[y]
if show_lvl & 2:
if str:
str += " | "
str += level.winds[y]
print str
for i in range(n_lvls):
print '%4d:' % i,
d = {'__name__': 'RandomLevels'}
execfile('levels/RandomLevels.py', d)
for i, Lvl in enumerate(d['GenerateLevels']()):
level = Lvl(i)
printlvl(level)
for x in range(2, level.width-2):
for y in range(0, level.height):
if level.walls[y][x] == ' ':
break
else:
for line in level.walls:
print line
raise AssertionError("full height wall in column %d" % x)

View File

@ -68,32 +68,32 @@ def test_generator():
yield lst.pop()
yield lst.pop()
g = gfunc()
assert g.next() == 6
assert next(g) == 6
g1 = statesaver.copy(g)
assert g.next() == 5
py.test.raises(StopIteration, g.next)
assert g1.next() == 5
py.test.raises(StopIteration, g1.next)
assert next(g) == 5
py.test.raises(StopIteration, g.__next__)
assert next(g1) == 5
py.test.raises(StopIteration, g1.__next__)
def test_exhausted_gen():
def gfunc():
yield 5
g = gfunc()
for i in g:
print i
print(i)
g1 = statesaver.copy(g)
assert iter(g1) is g1
py.test.raises(StopIteration, g1.next)
py.test.raises(StopIteration, g1.__next__)
g2 = statesaver.copy(g1)
assert iter(g2) is g2
py.test.raises(StopIteration, g2.next)
py.test.raises(StopIteration, g2.__next__)
def test_seqiter():
from UserList import UserList
from collections import UserList
seq = UserList([2, 4, 6, 8])
it = iter(seq)
assert it.next() == 2
assert it.next() == 4
assert next(it) == 2
assert next(it) == 4
it1 = statesaver.copy(it)
assert list(it) == [6, 8]
assert list(it1) == [6, 8]
@ -101,8 +101,8 @@ def test_seqiter():
def test_tupleiter():
tup = (2, 4, 6, 8)
it = iter(tup)
assert it.next() == 2
assert it.next() == 4
assert next(it) == 2
assert next(it) == 4
it1 = statesaver.copy(it)
assert list(it) == [6, 8]
assert list(it1) == [6, 8]
@ -110,8 +110,8 @@ def test_tupleiter():
def test_listiter():
lst = [2, 4, 6, 8]
it = iter(lst)
assert it.next() == 2
assert it.next() == 4
assert next(it) == 2
assert next(it) == 4
it1 = statesaver.copy(it)
lst.append(10)
assert list(it) == [6, 8, 10]
@ -120,8 +120,8 @@ def test_listiter():
def test_stringiter():
s = "hello"
it = iter(s)
assert it.next() == 'h'
assert it.next() == 'e'
assert next(it) == 'h'
assert next(it) == 'e'
it1 = statesaver.copy(it)
assert list(it) == ['l', 'l', 'o']
assert list(it1) == ['l', 'l', 'o']

View File

@ -0,0 +1,127 @@
import py
import statesaver
import new
def test_list():
lst = [None, 12, "hello", 3.4, ("foo", (), [])]
lst1 = statesaver.copy(lst)
assert lst1 == lst
assert lst1 is not lst
assert lst1[-1][-1] is not lst[-1][-1]
def test_dict():
dct = {1: "hi", 2: {}}
dct1 = statesaver.copy(dct)
assert dct1 == dct
assert dct1 is not dct
assert dct1[2] is not dct[2]
def test_instance():
class Foo:
def inst_build(self):
return Bar()
class Bar:
pass
x = Foo()
x.attr = [1, 2, 3]
y = statesaver.copy(x)
assert y.__class__ is Bar
assert y.attr == [1, 2, 3]
assert y.attr is not x.attr
glob = 2
def test_function():
# XXX closures not supported
def func(x, y=[]):
assert glob == 2
y.append(x)
return y
l = func(5)
l = func(6)
assert l == [5, 6]
func1 = statesaver.copy(func)
l = func(7)
l = func(8)
assert l == [5, 6, 7, 8]
l = func1(9)
l = func1(10)
assert l == [5, 6, 9, 10]
def test_method():
def func(x, y=[]):
assert glob == 2
y.append(x)
return y
m = new.instancemethod(func, {})
assert m() == [{}]
m1 = statesaver.copy(m)
assert m() == [{}, {}]
assert m() == [{}, {}, {}]
assert m1() == [{}, {}]
assert m1() == [{}, {}, {}]
l = m1()
assert l[0] is l[1] is l[2] is l[3]
def test_generator():
def gfunc():
lst = [5, 6]
yield lst.pop()
yield lst.pop()
g = gfunc()
assert g.next() == 6
g1 = statesaver.copy(g)
assert g.next() == 5
py.test.raises(StopIteration, g.next)
assert g1.next() == 5
py.test.raises(StopIteration, g1.next)
def test_exhausted_gen():
def gfunc():
yield 5
g = gfunc()
for i in g:
print i
g1 = statesaver.copy(g)
assert iter(g1) is g1
py.test.raises(StopIteration, g1.next)
g2 = statesaver.copy(g1)
assert iter(g2) is g2
py.test.raises(StopIteration, g2.next)
def test_seqiter():
from UserList import UserList
seq = UserList([2, 4, 6, 8])
it = iter(seq)
assert it.next() == 2
assert it.next() == 4
it1 = statesaver.copy(it)
assert list(it) == [6, 8]
assert list(it1) == [6, 8]
def test_tupleiter():
tup = (2, 4, 6, 8)
it = iter(tup)
assert it.next() == 2
assert it.next() == 4
it1 = statesaver.copy(it)
assert list(it) == [6, 8]
assert list(it1) == [6, 8]
def test_listiter():
lst = [2, 4, 6, 8]
it = iter(lst)
assert it.next() == 2
assert it.next() == 4
it1 = statesaver.copy(it)
lst.append(10)
assert list(it) == [6, 8, 10]
assert list(it1) == [6, 8]
def test_stringiter():
s = "hello"
it = iter(s)
assert it.next() == 'h'
assert it.next() == 'e'
it1 = statesaver.copy(it)
assert list(it) == ['l', 'l', 'o']
assert list(it1) == ['l', 'l', 'o']

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,8 @@
from __future__ import generators
from socket import *
from select import select
from struct import pack, unpack
import zlib, os, random, struct, md5, sys
import zlib, os, random, struct, hashlib, sys
from time import time, ctime
from msgstruct import *
from errno import EWOULDBLOCK
@ -37,7 +37,7 @@ class Icon:
framemsgappend(self.msgdef)
def getimage(self):
import pixmap
from . import pixmap
bitmap, x, y = self.origin
image = pixmap.decodepixmap(bitmap.read())
return pixmap.cropimage(image, (x, y, self.w, self.h))
@ -86,7 +86,7 @@ class DataChunk:
client.msgl.append(msgdef)
def getmd5def(self, fileid, data, offset=0):
checksum = md5.new(data).digest()
checksum = hashlib.md5.new(data).digest()
return message(MSG_MD5_FILE, fileid, protofilepath(self.filename),
offset, len(data), checksum)
@ -111,7 +111,7 @@ class Bitmap(DataChunk):
return ico
def geticonlist(self, w, h, count):
return map(lambda i, fn=self.geticon, w=w, h=h: fn(i*w, 0, w, h), range(count))
return list(map(lambda i, fn=self.geticon, w=w, h=h: fn(i*w, 0, w, h), list(range(count))))
def getmsgdef(self, data):
if self.colorkey is not None:
@ -121,7 +121,7 @@ class Bitmap(DataChunk):
def defall(self, client):
DataChunk.defall(self, client)
for i in self.icons.values():
for i in list(self.icons.values()):
client.msgl.append(i.msgdef)
@ -214,7 +214,8 @@ class Music(DataChunk):
self.md5msgs = {}
DataChunk.__init__(self)
def read(self, (start, length)):
def read(self, xxx_todo_changeme):
(start, length) = xxx_todo_changeme
self.f.seek(start)
return self.f.read(length)
@ -264,7 +265,7 @@ def compactsprites(insert_new=None, insert_before=None):
insert_before = None
newsprites = ['']
newd = {}
l = sprites_by_n.items()
l = list(sprites_by_n.items())
l.sort()
for n, s in l:
if n == insert_before:
@ -371,7 +372,7 @@ class Sprite:
n1 = 1
if self.alive > n1:
if n1 in sprites_by_n:
keys = sprites_by_n.keys()
keys = list(sprites_by_n.keys())
keys.remove(self.alive)
keys.sort()
keys = keys[keys.index(n1):]
@ -452,7 +453,7 @@ class Client:
self.activity = self.last_ping = time()
self.force_ping_delay = 0.6
for c in clients:
for id in c.players.keys():
for id in list(c.players.keys()):
self.msgl.append(message(MSG_PLAYER_JOIN, id, c is self))
def emit(self, udpdata, broadcast_extras):
@ -465,10 +466,10 @@ class Client:
if self.udpsocket is not None:
if self.sounds:
if broadcast_extras is None or self not in broadcast_clients:
udpdata = ''.join(self.sounds.keys() + [udpdata])
udpdata = ''.join(list(self.sounds.keys()) + [udpdata])
else:
broadcast_extras.update(self.sounds)
for key, value in self.sounds.items():
for key, value in list(self.sounds.items()):
if value:
self.sounds[key] = value-1
else:
@ -481,8 +482,8 @@ class Client:
for udpdata in udpdatas:
try:
self.udpsockcounter += self.udpsocket.send(udpdata)
except error, e:
print >> sys.stderr, 'ignored:', str(e)
except error as e:
print('ignored:', str(e), file=sys.stderr)
pass # ignore UDP send errors (buffer full, etc.)
if self.has_music > 1 and NOW >= self.musicstreamer:
self.musicstreamer += 0.99
@ -559,7 +560,7 @@ class Client:
def send_buffer(self, buffer):
try:
count = self.socket.send(buffer[:self.SEND_BOUND_PER_FRAME])
except error, e:
except error as e:
if e.args[0] != EWOULDBLOCK:
self.msgl = []
self.initialdata = ""
@ -588,7 +589,7 @@ class Client:
if fn:
fn(self, *values[1:])
else:
print "unknown message from", self.addr, ":", values
print("unknown message from", self.addr, ":", values)
self.buf = data
except struct.error:
import traceback
@ -608,7 +609,7 @@ then use the following address:
def input_handler(self):
try:
data = self.socket.recv(2048)
except error, e:
except error as e:
self.disconnect(e, "socket.recv")
else:
if data:
@ -628,9 +629,9 @@ then use the following address:
extra = ""
if infn:
extra += " in " + infn
print 'Disconnected by', self.addr, extra
print('Disconnected by', self.addr, extra)
self.log('disconnected' + extra)
for p in self.players.values():
for p in list(self.players.values()):
p._playerleaves()
try:
del broadcast_clients[self]
@ -646,7 +647,7 @@ then use the following address:
game.FnDisconnected()
def killplayer(self, player):
for id, p in self.players.items():
for id, p in list(self.players.items()):
if p is player:
framemsgappend(message(MSG_PLAYER_KILL, id))
del self.players[id]
@ -654,19 +655,19 @@ then use the following address:
game.updateplayers()
def joinplayer(self, id, *rest):
if self.players.has_key(id):
print "Note: player %s is already playing" % (self.addr+(id,),)
if id in self.players:
print("Note: player %s is already playing" % (self.addr+(id,),))
return
if game is None:
return # refusing new player before the game starts
p = game.FnPlayers()[id]
if p is None:
print "Too many players. New player %s refused." % (self.addr+(id,),)
print("Too many players. New player %s refused." % (self.addr+(id,),))
self.msgl.append(message(MSG_PLAYER_KILL, id))
elif p.isplaying():
print "Note: player %s is already played by another client" % (self.addr+(id,),)
print("Note: player %s is already played by another client" % (self.addr+(id,),))
else:
print "New player %s" % (self.addr+(id,),)
print("New player %s" % (self.addr+(id,),))
p._client = self
p.playerjoin()
p.setplayername('')
@ -679,7 +680,7 @@ then use the following address:
try:
p = self.players[id]
except KeyError:
print "Note: player %s is not playing" % (self.addr+(id,),)
print("Note: player %s is not playing" % (self.addr+(id,),))
else:
p._playerleaves()
@ -700,7 +701,7 @@ then use the following address:
if port == MSG_INLINE_FRAME or port == 0:
# client requests data in-line on the TCP stream
self.dyncompress = None
import udpovertcp
from . import udpovertcp
self.udpsocket = udpovertcp.SocketMarshaller(self.socket, self)
s = self.udpsocket.tcpsock
self.log('set_udp_port: udp-over-tcp')
@ -714,10 +715,10 @@ then use the following address:
self.udpsocket.setblocking(0)
addr = addr or self.addr[0]
self.udpsocket.connect((addr, port))
except error, e:
print >> sys.stderr, "Cannot set UDP socket to", addr, str(e)
except error as e:
print("Cannot set UDP socket to", addr, str(e), file=sys.stderr)
self.udpsocket = None
self.udpsockcounter = sys.maxint
self.udpsockcounter = sys.maxsize
else:
if self.proto >= 3:
self.setup_dyncompress()
@ -726,15 +727,15 @@ then use the following address:
if s:
try:
s.setsockopt(SOL_IP, IP_TOS, 0x10) # IPTOS_LOWDELAY
except error, e:
print >> sys.stderr, "Cannot set IPTOS_LOWDELAY:", str(e)
except error as e:
print("Cannot set IPTOS_LOWDELAY:", str(e), file=sys.stderr)
def enable_sound(self, sound_mode=1, *rest):
if sound_mode != self.has_sound:
self.sounds = {}
self.has_sound = sound_mode
if self.has_sound > 0:
for snd in samples.values():
for snd in list(samples.values()):
snd.defall(self)
#self.log('enable_sound %s' % sound_mode)
@ -766,10 +767,10 @@ then use the following address:
if self.initialized < 2:
# send all current bitmap data
self.initialized = 2
for b in bitmaps.values():
for b in list(bitmaps.values()):
b.defall(self)
self.finishinit(game)
for id, p in game.FnPlayers().items():
for id, p in list(game.FnPlayers().items()):
if p.standardplayericon is not None:
self.msgl.append(message(MSG_PLAYER_ICON, id, p.standardplayericon.code))
self.msgl.append(message(MSG_PONG, *rest))
@ -781,7 +782,7 @@ then use the following address:
pass
def log(self, message):
print self.addr, message
print(self.addr, message)
def protocol_version(self, version, *rest):
self.proto = version
@ -980,7 +981,7 @@ def opentcpsocket(port=None):
except error:
if port == INADDR_ANY:
for i in range(10):
port = random.choice(xrange(8000, 12000))
port = random.choice(range(8000, 12000))
try:
s.bind(('', port))
s.listen(1)
@ -989,7 +990,7 @@ def opentcpsocket(port=None):
else:
break
else:
raise error, "server cannot find a free TCP socket port"
raise error("server cannot find a free TCP socket port")
else:
raise
@ -1004,13 +1005,13 @@ def openpingsocket(only_port=None):
only_port = only_port or PORTS.get('PING', None)
s = findsocket('PING')
if s is None:
import hostchooser
from . import hostchooser
s = hostchooser.serverside_ping(only_port)
if s is None:
return None
def pingsocket_handler(s=s):
global game
import hostchooser
from . import hostchooser
if game is not None:
args = game.FnDesc, ('', game.address[1]), game.FnExtraDesc()
else:
@ -1032,10 +1033,10 @@ def openhttpsocket(ServerClass=None, HandlerClass=None,
s = findsocket('HTTP')
if s is None:
if ServerClass is None:
from BaseHTTPServer import HTTPServer as ServerClass
from http.server import HTTPServer as ServerClass
if HandlerClass is None:
import javaserver
from httpserver import MiniHandler as HandlerClass
from . import javaserver
from .httpserver import MiniHandler as HandlerClass
server_address = ('', port or 8000)
try:
httpd = ServerClass(server_address, HandlerClass)
@ -1044,8 +1045,8 @@ def openhttpsocket(ServerClass=None, HandlerClass=None,
server_address = ('', INADDR_ANY)
try:
httpd = ServerClass(server_address, HandlerClass)
except error, e:
print >> sys.stderr, "cannot start HTTP server", str(e)
except error as e:
print("cannot start HTTP server", str(e), file=sys.stderr)
return None
else:
raise
@ -1053,7 +1054,7 @@ def openhttpsocket(ServerClass=None, HandlerClass=None,
addsocket('HTTP', s, httpd.handle_request)
return s
BROADCAST_PORT_RANGE = xrange(18000, 19000)
BROADCAST_PORT_RANGE = range(18000, 19000)
#BROADCAST_MESSAGE comes from msgstruct
BROADCAST_DELAY = 0.6180
BROADCAST_DELAY_INCR = 2.7183
@ -1064,8 +1065,8 @@ def openbroadcastsocket(broadcastport=None):
try:
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
except error, e:
print >> sys.stderr, "Cannot broadcast", str(e)
except error as e:
print("Cannot broadcast", str(e), file=sys.stderr)
return None
port = broadcastport or random.choice(BROADCAST_PORT_RANGE)
addsocket('BROADCAST', s, port=port)
@ -1100,20 +1101,20 @@ class Game:
clearsprites()
game = self
if recording:
for b in bitmaps.values():
for b in list(bitmaps.values()):
b.defall(recording)
self.pendingclients = []
def openserver(self):
ps = openpingsocket()
print '%s server at %s:%d, Broadcast %d, UDP %d' % (
print('%s server at %s:%d, Broadcast %d, UDP %d' % (
self.FnDesc, self.address[0], self.address[1],
displaysockport(self.broadcast_s), displaysockport(ps))
displaysockport(self.broadcast_s), displaysockport(ps)))
hs = openhttpsocket()
if hs:
print 'HTTP server: http://%s:%d' % (
self.address[0], displaysockport(hs))
print('HTTP server: http://%s:%d' % (
self.address[0], displaysockport(hs)))
try:
from localmsg import autonotify
@ -1185,7 +1186,7 @@ class Game:
if recording:
recording.udpdata(udpdata)
if broadcast_extras is not None:
udpdata = ''.join(broadcast_extras.keys() + [udpdata])
udpdata = ''.join(list(broadcast_extras.keys()) + [udpdata])
try:
self.broadcast_s.sendto(udpdata,
('<broadcast>', self.broadcast_port))
@ -1212,18 +1213,18 @@ class Game:
def newclient(self, conn, addr):
if len(clients)==MAX_CLIENTS:
print "Too many connections; refusing new connection from", addr
print("Too many connections; refusing new connection from", addr)
conn.close()
else:
try:
addrname = (gethostbyaddr(addr[0])[0],) + addr[1:]
except:
addrname = addr
print 'Connected by', addrname
print('Connected by', addrname)
try:
c = FnClient(conn, addrname)
except error, e:
print 'Connexion already lost!', e
except error as e:
print('Connexion already lost!', e)
else:
if game is not None:
c.opengame(game)
@ -1240,14 +1241,14 @@ def recursiveloop(endtime, extra_sockets):
delay = game.mainstep()
else:
delay = 5.0
iwtd = extra_sockets + serversockets.keys()
iwtd = extra_sockets + list(serversockets.keys())
timediff = max(0.0, endtime - time())
iwtd, owtd, ewtd = select(iwtd, [], iwtd, min(delay, timediff))
if ewtd:
if game:
game.socketerrors(ewtd)
if ewtd:
print >> sys.stderr, "Unexpected socket error reported"
print("Unexpected socket error reported", file=sys.stderr)
for s in iwtd:
if s in serversockets:
serversockets[s]() # call handler
@ -1269,10 +1270,10 @@ def mainloop():
delay = game.mainstep()
else:
delay = SERVER_SHUTDOWN or 5.0
iwtd = serversockets.keys()
iwtd = list(serversockets.keys())
try:
iwtd, owtd, ewtd = select(iwtd, [], iwtd, delay)
except Exception, e:
except Exception as e:
from select import error as select_error
if not isinstance(e, select_error):
raise
@ -1281,7 +1282,7 @@ def mainloop():
if game:
game.socketerrors(ewtd)
if ewtd:
print >> sys.stderr, "Unexpected socket error reported"
print("Unexpected socket error reported", file=sys.stderr)
servertimeout = None
if iwtd:
for s in iwtd:
@ -1291,13 +1292,13 @@ def mainloop():
elif SERVER_SHUTDOWN and not ewtd and not owtd:
SERVER_SHUTDOWN -= delay
if SERVER_SHUTDOWN <= 0.001:
raise SystemExit, "Server shutdown requested."
raise SystemExit("Server shutdown requested.")
elif clients or getattr(game, 'autoreset', 0):
servertimeout = None
elif servertimeout is None:
servertimeout = time() + SERVER_TIMEOUT
elif time() > servertimeout:
raise SystemExit, "No more server activity, timing out."
raise SystemExit("No more server activity, timing out.")
except KeyboardInterrupt:
if game is None or not game.FnExcHandler(1):
raise
@ -1310,7 +1311,7 @@ def mainloop():
removesocket('LISTEN')
removesocket('PING')
if clients:
print "Server crash -- waiting for clients to terminate..."
print("Server crash -- waiting for clients to terminate...")
while clients:
iwtd = [c.socket for c in clients]
try:
@ -1325,12 +1326,12 @@ def mainloop():
elif c.socket in iwtd:
try:
data = c.socket.recv(2048)
except error, e:
except error as e:
c.disconnect(e)
else:
if not data and not hasattr(c.socket, 'RECV_CAN_RETURN_EMPTY'):
c.disconnect("end of data")
print "Server closed."
print("Server closed.")
def closeeverything():
global SERVER_SHUTDOWN

1378
common/gamesrv.py.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ def serverside_ping(only_port=None):
s.bind(('', port))
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
return s
except error, e:
except error as e:
if only_port is None:
s = socket(AF_INET, SOCK_DGRAM)
s.bind(('', INADDR_ANY))
@ -25,28 +25,27 @@ def serverside_ping(only_port=None):
def answer_ping(s, descr, addr, extra='', httpport=''):
try:
data, source = s.recvfrom(100)
except error, e:
print >> sys.stderr, 'ping error:', str(e)
except error as e:
print('ping error:', str(e), file=sys.stderr)
return
if data == PING_MESSAGE:
print >> sys.stderr, "ping by", source
print("ping by", source, file=sys.stderr)
answer = '%s:%s:%s:%s:%s:%s' % (PONG_MESSAGE, descr,
addr[0], addr[1], extra, httpport)
s.sendto(answer, source)
else:
print >> sys.stderr, \
"unexpected data on UDP port %d by" % UDP_PORT, source
print("unexpected data on UDP port %d by" % UDP_PORT, source, file=sys.stderr)
def pick(hostlist, delay=1):
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
for host in hostlist:
print >> sys.stderr, "* Looking for a server on %s... " % host
print("* Looking for a server on %s... " % host, file=sys.stderr)
try:
s.sendto(PING_MESSAGE, (host, UDP_PORT))
except error, e:
print >> sys.stderr, 'send:', str(e)
except error as e:
print('send:', str(e), file=sys.stderr)
continue
while 1:
iwtd, owtd, ewtd = select.select([s], [], [], delay)
@ -54,9 +53,9 @@ def pick(hostlist, delay=1):
break
try:
data, answer_from = s.recvfrom(200)
except error, e:
except error as e:
if e.args[0] != ETIMEDOUT:
print >> sys.stderr, 'recv:', str(e)
print('recv:', str(e), file=sys.stderr)
continue
break
data = data.split(':')
@ -68,20 +67,20 @@ def pick(hostlist, delay=1):
pass
else:
result = (hostname, port)
print >> sys.stderr, "* Picking %r at" % data[1], result
print("* Picking %r at" % data[1], result, file=sys.stderr)
return result
print >> sys.stderr, "got an unexpected answer", data, "from", answer_from
print >> sys.stderr, "no server found."
print("got an unexpected answer", data, "from", answer_from, file=sys.stderr)
print("no server found.", file=sys.stderr)
raise SystemExit
def find_servers(hostlist=[('127.0.0.1', None), ('<broadcast>', None)],
tries=2, delay=0.5, verbose=1, port_needed=1):
import gamesrv
from . import gamesrv
if verbose:
print >> sys.stderr, 'Looking for servers in the following list:'
print('Looking for servers in the following list:', file=sys.stderr)
for host, udpport in hostlist:
print >> sys.stderr, ' %s, UDP port %s' % (
host, udpport or ("%s (default)" % UDP_PORT))
print(' %s, UDP port %s' % (
host, udpport or ("%s (default)" % UDP_PORT)), file=sys.stderr)
events = {}
replies = []
s = socket(AF_INET, SOCK_DGRAM)
@ -93,21 +92,21 @@ def find_servers(hostlist=[('127.0.0.1', None), ('<broadcast>', None)],
if host != '<broadcast>':
try:
ipaddr = gethostbyname(host)
except error, e:
print >> sys.stderr, 'gethostbyname:', str(e)
except error as e:
print('gethostbyname:', str(e), file=sys.stderr)
s.sendto(PING_MESSAGE, (ipaddr, udpport or UDP_PORT))
hostsend, hostrecv = events.setdefault(ipaddr, ([], []))
hostsend.append(time.time())
except error, e:
print >> sys.stderr, 'send:', str(e)
except error as e:
print('send:', str(e), file=sys.stderr)
continue
endtime = time.time() + delay
while gamesrv.recursiveloop(endtime, [s]):
try:
data, answer_from = s.recvfrom(200)
except error, e:
except error as e:
if e.args[0] != ETIMEDOUT:
print >> sys.stderr, 'recv:', str(e)
print('recv:', str(e), file=sys.stderr)
continue
break
try:
@ -134,7 +133,7 @@ def find_servers(hostlist=[('127.0.0.1', None), ('<broadcast>', None)],
server = ':'.join(data[1:2]+data[4:])
replies.append((hostname, realhostname, port, server, ipaddr))
else:
print >> sys.stderr, "got an unexpected answer from", answer_from
print("got an unexpected answer from", answer_from, file=sys.stderr)
servers = {}
aliases = {}
timeout = time.time() + 2.0 # wait for gethostbyaddr() for 2 seconds
@ -155,8 +154,8 @@ def find_servers(hostlist=[('127.0.0.1', None), ('<broadcast>', None)],
if replies:
time.sleep(0.08) # time for gethostbyaddr() to finish
if verbose:
print >> sys.stderr, "%d answer(s):" % len(servers), servers.keys()
for host, port in servers.keys():
print("%d answer(s):" % len(servers), list(servers.keys()), file=sys.stderr)
for host, port in list(servers.keys()):
ping = None
ipaddr = aliases[host]
if ipaddr in events:
@ -176,7 +175,7 @@ def _lazygetter(hostname, resultlst):
try:
hostname = gethostbyaddr(hostname)[0]
if hostname == 'localhost':
from msgstruct import HOSTNAME as hostname
from .msgstruct import HOSTNAME as hostname
except error:
pass
finally:
@ -187,6 +186,6 @@ def lazy_gethostbyaddr(hostname):
return HOSTNAMECACHE[hostname]
except KeyError:
resultlst = HOSTNAMECACHE[hostname] = []
import thread
thread.start_new_thread(_lazygetter, (hostname, resultlst))
import _thread
_thread.start_new_thread(_lazygetter, (hostname, resultlst))
return resultlst

192
common/hostchooser.py.bak Normal file
View File

@ -0,0 +1,192 @@
from socket import *
import time, select, sys
from errno import ETIMEDOUT
UDP_PORT = 8056
PING_MESSAGE = "pclient-game-ping"
PONG_MESSAGE = "server-game-pong"
def serverside_ping(only_port=None):
port = only_port or UDP_PORT
s = socket(AF_INET, SOCK_DGRAM)
try:
s.bind(('', port))
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
return s
except error, e:
if only_port is None:
s = socket(AF_INET, SOCK_DGRAM)
s.bind(('', INADDR_ANY))
return s
else:
return None
def answer_ping(s, descr, addr, extra='', httpport=''):
try:
data, source = s.recvfrom(100)
except error, e:
print >> sys.stderr, 'ping error:', str(e)
return
if data == PING_MESSAGE:
print >> sys.stderr, "ping by", source
answer = '%s:%s:%s:%s:%s:%s' % (PONG_MESSAGE, descr,
addr[0], addr[1], extra, httpport)
s.sendto(answer, source)
else:
print >> sys.stderr, \
"unexpected data on UDP port %d by" % UDP_PORT, source
def pick(hostlist, delay=1):
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
for host in hostlist:
print >> sys.stderr, "* Looking for a server on %s... " % host
try:
s.sendto(PING_MESSAGE, (host, UDP_PORT))
except error, e:
print >> sys.stderr, 'send:', str(e)
continue
while 1:
iwtd, owtd, ewtd = select.select([s], [], [], delay)
if not iwtd:
break
try:
data, answer_from = s.recvfrom(200)
except error, e:
if e.args[0] != ETIMEDOUT:
print >> sys.stderr, 'recv:', str(e)
continue
break
data = data.split(':')
if len(data) >= 4 and data[0] == PONG_MESSAGE:
hostname = data[2] or answer_from[0]
try:
port = int(data[3])
except ValueError:
pass
else:
result = (hostname, port)
print >> sys.stderr, "* Picking %r at" % data[1], result
return result
print >> sys.stderr, "got an unexpected answer", data, "from", answer_from
print >> sys.stderr, "no server found."
raise SystemExit
def find_servers(hostlist=[('127.0.0.1', None), ('<broadcast>', None)],
tries=2, delay=0.5, verbose=1, port_needed=1):
import gamesrv
if verbose:
print >> sys.stderr, 'Looking for servers in the following list:'
for host, udpport in hostlist:
print >> sys.stderr, ' %s, UDP port %s' % (
host, udpport or ("%s (default)" % UDP_PORT))
events = {}
replies = []
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
for trynum in range(tries):
for host, udpport in hostlist:
try:
ipaddr = host
if host != '<broadcast>':
try:
ipaddr = gethostbyname(host)
except error, e:
print >> sys.stderr, 'gethostbyname:', str(e)
s.sendto(PING_MESSAGE, (ipaddr, udpport or UDP_PORT))
hostsend, hostrecv = events.setdefault(ipaddr, ([], []))
hostsend.append(time.time())
except error, e:
print >> sys.stderr, 'send:', str(e)
continue
endtime = time.time() + delay
while gamesrv.recursiveloop(endtime, [s]):
try:
data, answer_from = s.recvfrom(200)
except error, e:
if e.args[0] != ETIMEDOUT:
print >> sys.stderr, 'recv:', str(e)
continue
break
try:
ipaddr = gethostbyname(answer_from[0])
except error:
ipaddr = answer_from[0]
else:
hostsend, hostrecv = events.setdefault(ipaddr, ([], []))
hostrecv.append(time.time())
data = data.split(':')
if len(data) >= 4 and data[0] == PONG_MESSAGE:
try:
port = int(data[3])
except ValueError:
if port_needed:
continue
port = ''
if data[2]:
hostname = data[2]
realhostname = [hostname]
else:
hostname = answer_from[0]
realhostname = lazy_gethostbyaddr(hostname)
server = ':'.join(data[1:2]+data[4:])
replies.append((hostname, realhostname, port, server, ipaddr))
else:
print >> sys.stderr, "got an unexpected answer from", answer_from
servers = {}
aliases = {}
timeout = time.time() + 2.0 # wait for gethostbyaddr() for 2 seconds
while replies:
i = 0
now = time.time()
while i < len(replies):
hostname, realhostname, port, server, ipaddr = replies[i]
if realhostname:
hostname = realhostname[0] # got an answer
elif now < timeout:
i += 1 # must wait some more time
continue
result = (hostname, port)
servers[result] = server
aliases[hostname] = ipaddr
del replies[i]
if replies:
time.sleep(0.08) # time for gethostbyaddr() to finish
if verbose:
print >> sys.stderr, "%d answer(s):" % len(servers), servers.keys()
for host, port in servers.keys():
ping = None
ipaddr = aliases[host]
if ipaddr in events:
hostsend, hostrecv = events[ipaddr]
if len(hostsend) == len(hostrecv) == tries:
ping = min([t2-t1 for t1, t2 in zip(hostsend, hostrecv)])
servers[host, port] = (servers[host, port], ping)
sys.setcheckinterval(4096)
return servers
# ____________________________________________________________
HOSTNAMECACHE = {}
def _lazygetter(hostname, resultlst):
try:
try:
hostname = gethostbyaddr(hostname)[0]
if hostname == 'localhost':
from msgstruct import HOSTNAME as hostname
except error:
pass
finally:
resultlst.append(hostname)
def lazy_gethostbyaddr(hostname):
try:
return HOSTNAMECACHE[hostname]
except KeyError:
resultlst = HOSTNAMECACHE[hostname] = []
import thread
thread.start_new_thread(_lazygetter, (hostname, resultlst))
return resultlst

View File

@ -1,10 +1,10 @@
from __future__ import generators
from __future__ import nested_scopes
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import urlparse, cgi, htmlentitydefs
import http.server
from http.server import SimpleHTTPRequestHandler
import urllib.parse, cgi, html.entities
import sys, os, time
from cStringIO import StringIO
from io import StringIO
class Translator:
@ -28,7 +28,7 @@ class Translator:
prevstdout = sys.stdout
try:
sys.stdout = f = StringIO()
exec expr in self.globals, self.locals
exec(expr, self.globals, self.locals)
finally:
sys.stdout = prevstdout
return f.getvalue()
@ -59,7 +59,7 @@ class TranslatorIO:
# HTML quoting
text_to_html = {}
for key, value in htmlentitydefs.entitydefs.items():
for key, value in list(html.entities.entitydefs.items()):
text_to_html[value] = '&' + key + ';'
def htmlquote(s):
@ -107,7 +107,7 @@ class HTTPRequestError(Exception):
class MiniHandler(SimpleHTTPRequestHandler):
def send_head(self, query=''):
addr, host, path, query1, fragment = urlparse.urlsplit(self.path)
addr, host, path, query1, fragment = urllib.parse.urlsplit(self.path)
path = canonicalpath(path)
if path not in pathloaders:
if path + '/' in pathloaders:
@ -123,10 +123,10 @@ class MiniHandler(SimpleHTTPRequestHandler):
hdr = self.headers
hdr['remote host'] = self.client_address[0]
f, ctype = loader(headers=hdr, **kwds)
except IOError, e:
except IOError as e:
self.send_error(404, "I/O error: " + str(e))
return None
except HTTPRequestError, e:
except HTTPRequestError as e:
self.send_error(500, str(e))
return None
except:
@ -187,6 +187,6 @@ Please <a href="%s">click here</a> to continue.
actions_when_finished = []
def my_host():
import gamesrv
from . import gamesrv
port = gamesrv.socketports[gamesrv.openhttpsocket()]
return '127.0.0.1:%d' % port

192
common/httpserver.py.bak Normal file
View File

@ -0,0 +1,192 @@
from __future__ import generators
from __future__ import nested_scopes
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import urlparse, cgi, htmlentitydefs
import sys, os, time
from cStringIO import StringIO
class Translator:
"""For use with format strings.
'formatstring % translator' will evaluate all %(xxx)s expressions
found in the format string in the given globals/locals.
Multiline expressions are assumed to be one or several complete
statements; they are executed and whatever they print is inserted back
into the format string."""
def __init__(self, globals, locals):
self.globals = globals
self.locals = locals
def __getitem__(self, expr):
if '\n' in expr:
if not expr.endswith('\n'):
expr += '\n'
prevstdout = sys.stdout
try:
sys.stdout = f = StringIO()
exec expr in self.globals, self.locals
finally:
sys.stdout = prevstdout
return f.getvalue()
else:
return eval(expr, self.globals, self.locals)
class TranslatorIO:
"Lazy version of Translator."
def __init__(self, fmt, d):
self.gen = self.generate(fmt, d)
def read(self, ignored=None):
for text in self.gen:
if text:
return text
return ''
def close(self):
self.gen = ()
def generate(self, fmt, d):
t = Translator(d, d)
for data in fmt.split('\x0c'):
yield data % t
# HTML quoting
text_to_html = {}
for key, value in htmlentitydefs.entitydefs.items():
text_to_html[value] = '&' + key + ';'
def htmlquote(s):
return ''.join([text_to_html.get(c, c) for c in s])
# HTTP Request Handler
pathloaders = {}
def canonicalpath(url):
if url.startswith('/'):
url = url[1:]
return url.lower()
def register(url, loader):
pathloaders[canonicalpath(url)] = loader
def is_registered(url):
return canonicalpath(url) in pathloaders
def load(filename, mimetype=None, locals=None):
if mimetype and mimetype.startswith('text/'):
mode = 'r'
else:
mode = 'rb'
f = open(filename, mode)
if locals is not None:
data = f.read()
f.close()
#data = data.replace('%"', '%%"')
d = globals().copy()
d.update(locals)
f = TranslatorIO(data, d)
return f, mimetype
def fileloader(filename, mimetype=None):
def loader(**options):
return load(filename, mimetype)
return loader
class HTTPRequestError(Exception):
pass
class MiniHandler(SimpleHTTPRequestHandler):
def send_head(self, query=''):
addr, host, path, query1, fragment = urlparse.urlsplit(self.path)
path = canonicalpath(path)
if path not in pathloaders:
if path + '/' in pathloaders:
return self.redirect(path + '/')
self.send_error(404)
return None
kwds = {}
for q in [query1, query]:
if q:
kwds.update(cgi.parse_qs(q))
loader = pathloaders[path]
try:
hdr = self.headers
hdr['remote host'] = self.client_address[0]
f, ctype = loader(headers=hdr, **kwds)
except IOError, e:
self.send_error(404, "I/O error: " + str(e))
return None
except HTTPRequestError, e:
self.send_error(500, str(e))
return None
except:
f = StringIO()
import traceback
traceback.print_exc(file=f)
data = htmlquote(f.getvalue())
data = data.replace('\n', '<br>\n')
self.send_error(500)
return StringIO('<hr><p>'+data+'</p>')
if ctype is None:
ctype = self.guess_type(self.translate_path(self.path))
elif f is None:
return self.redirect(ctype)
self.send_response(200)
self.send_header("Content-type", ctype)
self.end_headers()
return f
def redirect(self, url):
self.send_response(302)
self.send_header("Content-type", 'text/html')
self.send_header("Location", url)
self.end_headers()
return StringIO('''<html><head></head><body>
Please <a href="%s">click here</a> to continue.
</body></html>
''' % url)
def do_POST(self):
try:
nbytes = int(self.headers.getheader('content-length'))
except:
nbytes = 0
query = self.rfile.read(nbytes).strip()
f = self.send_head(query)
if f:
self.copyfile(f, self.wfile)
f.close()
def parse_request(self):
if self.raw_requestline == '':
return False
else:
return SimpleHTTPRequestHandler.parse_request(self)
def address_string(self):
"""Override to avoid DNS lookups"""
return "%s:%d" % self.client_address
def finish(self):
SimpleHTTPRequestHandler.finish(self)
self.connection.close()
while actions_when_finished:
actions_when_finished.pop(0)()
actions_when_finished = []
def my_host():
import gamesrv
port = gamesrv.socketports[gamesrv.openhttpsocket()]
return '127.0.0.1:%d' % port

View File

@ -1,6 +1,6 @@
import sys, os
from cStringIO import StringIO
import httpserver
from io import StringIO
from . import httpserver
PLAYERNAMES = ['Bub', 'Bob', 'Boob', 'Beb',
'Biob', 'Bab', 'Bib',
@ -68,11 +68,11 @@ def indexloader(**options):
if 'cheat' in options:
for opt in options.pop('cheat'):
__cheat(opt)
import gamesrv
from . import gamesrv
if gamesrv.game is None:
indexdata = EMPTY_PAGE
else:
names = playernames(options).items()
names = list(playernames(options).items())
indexdata = INDEX_PAGE % {
'title': gamesrv.game.FnDesc,
'width': gamesrv.game.width,
@ -114,16 +114,16 @@ def wav2au(data):
return data
def sampleloader(code=[], **options):
import gamesrv
from . import gamesrv
try:
data = wave_cache[code[0]]
except KeyError:
for key, snd in gamesrv.samples.items():
for key, snd in list(gamesrv.samples.items()):
if str(getattr(snd, 'code', '')) == code[0]:
data = wave_cache[code[0]] = wav2au(snd.read())
break
else:
raise KeyError, code[0]
raise KeyError(code[0])
return StringIO(data), 'audio/wav'

157
common/javaserver.py.bak Normal file
View File

@ -0,0 +1,157 @@
import sys, os
from cStringIO import StringIO
import httpserver
PLAYERNAMES = ['Bub', 'Bob', 'Boob', 'Beb',
'Biob', 'Bab', 'Bib',
'Baub', 'Beab', 'Biab']
LOCALDIR = os.path.abspath(os.path.dirname(__file__))
DATADIR = os.path.join(LOCALDIR, os.pardir, 'http2', 'data')
EMPTY_PAGE = '''<html>
<head><title>No server is running</title></head>
<body><h1>No server is running at the moment.</h1>
</body>
</html>
'''
INDEX_PAGE = '''<html>
<head><title>%(title)s</title></head>
<body><h1>%(title)s</h1>
<applet code=pclient.class width=%(width)s height=%(height)s>
<param name="gameport" value="%(gameport)d">
%(names1)s
</applet>
<br>
<p align="center"><a href="name.html?%(names2)s">Player Names &amp; Teams</a></p>
</body>
</html>
'''
NAME_LINE1 = '<param name="%s" value="%s">'
NAME_SEP1 = '\n'
NAME_LINE2 = '%s=%s'
NAME_SEP2 = '&'
def playernames(options):
NUM_PLAYERS = len(PLAYERNAMES)
result = {}
anyname = None
for id in range(NUM_PLAYERS):
keyid = 'player%d' % id
if keyid in options:
value = options[keyid][0]
anyname = anyname or value
teamid = 'team%d' % id
if teamid in options:
team = options[teamid][0]
if len(team) == 1:
value = '%s (%s)' % (value, team)
result[keyid] = value
if 'c' in options:
for id in range(NUM_PLAYERS):
keyid = 'player%d' % id
try:
del result[keyid]
except KeyError:
pass
if 'f' in options:
for id in range(NUM_PLAYERS):
keyid = 'player%d' % id
if not result.get(keyid):
result[keyid] = anyname or PLAYERNAMES[id]
else:
anyname = result[keyid]
return result
def indexloader(**options):
if 'cheat' in options:
for opt in options.pop('cheat'):
__cheat(opt)
import gamesrv
if gamesrv.game is None:
indexdata = EMPTY_PAGE
else:
names = playernames(options).items()
indexdata = INDEX_PAGE % {
'title': gamesrv.game.FnDesc,
'width': gamesrv.game.width,
'height': gamesrv.game.height,
'gameport': gamesrv.game.address[1],
'names1': NAME_SEP1.join([NAME_LINE1 % kv for kv in names]),
'names2': NAME_SEP2.join([NAME_LINE2 % kv for kv in names]),
}
return StringIO(indexdata), 'text/html'
def nameloader(**options):
if 's' in options:
return indexloader(**options)
locals = {
'options': playernames(options),
}
return httpserver.load(os.path.join(DATADIR, 'name.html'),
'text/html', locals=locals)
wave_cache = {}
def wav2au(data):
# Very limited! Assumes a standard 8-bit mono .wav as input
import audioop, struct
freq, = struct.unpack("<i", data[24:28])
data = data[44:]
data = audioop.bias(data, 1, -128)
data, ignored = audioop.ratecv(data, 1, 1, freq, 8000, None)
data = audioop.lin2ulaw(data, 1)
data = struct.pack('>4siiiii8s',
'.snd', # header
struct.calcsize('>4siiiii8s'), # header size
len(data), # data size
1, # encoding
8000, # sample rate
1, # channels
'magic.au') + data
return data
def sampleloader(code=[], **options):
import gamesrv
try:
data = wave_cache[code[0]]
except KeyError:
for key, snd in gamesrv.samples.items():
if str(getattr(snd, 'code', '')) == code[0]:
data = wave_cache[code[0]] = wav2au(snd.read())
break
else:
raise KeyError, code[0]
return StringIO(data), 'audio/wav'
def setup():
dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
os.pardir,
'java'))
if not os.path.isdir(dir):
return
# register all '.class' files
for name in os.listdir(dir):
if name.endswith('.class'):
httpserver.register(name, httpserver.fileloader(os.path.join(dir, name)))
# register a '', an 'index.html', and a 'name.html' file
httpserver.register('', indexloader)
httpserver.register('index.html', indexloader)
httpserver.register('name.html', nameloader)
# 'name.html' has a few images, list the .png files in DATADIR
for fn in os.listdir(DATADIR):
fn = fn.lower()
if fn.endswith('.png'):
httpserver.register(fn, httpserver.fileloader(
os.path.join(DATADIR, fn)))
# register the sample loader
httpserver.register('sample.wav', sampleloader)
setup()

View File

@ -1,8 +1,8 @@
from __future__ import generators
import cStringIO
import io
def decodepixmap(data):
f = cStringIO.StringIO(data)
f = io.StringIO(data)
sig = f.readline().strip()
assert sig == "P6"
while 1:
@ -10,7 +10,7 @@ def decodepixmap(data):
if not line.startswith('#'):
break
wh = line.split()
w, h = map(int, wh)
w, h = list(map(int, wh))
sig = f.readline().strip()
assert sig == "255"
data = f.read()
@ -20,7 +20,9 @@ def decodepixmap(data):
def encodepixmap(w, h, data):
return 'P6\n%d %d\n255\n%s' % (w, h, data)
def cropimage((w, h, data), (x1, y1, w1, h1)):
def cropimage(xxx_todo_changeme, xxx_todo_changeme1):
(w, h, data) = xxx_todo_changeme
(x1, y1, w1, h1) = xxx_todo_changeme1
assert 0 <= x1 <= x1+w1 <= w
assert 0 <= y1 <= y1+h1 <= h
scanline = w*3
@ -80,10 +82,12 @@ translation_darker = ('\x00\x01' + '\x00'*126 +
''.join([chr(n//4) for n in range(0,128)]))
translation_dragon = translation_darker[:255] + '\xC0'
def make_dark((w, h, data), translation):
def make_dark(xxx_todo_changeme2, translation):
(w, h, data) = xxx_todo_changeme2
return w, h, data.translate(translation)
def col((r, g, b)):
def col(xxx_todo_changeme3):
(r, g, b) = xxx_todo_changeme3
r = ord(r)
g = ord(g)
b = ord(b)

163
common/pixmap.py.bak Normal file
View File

@ -0,0 +1,163 @@
from __future__ import generators
import cStringIO
def decodepixmap(data):
f = cStringIO.StringIO(data)
sig = f.readline().strip()
assert sig == "P6"
while 1:
line = f.readline().strip()
if not line.startswith('#'):
break
wh = line.split()
w, h = map(int, wh)
sig = f.readline().strip()
assert sig == "255"
data = f.read()
f.close()
return w, h, data
def encodepixmap(w, h, data):
return 'P6\n%d %d\n255\n%s' % (w, h, data)
def cropimage((w, h, data), (x1, y1, w1, h1)):
assert 0 <= x1 <= x1+w1 <= w
assert 0 <= y1 <= y1+h1 <= h
scanline = w*3
lines = [data[p:p+w1*3]
for p in range(y1*scanline + x1*3,
(y1+h1)*scanline + x1*3,
scanline)]
return w1, h1, ''.join(lines)
def vflip(w, h, data):
scanline = w*3
lines = [data[p:p+scanline] for p in range(0, len(data), scanline)]
lines.reverse()
return ''.join(lines)
def hflip(w, h, data):
scanline = w*3
lines = [''.join([data[p:p+3] for p in range(p1+scanline-3, p1-3, -3)])
for p1 in range(0, len(data), scanline)]
return ''.join(lines)
def rotate_cw(w, h, data):
scanline = w*3
lastline = len(data) - scanline
lines = [''.join([data[p:p+3] for p in range(lastline + p1, -1, -scanline)])
for p1 in range(0, scanline, 3)]
return ''.join(lines)
def rotate_ccw(w, h, data):
scanline = w*3
lines = [''.join([data[p:p+3] for p in range(p1, len(data), scanline)])
for p1 in range(scanline-3, -3, -3)]
return ''.join(lines)
def rotate_180(w, h, data):
scanline = w*3
lines = [''.join([data[p:p+3] for p in range(p1+scanline-3, p1-3, -3)])
for p1 in range(0, len(data), scanline)]
lines.reverse()
return ''.join(lines)
def makebkgnd(w, h, data):
scanline = 3*w
result = []
for position in range(0, scanline*h, scanline):
line = []
for p in range(position, position+scanline, 3):
line.append(2 * (chr(ord(data[p ]) >> 3) +
chr(ord(data[p+1]) >> 3) +
chr(ord(data[p+2]) >> 3)))
line = ''.join(line)
result.append(line)
result.append(line)
return w*2, h*2, ''.join(result)
translation_darker = ('\x00\x01' + '\x00'*126 +
''.join([chr(n//4) for n in range(0,128)]))
translation_dragon = translation_darker[:255] + '\xC0'
def make_dark((w, h, data), translation):
return w, h, data.translate(translation)
def col((r, g, b)):
r = ord(r)
g = ord(g)
b = ord(b)
return ((g>>2 + r>>3) << 24) | (b << 16) | (g << 8) | r
def imagezoomer(w, h, data):
"Zoom a cartoon image by a factor of three, progressively."
scale = 3
scanline = 3*w
rw = (w-1)*scale+1
rh = (h-1)*scale+1
pixels = []
colcache = {}
revcache = {}
for base in range(0, scanline*h, scanline):
line = []
for x in range(w):
key = data[base + 3*x : base + 3*(x+1)]
try:
c = colcache[key]
except KeyError:
c = colcache[key] = col(key)
revcache[c] = key
line.append(c)
pixels.append(line)
yield None
Pairs = {
(0, 0): [(0, 0, 0, 0),
(-1,0, 1, 0),
(0,-1, 0, 1)],
(1, 0): [(0, 0, 1, 0),
(0, 1, 1,-1),
(0,-1, 1, 1)],
(2, 0): [(0, 0, 1, 0),
(0, 1, 1,-1),
(0,-1, 1, 1)],
(0, 1): [(0, 0, 0, 1),
(-1,0, 1, 1),
(1, 0,-1, 1)],
(1, 1): [(0, 0, 1, 1),
(0, 1, 1, -1),
(1, 0,-1, 1)],
(2, 1): [(1, 0, 0, 1),
(0,-1, 1, 1),
(0, 0, 2, 1)],
(0, 2): [(0, 0, 0, 1),
(-1,0, 1, 1),
(1, 0,-1, 1)],
(1, 2): [(0, 1, 1, 0),
(-1,0, 1, 1),
(0, 0, 1, 2)],
(2, 2): [(0, 0, 1, 1),
(0, 1, 2, 0),
(1, 0, 0, 2)],
}
result = []
for y in range(rh):
yield None
for x in range(rw):
# ______________________________
i = x//scale
j = y//scale
ps = []
for dx1, dy1, dx2, dy2 in Pairs[x%scale, y%scale]:
if (0 <= i+dx1 < w and 0 <= i+dx2 < w and
0 <= j+dy1 < h and 0 <= j+dy2 < h):
p1 = pixels[j+dy1][i+dx1]
p2 = pixels[j+dy2][i+dx2]
ps.append(max(p1, p2))
p1 = min(ps)
# ______________________________
result.append(revcache[p1])
data = ''.join(result)
yield (rw, rh, data)

View File

@ -24,7 +24,7 @@ class LogFile:
self.f.close()
self.f = None
def __nonzero__(self):
def __bool__(self):
return self.f is not None
def _open(self, filename):
@ -42,8 +42,8 @@ class LogFile:
return 0
self.filename = filename
if self.f.tell() > 0:
print >> self.f
print >> self.f, '='*44
print(file=self.f)
print('='*44, file=self.f)
return 1
def _check(self):

106
common/stdlog.py.bak Normal file
View File

@ -0,0 +1,106 @@
import sys, os
from time import localtime, ctime
class LogFile:
def __init__(self, filename=None, limitsize=32768):
if filename is None:
filename = sys.argv[0]
if filename.endswith('.py'):
filename = filename[:-3]
filename += '.log'
self.limitsize = limitsize
if not self._open(filename):
import tempfile
filename = os.path.join(tempfile.gettempdir(),
os.path.basename(filename))
if not self._open(filename):
self.f = self.filename = None
self.lasttime = None
def close(self):
if self.f is not None:
self.f.close()
self.f = None
def __nonzero__(self):
return self.f is not None
def _open(self, filename):
try:
self.f = open(filename, 'r+', 1)
self.f.seek(0, 2)
except IOError:
# The open r+ might have failed simply because the file
# does not exist. Try to create it.
try:
self.f = open(filename, 'w+', 1)
except (OSError, IOError):
return 0
except OSError:
return 0
self.filename = filename
if self.f.tell() > 0:
print >> self.f
print >> self.f, '='*44
return 1
def _check(self):
if self.f is None:
return 0
lt = localtime()
if lt[:4] != self.lasttime:
self.lasttime = lt[:4]
if self.f.tell() >= self.limitsize:
self.f.seek(-(self.limitsize>>1), 1)
data = self.f.read()
self.f.seek(0)
self.f.write('(...)' + data)
self.f.truncate()
self.f.write('========= %s =========\n' % ctime())
return 1
def write(self, data):
if self._check():
self.f.write(data)
def writelines(self, data):
if self._check():
self.f.writelines(data)
def flush(self):
if self._check():
self.f.flush()
class Logger:
stdout_captured = 0
stderr_captured = 0
def __init__(self, f):
self.targets = [f]
def capture_stdout(self):
if not Logger.stdout_captured:
self.targets.append(sys.stdout)
sys.stdout = self
Logger.stdout_captured = 1
def capture_stderr(self):
if not Logger.stderr_captured:
self.targets.append(sys.stderr)
sys.stderr = self
Logger.stderr_captured = 1
def write(self, data):
for f in self.targets:
f.write(data)
def writelines(self, data):
for f in self.targets:
f.writelines(data)
def flush(self):
for f in self.targets:
f.flush()

View File

@ -1,5 +1,5 @@
from socket import *
from msgstruct import *
from .msgstruct import *
#from fcntl import ioctl
#from termios import TIOCOUTQ
from zlib import compressobj, Z_SYNC_FLUSH
@ -19,12 +19,12 @@ class SocketMarshaller:
# try to reduce TCP latency
try:
tcpsock.setsockopt(SOL_IP, IP_TOS, 0x10) # IPTOS_LOWDELAY
except error, e:
print "Cannot set IPTOS_LOWDELAY for client:", str(e)
except error as e:
print("Cannot set IPTOS_LOWDELAY for client:", str(e))
try:
tcpsock.setsockopt(SOL_TCP, TCP_NODELAY, 1)
except error, e:
print "Cannot set TCP_NODELAY for client:", str(e)
except error as e:
print("Cannot set TCP_NODELAY for client:", str(e))
compressor = compressobj(6)
self.compress = compressor.compress
self.compress_flush = compressor.flush

46
common/udpovertcp.py.bak Normal file
View File

@ -0,0 +1,46 @@
from socket import *
from msgstruct import *
#from fcntl import ioctl
#from termios import TIOCOUTQ
from zlib import compressobj, Z_SYNC_FLUSH
import struct
ZeroBuffer = struct.pack("i", 0)
class SocketMarshaller:
def __init__(self, tcpsock, mixer):
self.tcpsock = tcpsock
self.mixer = mixer
self.mixer_can_mix = mixer.send_can_mix
self.mixer_send = mixer.send_buffer
self.tcpsock_fd = tcpsock.fileno()
# try to reduce TCP latency
try:
tcpsock.setsockopt(SOL_IP, IP_TOS, 0x10) # IPTOS_LOWDELAY
except error, e:
print "Cannot set IPTOS_LOWDELAY for client:", str(e)
try:
tcpsock.setsockopt(SOL_TCP, TCP_NODELAY, 1)
except error, e:
print "Cannot set TCP_NODELAY for client:", str(e)
compressor = compressobj(6)
self.compress = compressor.compress
self.compress_flush = compressor.flush
def send(self, data):
if self.mixer_can_mix():
# discard all packets if there is still data waiting in tcpsock
# --- mmmh, works much better without this check ---
#try:
# if ioctl(self.tcpsock_fd, TIOCOUTQ, ZeroBuffer) != ZeroBuffer:
# return
#except IOError, e:
# print "ioctl(TIOCOUTQ) failed, disconnecting client"
# self.mixer.disconnect(e)
#else:
data = self.compress(data) + self.compress_flush(Z_SYNC_FLUSH)
self.mixer_send(message(MSG_INLINE_FRAME, data))
return len(data)
return 0

View File

@ -16,8 +16,8 @@ LOCALDIR = os.path.dirname(os.path.abspath(LOCALDIR))
sys.path.insert(0, os.path.dirname(LOCALDIR))
sys.path.insert(0, LOCALDIR)
import common
import pclient
import modes
from . import pclient
from . import modes
UdpLookForServer = [
@ -28,42 +28,42 @@ UdpLookForServer = [
def parse_cmdline(argv):
# parse command-line
def usage():
print >> sys.stderr, 'usage:'
print >> sys.stderr, ' python Client.py [-d#] [-s#] [extra options] [host[:port]]'
print >> sys.stderr
print >> sys.stderr, 'options:'
print >> sys.stderr, ' host search for a game on the given machine'
print >> sys.stderr, ' host:port connect to the given game server'
print >> sys.stderr, ' (default search for any local server)'
print >> sys.stderr, ' -d# --display=# graphic driver (see below)'
print >> sys.stderr, ' -s# --sound=# sound driver (see below)'
print >> sys.stderr, ' --music=no disable background music'
print >> sys.stderr, ' -h --help display this text'
print >> sys.stderr, ' -m --metaserver connect with the help of the metaserver'
print >> sys.stderr, ' (list servers with Client.py -m)'
print >> sys.stderr, ' -t --tcp for slow or proxy connections'
print >> sys.stderr, ' -u --udp for fast direct connections'
print >> sys.stderr, ' (default is to autodetect tcp or udp)'
print >> sys.stderr, ' --port UDP=# or #:# fixed inbound udp port or host:port'
print >> sys.stderr, ' --port TCP=# fixed inbound tcp port (-m only)'
print >> sys.stderr
print >> sys.stderr, 'graphic drivers:'
print('usage:', file=sys.stderr)
print(' python Client.py [-d#] [-s#] [extra options] [host[:port]]', file=sys.stderr)
print(file=sys.stderr)
print('options:', file=sys.stderr)
print(' host search for a game on the given machine', file=sys.stderr)
print(' host:port connect to the given game server', file=sys.stderr)
print(' (default search for any local server)', file=sys.stderr)
print(' -d# --display=# graphic driver (see below)', file=sys.stderr)
print(' -s# --sound=# sound driver (see below)', file=sys.stderr)
print(' --music=no disable background music', file=sys.stderr)
print(' -h --help display this text', file=sys.stderr)
print(' -m --metaserver connect with the help of the metaserver', file=sys.stderr)
print(' (list servers with Client.py -m)', file=sys.stderr)
print(' -t --tcp for slow or proxy connections', file=sys.stderr)
print(' -u --udp for fast direct connections', file=sys.stderr)
print(' (default is to autodetect tcp or udp)', file=sys.stderr)
print(' --port UDP=# or #:# fixed inbound udp port or host:port', file=sys.stderr)
print(' --port TCP=# fixed inbound tcp port (-m only)', file=sys.stderr)
print(file=sys.stderr)
print('graphic drivers:', file=sys.stderr)
for info in modes.graphicmodeslist():
info.printline(sys.stderr)
print >> sys.stderr
print >> sys.stderr, 'sound drivers:'
print(file=sys.stderr)
print('sound drivers:', file=sys.stderr)
for info in modes.soundmodeslist():
info.printline(sys.stderr)
print >> sys.stderr
print(file=sys.stderr)
sys.exit(2)
shortopts = 'd:s:htum'
longopts = ['display=', 'sound=', 'music=', 'help', 'tcp', 'udp',
'cfg=', 'metaserver', 'port=']
for info in modes.graphicmodeslist() + modes.soundmodeslist():
short, long = info.getformaloptions()
short, int = info.getformaloptions()
shortopts += short
longopts += long
longopts += int
try:
from getopt import gnu_getopt as getopt
except ImportError:
@ -71,9 +71,9 @@ def parse_cmdline(argv):
from getopt import error
try:
opts, args = getopt(argv, shortopts, longopts)
except error, e:
print >> sys.stderr, 'Client.py: %s' % str(e)
print >> sys.stderr
except error as e:
print('Client.py: %s' % str(e), file=sys.stderr)
print(file=sys.stderr)
usage()
metaserver = 0
@ -144,7 +144,7 @@ def parse_cmdline(argv):
return directconnect(server), mode
def directconnect(sockaddr):
print "connecting to %s:%d..." % sockaddr
print("connecting to %s:%d..." % sockaddr)
from socket import socket, AF_INET, SOCK_STREAM
s = socket(AF_INET, SOCK_STREAM)
s.connect(sockaddr)

170
display/Client.py.bak Normal file
View File

@ -0,0 +1,170 @@
#! /usr/bin/env python
# __________
import os, sys
if __name__ == '__main__':
LOCALDIR = sys.argv[0]
else:
LOCALDIR = __file__
try:
LOCALDIR = os.readlink(LOCALDIR)
except:
pass
LOCALDIR = os.path.dirname(os.path.abspath(LOCALDIR))
# ----------
sys.path.insert(0, os.path.dirname(LOCALDIR))
sys.path.insert(0, LOCALDIR)
import common
import pclient
import modes
UdpLookForServer = [
'127.0.0.1',
'<broadcast>',
]
def parse_cmdline(argv):
# parse command-line
def usage():
print >> sys.stderr, 'usage:'
print >> sys.stderr, ' python Client.py [-d#] [-s#] [extra options] [host[:port]]'
print >> sys.stderr
print >> sys.stderr, 'options:'
print >> sys.stderr, ' host search for a game on the given machine'
print >> sys.stderr, ' host:port connect to the given game server'
print >> sys.stderr, ' (default search for any local server)'
print >> sys.stderr, ' -d# --display=# graphic driver (see below)'
print >> sys.stderr, ' -s# --sound=# sound driver (see below)'
print >> sys.stderr, ' --music=no disable background music'
print >> sys.stderr, ' -h --help display this text'
print >> sys.stderr, ' -m --metaserver connect with the help of the metaserver'
print >> sys.stderr, ' (list servers with Client.py -m)'
print >> sys.stderr, ' -t --tcp for slow or proxy connections'
print >> sys.stderr, ' -u --udp for fast direct connections'
print >> sys.stderr, ' (default is to autodetect tcp or udp)'
print >> sys.stderr, ' --port UDP=# or #:# fixed inbound udp port or host:port'
print >> sys.stderr, ' --port TCP=# fixed inbound tcp port (-m only)'
print >> sys.stderr
print >> sys.stderr, 'graphic drivers:'
for info in modes.graphicmodeslist():
info.printline(sys.stderr)
print >> sys.stderr
print >> sys.stderr, 'sound drivers:'
for info in modes.soundmodeslist():
info.printline(sys.stderr)
print >> sys.stderr
sys.exit(2)
shortopts = 'd:s:htum'
longopts = ['display=', 'sound=', 'music=', 'help', 'tcp', 'udp',
'cfg=', 'metaserver', 'port=']
for info in modes.graphicmodeslist() + modes.soundmodeslist():
short, long = info.getformaloptions()
shortopts += short
longopts += long
try:
from getopt import gnu_getopt as getopt
except ImportError:
from getopt import getopt
from getopt import error
try:
opts, args = getopt(argv, shortopts, longopts)
except error, e:
print >> sys.stderr, 'Client.py: %s' % str(e)
print >> sys.stderr
usage()
metaserver = 0
driver = sound = None
extraopts = {}
for key, value in opts:
if key in ('-d', '--display'):
driver = value
elif key in ('-s', '--sound'):
sound = value
elif key in ('-t', '--tcp'):
extraopts['udp_over_tcp'] = 1
elif key in ('-u', '--udp'):
extraopts['udp_over_tcp'] = 0
elif key in ('-m', '--metaserver'):
metaserver = 1
elif key == '--port':
import common.msgstruct
try:
portname, value = value.split('=')
if portname == 'UDP':
portname = 'CLIENT'
elif portname == 'TCP':
portname = 'BACK'
except ValueError:
portname = 'CLIENT'
if portname == 'CLIENT' and ':' in value:
udphostname, value = value.split(':')
common.msgstruct.PORTS['sendudpto'] = udphostname
common.msgstruct.PORTS[portname] = int(value)
elif key == '--cfg':
extraopts['cfgfile'] = value
elif key in ('-h', '--help'):
usage()
else:
extraopts[key] = value
mode = driver, sound, extraopts
if metaserver:
if len(args) == 0:
metalist()
sys.exit(0)
elif len(args) != 1 or ':' not in args[0]:
usage()
return metaconnect(args[0]), mode
if args:
if len(args) > 1:
usage()
hosts = args[0].split(':')
if len(hosts) == 1:
host, = hosts
from common import hostchooser
server = hostchooser.pick([host] * 5)
elif len(hosts) == 2:
host, port = hosts
try:
port = int(port)
except ValueError:
usage()
server = host, port
else:
usage()
return directconnect(server), mode
from common import hostchooser
server = hostchooser.pick(UdpLookForServer * 3)
return directconnect(server), mode
def directconnect(sockaddr):
print "connecting to %s:%d..." % sockaddr
from socket import socket, AF_INET, SOCK_STREAM
s = socket(AF_INET, SOCK_STREAM)
s.connect(sockaddr)
return s, sockaddr
def metaconnect(metaaddr):
from metaserver import metaclient
import common.msgstruct
port = common.msgstruct.PORTS.get('BACK')
s = metaclient.meta_connect(metaaddr, port)
sockaddr = s.getpeername()
return s, sockaddr
def metalist():
from metaserver import metaclient
metaclient.print_server_list()
def main():
(s, sockaddr), mode = parse_cmdline(sys.argv[1:])
pclient.run(s, sockaddr, mode)
if __name__ == '__main__':
main()

View File

@ -1,4 +1,4 @@
from __future__ import generators
import os, md5, sys
#import common.debug
@ -18,7 +18,7 @@ class FileCache:
del self.cache[filename]
if filename not in self.cache:
if len(self.cache) >= FileCache.MAX_FILES:
(time, mode, f), k = min([(v,k) for (k,v) in self.cache.items()])
(time, mode, f), k = min([(v,k) for (k,v) in list(self.cache.items())])
f.close()
del self.cache[k]
try:
@ -54,13 +54,13 @@ class FileBlock:
def overwrite(self, newdata):
self.memorydata = newdata
if self.readonly:
print >> sys.stderr, "cannot overwrite file", self.filename
print("cannot overwrite file", self.filename, file=sys.stderr)
return
try:
f = Data.Cache.access(self.filename, self.position, writing=1)
f.write(newdata)
except (IOError, OSError):
print >> sys.stderr, "cache write error:", self.filename
print("cache write error:", self.filename, file=sys.stderr)
return
self.complete = 1
del self.memorydata
@ -107,7 +107,7 @@ class Data:
f.write(data)
f.flush()
except (IOError, OSError):
print >> sys.stderr, "cache write error:", self.backupfile
print("cache write error:", self.backupfile, file=sys.stderr)
def loadfrom(self, filename, position, length, checksum):
"""Try to load data from the given filename, with the given
@ -128,19 +128,19 @@ class Data:
# correct data
self.store(position, data, name, readonly)
return 1
if self.content is not None and not self.content.has_key(position):
if self.content is not None and position not in self.content:
self.content[position] = FileBlock(cachename, position, length,
readonly=0, complete=0)
elif self.readonly:
print >> sys.stderr, "Note: the music data has changed. You can get"
print >> sys.stderr, "the server's version by deleting", directname
print("Note: the music data has changed. You can get", file=sys.stderr)
print("the server's version by deleting", directname, file=sys.stderr)
return 1 # incorrect data, but ignored
return 0
def read(self):
"""Return the data as built so far."""
if self.content is not None:
items = self.content.items()
items = list(self.content.items())
items.sort()
result = ''
for position, block in items:
@ -155,7 +155,7 @@ class Data:
def fopen(self):
if self.content is not None:
from cStringIO import StringIO
from io import StringIO
return StringIO(self.read())
else:
return Data.Cache.access(self.backupfile, 0)
@ -166,19 +166,19 @@ class Data:
the file that we want."""
if not self.backupfile:
files = {}
for position, block in self.content.items():
for position, block in list(self.content.items()):
if not isinstance(block, FileBlock):
break
if block.complete:
files[block.filename] = block
else:
if len(files) == 1:
self.backupfile, block = files.items()[0]
self.backupfile, block = list(files.items())[0]
self.readonly = block.readonly
if not self.backupfile:
self.backupfile = mktemp(fileexthint)
f = Data.Cache.access(self.backupfile, 0, writing=1)
for position, block in self.content.items():
for position, block in list(self.content.items()):
f.seek(position)
f.write(block.read())
f.flush()
@ -258,4 +258,4 @@ def enumtempfiles():
i += 1
def mktemp(fileext, gen = enumtempfiles()):
return gen.next() + fileext
return next(gen) + fileext

261
display/caching.py.bak Normal file
View File

@ -0,0 +1,261 @@
from __future__ import generators
import os, md5, sys
#import common.debug
class FileCache:
MAX_FILES = 8
def __init__(self):
self.cache = {}
self.time = 0
def access(self, filename, position, writing=0):
if filename in self.cache:
time, mode, f = self.cache[filename]
if writing > mode:
f.close()
del self.cache[filename]
if filename not in self.cache:
if len(self.cache) >= FileCache.MAX_FILES:
(time, mode, f), k = min([(v,k) for (k,v) in self.cache.items()])
f.close()
del self.cache[k]
try:
f = open(filename, ('rb', 'r+b')[writing])
except (IOError, OSError):
if not writing:
raise
if not os.path.isdir(os.path.dirname(filename)):
os.mkdir(os.path.dirname(filename))
f = open(filename, 'w+b')
mode = writing
self.time += 1
self.cache[filename] = self.time, mode, f
f.seek(position)
return f
class MemoryBlock:
def __init__(self, data):
self.data = data
def overwrite(self, newdata):
self.data = newdata
def read(self):
return self.data
class FileBlock:
def __init__(self, filename, position, length, readonly=1, complete=1):
self.filename = filename
self.position = position
self.length = length
self.readonly = readonly
self.complete = complete
def overwrite(self, newdata):
self.memorydata = newdata
if self.readonly:
print >> sys.stderr, "cannot overwrite file", self.filename
return
try:
f = Data.Cache.access(self.filename, self.position, writing=1)
f.write(newdata)
except (IOError, OSError):
print >> sys.stderr, "cache write error:", self.filename
return
self.complete = 1
del self.memorydata
def read(self):
if self.complete:
f = Data.Cache.access(self.filename, self.position)
return f.read(self.length)
else:
return self.memorydata
class Data:
SafeChars = {}
for c in ".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789":
SafeChars[c] = c
Translate = ''.join([SafeChars.get(chr(c), '_') for c in range(256)])
del c, SafeChars
Cache = FileCache()
def __init__(self):
self.content = {}
self.backupfile = None
self.readonly = 0
clear = __init__
### Public interface ###
def store(self, position, data, filename=None, readonly=1):
"""This class assumes that all accesses to block within the data
are done for disjoint intervals: no overlapping writes !"""
if self.content is not None:
try:
self.content[position].overwrite(data)
except KeyError:
if filename is None:
self.content[position] = MemoryBlock(data)
else:
self.content[position] = FileBlock(filename, position,
len(data), readonly)
if self.backupfile and not self.readonly:
try:
f = Data.Cache.access(self.backupfile, position, writing=1)
f.write(data)
f.flush()
except (IOError, OSError):
print >> sys.stderr, "cache write error:", self.backupfile
def loadfrom(self, filename, position, length, checksum):
"""Try to load data from the given filename, with the given
expected MD5 checksum. The filename must be Unix-style, and is
looked up both in the directory SOURCEDIR and with a mangled name
in the cache directory CACHEDIR."""
directname = os.path.join(self.SOURCEDIR, *filename.split('/'))
mangledname = filename.translate(Data.Translate)
cachename = os.path.join(self.CACHEDIR, mangledname)
for name, readonly in ((directname, 1), (cachename, 0)):
try:
f = Data.Cache.access(name, position)
data = f.read(length)
except (IOError, OSError):
pass
else:
if len(data) == length and md5.new(data).digest() == checksum:
# correct data
self.store(position, data, name, readonly)
return 1
if self.content is not None and not self.content.has_key(position):
self.content[position] = FileBlock(cachename, position, length,
readonly=0, complete=0)
elif self.readonly:
print >> sys.stderr, "Note: the music data has changed. You can get"
print >> sys.stderr, "the server's version by deleting", directname
return 1 # incorrect data, but ignored
return 0
def read(self):
"""Return the data as built so far."""
if self.content is not None:
items = self.content.items()
items.sort()
result = ''
for position, block in items:
if len(result) < position:
result += '\x00' * (position-len(result))
data = block.read()
result = result[:position] + data + result[position+len(data):]
return result
else:
f = Data.Cache.access(self.backupfile, 0)
return f.read()
def fopen(self):
if self.content is not None:
from cStringIO import StringIO
return StringIO(self.read())
else:
return Data.Cache.access(self.backupfile, 0)
def freezefilename(self, fileexthint='.wav'):
"""Return the name of a file from which the data can be read. If all
the current data comes from the same file, it is assumed to be exactly
the file that we want."""
if not self.backupfile:
files = {}
for position, block in self.content.items():
if not isinstance(block, FileBlock):
break
if block.complete:
files[block.filename] = block
else:
if len(files) == 1:
self.backupfile, block = files.items()[0]
self.readonly = block.readonly
if not self.backupfile:
self.backupfile = mktemp(fileexthint)
f = Data.Cache.access(self.backupfile, 0, writing=1)
for position, block in self.content.items():
f.seek(position)
f.write(block.read())
f.flush()
#print 'freezefilename ->', self.backupfile
#print ' readonly =', self.readonly
self.content = None
return self.backupfile
# ____________________________________________________________
# Temporary files management
# from the 'py' lib, mostly written by hpk
def try_remove_dir(udir):
try:
for name in os.listdir(udir):
try:
os.unlink(os.path.join(udir, name))
except:
pass
os.rmdir(udir)
except:
pass
def make_numbered_dir(prefix='tmp-bub-n-bros-', rootdir=None, keep=0,
lock_timeout = 172800): # two days
""" return unique directory with a number greater than the current
maximum one. The number is assumed to start directly after prefix.
Directories with a number less than (maxnum-keep) will be removed.
"""
import atexit, tempfile
if rootdir is None:
rootdir = tempfile.gettempdir()
def parse_num(bn):
""" parse the number out of a path (if it matches the prefix) """
if bn.startswith(prefix):
try:
return int(bn[len(prefix):])
except ValueError:
pass
# compute the maximum number currently in use with the
# prefix
maxnum = -1
for basename in os.listdir(rootdir):
num = parse_num(basename)
if num is not None:
maxnum = max(maxnum, num)
# make the new directory
udir = os.path.join(rootdir, prefix + str(maxnum+1))
os.mkdir(udir)
# try to remove the directory at process exit
atexit.register(try_remove_dir, udir)
# prune old directories
for basename in os.listdir(rootdir):
num = parse_num(basename)
if num is not None and num <= (maxnum - keep):
d1 = os.path.join(rootdir, basename)
try:
t1 = os.stat(d1).st_mtime
t2 = os.stat(udir).st_mtime
if abs(t2-t1) < lock_timeout:
continue # skip directories still recently used
except:
pass
try_remove_dir(d1)
return udir
def enumtempfiles():
tempdir = make_numbered_dir()
i = 0
while True:
yield os.path.join(tempdir, 'b%d' % i)
i += 1
def mktemp(fileext, gen = enumtempfiles()):
return gen.next() + fileext

View File

@ -4,8 +4,8 @@
################################################
import os, sys, math
from modes import KeyPressed, KeyReleased
import caching
from .modes import KeyPressed, KeyReleased
from . import caching
def import_trickery():
global gtk, gdk
@ -59,7 +59,8 @@ class Display:
pb = self.pixmap(32, 32, ((pixel+hole)*16 + (hole+pixel)*16) * 16, 0x010101)
self.taskbkgnd = self.renderpixbuf(pb)
def taskbar(self, (x, y, w, h)):
def taskbar(self, xxx_todo_changeme):
(x, y, w, h) = xxx_todo_changeme
scale = self.scale
x2 = x+w
y2 = y+h
@ -74,9 +75,9 @@ class Display:
def pixmap(self, w, h, data, colorkey=-1):
filename = self.tempppmfile
f = open(filename, 'wb')
print >> f, 'P6'
print >> f, w, h
print >> f, 255
print('P6', file=f)
print(w, h, file=f)
print(255, file=f)
f.write(data)
f.close()
pb = gdk.pixbuf_new_from_file(filename)
@ -101,7 +102,8 @@ class Display:
else:
return (pixmap, self.gc, None)
def getopticon(self, input, (x, y, w, h), ignored_alpha=255):
def getopticon(self, input, xxx_todo_changeme1, ignored_alpha=255):
(x, y, w, h) = xxx_todo_changeme1
if len(input) == 3:
return None
pb, = input
@ -116,7 +118,8 @@ class Display:
else:
return self.renderpixbuf((newpb,))
def getppm(self, (x, y, w, h), int=int, ceil=math.ceil):
def getppm(self, xxx_todo_changeme2, int=int, ceil=math.ceil):
(x, y, w, h) = xxx_todo_changeme2
scale = self.scale
if isinstance(scale, int):
x *= scale
@ -134,7 +137,8 @@ class Display:
bkgnd.draw_drawable(self.gc, self.offscreen, x, y, 0, 0, w, h)
return bkgnd, self.gc, None
def putppm(self, x, y, (pixmap, gc, ignored), rect=None, int=int):
def putppm(self, x, y, xxx_todo_changeme3, rect=None, int=int):
(pixmap, gc, ignored) = xxx_todo_changeme3
if pixmap is None:
return
scale = self.scale

204
display/dpy_gtk.py.bak Normal file
View File

@ -0,0 +1,204 @@
################################################
## GTK-based implementation of xshm ##
################################################
import os, sys, math
from modes import KeyPressed, KeyReleased
import caching
def import_trickery():
global gtk, gdk
argv = sys.argv[:]
del sys.argv[1:]
import gtk
from gtk import gdk
sys.argv[:] = argv
import_trickery()
class Display:
def __init__(self, width, height, title, zoom="100"):
if zoom.endswith('%'):
zoom = zoom[:-1]
scale = float(zoom) / 100.0
iscale = int(scale+0.001)
if abs(scale - iscale) < 0.002:
scale = iscale
self.scale = scale
self.width = int(width * scale)
self.height = int(height * scale)
self.tempppmfile = caching.mktemp('.ppm')
# create a top level window
w = self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
w.connect("destroy", lambda w: sys.exit())
w.connect("key-press-event", self.key_press_event)
w.connect("key-release-event", self.key_release_event)
w.connect("motion-notify-event", self.motion_notify_event)
w.connect("button-press-event", self.button_press_event)
w.add_events(gdk.KEY_PRESS_MASK |
gdk.POINTER_MOTION_MASK |
gdk.BUTTON_PRESS_MASK)
w.resize(self.width, self.height)
w.set_title(title)
w.show()
self.offscreen = gtk.create_pixmap(w.window, self.width, self.height)
self.gc = gdk.gc_new(w.window)
self.gc.set_rgb_fg_color(gdk.color_parse('#000000'))
self.events_key = []
self.events_mouse = []
self.event_motion = None
pixel = "\x00\x00\x80"
hole = "\x01\x01\x01"
pb = self.pixmap(32, 32, ((pixel+hole)*16 + (hole+pixel)*16) * 16, 0x010101)
self.taskbkgnd = self.renderpixbuf(pb)
def taskbar(self, (x, y, w, h)):
scale = self.scale
x2 = x+w
y2 = y+h
x, y, x2, y2 = int(x*scale), int(y*scale), int(x2*scale), int(y2*scale)
pixmap, gc, ignored = self.taskbkgnd
for j in range(y, y2, 32):
for i in range(x, x2, 32):
gc.set_clip_origin(i, j)
self.offscreen.draw_drawable(gc, pixmap, 0, 0,
i, j, x2-i, y2-j)
def pixmap(self, w, h, data, colorkey=-1):
filename = self.tempppmfile
f = open(filename, 'wb')
print >> f, 'P6'
print >> f, w, h
print >> f, 255
f.write(data)
f.close()
pb = gdk.pixbuf_new_from_file(filename)
if colorkey >= 0:
pb = pb.add_alpha(1, chr(colorkey >> 16),
chr((colorkey >> 8) & 0xFF),
chr(colorkey & 0xFF))
if self.scale == 1:
return self.renderpixbuf((pb,))
else:
return (pb,)
def renderpixbuf(self, input):
if len(input) == 3:
return input
pb, = input
pixmap, mask = pb.render_pixmap_and_mask()
if mask is not None:
gc = gdk.gc_new(self.window.window)
gc.set_clip_mask(mask)
return (pixmap, gc, mask)
else:
return (pixmap, self.gc, None)
def getopticon(self, input, (x, y, w, h), ignored_alpha=255):
if len(input) == 3:
return None
pb, = input
scale = self.scale
newpb = gdk.Pixbuf("rgb", 1, 8, w, h)
newpb.fill(0)
pb.copy_area(x, y, w, h, newpb, 0, 0)
newpb = newpb.scale_simple(int(w*scale), int(h*scale),
gdk.INTERP_HYPER)
if newpb is None:
return None, None, None
else:
return self.renderpixbuf((newpb,))
def getppm(self, (x, y, w, h), int=int, ceil=math.ceil):
scale = self.scale
if isinstance(scale, int):
x *= scale
y *= scale
w *= scale
h *= scale
else:
w = int(ceil((x+w)*scale))
h = int(ceil((y+h)*scale))
x = int(x*scale)
y = int(y*scale)
w -= x
h -= y
bkgnd = gtk.create_pixmap(self.window.window, w, h)
bkgnd.draw_drawable(self.gc, self.offscreen, x, y, 0, 0, w, h)
return bkgnd, self.gc, None
def putppm(self, x, y, (pixmap, gc, ignored), rect=None, int=int):
if pixmap is None:
return
scale = self.scale
if rect is None:
srcx = srcy = 0
w = h = 4095
else:
srcx, srcy, w, h = rect
x = int(x*scale)
y = int(y*scale)
if gc is not self.gc:
gc.set_clip_origin(x-srcx, y-srcy)
self.offscreen.draw_drawable(gc, pixmap, srcx, srcy, x, y, w, h)
def flip(self):
self.window.window.draw_drawable(self.gc, self.offscreen,
0, 0, 0, 0, self.width, self.height)
gdk.flush()
self.events_poll()
def close(self):
self.window.destroy()
def clear(self):
self.offscreen.draw_rectangle(self.gc, 1,
0, 0, self.width, self.height)
def events_poll(self):
while gtk.events_pending():
gtk.main_iteration()
def key_press_event(self, window, event):
self.events_key.append((event.keyval, KeyPressed))
def key_release_event(self, window, event):
self.events_key.append((event.keyval, KeyReleased))
def motion_notify_event(self, window, event):
self.event_motion = (int(event.x/self.scale), int(event.y/self.scale))
def button_press_event(self, window, event):
self.events_mouse.append((int(event.x/self.scale), int(event.y/self.scale)))
def keyevents(self):
self.events_poll()
result = self.events_key
self.events_key = []
return result
def pointermotion(self):
result = self.event_motion
self.event_motion = None
return result
def mouseevents(self):
self.events_poll()
result = self.events_mouse
self.events_mouse = []
return result
def selectlist(self):
return []
def htmloptionstext(nameval):
return 'Scale image by <%s size=5>%%' % (
nameval('text', 'zoom', default='100'))

View File

@ -6,7 +6,7 @@
import os
import pygame
from pygame.locals import *
from modes import KeyPressed, KeyReleased
from .modes import KeyPressed, KeyReleased
class Display:
@ -154,7 +154,8 @@ class Display:
def selectlist(self):
return []
def taskbar(self, (x, y, w, h)):
def taskbar(self, xxx_todo_changeme):
(x, y, w, h) = xxx_todo_changeme
tbs, tbh = self.tbcache
if tbh != h:
tbs = pygame.Surface((32, h)).convert_alpha(self.offscreen)
@ -192,7 +193,7 @@ def events_dispatch(handlers = EVENT_HANDLERS):
e = pygame.event.poll()
if e.type == NOEVENT:
break
elif handlers.has_key(e.type):
elif e.type in handlers:
handlers[e.type](e)

206
display/dpy_pygame.py.bak Normal file
View File

@ -0,0 +1,206 @@
################################################
## pygame-based implementation of xshm ##
################################################
import os
import pygame
from pygame.locals import *
from modes import KeyPressed, KeyReleased
class Display:
musthidemouse = 0
mousevisible = 1
def __init__(self, width, height, title, transparency='yes', fullscreen='no'):
self.use_transparency = not transparency.startswith('n')
self.use_fullscreen = fullscreen.startswith('y')
# Initialize pygame
pygame.init()
# Set the display mode
winstyle = HWSURFACE
if self.use_fullscreen:
winstyle |= FULLSCREEN
bestdepth = pygame.display.mode_ok((width, height), winstyle, 32)
self.screen = pygame.display.set_mode((width, height),
winstyle, bestdepth)
self.offscreen = pygame.Surface((width, height))
#decorate the game window
pygame.display.set_caption(title)
#pygame.mouse.set_visible(0)
self.tbcache = None, None
self.events_key = []
self.events_mouse = []
self.prevposition = None
EVENT_HANDLERS[KEYDOWN] = self.keydown_handler
EVENT_HANDLERS[KEYUP] = self.keyup_handler
EVENT_HANDLERS[MOUSEBUTTONDOWN] = self.mousebuttondown_handler
def keydown_handler(self, e):
if e.key == K_ESCAPE and self.use_fullscreen:
raise SystemExit # ESC to exit the game if full-screen
self.showmouse(not self.musthidemouse)
self.events_key.append((e.key, KeyPressed))
del self.events_key[:-16]
def keyup_handler(self, e):
self.events_key.append((e.key, KeyReleased))
del self.events_key[:-16]
def mousebuttondown_handler(self, e):
self.showmouse(1)
self.events_mouse.append(e.pos)
del self.events_mouse[:-8]
def pixmap(self, w, h, data, colorkey=-1):
img = pygame.image.fromstring(data, (w, h), "RGB")
if colorkey >= 0:
r = colorkey & 0xFF
g = (colorkey >> 8) & 0xFF
b = (colorkey >> 16) & 0xFF
img.set_colorkey([r, g, b])
return img # not optimized -- must use getopticon()
def getopticon(self, pixmap, rect, alpha=255):
if not self.use_transparency:
alpha = 255
img = pixmap.subsurface(rect)
colorkey = pixmap.get_colorkey()
if alpha == 255 and not colorkey:
return img.convert(self.offscreen)
else:
if colorkey:
img.set_colorkey(colorkey, RLEACCEL)
if alpha < 255:
img.set_alpha(alpha, RLEACCEL)
img = img.convert_alpha(self.offscreen)
img.set_alpha(255, RLEACCEL)
return img
## def vflipppm(self, img):
## w, h = img.get_size()
## colorkey = img.get_colorkey()
## data = pygame.image.tostring(img, "RGB", 1)
## flipimg = pygame.image.fromstring(data, (w, h), "RGB")
## flipimg.set_colorkey(colorkey, RLEACCEL)
## return flipimg, h
def getppm(self, rect):
bkgnd = pygame.Surface(rect[2:])
bkgnd.blit(self.offscreen, (0, 0), rect)
return bkgnd
def putppm(self, x, y, bitmap, rect=None):
if rect:
self.offscreen.blit(bitmap, (x, y), rect)
else:
self.offscreen.blit(bitmap, (x, y))
def flip(self):
self.screen.blit(self.offscreen, (0, 0))
pygame.display.flip()
events_dispatch()
def close(self):
self.showmouse(1)
pygame.display.quit()
def clear(self):
self.offscreen.fill([0,0,0,])
def events_poll(self):
while 1:
e = pygame.event.poll()
if e.type == NOEVENT:
break
elif e.type == KEYDOWN:
self.events_key.append((e.key, KeyPressed))
del self.events_key[:-16]
elif e.type == KEYUP:
self.events_key.append((e.key, KeyReleased))
del self.events_key[:-16]
elif e.type == MOUSEBUTTONDOWN:
self.events_mouse.append(e.pos)
del self.events_mouse[:-8]
elif e.type == ENDMUSICEVENT:
self.next_music()
elif e.type == QUIT:
raise SystemExit
def keyevents(self):
events_dispatch()
events = self.events_key
self.events_key = []
return events
def pointermotion(self):
position = pygame.mouse.get_pos()
if position != self.prevposition:
self.showmouse(1)
self.prevposition = position
return position
else:
return None
def mouseevents(self):
events_dispatch()
events = self.events_mouse
self.events_mouse = []
return events
def selectlist(self):
return []
def taskbar(self, (x, y, w, h)):
tbs, tbh = self.tbcache
if tbh != h:
tbs = pygame.Surface((32, h)).convert_alpha(self.offscreen)
alpha_f = 256.0 / h
for j in range(h):
tbs.fill((128, 128, 255, int(j*alpha_f)),
(0, j, 32, 1))
self.tbcache = tbs, h
for i in range(x, x+w, 32):
dw = x+w-i
if dw < 32:
self.offscreen.blit(tbs, (i, y), (0, 0, dw, h))
else:
self.offscreen.blit(tbs, (i, y))
def settaskbar(self, tb_visible):
self.showmouse(1)
self.musthidemouse = not tb_visible # and self.use_fullscreen
def showmouse(self, v):
if v != self.mousevisible:
self.mousevisible = v
pygame.mouse.set_visible(v)
def quit_handler(e):
raise SystemExit
EVENT_HANDLERS = {
QUIT: quit_handler,
}
def events_dispatch(handlers = EVENT_HANDLERS):
while 1:
e = pygame.event.poll()
if e.type == NOEVENT:
break
elif handlers.has_key(e.type):
handlers[e.type](e)
def htmloptionstext(nameval):
return '''
<%s> Full Screen (Esc key to exit)</input><%s><br>
<%s> Draw slightly transparent bubbles</input><%s><br>
''' % (nameval("checkbox", "fullscreen", "yes", default="no"),
nameval("hidden", "fullscreen", "no"),
nameval("checkbox", "transparency", "yes", default="yes"),
nameval("hidden", "transparency", "no"))

View File

@ -1,7 +1,7 @@
import sys
import wingame
from modes import BaseDisplay
from cStringIO import StringIO
from .modes import BaseDisplay
from io import StringIO
class Display(BaseDisplay):

23
display/dpy_windows.py.bak Executable file
View File

@ -0,0 +1,23 @@
import sys
import wingame
from modes import BaseDisplay
from cStringIO import StringIO
class Display(BaseDisplay):
def __init__(self, width, height, title):
self.xdpy = xdpy = wingame.Display(width, height)
xdpy.settitle(title)
self.pixmap = xdpy.pixmap
self.getppm = xdpy.getppm
self.putppm = xdpy.putppm
self.close = xdpy.close
self.clear = xdpy.clear
self.flip = xdpy.flip
self.keyevents = xdpy.keyevents
self.mouseevents = xdpy.mouseevents
self.pointermotion = xdpy.pointermotion
def selectlist(self):
return []

View File

@ -1,7 +1,7 @@
import sys
import xshm
from modes import BaseDisplay
from cStringIO import StringIO
from .modes import BaseDisplay
from io import StringIO
class Display(BaseDisplay):
@ -20,9 +20,8 @@ class Display(BaseDisplay):
self.mouseevents = xdpy.mouseevents
self.pointermotion = xdpy.pointermotion
if use_shm and not xdpy.shmmode():
print >> sys.stderr, \
"Note: cannot use SHM extension (%dx%d), display will be slow." % \
(width, height)
print("Note: cannot use SHM extension (%dx%d), display will be slow." % \
(width, height), file=sys.stderr)
def selectlist(self):
if hasattr(self.xdpy, 'fd'):

40
display/dpy_x.py.bak Normal file
View File

@ -0,0 +1,40 @@
import sys
import xshm
from modes import BaseDisplay
from cStringIO import StringIO
class Display(BaseDisplay):
def __init__(self, width, height, title, shm='yes'):
use_shm = not shm.startswith('n')
self.xdpy = xdpy = xshm.Display(width, height, use_shm)
self.pixmap = xdpy.pixmap
self.getppm = xdpy.getppm
self.putppm = xdpy.putppm
self.overlayppm = xdpy.overlayppm
self.close = xdpy.close
self.clear = xdpy.clear
self.flip = xdpy.flip
self.keyevents = xdpy.keyevents
self.mouseevents = xdpy.mouseevents
self.pointermotion = xdpy.pointermotion
if use_shm and not xdpy.shmmode():
print >> sys.stderr, \
"Note: cannot use SHM extension (%dx%d), display will be slow." % \
(width, height)
def selectlist(self):
if hasattr(self.xdpy, 'fd'):
from socket import fromfd, AF_INET, SOCK_STREAM
return [fromfd(self.xdpy.fd(), AF_INET, SOCK_STREAM)]
else:
return []
def htmloptionstext(nameval):
return '''
<%s> Use the shared memory extension</input><%s><br>
<font size=-1>Note: Disable it for remote connections or old X servers</font>
''' % (nameval("checkbox", "shm", "yes", default="yes"),
nameval("hidden", "shm", "no"))

View File

@ -7,7 +7,8 @@ KeyReleased = 3
class BaseDisplay:
__taskbkgnd = None
def taskbar(self, (x, y, w, h)):
def taskbar(self, xxx_todo_changeme):
(x, y, w, h) = xxx_todo_changeme
if self.__taskbkgnd is None:
pixel = "\x00\x00\x80"
hole = "\x01\x01\x01"
@ -56,22 +57,22 @@ class Mode:
state = ' [%s]' % err
else:
state = ''
print >> f, ' %-8s %s%s' % (self.name, self.descr, state)
print(' %-8s %s%s' % (self.name, self.descr, state), file=f)
if self.url:
print >> f, ' %s' % self.url
print(' %s' % self.url, file=f)
for line in self.extraoptsdescr:
print >> f, ' %s' % line
print(' %s' % line, file=f)
def getformaloptions(self):
return '', [c+'=' for c in self.options.keys()]
return '', [c+'=' for c in list(self.options.keys())]
def setoptions(self, options):
for key in self.options.keys():
if options.has_key('--'+key):
for key in list(self.options.keys()):
if '--'+key in options:
self.options[key] = options['--'+key]
def currentdriver(self):
lst = self.options.items()
lst = list(self.options.items())
lst.sort()
lst = ['--%s=%s' % keyvalue for keyvalue in lst]
return ' '.join([self.name] + lst)
@ -142,22 +143,22 @@ def findmode(name, lst):
return info
if last_chance is not None:
return last_chance
raise KeyError, 'no driver available!'
raise KeyError('no driver available!')
else:
# find mode by name
for info in lst:
if info.name.upper() == name.upper():
err = info.imperror()
if err:
raise KeyError, '%s: %s' % (info.name, err)
raise KeyError('%s: %s' % (info.name, err))
return info
raise KeyError, '%s: no such driver' % name
raise KeyError('%s: no such driver' % name)
def findmode_err(*args):
try:
return findmode(*args)
except KeyError, e:
print >> sys.stderr, str(e)
except KeyError as e:
print(str(e), file=sys.stderr)
sys.exit(1)
def open_dpy(mode, width, height, title):
@ -165,7 +166,7 @@ def open_dpy(mode, width, height, title):
ginfo = findmode_err(driver, graphicmodeslist())
ginfo.setoptions(extraopts)
dpy = ginfo.getmodule().Display(width, height, title, **ginfo.options)
print 'graphics driver:', ginfo.currentdriver()
print('graphics driver:', ginfo.currentdriver())
return dpy
def open_snd(mode):
@ -179,7 +180,7 @@ def open_snd(mode):
if (sinfo.options['music'].startswith('n') or
sinfo.options['music'] == 'off'):
snd.has_music = 0
print 'sound driver:', sinfo.currentdriver()
print('sound driver:', sinfo.currentdriver())
return snd
else:
return None

192
display/modes.py.bak Normal file
View File

@ -0,0 +1,192 @@
import sys
KeyPressed = 2
KeyReleased = 3
class BaseDisplay:
__taskbkgnd = None
def taskbar(self, (x, y, w, h)):
if self.__taskbkgnd is None:
pixel = "\x00\x00\x80"
hole = "\x01\x01\x01"
self.__taskbkgnd = self.pixmap(32, 32,
((pixel+hole)*16 + (hole+pixel)*16) * 16, 0x010101)
for j in range(y, y+h, 32):
for i in range(x, x+w, 32):
self.putppm(i, j, self.__taskbkgnd,
(0, 0, x+w-i, y+h-j))
class Mode:
low_priority = 0
def __init__(self, name, descr, extraoptsdescr,
options={}, url=None):
self.name = name
self.descr = descr
self.extraoptsdescr = extraoptsdescr
self.options = options.copy()
self.url = url
def getmodule(self):
return __import__(self.prefix + self.name.lower(), globals(),
locals(), ['available'])
def imperror(self):
try:
return self.__imperror
except AttributeError:
try:
module = self.getmodule()
except ImportError:
result = 'not installed'
else:
result = hasattr(module, 'imperror') and module.imperror()
self.__imperror = result
return result
def unique_id(self):
return self.prefix + self.name
def printline(self, f):
err = self.imperror()
if err:
state = ' [%s]' % err
else:
state = ''
print >> f, ' %-8s %s%s' % (self.name, self.descr, state)
if self.url:
print >> f, ' %s' % self.url
for line in self.extraoptsdescr:
print >> f, ' %s' % line
def getformaloptions(self):
return '', [c+'=' for c in self.options.keys()]
def setoptions(self, options):
for key in self.options.keys():
if options.has_key('--'+key):
self.options[key] = options['--'+key]
def currentdriver(self):
lst = self.options.items()
lst.sort()
lst = ['--%s=%s' % keyvalue for keyvalue in lst]
return ' '.join([self.name] + lst)
def htmloptionstext(self, *args):
if self.imperror():
return None
module = self.getmodule()
return (hasattr(module, 'htmloptionstext') and
module.htmloptionstext(*args))
class GraphicMode(Mode):
prefix = 'dpy_'
class SoundMode(Mode):
prefix = 'snd_'
def graphicmodeslist():
return [
GraphicMode('X', 'XWindow (Linux/Unix)',
['--shm=yes use the Shared Memory extension (default)',
'--shm=no disable it (for remote connections or old X servers)',
],
{'shm': 'yes'}),
GraphicMode('windows', 'MS Windows', []),
GraphicMode('pygame', 'PyGame library (all platforms)',
['--fullscreen=yes go full screen (Esc key to exit)',
'--transparency=yes slightly transparent bubbles (default)',
'--transparency=no disable it (a bit faster)'],
{'transparency': 'yes', 'fullscreen': 'no'},
url='http://www.pygame.org'),
GraphicMode('gtk', 'PyGTK (Gnome)',
['--zoom=xxx% scale image by xxx %'],
{'zoom': '100'},
url='http://www.pygtk.org/'),
]
def soundmodeslist():
return [
SoundMode('pygame', 'PyGame library mixer (all platforms)',
[], url='http://www.pygame.org'),
SoundMode('linux', 'audio mixer for Linux',
['--freq=# mixer frequency (default 44100)',
'--fmt=# data format (default S16_NE, --fmt=list for a list)'],
{'freq': '44100', 'fmt': 'S16_NE'}),
SoundMode('windows', 'audio mixer for Windows',
['--freq=# mixer frequency (default 44100)',
'--bits=# bits per sample (8 or default 16)'],
{'freq': '44100', 'bits': '16'}),
SoundMode('off', 'no sounds', []),
]
def findmode(name, lst):
if name is None:
# find the first installed mode
last_chance = None
for info in lst:
err = info.imperror()
if err:
continue
if info.low_priority:
if last_chance is None:
last_chance = info
else:
return info
if last_chance is not None:
return last_chance
raise KeyError, 'no driver available!'
else:
# find mode by name
for info in lst:
if info.name.upper() == name.upper():
err = info.imperror()
if err:
raise KeyError, '%s: %s' % (info.name, err)
return info
raise KeyError, '%s: no such driver' % name
def findmode_err(*args):
try:
return findmode(*args)
except KeyError, e:
print >> sys.stderr, str(e)
sys.exit(1)
def open_dpy(mode, width, height, title):
driver, sound, extraopts = mode
ginfo = findmode_err(driver, graphicmodeslist())
ginfo.setoptions(extraopts)
dpy = ginfo.getmodule().Display(width, height, title, **ginfo.options)
print 'graphics driver:', ginfo.currentdriver()
return dpy
def open_snd(mode):
driver, sound, extraopts = mode
sinfo = findmode_err(sound, soundmodeslist())
sinfo.setoptions(extraopts)
snd = sinfo.getmodule().Sound(**sinfo.options)
if snd.has_sound:
sinfo.options['music'] = 'yes'
sinfo.setoptions(extraopts)
if (sinfo.options['music'].startswith('n') or
sinfo.options['music'] == 'off'):
snd.has_music = 0
print 'sound driver:', sinfo.currentdriver()
return snd
else:
return None
def musichtmloptiontext(nameval):
return '''<font size=-1>
<%s> Background music</input><%s>
</font>''' % (nameval("checkbox", "music", "yes", default="yes", mangling=0),
nameval("hidden", "music", "no", mangling=0))

View File

@ -8,9 +8,9 @@ import time
from common.msgstruct import *
from common.pixmap import decodepixmap
from common import hostchooser
import modes
from modes import KeyPressed, KeyReleased
import caching
from . import modes
from .modes import KeyPressed, KeyReleased
from . import caching
#import psyco; psyco.full()
@ -44,13 +44,13 @@ class Icon:
self.rect = None
return self.pixmap
elif attr in ('bmpcode', 'rect'):
raise KeyError, attr
raise KeyError(attr)
elif attr == 'originalrect':
self.originalrect = self.rect
return self.originalrect
raise AttributeError, attr
raise AttributeError(attr)
def clear(self):
if self.__dict__.has_key('pixmap'):
if 'pixmap' in self.__dict__:
del self.pixmap
class DataChunk(caching.Data):
@ -77,7 +77,7 @@ class DataChunk(caching.Data):
DataChunk.TOTAL += lendata
total = DataChunk.TOTAL >> 10
if total != prev:
print "downloaded %dkb of data from server" % total
print("downloaded %dkb of data from server" % total)
self.store(position, data)
try:
self.pending.remove((0, position))
@ -104,24 +104,24 @@ class Playfield:
self.sockaddr = sockaddr
try:
self.s.setsockopt(SOL_IP, IP_TOS, 0x10) # IPTOS_LOWDELAY
except error, e:
print >> sys.stderr, "Cannot set IPTOS_LOWDELAY:", str(e)
except error as e:
print("Cannot set IPTOS_LOWDELAY:", str(e), file=sys.stderr)
try:
self.s.setsockopt(SOL_TCP, TCP_NODELAY, 1)
except error, e:
print >> sys.stderr, "Cannot set TCP_NODELAY:", str(e)
except error as e:
print("Cannot set TCP_NODELAY:", str(e), file=sys.stderr)
initialbuf = ""
while 1:
t = self.s.recv(200)
if not t and not hasattr(self.s, 'RECV_CAN_RETURN_EMPTY'):
raise error, "connexion closed"
raise error("connexion closed")
initialbuf += t
if len(initialbuf) >= len(MSG_WELCOME):
head = initialbuf[:len(MSG_WELCOME)]
tail = initialbuf[len(MSG_WELCOME):]
if head != MSG_WELCOME:
raise error, "connected to something not a game server"
raise error("connected to something not a game server")
if '\n' in tail:
break
n = tail.index('\n')
@ -135,7 +135,7 @@ class Playfield:
## if i >= 0:
## self.gameident, self.datapath = (self.gameident[:i].strip(),
## self.gameident[i+1:-1])
print "connected to %r." % self.gameident
print("connected to %r." % self.gameident)
self.s.sendall(message(CMSG_PROTO_VERSION, 3))
def setup(self, mode, udp_over_tcp):
@ -156,10 +156,10 @@ class Playfield:
self.playericons = {}
self.screenmode = mode
self.initlevel = 0
if mode[-1].has_key('udp_over_tcp'):
if 'udp_over_tcp' in mode[-1]:
udp_over_tcp = mode[-1]['udp_over_tcp']
self.trackcfgmtime = None
if mode[-1].has_key('cfgfile'):
if 'cfgfile' in mode[-1]:
self.trackcfgfile = mode[-1]['cfgfile']
else:
self.trackcfgfile = os.path.join(DataChunk.SOURCEDIR,
@ -217,8 +217,8 @@ class Playfield:
while self.udpsock in iwtd:
try:
udpdata = self.udpsock.recv(65535)
except error, e:
print >> sys.stderr, e
except error as e:
print(e, file=sys.stderr)
errors += 1
if errors > 10:
raise
@ -420,9 +420,9 @@ class Playfield:
t = time.time()
t, t0 = t-t0, t
if t:
print "%.2f images per second, %.1f kbytes per second" % (
print("%.2f images per second, %.1f kbytes per second" % (
float(n)/t,
float(self.tcpbytecounter+self.udpbytecounter)/1024/t)
float(self.tcpbytecounter+self.udpbytecounter)/1024/t))
self.tcpbytecounter = -self.udpbytecounter
n = 0
self.painttimes = t0, n
@ -432,7 +432,7 @@ class Playfield:
iconlist = []
f = 1.5 * time.time()
f = f-int(f)
pi = self.playericons.items()
pi = list(self.playericons.items())
pi.sort()
xpos = 0
for id, ico in pi:
@ -460,7 +460,8 @@ class Playfield:
self.animdelay = 0.04
return y0, iconlist
def clic_taskbar(self, (cx,cy)):
def clic_taskbar(self, xxx_todo_changeme):
(cx,cy) = xxx_todo_changeme
y0, icons = self.get_taskbar()
if cy >= y0:
for x, y, ico, id in icons:
@ -480,13 +481,14 @@ class Playfield:
pass
return y0, bkgnd
def erase_taskbar(self, (y0, bkgnd)):
def erase_taskbar(self, xxx_todo_changeme1):
(y0, bkgnd) = xxx_todo_changeme1
self.dpy.putppm(0, y0, bkgnd)
def nextkeyname(self):
pid, df = self.keydefinition
undef = [(num, keyname) for keyname, (num, icons) in self.keys.items()
if not df.has_key(keyname) and icons]
undef = [(num, keyname) for keyname, (num, icons) in list(self.keys.items())
if keyname not in df and icons]
if undef:
num, keyname = min(undef)
return keyname
@ -556,7 +558,7 @@ class Playfield:
pending = {}
for keysym, event in keyevents:
pending[keysym] = event
for keysym, event in pending.items():
for keysym, event in list(pending.items()):
code = self.keycodes.get((keysym, event))
if code and self.playing.get(code[0]) == 'l':
if (code == self.last_key_event[0] and
@ -588,7 +590,7 @@ class Playfield:
self.taskbartimeout = None
if self.taskbarfree:
self.taskbarmode = (nmode or
'l' not in self.playing.values() or
'l' not in list(self.playing.values()) or
(self.keydefinition is not None))
if nmode:
self.taskbartimeout = time.time() + 5.0
@ -597,26 +599,26 @@ class Playfield:
def define_key(self, keysym):
clic_id, df = self.keydefinition
if keysym in df.values():
if keysym in list(df.values()):
return
df[self.nextkeyname()] = keysym
if self.nextkeyname() is not None:
return
self.keydefinition = None
self.s.sendall(message(CMSG_ADD_PLAYER, clic_id))
for keyname, (num, icons) in self.keys.items():
for keyname, (num, icons) in list(self.keys.items()):
if keyname[:1] == '-':
event = KeyReleased
keyname = keyname[1:]
else:
event = KeyPressed
if df.has_key(keyname):
if keyname in df:
keysym = df[keyname]
self.keycodes[keysym, event] = \
clic_id, message(CMSG_KEY, clic_id, num)
def msg_unknown(self, *rest):
print >> sys.stderr, "?"
print("?", file=sys.stderr)
def msg_player_join(self, id, local, *rest):
if local:
@ -628,7 +630,7 @@ class Playfield:
def msg_player_kill(self, id, *rest):
self.playing[id] = 0
for key, (pid, msg) in self.keycodes.items():
for key, (pid, msg) in list(self.keycodes.items()):
if pid == id:
del self.keycodes[key]
@ -651,8 +653,8 @@ class Playfield:
self.udpsock2 = socket(AF_INET, SOCK_DGRAM)
self.udpsock2.bind(('', port))
self.udpsock2.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
except error, e:
print "Cannot listen on the broadcast port %d" % port, str(e)
except error as e:
print("Cannot listen on the broadcast port %d" % port, str(e))
self.udpsock2 = None
else:
self.iwtd.append(self.udpsock2)
@ -664,7 +666,7 @@ class Playfield:
# self.snd.close()
if self.dpy is not None:
# clear all pixmaps
for ico in self.icons.values():
for ico in list(self.icons.values()):
ico.clear()
self.pixmaps.clear()
self.dpy.close()
@ -726,7 +728,7 @@ class Playfield:
f.when_ready(ready)
def msg_patch_file(self, fileid, position, data, lendata=None, *rest):
if self.fileids.has_key(fileid):
if fileid in self.fileids:
f = self.fileids[fileid]
else:
f = self.fileids[fileid] = DataChunk(fileid)
@ -737,7 +739,7 @@ class Playfield:
self.msg_patch_file(fileid, position, data1, len(data), *rest)
def msg_md5_file(self, fileid, filename, position, length, checksum, *rest):
if self.fileids.has_key(fileid):
if fileid in self.fileids:
f = self.fileids[fileid]
else:
f = self.fileids[fileid] = DataChunk(fileid)
@ -777,13 +779,13 @@ class Playfield:
f.close()
d = eval(data or '{}', {}, {})
except:
print >> sys.stderr, 'Invalid config file format'
print('Invalid config file format', file=sys.stderr)
else:
d = d.get(gethostname(), {})
namemsg = ''
for id, local in self.playing.items():
for id, local in list(self.playing.items()):
keyid = 'player%d' % id
if local == 'l' and d.has_key(keyid):
if local == 'l' and keyid in d:
namemsg = namemsg + message(
CMSG_PLAYER_NAME, id, d[keyid])
if namemsg:
@ -803,9 +805,9 @@ class Playfield:
self.udpsock_low += 1
if self.udpsock_low >= 3 and self.initlevel >= 1:
# third time now -- that's too much
print "Note: routing UDP traffic over TCP",
print("Note: routing UDP traffic over TCP", end=' ')
inp = self.udpbytecounter / (udpkbytes*1024.0)
print "(%d%% packet loss)" % int(100*(1.0-inp))
print("(%d%% packet loss)" % int(100*(1.0-inp)))
self.start_udp_over_tcp()
self.s.sendall(message(CMSG_UDP_PORT, MSG_INLINE_FRAME))
else:

860
display/pclient.py.bak Normal file
View File

@ -0,0 +1,860 @@
#! /usr/bin/env python
import sys, os
from socket import *
from select import select
import struct, zlib
import time
from common.msgstruct import *
from common.pixmap import decodepixmap
from common import hostchooser
import modes
from modes import KeyPressed, KeyReleased
import caching
#import psyco; psyco.full()
# switch to udp_over_tcp if the udp socket didn't receive at least 60% of
# the packets sent by the server
UDP_EXPECTED_RATIO = 0.60
def loadpixmap(dpy, data, colorkey=None):
w, h, data = decodepixmap(data)
if colorkey is None:
colorkey = -1
elif colorkey < 0:
r, g, b = struct.unpack("BBB", self.data[:3])
colorkey = b | (g<<8) | (r<<16)
return dpy.pixmap(w, h, data, colorkey)
class Icon:
alpha = 255
def __init__(self, playfield):
self.playfield = playfield
self.size = 0, 0
def __getattr__(self, attr):
if attr == 'pixmap':
self.pixmap = self.playfield.getpixmap(self.bmpcode)
if hasattr(self.playfield.dpy, 'getopticon'):
ico = self.playfield.dpy.getopticon(
self.pixmap, self.originalrect, self.alpha)
if ico is not None:
self.pixmap = ico
self.rect = None
return self.pixmap
elif attr in ('bmpcode', 'rect'):
raise KeyError, attr
elif attr == 'originalrect':
self.originalrect = self.rect
return self.originalrect
raise AttributeError, attr
def clear(self):
if self.__dict__.has_key('pixmap'):
del self.pixmap
class DataChunk(caching.Data):
SOURCEDIR = os.path.abspath(os.path.join(os.path.dirname(caching.__file__),
os.pardir))
CACHEDIR = os.path.join(SOURCEDIR, 'cache')
TOTAL = 0
def __init__(self, fileid):
caching.Data.__init__(self)
self.fileid = fileid
self.pending = []
self.progresshook = None
def server_md5(self, playfield, filename, position, length, checksum):
if not self.loadfrom(filename, position, length, checksum):
self.pending.append((0, position))
playfield.s.sendall(message(CMSG_DATA_REQUEST, self.fileid,
position, length))
def server_patch(self, position, data, lendata):
#print 'server_patch', self.fileid, position, len(data)
prev = DataChunk.TOTAL >> 10
DataChunk.TOTAL += lendata
total = DataChunk.TOTAL >> 10
if total != prev:
print "downloaded %dkb of data from server" % total
self.store(position, data)
try:
self.pending.remove((0, position))
except ValueError:
pass
else:
while self.pending and self.pending[0][0]:
callback = self.pending[0][1]
del self.pending[0]
callback(self)
def when_ready(self, callback):
if self.pending:
self.pending.append((1, callback))
else:
callback(self)
class Playfield:
TASKBAR_HEIGHT = 48
def __init__(self, s, sockaddr):
self.s = s
self.sockaddr = sockaddr
try:
self.s.setsockopt(SOL_IP, IP_TOS, 0x10) # IPTOS_LOWDELAY
except error, e:
print >> sys.stderr, "Cannot set IPTOS_LOWDELAY:", str(e)
try:
self.s.setsockopt(SOL_TCP, TCP_NODELAY, 1)
except error, e:
print >> sys.stderr, "Cannot set TCP_NODELAY:", str(e)
initialbuf = ""
while 1:
t = self.s.recv(200)
if not t and not hasattr(self.s, 'RECV_CAN_RETURN_EMPTY'):
raise error, "connexion closed"
initialbuf += t
if len(initialbuf) >= len(MSG_WELCOME):
head = initialbuf[:len(MSG_WELCOME)]
tail = initialbuf[len(MSG_WELCOME):]
if head != MSG_WELCOME:
raise error, "connected to something not a game server"
if '\n' in tail:
break
n = tail.index('\n')
line2 = tail[:n]
self.initialbuf = tail[n+1:]
self.gameident = line2.strip()
## self.datapath = None
## if self.gameident.endswith(']'):
## i = self.gameident.rfind('[')
## if i >= 0:
## self.gameident, self.datapath = (self.gameident[:i].strip(),
## self.gameident[i+1:-1])
print "connected to %r." % self.gameident
self.s.sendall(message(CMSG_PROTO_VERSION, 3))
def setup(self, mode, udp_over_tcp):
self.playing = {} # 0, 1, or 'l' for local
self.keys = {}
self.keycodes = {}
self.last_key_event = (None, None)
self.dpy = None
self.snd = None
self.pixmaps = {} # {bmpcode: dpy_pixmap}
self.bitmaps = {} # {bmpcode: (fileid_or_data, colorkey)}
self.icons = {}
self.sounds = {}
self.currentmusic = None
self.fileids = {}
self.sprites = []
self.playingsounds = {}
self.playericons = {}
self.screenmode = mode
self.initlevel = 0
if mode[-1].has_key('udp_over_tcp'):
udp_over_tcp = mode[-1]['udp_over_tcp']
self.trackcfgmtime = None
if mode[-1].has_key('cfgfile'):
self.trackcfgfile = mode[-1]['cfgfile']
else:
self.trackcfgfile = os.path.join(DataChunk.SOURCEDIR,
'http2', 'config.txt')
self.udpsock = None
self.udpsock_low = None
self.udpsock2 = None
self.accepted_broadcast = 0
self.tcpbytecounter = 0
self.udpbytecounter = 0
if udp_over_tcp == 1:
self.start_udp_over_tcp()
else:
self.pending_udp_data = None
if udp_over_tcp == 'auto':
self.udpsock_low = 0
self.dyndecompress = [[None, None, None, None] for i in range(8)]
self.dynnorepeat = None
def run(self, mode, udp_over_tcp='auto'):
self.setup(mode, udp_over_tcp)
try:
self.mainloop()
finally:
if self.dpy:
self.dpy.close()
try:
self.s.close()
except:
pass
def mainloop(self):
pss = hostchooser.serverside_ping()
self.initial_iwtd = [self.s, pss]
self.iwtd = self.initial_iwtd[:]
self.animdelay = 0.0
inbuf = self.process_inbuf(self.initialbuf)
self.initialbuf = ""
errors = 0
while 1:
if self.dpy:
self.processkeys()
iwtd, owtd, ewtd = select(self.iwtd, [], [], self.animdelay)
self.animdelay = 0.5
if self.dpy:
self.processkeys()
if self.s in iwtd:
inputdata = self.s.recv(0x6000)
self.tcpbytecounter += len(inputdata)
inbuf += inputdata
inbuf = self.process_inbuf(inbuf)
if self.dpy:
if self.udpsock in iwtd:
udpdata1 = None
while self.udpsock in iwtd:
try:
udpdata = self.udpsock.recv(65535)
except error, e:
print >> sys.stderr, e
errors += 1
if errors > 10:
raise
break
self.udpbytecounter += len(udpdata)
if len(udpdata) > 3 and '\x80' <= udpdata[0] < '\x90':
udpdata = self.dynamic_decompress(udpdata)
if udpdata is not None:
udpdata1 = udpdata
iwtd, owtd, ewtd = select(self.iwtd, [], [], 0)
if udpdata1 is not None:
self.update_sprites(udpdata1)
if self.udpsock2 in iwtd:
while self.udpsock2 in iwtd:
udpdata = self.udpsock2.recv(65535)
self.udpbytecounter += len(udpdata)
if udpdata == BROADCAST_MESSAGE:
if not self.accepted_broadcast:
self.s.sendall(message(CMSG_UDP_PORT, '*'))
self.accepted_broadcast = 1
#self.udpsock_low = None
udpdata = ''
iwtd, owtd, ewtd = select(self.iwtd, [], [], 0)
if udpdata and self.accepted_broadcast:
self.update_sprites(udpdata)
if self.pending_udp_data:
self.update_sprites(self.pending_udp_data)
self.pending_udp_data = ''
erasetb = self.taskbarmode and self.draw_taskbar()
d = self.dpy.flip()
if d:
self.animdelay = min(self.animdelay, d)
if self.snd:
d = self.snd.flop()
if d:
self.animdelay = min(self.animdelay, d)
if erasetb:
self.erase_taskbar(erasetb)
if pss in iwtd:
hostchooser.answer_ping(pss, self.gameident, self.sockaddr)
def process_inbuf(self, inbuf):
while inbuf:
values, inbuf = decodemessage(inbuf)
if not values:
break # incomplete message
fn = Playfield.MESSAGES.get(values[0], self.msg_unknown)
fn(self, *values[1:])
return inbuf
def dynamic_decompress(self, udpdata):
# Format of a UDP version 3 packet:
# header byte: 0x80 - 0x87 packet from thread 0 - 7
# or 0x88 - 0x8F reset packet from thread 0 - 7
# previous frame in same thread (1 byte)
# frame number (1 byte)
thread = self.dyndecompress[ord(udpdata[0]) & 7]
# thread==[decompress, lastframenumber, recompressed, lastframedata]
prevframe = udpdata[1]
thisframe = udpdata[2]
#print '---'
#for t in self.dyndecompress:
# print repr(t)[:120]
#print
#print `udpdata[:3]`
if udpdata[0] >= '\x88':
# reset
d = zlib.decompressobj().decompress
if prevframe != thisframe: # if not global sync point
# sync point from a previous frame
# find all threads with the same prevframe
threads = [t for t in self.dyndecompress if prevframe == t[1]]
if not threads:
return None # lost
# find a thread with already-recompressed data
for t in threads:
if t[2]:
data = t[3]
break
else:
# recompress and cache the prevframe data
t = threads[0]
data = t[3]
co = zlib.compressobj(6)
data = co.compress(data) + co.flush(zlib.Z_SYNC_FLUSH)
t[2] = 1
t[3] = data
d(data) # use it to initialize the state of the decompressobj
#print d
thread[0] = d
elif prevframe != thread[1]:
#print 'lost'
return None # lost
else:
d = thread[0]
# go forward in thread
try:
framedata = d(udpdata[3:])
#print d
thread[1] = thisframe
thread[2] = 0
thread[3] = framedata
if thisframe == self.dynnorepeat:
return None
self.dynnorepeat = thisframe
return framedata
except zlib.error:
#print 'crash'
return None
def geticon(self, icocode):
try:
return self.icons[icocode]
except KeyError:
ico = self.icons[icocode] = Icon(self)
return ico
def getpixmap(self, bmpcode):
try:
return self.pixmaps[bmpcode]
except KeyError:
data, colorkey = self.bitmaps[bmpcode]
if type(data) is type(''):
data = zlib.decompress(data)
else:
if data.pending:
raise KeyError
data = data.read()
pixmap = loadpixmap(self.dpy, data, colorkey)
self.pixmaps[bmpcode] = pixmap
return pixmap
def update_sprites(self, udpdata):
sprites = self.sprites
unpack = struct.unpack
currentsounds = {}
base = 0
while udpdata[base+4:base+6] == '\xFF\xFF':
key, lvol, rvol = struct.unpack("!hBB", udpdata[base:base+4])
try:
snd = self.sounds[key]
except KeyError:
pass # ignore sounds with bad code (probably not defined yet)
else:
n = self.playingsounds.get(key)
if n:
currentsounds[key] = n-1
elif self.snd:
self.snd.play(snd,
lvol / 255.0,
rvol / 255.0)
currentsounds[key] = 4
base += 6
self.playingsounds = currentsounds
for j in range(len(sprites)):
if sprites[j][0] != udpdata[base:base+6]:
removes = sprites[j:]
del sprites[j:]
removes.reverse()
eraser = self.dpy.putppm
for reserved, eraseargs in removes:
eraser(*eraseargs)
break
base += 6
#print "%d sprites redrawn" % (len(udpdata)/6-j)
try:
overlayer = self.dpy.overlayppm
except AttributeError:
getter = self.dpy.getppm
setter = self.dpy.putppm
for j in range(base, len(udpdata)-5, 6):
info = udpdata[j:j+6]
x, y, icocode = unpack("!hhh", info[:6])
try:
ico = self.icons[icocode]
sprites.append((info, (x, y, getter((x, y) + ico.size))))
setter(x, y, ico.pixmap, ico.rect)
except KeyError:
#print "bad ico code", icocode
pass # ignore sprites with bad ico (probably not defined yet)
else:
for j in range(base, len(udpdata)-5, 6):
info = udpdata[j:j+6]
x, y, icocode = unpack("!hhh", info[:6])
try:
ico = self.icons[icocode]
overlay = overlayer(x, y, ico.pixmap, ico.rect, ico.alpha)
sprites.append((info, overlay))
except KeyError:
#print "bad ico code", icocode
pass # ignore sprites with bad ico (probably not defined yet)
t0, n = self.painttimes
n = n + 1
if n == 50:
t = time.time()
t, t0 = t-t0, t
if t:
print "%.2f images per second, %.1f kbytes per second" % (
float(n)/t,
float(self.tcpbytecounter+self.udpbytecounter)/1024/t)
self.tcpbytecounter = -self.udpbytecounter
n = 0
self.painttimes = t0, n
def get_taskbar(self):
y0 = self.height - self.TASKBAR_HEIGHT
iconlist = []
f = 1.5 * time.time()
f = f-int(f)
pi = self.playericons.items()
pi.sort()
xpos = 0
for id, ico in pi:
if self.playing.get(id) != 'l':
w, h = ico.size
xpos += int(w * 5 / 3)
if not self.playing.get(id):
y = self.height - h
if self.keydefinition and id == self.keydefinition[0]:
num, icons = self.keys[self.nextkeyname()]
ico = icons[int(f*len(icons))-1]
y = y0 + int((self.TASKBAR_HEIGHT-ico.size[1])/2)
self.animdelay = 0.04
iconlist.append((xpos-w, y, ico, id))
pi.reverse()
f = f * (1.0-f) * 4.0
xpos = self.width
for id, ico in pi:
if self.playing.get(id) == 'l':
w, h = ico.size
xpos -= int(w * 5 / 3)
dy = self.TASKBAR_HEIGHT - h - 1
y = self.height - h - int(dy*f)
iconlist.append((xpos, y, ico, id))
self.animdelay = 0.04
return y0, iconlist
def clic_taskbar(self, (cx,cy)):
y0, icons = self.get_taskbar()
if cy >= y0:
for x, y, ico, id in icons:
if x <= cx < x+ico.size[0]:
return id
return None
def draw_taskbar(self):
y0, icons = self.get_taskbar()
rect = (0, y0, self.width, self.TASKBAR_HEIGHT)
bkgnd = self.dpy.getppm(rect)
self.dpy.taskbar(rect)
for x, y, ico, id in icons:
try:
self.dpy.putppm(x, y, ico.pixmap, ico.rect)
except KeyError:
pass
return y0, bkgnd
def erase_taskbar(self, (y0, bkgnd)):
self.dpy.putppm(0, y0, bkgnd)
def nextkeyname(self):
pid, df = self.keydefinition
undef = [(num, keyname) for keyname, (num, icons) in self.keys.items()
if not df.has_key(keyname) and icons]
if undef:
num, keyname = min(undef)
return keyname
else:
return None
def startplaying(self):
args = ()
if hasattr(self.s, 'udp_over_udp_mixer'):
# for SocketOverUdp: reuse the UDP address
port = self.s.getsockname()[1]
self.udpsock_low = None
self.s.udp_over_udp_decoder = self.udp_over_udp_decoder
self.start_udp_over_tcp()
elif self.pending_udp_data is not None:
port = MSG_INLINE_FRAME
else:
if '*udpsock*' in PORTS:
self.udpsock, (host, port) = PORTS['*udpsock*']
args = (host,)
else:
self.udpsock = socket(AF_INET, SOCK_DGRAM)
self.udpsock.bind(('', PORTS.get('CLIENT', INADDR_ANY)))
host, port = self.udpsock.getsockname()
# Send a dummy UDP message to the server. Some NATs will
# then let through the UDP messages from the server.
self.udpsock.sendto('.', self.s.getpeername())
self.iwtd.append(self.udpsock)
self.initial_iwtd.append(self.udpsock)
if 'sendudpto' in PORTS:
args = (PORTS['sendudpto'],)
outbound = []
outbound.append(message(CMSG_UDP_PORT, port, *args))
if self.snd and self.snd.has_music:
outbound.append(message(CMSG_ENABLE_MUSIC, 1))
outbound.append(message(CMSG_PING))
self.s.sendall(''.join(outbound))
def start_udp_over_tcp(self):
self.pending_udp_data = ''
self.udp_over_tcp_decompress = zlib.decompressobj().decompress
self.udpsock_low = None
for name in ('udpsock', 'udpsock2'):
sock = getattr(self, name)
if sock is not None:
try:
self.iwtd.remove(sock)
except ValueError:
pass
try:
self.initial_iwtd.remove(sock)
except ValueError:
pass
sock.close()
setattr(self, name, None)
def udp_over_udp_decoder(self, udpdata):
if len(udpdata) > 3 and '\x80' <= udpdata[0] < '\x90':
data = self.dynamic_decompress(udpdata)
if data:
self.pending_udp_data = data
def processkeys(self):
keyevents = self.dpy.keyevents()
if keyevents:
now = time.time()
pending = {}
for keysym, event in keyevents:
pending[keysym] = event
for keysym, event in pending.items():
code = self.keycodes.get((keysym, event))
if code and self.playing.get(code[0]) == 'l':
if (code == self.last_key_event[0] and
now - self.last_key_event[1] < 0.77):
continue # don't send too much events for auto-repeat
self.last_key_event = code, now
self.s.sendall(code[1])
elif self.keydefinition:
self.define_key(keysym)
pointermotion = self.dpy.pointermotion()
if pointermotion:
x, y = pointermotion
self.settaskbar(y >= self.height - 2*self.TASKBAR_HEIGHT)
mouseevents = self.dpy.mouseevents()
if mouseevents:
self.settaskbar(1)
self.keydefinition = None
for clic in mouseevents:
clic_id = self.clic_taskbar(clic)
if clic_id is not None:
if self.playing.get(clic_id) == 'l':
self.s.sendall(message(CMSG_REMOVE_PLAYER, clic_id))
else:
self.keydefinition = clic_id, {}
if self.taskbartimeout is not None and time.time() > self.taskbartimeout:
self.settaskbar(0)
def settaskbar(self, nmode):
self.taskbartimeout = None
if self.taskbarfree:
self.taskbarmode = (nmode or
'l' not in self.playing.values() or
(self.keydefinition is not None))
if nmode:
self.taskbartimeout = time.time() + 5.0
if hasattr(self.dpy, 'settaskbar'):
self.dpy.settaskbar(self.taskbarmode)
def define_key(self, keysym):
clic_id, df = self.keydefinition
if keysym in df.values():
return
df[self.nextkeyname()] = keysym
if self.nextkeyname() is not None:
return
self.keydefinition = None
self.s.sendall(message(CMSG_ADD_PLAYER, clic_id))
for keyname, (num, icons) in self.keys.items():
if keyname[:1] == '-':
event = KeyReleased
keyname = keyname[1:]
else:
event = KeyPressed
if df.has_key(keyname):
keysym = df[keyname]
self.keycodes[keysym, event] = \
clic_id, message(CMSG_KEY, clic_id, num)
def msg_unknown(self, *rest):
print >> sys.stderr, "?"
def msg_player_join(self, id, local, *rest):
if local:
self.playing[id] = 'l'
self.settaskbar(0)
self.checkcfgfile(1)
else:
self.playing[id] = 1
def msg_player_kill(self, id, *rest):
self.playing[id] = 0
for key, (pid, msg) in self.keycodes.items():
if pid == id:
del self.keycodes[key]
def msg_broadcast_port(self, port):
if self.pending_udp_data is not None:
return
if self.udpsock2 is not None:
try:
self.iwtd.remove(self.udpsock2)
except ValueError:
pass
try:
self.initial_iwtd.remove(self.udpsock2)
except ValueError:
pass
self.udpsock2.close()
self.udpsock2 = None
self.accepted_broadcast = 0
try:
self.udpsock2 = socket(AF_INET, SOCK_DGRAM)
self.udpsock2.bind(('', port))
self.udpsock2.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
except error, e:
print "Cannot listen on the broadcast port %d" % port, str(e)
self.udpsock2 = None
else:
self.iwtd.append(self.udpsock2)
self.initial_iwtd.append(self.udpsock2)
def msg_def_playfield(self, width, height, backcolor=None,
gameident=None, *rest):
#if self.snd is not None:
# self.snd.close()
if self.dpy is not None:
# clear all pixmaps
for ico in self.icons.values():
ico.clear()
self.pixmaps.clear()
self.dpy.close()
del self.sprites[:]
self.width = width
self.height = height
if gameident:
self.gameident = gameident
self.dpy = modes.open_dpy(self.screenmode, width, height, self.gameident)
self.snd = self.snd or modes.open_snd(self.screenmode)
if self.snd:
self.s.sendall(message(CMSG_ENABLE_SOUND))
self.iwtd = self.dpy.selectlist() + self.initial_iwtd
self.dpy.clear() # backcolor is ignored
self.painttimes = (time.time(), 0)
self.s.sendall(message(CMSG_PING))
self.taskbarmode = 0
self.taskbarfree = 0
self.taskbartimeout = None
self.keydefinition = None
def msg_def_key(self, name, num, *icons):
self.keys[name] = num, [self.geticon(ico) for ico in icons]
def msg_def_icon(self, bmpcode, icocode, x, y, w, h, alpha=255, *rest):
## if h<0:
## try:
## bitmap, height = self.flippedbitmaps[bmpcode]
## except KeyError:
## bitmap, height = self.dpy.vflipppm(self.bitmaps[bmpcode])
## self.flippedbitmaps[bmpcode] = bitmap, height
## y = height - y
## h = - h
## else:
ico = self.geticon(icocode)
ico.bmpcode = bmpcode
ico.rect = x, y, w, h
ico.size = w, h
if alpha < 255:
ico.alpha = alpha
def msg_def_bitmap(self, bmpcode, data, colorkey=None, *rest):
if type(data) is not type(''):
data = self.fileids[data]
self.bitmaps[bmpcode] = data, colorkey
def msg_def_sample(self, smpcode, data, *rest):
def ready(f, self=self, smpcode=smpcode):
if self.snd:
self.sounds[smpcode] = self.snd.sound(f)
f.clear()
if type(data) is type(''):
data = zlib.decompress(data)
f = DataChunk(None)
f.store(0, data)
ready(f)
else:
f = self.fileids[data]
f.when_ready(ready)
def msg_patch_file(self, fileid, position, data, lendata=None, *rest):
if self.fileids.has_key(fileid):
f = self.fileids[fileid]
else:
f = self.fileids[fileid] = DataChunk(fileid)
f.server_patch(position, data, lendata or len(data))
def msg_zpatch_file(self, fileid, position, data, *rest):
data1 = zlib.decompress(data)
self.msg_patch_file(fileid, position, data1, len(data), *rest)
def msg_md5_file(self, fileid, filename, position, length, checksum, *rest):
if self.fileids.has_key(fileid):
f = self.fileids[fileid]
else:
f = self.fileids[fileid] = DataChunk(fileid)
f.server_md5(self, filename, position, length, checksum)
def msg_play_music(self, loop_from, *codes):
codes = [self.fileids[c] for c in codes]
self.currentmusic = loop_from, codes, list(codes)
self.activate_music()
def activate_music(self, f=None):
loop_from, codes, checkcodes = self.currentmusic
if checkcodes:
checkcodes.pop().when_ready(self.activate_music)
elif self.snd:
self.snd.play_musics(codes, loop_from)
def msg_fadeout(self, time, *rest):
if self.snd:
self.snd.fadeout(time)
def msg_player_icon(self, pid, icocode, *rest):
self.playericons[pid] = self.geticon(icocode)
def checkcfgfile(self, force=0):
if self.trackcfgfile:
try:
st = os.stat(self.trackcfgfile)
except OSError:
pass
else:
if force or (st.st_mtime != self.trackcfgmtime):
self.trackcfgmtime = st.st_mtime
try:
f = open(self.trackcfgfile, 'r')
data = f.read().strip()
f.close()
d = eval(data or '{}', {}, {})
except:
print >> sys.stderr, 'Invalid config file format'
else:
d = d.get(gethostname(), {})
namemsg = ''
for id, local in self.playing.items():
keyid = 'player%d' % id
if local == 'l' and d.has_key(keyid):
namemsg = namemsg + message(
CMSG_PLAYER_NAME, id, d[keyid])
if namemsg:
self.s.sendall(namemsg)
def msg_ping(self, *rest):
self.s.sendall(message(CMSG_PONG, *rest))
self.checkcfgfile()
if rest and self.udpsock_low is not None:
udpkbytes = rest[0]
if not udpkbytes:
return
#inp = self.udpbytecounter / (udpkbytes*1024.0)
#print "(%d%% packet loss)" % int(100*(1.0-inp))
if (udpkbytes<<10) * UDP_EXPECTED_RATIO > self.udpbytecounter:
# too many packets were dropped (including, maybe, all of them)
self.udpsock_low += 1
if self.udpsock_low >= 3 and self.initlevel >= 1:
# third time now -- that's too much
print "Note: routing UDP traffic over TCP",
inp = self.udpbytecounter / (udpkbytes*1024.0)
print "(%d%% packet loss)" % int(100*(1.0-inp))
self.start_udp_over_tcp()
self.s.sendall(message(CMSG_UDP_PORT, MSG_INLINE_FRAME))
else:
# enough packets received
self.udpsock_low = 0
def msg_pong(self, *rest):
if self.initlevel == 0:
self.startplaying()
self.initlevel = 1
elif self.initlevel == 1:
if self.snd and self.snd.has_music:
self.s.sendall(message(CMSG_ENABLE_MUSIC, 2))
self.initlevel = 2
if not self.taskbarfree and not self.taskbarmode:
self.taskbarfree = 1
self.settaskbar(1)
def msg_inline_frame(self, data, *rest):
if self.pending_udp_data is not None:
self.pending_udp_data = self.udp_over_tcp_decompress(data)
MESSAGES = {
MSG_BROADCAST_PORT:msg_broadcast_port,
MSG_DEF_PLAYFIELD: msg_def_playfield,
MSG_DEF_KEY : msg_def_key,
MSG_DEF_ICON : msg_def_icon,
MSG_DEF_BITMAP : msg_def_bitmap,
MSG_DEF_SAMPLE : msg_def_sample,
MSG_PLAY_MUSIC : msg_play_music,
MSG_FADEOUT : msg_fadeout,
MSG_PLAYER_JOIN : msg_player_join,
MSG_PLAYER_KILL : msg_player_kill,
MSG_PLAYER_ICON : msg_player_icon,
MSG_PING : msg_ping,
MSG_PONG : msg_pong,
MSG_INLINE_FRAME : msg_inline_frame,
MSG_PATCH_FILE : msg_patch_file,
MSG_ZPATCH_FILE : msg_zpatch_file,
MSG_MD5_FILE : msg_md5_file,
## MSG_LOAD_PREFIX : msg_load_prefix,
}
def run(s, sockaddr, *args, **kw):
try:
import psyco
except ImportError:
pass
else:
psyco.bind(Playfield.update_sprites)
Playfield(s, sockaddr).run(*args, **kw)

View File

@ -3,13 +3,13 @@
import sys, os, gzip
from socket import *
from select import select
import cStringIO, struct, zlib
import io, struct, zlib
import time
sys.path.insert(0, os.pardir)
from common.msgstruct import *
from common import hostchooser
import modes
from modes import KeyPressed, KeyReleased
from . import modes
from .modes import KeyPressed, KeyReleased
#import psyco; psyco.full()
@ -17,7 +17,7 @@ SOURCEDIR = os.pardir
def loadpixmap(dpy, data, colorkey=None):
f = cStringIO.StringIO(data)
f = io.StringIO(data)
sig = f.readline().strip()
assert sig == "P6"
while 1:
@ -25,7 +25,7 @@ def loadpixmap(dpy, data, colorkey=None):
if not line.startswith('#'):
break
wh = line.split()
w, h = map(int, wh)
w, h = list(map(int, wh))
sig = f.readline().strip()
assert sig == "255"
data = f.read()
@ -38,7 +38,8 @@ def loadpixmap(dpy, data, colorkey=None):
return dpy.pixmap(w, h, data, colorkey)
class Icon:
def __init__(self, bitmap, (x, y, w, h), alpha):
def __init__(self, bitmap, xxx_todo_changeme, alpha):
(x, y, w, h) = xxx_todo_changeme
self.rect = x, y, w, h
self.size = w, h
self.bitmap = bitmap
@ -70,7 +71,7 @@ class Playback:
#print values[0],
fn = Playback.MESSAGES.get(values[0], self.msg_unknown)
fn(self, *values[1:])
print '%d frames in file.' % len(self.frames)
print('%d frames in file.' % len(self.frames))
f.close()
assert self.width, "no playfield definition found in file"
@ -83,13 +84,13 @@ class Playback:
def buildicons(self):
bitmaps = {}
for bmpcode, (data, colorkey) in self.defbitmaps.items():
for bmpcode, (data, colorkey) in list(self.defbitmaps.items()):
if isinstance(data, str):
data = zlib.decompress(data)
else:
data = self.deffiles[data]
bitmaps[bmpcode] = loadpixmap(self.dpy, data, colorkey)
for icocode, (bmpcode, rect, alpha) in self.deficons.items():
for icocode, (bmpcode, rect, alpha) in list(self.deficons.items()):
self.icons[icocode] = Icon(bitmaps[bmpcode], rect, alpha)
def go(self, n):
@ -101,9 +102,9 @@ class Playback:
"shm only!"
w, h, data, reserved = self.dpy.getppm((0, 0, self.width, self.height))
f = open(filename or ('frame%d.ppm' % self.n), 'wb')
print >> f, 'P6'
print >> f, w, h
print >> f, 255
print('P6', file=f)
print(w, h, file=f)
print(255, file=f)
for i in range(0, len(data), 4):
f.write(data[i+2]+data[i+1]+data[i])
f.close()

203
display/playback.py.bak Normal file
View File

@ -0,0 +1,203 @@
#! /usr/bin/env python
import sys, os, gzip
from socket import *
from select import select
import cStringIO, struct, zlib
import time
sys.path.insert(0, os.pardir)
from common.msgstruct import *
from common import hostchooser
import modes
from modes import KeyPressed, KeyReleased
#import psyco; psyco.full()
SOURCEDIR = os.pardir
def loadpixmap(dpy, data, colorkey=None):
f = cStringIO.StringIO(data)
sig = f.readline().strip()
assert sig == "P6"
while 1:
line = f.readline().strip()
if not line.startswith('#'):
break
wh = line.split()
w, h = map(int, wh)
sig = f.readline().strip()
assert sig == "255"
data = f.read()
f.close()
if colorkey is None:
colorkey = -1
elif colorkey < 0:
r, g, b = struct.unpack("BBB", self.data[:3])
colorkey = b | (g<<8) | (r<<16)
return dpy.pixmap(w, h, data, colorkey)
class Icon:
def __init__(self, bitmap, (x, y, w, h), alpha):
self.rect = x, y, w, h
self.size = w, h
self.bitmap = bitmap
self.alpha = alpha
class Playback:
gameident = 'Playback'
def __init__(self, filename, mode=('x', 'off', {})):
f = gzip.open(filename, 'rb')
self.screenmode = mode
self.width = None
self.deffiles = {}
self.defbitmaps = {}
self.deficons = {}
self.icons = {}
self.frames = []
inbuf = ''
while 1:
values, inbuf = decodemessage(inbuf)
if not values:
# incomplete message
data = f.read(8192)
if not data:
break
inbuf += data
else:
#print values[0],
fn = Playback.MESSAGES.get(values[0], self.msg_unknown)
fn(self, *values[1:])
print '%d frames in file.' % len(self.frames)
f.close()
assert self.width, "no playfield definition found in file"
self.dpy = modes.open_dpy(self.screenmode,
self.width, self.height, self.gameident)
self.dpy.clear() # backcolor is ignored
self.sprites = []
self.buildicons()
self.go(0)
def buildicons(self):
bitmaps = {}
for bmpcode, (data, colorkey) in self.defbitmaps.items():
if isinstance(data, str):
data = zlib.decompress(data)
else:
data = self.deffiles[data]
bitmaps[bmpcode] = loadpixmap(self.dpy, data, colorkey)
for icocode, (bmpcode, rect, alpha) in self.deficons.items():
self.icons[icocode] = Icon(bitmaps[bmpcode], rect, alpha)
def go(self, n):
self.n = n
self.update_sprites(self.frames[n])
self.dpy.flip()
def save(self, filename=None):
"shm only!"
w, h, data, reserved = self.dpy.getppm((0, 0, self.width, self.height))
f = open(filename or ('frame%d.ppm' % self.n), 'wb')
print >> f, 'P6'
print >> f, w, h
print >> f, 255
for i in range(0, len(data), 4):
f.write(data[i+2]+data[i+1]+data[i])
f.close()
def update_sprites(self, udpdata):
sprites = self.sprites
unpack = struct.unpack
base = 0
for j in range(len(sprites)):
if sprites[j][0] != udpdata[base:base+6]:
removes = sprites[j:]
del sprites[j:]
removes.reverse()
eraser = self.dpy.putppm
for reserved, eraseargs in removes:
eraser(*eraseargs)
break
base += 6
try:
overlayer = self.dpy.overlayppm
except AttributeError:
getter = self.dpy.getppm
setter = self.dpy.putppm
#print "%d sprites redrawn" % (len(udpdata)/6-j)
for j in range(base, len(udpdata)-5, 6):
info = udpdata[j:j+6]
x, y, icocode = unpack("!hhh", info[:6])
try:
ico = self.icons[icocode]
sprites.append((info, (x, y, getter((x, y) + ico.size))))
setter(x, y, ico.bitmap, ico.rect)
except KeyError:
#print "bad ico code", icocode
pass # ignore sprites with bad ico (probably not defined yet)
else:
for j in range(base, len(udpdata)-5, 6):
info = udpdata[j:j+6]
x, y, icocode = unpack("!hhh", info[:6])
try:
ico = self.icons[icocode]
overlay = overlayer(x, y, ico.bitmap, ico.rect, ico.alpha)
sprites.append((info, overlay))
except KeyError:
#print "bad ico code", icocode
pass # ignore sprites with bad ico (probably not defined yet)
def msg_unknown(self, *rest):
pass
def msg_patch_file(self, fileid, position, data, lendata=None, *rest):
try:
s = self.deffiles[fileid]
except KeyError:
s = ''
if len(s) < position:
s += '\x00' * (position-len(s))
s = s[:position] + data + s[position+len(s):]
self.deffiles[fileid] = s
def msg_zpatch_file(self, fileid, position, data, *rest):
data1 = zlib.decompress(data)
self.msg_patch_file(fileid, position, data1, len(data), *rest)
def msg_md5_file(self, fileid, filename, position, length, checksum, *rest):
fn = os.path.join(SOURCEDIR, filename)
f = open(fn, 'rb')
f.seek(position)
data = f.read(length)
f.close()
assert len(data) == length
self.msg_patch_file(fileid, position, data)
def msg_def_playfield(self, width, height, *rest):
self.width, self.height = width, height
def msg_def_icon(self, bmpcode, icocode, x, y, w, h, alpha=255, *rest):
self.deficons[icocode] = bmpcode, (x, y, w, h), alpha
def msg_def_bitmap(self, bmpcode, data, colorkey=None, *rest):
self.defbitmaps[bmpcode] = data, colorkey
def msg_recorded(self, data):
self.frames.append(data)
MESSAGES = {
MSG_PATCH_FILE : msg_patch_file,
MSG_ZPATCH_FILE : msg_zpatch_file,
MSG_MD5_FILE : msg_md5_file,
MSG_DEF_PLAYFIELD: msg_def_playfield,
MSG_DEF_ICON : msg_def_icon,
MSG_DEF_BITMAP : msg_def_bitmap,
MSG_RECORDED : msg_recorded,
}
if __name__ == '__main__' and len(sys.argv) > 1:
p = Playback(sys.argv[1])

View File

@ -64,7 +64,7 @@ class PureMixer:
byteorder = self.byteorder
# done
if (freq, bytes, signed, channels, byteorder) != self.parameters:
raise ValueError, 'sound sample conversion failed'
raise ValueError('sound sample conversion failed')
return data
def wavesample(self, file):
@ -87,7 +87,7 @@ class PureMixer:
channels = mixer_channels[:]
channels.reverse()
for c in channels:
if already_seen.has_key(c):
if c in already_seen:
data1 = ''
else:
data1 = c.read(bufsize)
@ -114,10 +114,10 @@ def byteswap(data, byte):
elif byte == 4:
typecode = 'i'
else:
raise ValueError, 'cannot convert endianness for samples of %d bytes' % byte
raise ValueError('cannot convert endianness for samples of %d bytes' % byte)
import array
a = array.array(typecode, data)
if a.itemsize != byte:
raise ValueError, 'endianness convertion failed'
raise ValueError('endianness convertion failed')
a.byteswap()
return a.tostring()

123
display/puremixer.py.bak Normal file
View File

@ -0,0 +1,123 @@
import sys, audioop
class PureMixer:
#
# An audio mixer in Python based on audioop
#
# Note that opening the audio device itself is outside the scope of
# this module. Anything else could also be done with the mixed data,
# e.g. stored on disk, for all this module knows.
def __init__(self, freq=44100, bits=8, signed=0,
channels=1, byteorder=None):
"""Open the mixer and set its parameters."""
self.freq = freq
self.bytes = bits/8
self.signed = signed
self.channels = channels
self.byteorder = byteorder or sys.byteorder
self.parameters = (freq, self.bytes, signed, channels, self.byteorder)
self.bytespersample = channels*self.bytes
self.queue = '\x00' * self.bytes
def resample(self, data, freq=44100, bits=8, signed=0,
channels=1, byteorder=None):
"Convert a sample to the mixer's own format."
bytes = bits/8
byteorder = byteorder or sys.byteorder
if (freq, bytes, signed, channels, byteorder) == self.parameters:
return data
# convert to native endianness
if byteorder != sys.byteorder:
data = byteswap(data, bytes)
byteorder = sys.byteorder
# convert unsigned -> signed for the next operations
if not signed:
data = audioop.bias(data, bytes, -(1<<(bytes*8-1)))
signed = 1
# convert stereo -> mono
while channels > self.channels:
assert channels % 2 == 0
data = audioop.tomono(data, bytes, 0.5, 0.5)
channels /= 2
# resample to self.freq
if freq != self.freq:
data, ignored = audioop.ratecv(data, bytes, channels,
freq, self.freq, None)
freq = self.freq
# convert between 8bits and 16bits
if bytes != self.bytes:
data = audioop.lin2lin(data, bytes, self.bytes)
bytes = self.bytes
# convert mono -> stereo
while channels < self.channels:
data = audioop.tostereo(data, bytes, 1.0, 1.0)
channels *= 2
# convert signed -> unsigned
if not self.signed:
data = audioop.bias(data, bytes, 1<<(bytes*8-1))
signed = 0
# convert to mixer endianness
if byteorder != self.byteorder:
data = byteswap(data, bytes)
byteorder = self.byteorder
# done
if (freq, bytes, signed, channels, byteorder) != self.parameters:
raise ValueError, 'sound sample conversion failed'
return data
def wavesample(self, file):
"Read a sample from a .wav file (or file-like object)."
import wave
w = wave.open(file, 'r')
return self.resample(w.readframes(w.getnframes()),
freq = w.getframerate(),
bits = w.getsampwidth() * 8,
signed = w.getsampwidth() > 1,
channels = w.getnchannels(),
byteorder = 'little')
def mix(self, mixer_channels, bufsize):
"""Mix the next batch buffer.
Each object in the mixer_channels list must be a file-like object
with a 'read(size)' method."""
data = ''
already_seen = {}
channels = mixer_channels[:]
channels.reverse()
for c in channels:
if already_seen.has_key(c):
data1 = ''
else:
data1 = c.read(bufsize)
already_seen[c] = 1
if data1:
l = min(len(data), len(data1))
data = (audioop.add(data[:l], data1[:l], 1) +
(data1[l:] or data[l:]))
else:
try:
mixer_channels.remove(c)
except ValueError:
pass
data += self.queue * ((bufsize - len(data)) / self.bytes)
self.queue = data[-self.bytes:]
return data
def byteswap(data, byte):
if byte == 1:
return
if byte == 2:
typecode = 'h'
elif byte == 4:
typecode = 'i'
else:
raise ValueError, 'cannot convert endianness for samples of %d bytes' % byte
import array
a = array.array(typecode, data)
if a.itemsize != byte:
raise ValueError, 'endianness convertion failed'
a.byteswap()
return a.tostring()

View File

@ -51,7 +51,7 @@ class Display:
0x010101)
def pixmap(self, w, h, data, colorkey=-1):
print >> sys.stderr, '.',
print('.', end=' ', file=sys.stderr)
extent = w*h
depth = self.depth
if depth >= 24:
@ -72,7 +72,7 @@ class Display:
elif depth == 24 or depth == 32:
p_size = 8, 8, 8
else:
raise ValueError, 'unsupported screen depth %d' % depth
raise ValueError('unsupported screen depth %d' % depth)
imgdata = []
maskdata = []
@ -82,9 +82,9 @@ class Display:
while plane >= (1<<(8-p_size[color])):
src = 0
for y in range(h):
imgline = 0L
maskline = 0L
shifter = 1L
imgline = 0
maskline = 0
shifter = 1
for x in range(w):
if data[src:src+3] == key:
# transparent
@ -111,7 +111,8 @@ class Display:
image.size = w, h
return image
def getppm(self, (x, y, w, h), bkgnd=None):
def getppm(self, xxx_todo_changeme, bkgnd=None):
(x, y, w, h) = xxx_todo_changeme
if bkgnd is None:
bkgnd = self.win.create_pixmap(w, h, self.depth)
bkgnd.mask = None
@ -191,7 +192,8 @@ class Display:
from socket import fromfd, AF_INET, SOCK_STREAM
return [fromfd(self.dpy.fileno(), AF_INET, SOCK_STREAM)]
def taskbar(self, (x, y, w, h)):
def taskbar(self, xxx_todo_changeme1):
(x, y, w, h) = xxx_todo_changeme1
for j in range(y, y+h, 32):
for i in range(x, x+w, 32):
self.putppm(i, j, self.taskbkgnd,

View File

@ -0,0 +1,202 @@
################################################
## pygame-based implementation of xshm ##
################################################
import os, sys
from Xlib import X, display
# -*-*- SLOOWWW -*-*-
import psyco; psyco.full()
class Display:
def __init__(self, width, height, title):
self.dpy = display.Display()
self.default_scr = self.dpy.screen()
self.root = self.default_scr.root
self.width = width
self.height = height
self.depth = self.default_scr.root_depth
self.backpixmap = self.root.create_pixmap(width, height, self.depth)
self.win = self.root.create_window(
0, 0, width, height, 0, self.depth,
override_redirec = 0,
background_pixel = self.default_scr.black_pixel,
backing_store = X.NotUseful,
)
self.win.map()
self.gc = self.win.create_gc()
self.gc_and = self.win.create_gc()
self.gc_or = self.win.create_gc()
self.gc.change(foreground = self.default_scr.black_pixel)
self.gc_and.change(function = X.GXand)
self.gc_or .change(function = X.GXor)
self.selectinput = 0
self.keyev = []
self.mouseev = []
self.motionev = None
self.dpy.flush()
pixel = "\x00\x00\x80"
hole = "\x01\x01\x01"
self.taskbkgnd = self.pixmap(32, 32,
((pixel+hole)*16 + (hole+pixel)*16) * 16,
0x010101)
def pixmap(self, w, h, data, colorkey=-1):
print >> sys.stderr, '.',
extent = w*h
depth = self.depth
if depth >= 24:
bitmap_pad = 32
else:
bitmap_pad = 16
scanline = ((w+bitmap_pad-1) & ~(bitmap_pad-1)) / 8;
if colorkey >= 0:
key = (chr(colorkey >> 16) +
chr((colorkey>>8) & 0xFF) +
chr(colorkey & 0xFF))
else:
key = None
if depth == 15:
p_size = 5, 5, 5
elif depth == 16:
p_size = 5, 6, 5
elif depth == 24 or depth == 32:
p_size = 8, 8, 8
else:
raise ValueError, 'unsupported screen depth %d' % depth
imgdata = []
maskdata = []
for color in range(3):
plane = 128
while plane >= (1<<(8-p_size[color])):
src = 0
for y in range(h):
imgline = 0L
maskline = 0L
shifter = 1L
for x in range(w):
if data[src:src+3] == key:
# transparent
maskline |= shifter
elif ord(data[src+color]) & plane:
imgline |= shifter
shifter <<= 1
src += 3
imgdata.append(long2string(imgline, scanline))
maskdata.append(long2string(maskline, scanline))
plane /= 2
imgdata = ''.join(imgdata)
if colorkey >= 0:
maskdata = ''.join(maskdata)
mask = self.win.create_pixmap(w, h, depth)
mask.put_image(self.gc, 0, 0, w, h, X.XYPixmap, depth, 0, maskdata)
else:
mask = None
imgdata = ''.join(imgdata)
image = self.win.create_pixmap(w, h, depth)
image.put_image(self.gc, 0, 0, w, h, X.XYPixmap, depth, 0, imgdata)
image.mask = mask
image.size = w, h
return image
def getppm(self, (x, y, w, h), bkgnd=None):
if bkgnd is None:
bkgnd = self.win.create_pixmap(w, h, self.depth)
bkgnd.mask = None
bkgnd.size = w, h
bkgnd.copy_area(self.gc, self.backpixmap, x, y, w, h, 0, 0)
return bkgnd
def putppm(self, x, y, image, rect=None):
if rect:
x1, y1, w1, h1 = rect
else:
x1 = y1 = 0
w1, h1 = image.size
if image.mask is None:
self.backpixmap.copy_area(self.gc, image, x1, y1, w1, h1, x, y)
else:
self.backpixmap.copy_area(self.gc_and, image.mask,
x1, y1, w1, h1, x, y)
self.backpixmap.copy_area(self.gc_or, image,
x1, y1, w1, h1, x, y)
def flip(self):
self.win.copy_area(self.gc, self.backpixmap,
0, 0, self.width, self.height, 0, 0)
self.dpy.flush()
self.readXevents()
def close(self):
self.dpy.close()
def clear(self):
self.backpixmap.fill_rectangle(self.gc, 0, 0, self.width, self.height)
def readXevents(self):
n = self.dpy.pending_events()
if n:
for i in range(n):
event = self.dpy.next_event()
if event.type == X.KeyPress or event.type == X.KeyRelease:
self.keyev.append((event.detail, event.type))
elif event.type == X.ButtonPress:
self.mouseev.append((event.event_x, event.event_y))
elif event.type == X.MotionNotify:
self.motionev = event.event_x, event.event_y
elif event.type == X.DestroyNotify:
raise SystemExit
self.readXevents()
def enable_event(self, mask):
self.selectinput |= mask
self.win.change_attributes(event_mask=self.selectinput)
def keyevents(self):
if not (self.selectinput & X.KeyReleaseMask):
self.enable_event(X.KeyPressMask | X.KeyReleaseMask)
self.readXevents()
result = self.keyev
self.keyev = []
return result
def mouseevents(self):
if not (self.selectinput & X.ButtonPressMask):
self.enable_event(X.ButtonPressMask)
result = self.mouseev
self.mouseev = []
return result
def pointermotion(self):
result = self.motionev
self.motionev = None
return result
def has_sound(self):
return 0
def selectlist(self):
from socket import fromfd, AF_INET, SOCK_STREAM
return [fromfd(self.dpy.fileno(), AF_INET, SOCK_STREAM)]
def taskbar(self, (x, y, w, h)):
for j in range(y, y+h, 32):
for i in range(x, x+w, 32):
self.putppm(i, j, self.taskbkgnd,
(0, 0, x+w-i, y+h-j))
def long2string(bits, strlen):
return ''.join([chr((bits>>n)&0xFF) for n in range(0, 8*strlen, 8)])

View File

@ -1,7 +1,7 @@
import sys
from cStringIO import StringIO
import puremixer
from music1 import Music
from io import StringIO
from . import puremixer
from .music1 import Music
class Sound:
@ -30,10 +30,10 @@ class Sound:
if name == self.format:
break
else:
print >> sys.stderr, 'available sound formats:'
print('available sound formats:', file=sys.stderr)
for name, bits, signed, byteorder in self.Formats:
print >> sys.stderr, ' %-8s %s' % (name, nicefmttext(
bits, signed, byteorder))
print(' %-8s %s' % (name, nicefmttext(
bits, signed, byteorder)), file=sys.stderr)
sys.exit(2)
import linuxaudiodev
@ -41,9 +41,9 @@ class Sound:
f = linuxaudiodev.open('w')
f.setparameters(self.freq, p['bits'], 1,
getattr(linuxaudiodev, 'AFMT_' + self.format))
except Exception, e:
print >> sys.stderr, "sound disabled: %s: %s" % (
e.__class__.__name__, e)
except Exception as e:
print("sound disabled: %s: %s" % (
e.__class__.__name__, e), file=sys.stderr)
return
self.f = f
self.mixer = mixer = puremixer.PureMixer(**p)
@ -136,7 +136,7 @@ def nicefmttext(bits, signed, byteorder):
return s
def htmloptionstext(nameval):
import modes
from . import modes
l = ['<font size=-1>Sampling <%s>' % nameval('select', 'fmt')]
for name, bits, signed, byteorder in Sound.Formats:
l.append('<'+nameval('option', 'fmt', name, default='S16_NE')+'>'+

148
display/snd_linux.py.bak Normal file
View File

@ -0,0 +1,148 @@
import sys
from cStringIO import StringIO
import puremixer
from music1 import Music
class Sound:
# Mono only
has_sound = has_music = 0 # until initialized
BUFFERTIME = 0.09
FLOPTIME = 0.07
Formats = [
('U8', 8, 0, None),
('S8', 8, 1, None),
('S16_NE', 16, 1, None),
('S16_LE', 16, 1, 'little'),
('S16_BE', 16, 1, 'big'),
('U16_LE', 16, 0, 'little'),
('U16_BE', 16, 0, 'big'),
]
def __init__(self, freq=44100, fmt='S16_NE'):
self.f = None
self.freq = int(freq)
self.format = fmt.upper()
self.params = p = {}
for name, p['bits'], p['signed'], p['byteorder'] in self.Formats:
if name == self.format:
break
else:
print >> sys.stderr, 'available sound formats:'
for name, bits, signed, byteorder in self.Formats:
print >> sys.stderr, ' %-8s %s' % (name, nicefmttext(
bits, signed, byteorder))
sys.exit(2)
import linuxaudiodev
try:
f = linuxaudiodev.open('w')
f.setparameters(self.freq, p['bits'], 1,
getattr(linuxaudiodev, 'AFMT_' + self.format))
except Exception, e:
print >> sys.stderr, "sound disabled: %s: %s" % (
e.__class__.__name__, e)
return
self.f = f
self.mixer = mixer = puremixer.PureMixer(**p)
buffertime = self.BUFFERTIME
self.bufsize = int(mixer.bytespersample*mixer.freq*buffertime +
255.5) & ~ 255
if self.bufsize > f.bufsize():
self.bufsize = f.bufsize()
buffertime = self.bufsize / float(freq)
self.buffertime = buffertime
self.mixer_channels = []
self.mixer_accum = {}
self.has_sound = 1
self.has_music = 1
def close(self):
self.f.close()
self.f = None
def sound(self, f):
return self.mixer.wavesample(f.fopen())
def flop(self):
self.mixer_accum = {}
if self.f is None:
return
for i in range(3):
bufsize = self.bufsize - self.f.obufcount()
if bufsize <= 0:
break
self.f.write(self.mixer.mix(self.mixer_channels, bufsize))
#cnt = getattr(self, 'CNT', 0)
#import time
#print cnt, time.time()
#self.CNT = cnt+1
return self.FLOPTIME
def play(self, sound, lvolume, rvolume):
# volume ignored
if sound not in self.mixer_accum:
self.mixer_channels.append(StringIO(sound))
self.mixer_accum[sound] = 1
def play_musics(self, musics, loop_from):
self.cmusics = musics, loop_from, -1
if self.mixer_channels[:1] != [self]:
self.mixer_channels.insert(0, self)
def read(self, size):
"Provide some more data to self.mixer.poll()."
musics, loop_from, c = self.cmusics
if c < 0:
data = ''
else:
data = musics[c].mixed.decode(self.mixer, size)
if not data:
c += 1
if c >= len(musics): # end
c = loop_from
if c >= len(musics):
return ''
self.cmusics = musics, loop_from, c
try:
mixed = musics[c].mixed
except AttributeError:
mixed = musics[c].mixed = Music(musics[c].freezefilename())
mixed.openchannel()
data = mixed.decode(self.mixer, size)
if 0 < len(data) < size:
data += self.read(size - len(data))
return data
def fadeout(self, millisec):
self.cmusics = [], 0, -1
def imperror():
try:
import linuxaudiodev
except ImportError:
if sys.platform.startswith('linux'):
return 'linuxaudiodev module not installed'
else:
return 'only available on Linux'
def nicefmttext(bits, signed, byteorder):
s = '%s %d bits' % (signed and 'signed' or 'unsigned', bits)
if byteorder:
s += ' %s endian' % byteorder
return s
def htmloptionstext(nameval):
import modes
l = ['<font size=-1>Sampling <%s>' % nameval('select', 'fmt')]
for name, bits, signed, byteorder in Sound.Formats:
l.append('<'+nameval('option', 'fmt', name, default='S16_NE')+'>'+
nicefmttext(bits, signed, byteorder))
l+= ['</select> rate ',
'<%s size=5>Hz</font>' % nameval('text', 'freq', default='44100'),
'<br>',
modes.musichtmloptiontext(nameval)]
return '\n'.join(l)

View File

@ -1,5 +1,5 @@
import sys
from modes import musichtmloptiontext as htmloptionstext
from .modes import musichtmloptiontext as htmloptionstext
from pygame.locals import *
import pygame.mixer
@ -16,8 +16,8 @@ class Sound:
def __init__(self):
try:
pygame.mixer.init()
except pygame.error, e:
print >> sys.stderr, "sound disabled: %s" % str(e)
except pygame.error as e:
print("sound disabled: %s" % str(e), file=sys.stderr)
else:
self.has_sound = 1
try:

82
display/snd_pygame.py.bak Normal file
View File

@ -0,0 +1,82 @@
import sys
from modes import musichtmloptiontext as htmloptionstext
from pygame.locals import *
import pygame.mixer
if pygame.mixer is None:
raise ImportError
#ENDMUSICEVENT = USEREVENT
class Sound:
has_sound = has_music = 0 # until initialized
def __init__(self):
try:
pygame.mixer.init()
except pygame.error, e:
print >> sys.stderr, "sound disabled: %s" % str(e)
else:
self.has_sound = 1
try:
from pygame.mixer import music
except ImportError:
pass
else:
self.has_music = music is not None
self.cmusics = None
def close(self):
try:
pygame.mixer.stop()
except pygame.error:
pass
if self.has_music:
try:
pygame.mixer.music.stop()
except pygame.error:
pass
def sound(self, f):
return pygame.mixer.Sound(f.freezefilename())
def flop(self):
# the events are not processed if pygame is not also the display,
# so ENDMUSICEVENT will not arrive -- poll for end of music
if self.cmusics and not pygame.mixer.music.get_busy():
self.next_music()
def play(self, sound, lvolume, rvolume):
channel = pygame.mixer.find_channel(1)
channel.stop()
try:
channel.set_volume(lvolume, rvolume)
except TypeError:
channel.set_volume(0.5 * (lvolume+rvolume))
channel.play(sound)
def play_musics(self, musics, loop_from):
#dpy_pygame.EVENT_HANDLERS[ENDMUSICEVENT] = self.next_music
#pygame.mixer.music.set_endevent(ENDMUSICEVENT)
self.cmusics = musics, loop_from, 0
self.next_music()
def next_music(self, e=None):
if self.cmusics:
musics, loop_from, c = self.cmusics
if c >= len(musics): # end
c = loop_from
if c >= len(musics):
pygame.mixer.music.stop()
self.cmusics = None
return
pygame.mixer.music.load(musics[c].freezefilename())
pygame.mixer.music.play()
self.cmusics = musics, loop_from, c+1
def fadeout(self, millisec):
#print "fadeout:", millisec
pygame.mixer.music.fadeout(millisec)
self.cmusics = None

View File

@ -1,8 +1,8 @@
import sys
from cStringIO import StringIO
import puremixer
from io import StringIO
from . import puremixer
import wingame
from music1 import Music
from .music1 import Music
class Sound:
@ -19,9 +19,9 @@ class Sound:
try:
self.audio = wingame.Audio(1, self.freq, self.bits, self.bufsize)
except Exception, e:
print >> sys.stderr, "sound disabled: %s: %s" % (
e.__class__.__name__, e)
except Exception as e:
print("sound disabled: %s: %s" % (
e.__class__.__name__, e), file=sys.stderr)
return
self.mixer = puremixer.PureMixer(self.freq, self.bits, self.bits==16,
byteorder='little')
@ -81,7 +81,7 @@ class Sound:
def htmloptionstext(nameval):
import modes
from . import modes
l = ['<font size=-1>Sampling <%s>' % nameval('select', 'bits')]
for bits in (8, 16):
l.append('<'+nameval('option', 'bits', str(bits), default='16')+'>'+

View File

@ -0,0 +1,93 @@
import sys
from cStringIO import StringIO
import puremixer
import wingame
from music1 import Music
class Sound:
# Mono only
has_sound = has_music = 0 # until initialized
BUFFERTIME = 0.09
FLOPTIME = 0.07
def __init__(self, freq=44100, bits=16):
self.freq = int(freq)
self.bits = int(bits)
self.bufsize = (int(self.BUFFERTIME*self.freq*self.bits/8) + 64) & ~63
try:
self.audio = wingame.Audio(1, self.freq, self.bits, self.bufsize)
except Exception, e:
print >> sys.stderr, "sound disabled: %s: %s" % (
e.__class__.__name__, e)
return
self.mixer = puremixer.PureMixer(self.freq, self.bits, self.bits==16,
byteorder='little')
self.mixer_channels = []
self.mixer_accum = {}
self.has_sound = 1
self.has_music = 1
def stop(self):
self.audio.close()
def sound(self, f):
return self.mixer.wavesample(f.fopen())
def flop(self):
self.mixer_accum = {}
while self.audio.ready():
self.audio.write(self.mixer.mix(self.mixer_channels, self.bufsize))
return self.FLOPTIME
def play(self, sound, lvolume, rvolume):
# volume ignored
if sound not in self.mixer_accum:
self.mixer_channels.append(StringIO(sound))
self.mixer_accum[sound] = 1
def play_musics(self, musics, loop_from):
self.cmusics = musics, loop_from, -1
self.mixer_channels.insert(0, self)
def read(self, size):
"Provide some more data to self.mixer.poll()."
musics, loop_from, c = self.cmusics
if c < 0:
data = ''
else:
data = musics[c].mixed.decode(self.mixer, size)
if not data:
c += 1
if c >= len(musics): # end
c = loop_from
if c >= len(musics):
return ''
self.cmusics = musics, loop_from, c
try:
mixed = musics[c].mixed
except AttributeError:
mixed = musics[c].mixed = Music(musics[c].freezefilename())
mixed.openchannel()
data = mixed.decode(self.mixer, size)
if 0 < len(data) < size:
data += self.read(size - len(data))
return data
def fadeout(self, millisec):
self.cmusics = [], 0, -1
def htmloptionstext(nameval):
import modes
l = ['<font size=-1>Sampling <%s>' % nameval('select', 'bits')]
for bits in (8, 16):
l.append('<'+nameval('option', 'bits', str(bits), default='16')+'>'+
'%d bits' % bits)
l+= ['</select> rate ',
'<%s size=5>Hz</font>' % nameval('text', 'freq', default='44100'),
'<br>',
modes.musichtmloptiontext(nameval)]
return '\n'.join(l)

View File

@ -1,5 +1,5 @@
import os, sys, random
from cStringIO import StringIO
from io import StringIO
import socket, time
PLAYERNAMES = ['Bub', 'Bob', 'Boob', 'Beb',
@ -34,7 +34,7 @@ class Options:
if not attr.startswith('_'):
return None
else:
raise AttributeError, attr
raise AttributeError(attr)
class PageServer:
@ -81,8 +81,8 @@ class PageServer:
self.httpport = port = gamesrv.displaysockport(hs)
self.indexurl = 'http://127.0.0.1:%d/%s/' % (port, self.seed)
if self.Game:
print self.Game.FnDesc,
print 'server is ready at', self.indexurl
print(self.Game.FnDesc, end=' ')
print('server is ready at', self.indexurl)
return 1
def getlocalservers(self):
@ -91,8 +91,8 @@ class PageServer:
return self.localservers
def searchlocalservers(self):
servers = hostchooser.find_servers().items()
servers = filter(self.filterserver, servers)
servers = list(hostchooser.find_servers().items())
servers = list(filter(self.filterserver, servers))
servers.sort()
self.localservers = servers
@ -136,7 +136,8 @@ class PageServer:
## self.inetservers[host, port] = info
## #print 'hostchooser:', self.inetserverlist, '->', self.inetservers
def filterserver(self, ((host, port), info)):
def filterserver(self, xxx_todo_changeme):
((host, port), info) = xxx_todo_changeme
for c in host+str(port):
if c not in "-.0123456789:@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_abcdefghijklmnopqrstuvwxyz":
return 0
@ -166,15 +167,15 @@ class PageServer:
data[self.localhost] = self.localoptions.dict()
try:
f = open(self.filename, 'w')
print >> f, `data`
print(repr(data), file=f)
f.close()
except IOError, e:
print >> sys.stderr, "! Cannot save config file: " + str(e)
except IOError as e:
print("! Cannot save config file: " + str(e), file=sys.stderr)
def reloadports(self):
import msgstruct
msgstruct.PORTS.clear()
for key, value in self.localoptions.dict().items():
for key, value in list(self.localoptions.dict().items()):
if key.startswith('port_'):
key = key[5:]
if key == 'CLIENT' and type(value) == str and ':' in value:
@ -230,7 +231,7 @@ class PageServer:
def indexloader(self, headers, cheat=[], **options):
if cheat:
import __builtin__
import builtins
for c in cheat:
getattr(__builtin__, '__cheat')(c)
else:
@ -241,7 +242,7 @@ class PageServer:
host = headers['remote host']
host = socket.gethostbyname(host)
if host != '127.0.0.1':
raise HTTPRequestError, "Access denied"
raise HTTPRequestError("Access denied")
return None, self.indexurl
## def listloader(self, headers, s=[], **options):
@ -257,7 +258,7 @@ class PageServer:
def newloader(self, headers, **options):
if not self.Game:
raise HTTPRequestError, "Complete bub-n-bros installation needed"
raise HTTPRequestError("Complete bub-n-bros installation needed")
locals = {
'Game': self.Game,
'options': self.globaloptions,
@ -269,7 +270,7 @@ class PageServer:
def runloader(self, headers, **options):
self.globaloptions.metapublish = 'n'
self.globaloptions.autoreset = 'n'
for key, value in options.items():
for key, value in list(options.items()):
if len(value) == 1:
setattr(self.globaloptions, key, value[0])
self.saveoptions()
@ -327,9 +328,9 @@ class PageServer:
httpport = int(httpport[0])
except (ValueError, IndexError):
if port:
raise HTTPRequestError, "This server is not running HTTP."
raise HTTPRequestError("This server is not running HTTP.")
else:
raise HTTPRequestError, "Sorry, I cannot connect the Java applet to a server using this field."
raise HTTPRequestError("Sorry, I cannot connect the Java applet to a server using this field.")
return None, 'http://%s:%s/' % (host, httpport)
# now is a good time to generate the color files if we can
@ -337,7 +338,7 @@ class PageServer:
'buildcolors.py')
if os.path.exists(file):
g = {'__name__': '__auto__', '__file__': file}
execfile(file, g)
exec(compile(open(file, "rb").read(), file, 'exec'), g)
if port:
address = '%s:%s' % (host, port)
@ -370,7 +371,7 @@ class PageServer:
self.localoptions.port_CLIENT = None
self.localoptions.port_LISTEN = None
self.localoptions.port_HTTP = None
for key, value in options.items():
for key, value in list(options.items()):
setattr(self.localoptions, key, value[0])
self.saveoptions()
locals = {
@ -451,8 +452,8 @@ class PageServer:
except KeyError:
try:
mode = display.modes.findmode(None, lst)
except KeyError, e:
print >> sys.stderr, str(e) # no mode!
except KeyError as e:
print(str(e), file=sys.stderr) # no mode!
mode = None
currentmodes.append(mode)
return currentmodes
@ -462,10 +463,10 @@ class PageServer:
if dpy.getmodule() is None:
return None # redirect to the Java applet
if dpy is None or snd is None:
raise HTTPRequestError, "No installed graphics or sounds drivers. See the settings page."
raise HTTPRequestError("No installed graphics or sounds drivers. See the settings page.")
options = self.localoptions
result = ['--cfg='+no_quote_worries(self.filename)]
for key, value in options.dict().items():
for key, value in list(options.dict().items()):
if key.startswith('port_') and value:
result.append('--port')
result.append('%s=%s' % (key[5:], value))
@ -476,7 +477,7 @@ class PageServer:
('--sound', snd)]:
result.append(optname + '=' + mode.name)
uid = mode.unique_id() + '_'
for key, value in options.dict().items():
for key, value in list(options.dict().items()):
if key.startswith(uid):
result.append('--%s=%s' % (key[len(uid):], value))
return result
@ -574,7 +575,7 @@ def main(Game, save_url_to=None, quiet=0):
srv = PageServer(Game)
srv.registerpages()
if not srv.opensocket():
print >> sys.stderr, "server aborted."
print("server aborted.", file=sys.stderr)
sys.exit(1)
if quiet:
if Game:
@ -582,7 +583,7 @@ def main(Game, save_url_to=None, quiet=0):
import stdlog
f = stdlog.LogFile()
if f:
print "Logging to", f.filename
print("Logging to", f.filename)
sys.stdout = sys.stderr = f
if save_url_to:
data = srv.indexurl + '\n'
@ -595,7 +596,7 @@ def main(Game, save_url_to=None, quiet=0):
atexit.register(try_to_unlink, save_url_to)
try:
fno = os.open(save_url_to, os.O_CREAT | os.O_TRUNC | os.O_WRONLY,
0600)
0o600)
if os.write(fno, data) != len(data):
raise OSError
os.close(fno)
@ -619,17 +620,17 @@ def schedule_launch(args):
def launch(args):
# platform-specific hacks
print 'Running client -> ', ' '.join(args)
print('Running client -> ', ' '.join(args))
if 0: # OLD CODE sys.platform == 'darwin': # must start as a UI process
import tempfile
cmdname = tempfile.mktemp('_BubBob.py')
f = open(cmdname, 'w')
print >> f, 'import sys, os'
print >> f, 'try: os.unlink(%r)' % cmdname
print >> f, 'except OSError: pass'
print >> f, 'sys.argv[:] = %r' % (args,)
print >> f, '__file__ = %r' % cmdname
print >> f, 'execfile(%r)' % args[0]
print('import sys, os', file=f)
print('try: os.unlink(%r)' % cmdname, file=f)
print('except OSError: pass', file=f)
print('sys.argv[:] = %r' % (args,), file=f)
print('__file__ = %r' % cmdname, file=f)
print('execfile(%r)' % args[0], file=f)
f.close()
os.system('/usr/bin/open -a PythonLauncher "%s"' % cmdname)
else:
@ -692,14 +693,14 @@ else:
assert s[len(absroot)] == os.sep
relpath = s[len(absroot)+1:]
result = os.path.join(ROOTDIR, relpath)
print "no_quote_worries %r => %r" % (s, result)
print("no_quote_worries %r => %r" % (s, result))
return result
if __name__ == '__main__':
if (len(sys.argv) != 3 or sys.argv[1] != '--quiet' or
not sys.argv[2].startswith('--saveurlto=')):
print >> sys.stderr, "This script should only be launched by BubBob.py."
print("This script should only be launched by BubBob.py.", file=sys.stderr)
sys.exit(2)
main(None, sys.argv[2][len('--saveurlto='):], quiet=1)
gamesrv.mainloop()

Some files were not shown because too many files have changed in this diff Show More