pythonverse

Python-based client for OpenVerse with extra features
git clone https://code.literati.org/pythonverse.git
Log | Files | Refs | README | LICENSE

commit fbd0d682907cf7ec02c8e7d9b69836a73eb77a55
parent 98994749589045d00246cf1459c70e9bc2bece6f
Author: renze <renze>
Date:   Sun, 20 Jan 2002 08:21:57 +0000

Implemented exits (including the ORT) and graphical URL links (they probably still need tweaking). Some bug fixes also.

Diffstat:
MOpenVerse.py | 9+++++++++
Mpvui_pygame.py | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 142 insertions(+), 11 deletions(-)

diff --git a/OpenVerse.py b/OpenVerse.py @@ -162,6 +162,9 @@ class ServerConnection(transutil.Connection): '(\S+) (\d+) (\d+) (\S+) (-?\d+) (-?\d+) (\d+) (-?\d+) (-?\d+)', (str, int, int, str, int, int, int, int, int)), ('NOMORE', self.cmd_NOMORE, '(\S+)', (str,)), + ('EXIT_OBJ', self.cmd_EXIT_OBJ, + '(\S+) (-?\d+) (-?\d+) (-?\d+) (-?\d+) (\d+) (\S+) (\d+)', + (str, int, int, int, int, int, str, int)), ('DCCGETAV', self.cmd_DCCGET, '(\d+) (\S+) (\d+)', (int, str, int)), ('DCCGETROOM', self.cmd_DCCGET, '(\d+) (\S+) (\d+)', @@ -340,6 +343,9 @@ class ServerConnection(transutil.Connection): def whois(self, nick): self.write('WHOIS %s\r\n' % nick) + def whichmouseover(self, name): + self.client.setmouseover(name) + # Command handlers def cmd_ABOVE(self, name): @@ -397,6 +403,9 @@ class ServerConnection(transutil.Connection): def cmd_NOMORE(self, nick): self.client.del_avatar(nick) + def cmd_EXIT_OBJ(self, name, x1, y1, x2, y2, duration, host, port): + self.client.exit_obj(name, duration, host, port) + def cmd_DCCGET(self, port, filename, size): DCCGet(self.host, port, filename, size, self.progress_callback, self.image_callback) diff --git a/pvui_pygame.py b/pvui_pygame.py @@ -19,7 +19,7 @@ # # vim:syntax=python -import sys, bisect, string +import sys, bisect, string, random, webbrowser import pygame, pygame.font, pygame.image, pygame.time, pygame.draw from math import * from pygame.locals import * @@ -255,15 +255,19 @@ class ClampingSprite(Sprite): class Mouseover(Sprite): mouseme = 1 - def __init__(self, pos, image1, image2): + def __init__(self, server, name, pos, image1, image2): Sprite.__init__(self, pos, image1) + self.server = server + self.name = name self.image1 = image1 self.image2 = image2 def mouseon(self): + self.server.whichmouseover(self.name) # for EXIT_OBJs return [self.set_image(self.image2)] def mouseoff(self): + self.server.whichmouseover('') # for EXIT_OBJs return [self.set_image(self.image1)] def set_image1(self, image): @@ -276,8 +280,9 @@ class Mouseover(Sprite): class Avatar(Sprite): mouseme = 1 - def __init__(self, group, position, image, nick, noffset, boffset): + def __init__(self, server, group, position, image, nick, noffset, boffset): Sprite.__init__(self, position, image) + self.server = server self.rect = self.rect.clamp((0, 0, 640, 480)) self.group = group self.nick = nick @@ -290,6 +295,7 @@ class Avatar(Sprite): self.effect_step = 0 self.pollme = 0 self.stoptime = 0 + self.lastpoll = 0 self.moving = 0 self.set(noffset, boffset) @@ -303,6 +309,9 @@ class Avatar(Sprite): self.noffset = nx, ny def mouseon(self): + # we want the ORT to behave like an exit + if self.nick == 'ORT_Number_1': + self.server.whichmouseover('ov_tram_exit') if self.label is not None: print self.nick, 'on' self.label.die() @@ -412,7 +421,13 @@ class Avatar(Sprite): if self.effect_count > 0: self.effect_step = 6 self.rect.center = (x, y) - pygame.time.delay(15) + now = pygame.time.get_ticks() + if self.lastpoll == 0: + self.lastpoll = pygame.time.get_ticks() + delay = 30 - (now - self.lastpoll) + self.lastpoll = now + if delay > 0: + pygame.time.delay(delay) self.effect_step = self.effect_step -1 self.effect_count = self.effect_count -1 if self.effect_count == -1: @@ -838,6 +853,9 @@ class Client: self.balloons = Group() self.text = Group() self.avatars = {} + self.exits = {} + self.urls = [] + self.whichmouseover = '' self.console_height = self.height - (linesize(_font) + 2) self.entry = Entry((0, self.console_height + 1)) self.text.add(self.entry) @@ -901,6 +919,8 @@ class Client: # delete all objects/avatars here self.sprites = Group() self.avatars = {} + self.exits = {} + self.urls = [] self.set_title('PythonVerse') self.redraw() self.server.new_connect(host, port) @@ -957,6 +977,19 @@ class Client: """Update moving stuff, clean up old balloons, etc""" dirtyrects = self.sprites.update() dirtyrects.extend(self.balloons.update()) + # purge old URLs + if self.urls != []: + timetodie, url = self.urls[0] + if pygame.time.get_ticks() >= timetodie: + del self.urls[0] + try: urlmo = self.avatars[url] + except KeyError: self.debug('No URL %s' % url) + else: + dirtyrects.append(urlmo.rect) + del self.avatars[url] + try: del self.exits['{' + url + '}_link'] + except: print url, 'not in exits' + self.sprites.remove(urlmo) if dirtyrects: self.redraw(dirtyrects) def mouse(self, event): @@ -999,7 +1032,21 @@ class Client: self.server.chat(text.encode('utf-8')) else: self.redraw(self.entry.insert(event.unicode)) - elif event.type == MOUSEBUTTONDOWN: self.server.move(event.pos) + elif event.type == MOUSEBUTTONDOWN: + if self.whichmouseover == '': + self.server.move(event.pos) + else: + if self.whichmouseover != 'ov_tram_exit': + self.whichmouseover = '{' + self.whichmouseover + '}_link' + try: remtime, host, port = self.exits[self.whichmouseover] + except: self.server.move(event.pos) + else: + if port == -1: + webbrowser.open(host) + if port == -2: + print 'TODO: file transfers' + if port > 0: + self.cmd_connect(host, port) # Transport-called functions @@ -1027,7 +1074,7 @@ class Client: def mouseover(self, name, pos, image1, image2): """Create a mouseover object""" - mo = Mouseover(pos, image1, image2) + mo = Mouseover(self.server, name, pos, image1, image2) self.sprites.add(mo) self.avatars[name] = mo self.redraw(mo.rect) @@ -1041,7 +1088,7 @@ class Client: def new_avatar(self, nick, pos, image, noffset, boffset): # Fixme: need a real default image - avatar = Avatar(self.sprites, pos, image, nick, noffset, boffset) + avatar = Avatar(self.server, self.sprites, pos, image, nick, noffset, boffset) self.sprites.add(avatar) self.avatars[nick] = avatar dirtyrects = self.write('*%s* entered the room.' % nick) @@ -1063,6 +1110,16 @@ class Client: self.sprites.remove(avatar) self.redraw(dirtyrects) + def exit_obj(self, name, duration, host, port): + if host != 'dummyhost': + if duration > 0: + remtime = pygame.time.get_ticks() + (duration * 1000) + else: + remtime = 0 + self.exits[name] = (remtime, host, port) + else: + del self.exits[name] + def avatar(self, nick, image, noffset, boffset): """Change the avatar for a nick""" # FIXME: need to handle other parameters (bubble position, nametag) @@ -1114,9 +1171,66 @@ class Client: else: self.redraw(dirtyrects + avatar.chat(self.balloons, s)) def url(self, nick, url): - dirtyrects = self.write('[URL from %s] %s' % (nick, url)) - # add in temporary URL links here - self.redraw(dirtyrects) + try: test = self.avatars[url] + except: + dirtyrects = self.write('[URL from %s] %s' % (nick, url)) + # TODO: the 30000 should be replaced with URL timeout from Setup + self.urls.append((pygame.time.get_ticks() + 30000, url)) + # parse URL to find out what we want to do with it + text = 'Bad' + tagcolor = (255, 0, 0) + head = url[0:3] + head.lower() + if head == 'ope': + offset = url.find('://') + 3 + offset2 = url.find(':', offset) + host = url[offset:offset2] + port = int(url[offset2 + 1:]) + self.exit_obj('{' + url + '}_link', 0, host, port) + text = 'OV:' + tagcolor = (255, 255, 0) + if head == 'fil': + offset = url.find('://') + 3 + offset2 = url.find(':', offset) + offset3 = url.find('/', offset2) + offset4 = url.find(':', offset3) + host = url[offset:offset2] + port = url[offset2 + 1:offset3] + filename = url[offset3+1:offset4] + filesize = url[offset4:] + text = 'File' + tagcolor = (0, 255, 255) + # have to implement DCC first + if head == 'htt' or head == 'ftp' or head == 'mai': + text = 'URL' + tagcolor = (0, 255, 0) + self.exit_obj('{' + url + '}_link', 0, url, -1) + # generate images for URL links + image1 = pygame.Surface((40, 16)) + image2 = pygame.Surface((40, 16)) + image1.set_colorkey((255,165,0)) + image1.fill((255,165,0)) + image2.set_colorkey((255,165,0)) + image2.fill((255,165,0)) + pygame.draw.polygon(image2, (0, 0, 0), + ((1,1), (1, 15), (39, 15), (39, 6), (34, 1), (1,1)), + 0) + pygame.draw.polygon(image2, tagcolor, + ((0,0), (0, 14), (38, 14), (38, 5), (33, 0), (0,0)), + 0) + pygame.draw.polygon(image2, (0, 0, 255), + ((0,0), (0, 14), (28, 14), (28, 5), (23, 0), (0,0)), + 0) + image2.blit(_font.render(text, 1, (255, 255, 255)), (2, 0)) + image1.blit(image2, (0, 0)) + image1.set_alpha(127) + pos = (int((random.random()*600)+20), int((random.random()*458)+8)) + urlmo = Mouseover(self.server, url, pos, image1, image2) + self.sprites.add(urlmo) + self.avatars[url] = urlmo + dirtyrects.append(urlmo.rect) + self.redraw(dirtyrects) + else: print url, 'already exits' def chat(self, nick, s): dirtyrects = self.write('<%s> %s' % (nick, s)) @@ -1125,6 +1239,14 @@ class Client: else: dirtyrects.extend(avatar.chat(self.balloons, s)) self.redraw(dirtyrects) + def setmouseover(self, name): + if name == 'ov_tram_exit': + try: test = self.exits[name] # is this really the ORT? + except: self.whichmouseover = '' + else: self.whichmouseover = name + else: + self.whichmouseover = name + # Exported functions @@ -1145,7 +1267,7 @@ def init(): global _font, _display, _lastpoll pygame.init() - _display = pygame.display.set_mode((640,480)) + _display = pygame.display.set_mode((640, 480)) # display startup image s = pygame.display.get_surface() i = pygame.image.load('pvstart.jpg')