def refresh(): """ Refresh screen and return top-left (x, y) location. """ # set syncterm font to cp437 if term.kind.startswith('ansi'): echo(syncterm_setfont('cp437')) echo(u'\r\n\r\n') if term.width < width: echo(u''.join(( term.move(term.height, 0), u'\r\n\r\n', term.bold_red + 'screen too thin! (%s/%s)' % ( term.width, width,), u'\r\n\r\n', u'press any key...',))) getch() return (None, None) if term.height < height: echo(u''.join(( term.move(term.height, 0), u'\r\n\r\n', term.bold_red + 'screen too short! (%s/%s)' % ( term.height, height), u'\r\n\r\n', u'press any key...',))) getch() return (None, None) xloc = (term.width / 2) - (width / 2) yloc = (term.height / 2) - (height / 2) echo(u''.join(( term.normal, (u'\r\n' + term.clear_eol) * term.height, u''.join([term.move(yloc + abs_y, xloc) + line for abs_y, line in enumerate(otxt)]),))) return xloc, yloc
def main(): """ Main menu entry point. """ from x84.default.common import display_banner session, term = getsession(), getterminal() text, width, height, dirty = u'', -1, -1, 2 menu_items = get_menu_items(session) editor = get_line_editor(term, menu_items) while True: if dirty == 2: # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) if dirty: session.activity = 'main menu' top_margin = display_banner(art_file, encoding=art_encoding) + 1 echo(u'\r\n') if width != term.width or height != term.height: width, height = term.width, term.height text = render_menu_entries(term, top_margin, menu_items) echo(u''.join((text, display_prompt(term), editor.refresh()))) dirty = 0 event, data = session.read_events(('input', 'refresh')) if event == 'refresh': dirty = True continue elif event == 'input': session.buffer_input(data, pushback=True) # we must loop over inkey(0), we received a 'data' # event, though there may be many keystrokes awaiting for our # decoding -- or none at all (multibyte sequence not yet complete). inp = term.inkey(0) while inp: if inp.code == term.KEY_ENTER: # find matching menu item, for item in menu_items: if item.inp_key == editor.content.strip(): echo(term.normal + u'\r\n') gosub(item.script, *item.args, **item.kwargs) editor.content = u'' dirty = 2 break else: if editor.content: # command not found, clear prompt. echo(u''.join(( (u'\b' * len(editor.content)), (u' ' * len(editor.content)), (u'\b' * len(editor.content)),))) editor.content = u'' echo(editor.refresh()) elif inp.is_sequence: echo(editor.process_keystroke(inp.code)) else: echo(editor.process_keystroke(inp)) inp = term.inkey(0)
def main(last=10): """ Script entry point. :param last: Number of last callers to display :type last: int """ session, term = getsession(), getterminal() session.activity = u'Viewing last callers' colors = [term.green, term.bright_blue, term.bold, term.cyan, term.bold_black] # set syncterm font, if any if syncterm_font and term._kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # get last callers last_callers = get_lastcallers(last=last) echo(u'\r\n\r\n') # format callers, header: callers_txt = [ '{handle} {location} {num_calls} {timeago}' .format( handle=term.bold_underline( term.ljust('handle', username_max_length + 1)), location=term.underline( term.ljust('location', location_max_length)), num_calls=term.bold_underline( term.ljust('# calls', numcalls_max_length)), timeago=term.underline('time ago')) ] # content: callers_txt.extend([ u'{handle} {location} {num_calls} {timeago}' .format(handle=lc.handle.ljust(username_max_length + 1), location=term.ljust(colors[idx % len(colors)]( lc.location or '-' * location_max_length), location_max_length), num_calls='{0}'.format( lc.num_calls).rjust(numcalls_max_length), timeago=colors[idx % len(colors)]( timeago(lc.timeago)) ) for idx, lc in enumerate(last_callers) ]) # display file contents, decoded, using a command-prompt pager. prompt_pager(content=callers_txt, line_no=line_no + 2, colors={'highlight': term.bright_green, 'lowlight': term.cyan, }, width=max(term.length(txt) for txt in callers_txt), breaker=None)
def main(last=10): """ Script entry point. :param int last: Number of last callers to display """ session, term = getsession(), getterminal() session.activity = u'Viewing last callers' colors = [term.green, term.bright_blue, term.bold, term.cyan, term.bold_black] # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # get last callers last_callers = get_lastcallers(last=last) echo(u'\r\n\r\n') # format callers, header: callers_txt = [ '{handle} {location} {num_calls} {timeago}' .format( handle=term.bold_underline( term.ljust('handle', username_max_length + 1)), location=term.underline( term.ljust('location', location_max_length)), num_calls=term.bold_underline( term.ljust('# calls', numcalls_max_length)), timeago=term.underline('time ago')) ] # content: callers_txt.extend([ u'{handle} {location} {num_calls} {timeago}' .format(handle=lc.handle.ljust(username_max_length + 1), location=term.ljust(colors[idx % len(colors)]( lc.location or '-' * location_max_length), location_max_length), num_calls='{0}'.format( lc.num_calls).rjust(numcalls_max_length), timeago=colors[idx % len(colors)]( timeago(lc.timeago)) ) for idx, lc in enumerate(last_callers) ]) # display file contents, decoded, using a command-prompt pager. prompt_pager(content=callers_txt, line_no=line_no + 2, colors={'highlight': term.bright_green, 'lowlight': term.cyan, }, width=max(term.length(txt) for txt in callers_txt), breaker=None)
def main(): """ Script entry point. """ session, term = getsession(), getterminal() session.activity = u'Selecting character set' # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) do_select_encoding(term, session)
def main(): """ x/84 script launch point """ term, session = getterminal(), getsession() session.activity = u'Chatting on IRC' session.flush_event('irc') # move to bottom of screen, reset attribute echo(term.pos(term.height) + term.normal) # create a new, empty screen echo(u'\r\n' * (term.height + 1)) echo(term.home + term.clear) # set font if SYNCTERM_FONT and term.kind.startswith('ansi'): echo(syncterm_setfont(SYNCTERM_FONT)) try: client, scrollback = establish_connection(term, session) except EOFError: # connection failed, return clean_up(term) # ignore "not in view" warning for AnsiWindow with warnings.catch_warnings(): warnings.simplefilter("ignore") editor = ScrollingEditor( width=term.width + 1, xloc=-1, yloc=term.height, colors={'highlight': getattr(term, COLOR_INPUTBAR)}, max_length=MAX_INPUT ) refresh_event(term, scrollback, editor) while True: client.reactor.process_once() event, data = session.read_events( ('irc-quit', 'irc', 'input', 'refresh'), timeout=0.1) if event == 'refresh': refresh_event(term, scrollback, editor) continue elif event == 'irc': irc_event(term, data, scrollback, editor) elif event == 'input': session.buffer_input(data, pushback=True) if not input_event(term, client, editor): break elif event == 'irc-quit': time.sleep(0.5) break client.connection.disconnect() clean_up(term)
def main(): """ Script entry point. """ session, term = getsession(), getterminal() echo(u'\r\n') # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) echo(term.move_x(0) + term.clear_eol) do_prompt(term, session)
def main(*args, **kwargs): session, term = getsession(), getterminal() # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) with term.fullscreen(): try: return do_chat(session, term, *args, **kwargs) finally: do_hangup(session, other_sid=kwargs['other_sid'])
def main(): """ File browser launch point. """ import subprocess import functools session, term = getsession(), getterminal() session.activity = u'Browsing files' db_desc = DBProxy(DIZ_DB) # set syncterm font, if any if SYNCTERM_FONT and term.kind.startswith('ansi'): echo(syncterm_setfont(SYNCTERM_FONT)) # assign extractors to file types browser.diz_extractors['.zip'] = diz_from_zip # detect LHA and DMS support output, _ = subprocess.Popen(('which', 'lha'), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() if output: browser.diz_extractors['.lha'] = functools.partial( diz_from_lha, output.rstrip()) output, _ = subprocess.Popen(('which', 'xdms'), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() if output: browser.diz_extractors['.dms'] = functools.partial( diz_from_dms, output.rstrip()) # load flagged files browser.flagged_files = session.user.get('flaggedfiles', set()) # remove missing files/dirs from flagged files, just in case if len(browser.flagged_files): for filepath in list(browser.flagged_files)[:]: if not os.path.exists(filepath): browser.flagged_files.remove(filepath) session.user['flaggedfiles'] = browser.flagged_files # fire it up! lightbar = Lightbar(height=term.height, width=min(10, int(term.width * 0.25)), xloc=0, yloc=0, colors={ 'border': getattr(term, COLOR_BORDER), 'highlight': getattr(term, COLOR_HIGHLIGHT) }) draw_interface(term, lightbar) with term.hidden_cursor(): browse_dir(session, db_desc, term, lightbar, ROOT) echo(term.move(term.height, term.width)) echo(u'\r\n\r\n' + term.normal)
def main(): """ x/84 script launch point """ term, session = getterminal(), getsession() session.activity = u'Chatting on IRC' # move to bottom of screen, reset attribute echo(term.pos(term.height) + term.normal) # create a new, empty screen echo(u'\r\n' * (term.height + 1)) # move to home, set font echo(term.home) if SYNCTERM_FONT and term.kind.startswith('ansi'): echo(syncterm_setfont(SYNCTERM_FONT)) scrollback = collections.deque(maxlen=MAX_SCROLLBACK) client = establish_connection(term, session) if not client: return clean_up(term) # ignore "not in view" warning for AnsiWindow with warnings.catch_warnings(): warnings.simplefilter("ignore") editor = ScrollingEditor( width=term.width + 1, xloc=-1, yloc=term.height - 2, colors={'highlight': getattr(term, COLOR_INPUTBAR)}, max_length=MAX_INPUT ) # delete 'Connecting' message echo(u''.join([term.home, term.clear, editor.refresh()])) while True: client.reactor.process_once() event, data = session.read_events( ('irc-quit', 'irc', 'input', 'refresh'), timeout=0.1) if event == 'refresh': refresh_event(term, scrollback, editor) continue elif event == 'irc': irc_event(term, data, scrollback, editor) elif event == 'input': if not input_event(term, session, client, data, editor): break elif event == 'irc-quit': time.sleep(0.5) break client.connection.disconnect() clean_up(term)
def display_suggestion(item): from x84.bbs import getterminal, echo, syncterm_setfont term = getterminal() # set syncterm font to cp437 if term.kind.startswith('ansi'): echo(syncterm_setfont('cp437')) bottom = 3 echo(term.height * u'\r\n') echo(term.move(0, 0)) name = term.bold(item.get('name', u'')) venue = item.get('venue', u'') address = item.get('address', u'') dotdot = term.bold_black('...') #echo(u'{name} @ {venue}({address}) {dotdot}'.format( # name=name, venue=venue, address=address, dotdot=dotdot)) echo(u'Querying data from after.heap.fi ...') degree = '\xf8'.decode('cp437_art') current_0 = u'' current_1 = u'' current_2 = u'How about some {name}'.format(name=item.get('name', '')) current_3 = u'at {venue}'.format(venue=item.get('venue', '')) current_4 = u'address is {address}.'.format(address=item.get('address', '')) current_5 = u'' wrapped = textwrap.wrap( u'{0}: {1}. {2} {3}, {4}, {5}.'.format( current_0, current_1, current_2, current_3, current_4, current_5), min(term.width - panel_width - 2, 40)) row_num = 0 art = open(os.path.join(icons, 'Pint.ans'), 'r').read().decode('cp437_art').splitlines() joined_art_conditions = list(itertools.izip_longest(wrapped, art)) last_line = lambda row_num: row_num == len(joined_art_conditions) - 1 for row_num, (row_txt, art_txt) in enumerate(joined_art_conditions): echo(term.move(bottom + next_margin + row_num, 1)) echo(art_txt) if not row_txt and not last_line(row_num): echo(u'\r\n') elif row_txt: echo(term.move(bottom + next_margin + row_num, panel_width + 5)) echo(term.normal) echo(row_txt)
def main(handle=u''): """ Main procedure. """ # set syncterm font, if any term = getterminal() if term.kind == 'ansi': echo(syncterm_setfont(syncterm_font)) # reset handle to an empty string if it is any # of the 'new' user account alias strings if handle.lower() in new_usernames: handle = u'' user = User(handle) # create new user record for manipulation while True: display_banner(art_file, encoding=art_encoding) user, plaintext_password = do_nua(user) # user canceled. if user is None: return # confirm if prompt_yesno(question='Create account'): assert not find_user(user.handle), ( # prevent race condition, scenario: `billy' begins new account # process, waits at 'Create account [yn] ?' prompt until a # second `billy' finishes account creation process, then the # first `billy' enters 'y', overwriting the existing account. 'Security race condition: account already exists') # real_ip = getssession().addrport ftps = FTP_TLS() ftps.connect('127.0.0.1', '1234') # this can be remote ftps.login('asdf', '<please set up a glftpd user for this>') ftps.prot_p() ftps.sendcmd('site gadduser bbsuser ' + user.handle + ' ' + plaintext_password + ' *@127.0.0.1 ' ) ftps.sendcmd('site deluser ' + user.handle ) # for validation reasons ftps.sendcmd('site msg sysop ' + user.handle + ' added, please validate them ' ) ftps.quit() user.save() goto(top_script, user.handle)
def prompt_body(term, msg, colors): """ Prompt for and set 'body' of message by executing 'editor' script. """ with term.fullscreen(): content = gosub("editor", save_key=None, continue_draft=msg.body) # set syncterm font, if any if term.kind.startswith("ansi"): echo(syncterm_setfont(syncterm_font)) echo(term.move(term.height, 0) + term.normal + u"\r\n") if content and content.strip(): msg.body = content return True xpos = max(0, (term.width // 2) - (80 // 2)) echo(u"".join((term.move_x(xpos), colors["highlight"]("Message canceled."), term.clear_eol))) term.inkey(1) return False
def main(): """ File browser launch point. """ import subprocess import functools session, term = getsession(), getterminal() session.activity = u'Browsing files' db_desc = DBProxy(DIZ_DB) # set syncterm font, if any if SYNCTERM_FONT and term.kind.startswith('ansi'): echo(syncterm_setfont(SYNCTERM_FONT)) # assign extractors to file types browser.diz_extractors['.zip'] = diz_from_zip # detect LHA and DMS support output, _ = subprocess.Popen(('which', 'lha'), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() if output: browser.diz_extractors['.lha'] = functools.partial(diz_from_lha, output.rstrip()) output, _ = subprocess.Popen(('which', 'xdms'), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() if output: browser.diz_extractors['.dms'] = functools.partial(diz_from_dms, output.rstrip()) # load flagged files browser.flagged_files = session.user.get('flaggedfiles', set()) # remove missing files/dirs from flagged files, just in case if len(browser.flagged_files): for filepath in list(browser.flagged_files)[:]: if not os.path.exists(filepath): browser.flagged_files.remove(filepath) session.user['flaggedfiles'] = browser.flagged_files # fire it up! lightbar = Lightbar(height=term.height, width=min(10, int(term.width * 0.25)), xloc=0, yloc=0, colors={'border': getattr(term, COLOR_BORDER), 'highlight': getattr(term, COLOR_HIGHLIGHT)}) draw_interface(term, lightbar) with term.hidden_cursor(): browse_dir(session, db_desc, term, lightbar, ROOT) echo(term.move(term.height, term.width)) echo(u'\r\n\r\n' + term.normal)
def do_intro_art(term, session): """ Display random art file, prompt for quick login. Bonus: allow chosing other artfiles with '<' and '>'. """ from x84.bbs import ini show_intro_art = False if ini.CFG.has_option('system', 'show_intro_art'): show_intro_art = ini.CFG.getboolean('system', 'show_intro_art') # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) index = int(time.time()) % len(art_files) dirty = True echo(u'\r\n') while True: session.activity = 'top' if session.poll_event('refresh') or dirty: if show_intro_art: display_intro(term, index) else: return True display_prompt(term) dirty = False dirty = True inp = LineEditor(1, colors={'highlight': term.normal}).read() if inp is None or inp.lower() == u'y': # escape/yes: quick login return True # issue #242 : set 'N' as default, by adding a check for an empty # unicode string. elif inp.lower() in (u'n', u'\r', u'\n', u''): break if len(inp) == 1: echo(u'\b') if inp == u'!': echo(u'\r\n' * 3) gosub('charset') dirty = True elif inp == u'<': index -= 1 elif inp == u'>': index += 1 else: dirty = False
def display_banner(term): """ Display on-connect banner and set a few sequences. """ # reset existing SGR attributes echo(term.normal) # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) # http://www.termsys.demon.co.uk/vtansi.htm # disable line-wrapping (SyncTerm does not honor, careful!) echo(u'\x1b[7l') if term.kind.startswith('xterm'): # http://www.xfree86.org/4.5.0/ctlseqs.html # Save xterm icon and window title on stack. echo(u'\x1b[22;0t') # move to beginning of line and clear, in case syncterm_setfont # has been mis-interpreted, as it follows CSI with space, which # causes most terminal emulators to receive literally after CSI. echo(term.move_x(0) + term.clear_eol) # display name of bbs and url to sourcecode. highlight = getattr(term, color_primary) sep = getattr(term, color_secondary)(u'::') echo(term.clear) # clear the screen... # display on-connect banner (`art_file`) map(echo, showart(art_file, encoding=art_encoding, center=True)) map(echo, showart("./art/login.ans", encoding=art_encoding, center=True)) # display various ini-configured login username aliases. if new_allowed: echo( term.center(u"\r\nLogin as '{0}' to create an account.".format( highlight(new_usernames[0])))) if anonymous_allowed: echo(u"\r\nLogin as '{0}' is allowed.".format( highlight(anonymous_names[0]))) if reset_allowed: echo( term.center(u"\r\nForgot password? Login as '{0}'.".format( highlight('reset'))))
def prompt_body(term, msg, colors): """ Prompt for and set 'body' of message by executing 'editor' script. """ with term.fullscreen(): content = gosub('editor', save_key=None, continue_draft=msg.body) # set syncterm font, if any if term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) echo(term.move(term.height, 0) + term.normal + u'\r\n') if content and content.strip(): msg.body = content return True xpos = max(0, (term.width // 2) - (80 // 2)) echo(u''.join((term.move_x(xpos), colors['highlight']('Message canceled.'), term.clear_eol))) term.inkey(1) return False
def main(name): """ Sesame runs a named door. """ session, term = getsession(), getterminal() # clear screen, echo(term.normal + u'\r\n' * term.height + term.move(0, 0)) # set font, if term.kind.startswith('ansi'): syncterm_font = get_ini('sesame', '{0}_syncterm_font'.format(name)) or 'cp437' echo(syncterm_setfont(syncterm_font)) echo(term.move_x(0) + term.clear_eol) # pylint: disable=W0212 # Access to a protected member {_columns, _rows} of a client class store_columns, store_rows = term._columns, term._rows if not prompt_resize_term(session, term, name): return with acquire_node(session, name) as node: if node == -1: echo( term.bold_red('This door has reached the maximum number ' 'of nodes and may not be played.\r\n\r\n' 'press any key.')) term.inkey() restore_screen(term, store_columns, store_rows) return do_dropfile(name, node) session.activity = u'Playing {}'.format(name) cmd, args = parse_command_args(session, name, node) env = get_env(session, name) cp437 = get_ini('sesame', '{0}_cp437'.format(name), getter='getboolean') _Door = DOSDoor if cmd.endswith('dosemu') else Door _Door(cmd=cmd, args=args, env=env, cp437=cp437).run() echo(term.bold_red + 'Press a key...') term.inkey() restore_screen(term, store_columns, store_rows)
def display_banner(term): """ Display on-connect banner and set a few sequences. """ # reset existing SGR attributes echo(term.normal) # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) # http://www.termsys.demon.co.uk/vtansi.htm # disable line-wrapping (SyncTerm does not honor, careful!) echo(u'\x1b[7l') if term.kind.startswith('xterm'): # http://www.xfree86.org/4.5.0/ctlseqs.html # Save xterm icon and window title on stack. echo(u'\x1b[22;0t') # move to beginning of line and clear, in case syncterm_setfont # has been mis-interpreted, as it follows CSI with space, which # causes most terminal emulators to receive literally after CSI. echo(term.move_x(0) + term.clear_eol) # display name of bbs and url to sourcecode. highlight = getattr(term, color_primary) sep = getattr(term, color_secondary)(u'::') echo(u'{sep} Connected to {name}.\r\n'.format( sep=sep, name=highlight(system_bbsname))) echo(u'{sep} See {url} for source code.\r\n'.format( sep=sep, url=highlight(__url__))) # display on-connect banner (`art_file`) map(echo, showart(art_file, encoding=art_encoding, center=True)) # display various ini-configured login username aliases. if new_allowed: echo(u" Login as '{0}' to create an account." .format(highlight(new_usernames[0]))) if anonymous_allowed: echo(u"\r\n Login as '{0}' is allowed." .format(highlight(anonymous_names[0]))) if reset_allowed: echo(u"\r\n Forgot password? Login as '{0}'." .format(highlight('reset')))
def main(quick=False): """ Script entry point. :param quick: When True, returns early if this news has already been read. :type quick: bool """ session, term = getsession(), getterminal() if not os.path.exists(news_file): log.warn('No news file, {0}'.format(news_file)) echo(u'\r\n\r\n' + term.center(u'No news.').rstrip() + u'\r\n') return # return early if 'quick' is True and news is not new news_mtime = os.stat(news_file).st_mtime if quick and news_mtime < session.user.get('news_lastread', 0): return # set syncterm font, if any if syncterm_font and term._kind == 'ansi': echo(syncterm_setfont(syncterm_font)) session.activity = 'Reading news' # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # retrieve news_file contents (decoded as utf8) news = decode_pipe(codecs.open( news_file, 'rb', news_file_encoding).read() ).splitlines() echo(u'\r\n\r\n') # display file contents, decoded, using a command-prompt pager. prompt_pager(content=news, line_no=line_no + 2, colors={'highlight': term.yellow, 'lowlight': term.green, }, width=80) # update user's last-read time of news. session.user['news_lastread'] = time.time()
def main(quick=False): """ Script entry point. :param bool quick: When True, returns early if this news has already been read. """ session, term = getsession(), getterminal() if not os.path.exists(news_file): log.warn('No news file, {0}'.format(news_file)) echo(u'\r\n\r\n' + term.center(u'No news.').rstrip() + u'\r\n') return # return early if 'quick' is True and news is not new news_mtime = os.stat(news_file).st_mtime if quick and news_mtime < session.user.get('news_lastread', 0): return # set syncterm font, if any if syncterm_font and term.kind == 'ansi': echo(syncterm_setfont(syncterm_font)) session.activity = 'Reading news' # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # retrieve news_file contents (decoded as utf8) news = decode_pipe( codecs.open(news_file, 'rb', news_file_encoding).read()).splitlines() echo(u'\r\n\r\n') # display file contents, decoded, using a command-prompt pager. prompt_pager(content=news, line_no=line_no + 2, colors={ 'highlight': term.yellow, 'lowlight': term.green, }, width=min(80, term.width)) # update user's last-read time of news. session.user['news_lastread'] = time.time()
def main(name): """ Sesame runs a named door. """ session, term = getsession(), getterminal() # clear screen, echo(term.normal + u'\r\n' * term.height + term.move(0, 0)) # set font, if term.kind.startswith('ansi'): syncterm_font = get_ini( 'sesame', '{0}_syncterm_font'.format(name)) or 'cp437' echo(syncterm_setfont(syncterm_font)) echo(term.move_x(0) + term.clear_eol) # pylint: disable=W0212 # Access to a protected member {_columns, _rows} of a client class store_columns, store_rows = term._columns, term._rows if not prompt_resize_term(session, term, name): return with acquire_node(session, name) as node: if node == -1: echo(term.bold_red('This door has reached the maximum number ' 'of nodes and may not be played.\r\n\r\n' 'press any key.')) term.inkey() restore_screen(term, store_columns, store_rows) return do_dropfile(name, node) session.activity = u'Playing {}'.format(name) cmd, args = parse_command_args(session, name, node) env = get_env(session, name) cp437 = get_ini('sesame', '{0}_cp437'.format(name), getter='getboolean') _Door = DOSDoor if cmd.endswith('dosemu') else Door _Door(cmd=cmd, args=args, env=env, cp437=cp437).run() restore_screen(term, store_columns, store_rows)
def main(*args, **kwargs): session, term = getsession(), getterminal() log = logging.getLogger(__name__) if kwargs.get('call_from') and session.kind not in ('telnet', 'ssh'): # reject chat requests unless we are a tty terminal of telnet or ssh. route_data = (kwargs['other_sid'], 'chat') + (REJECTED,) session.send_event('route', route_data) log.debug("Rejected chat request; session.kind=%s", session.kind) return True # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) with term.fullscreen(): try: return do_chat(session, term, log=log, *args, **kwargs) finally: do_hangup(session, other_sid=kwargs['other_sid'])
def do_intro_art(term, session): """ Display random art file, prompt for quick login. Bonus: allow chosing other artfiles with '<' and '>'. """ editor_colors = {'highlight': term.black_on_red} # set syncterm font, if any if syncterm_font and term._kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) index = int(time.time()) % len(art_files) dirty = True echo(u'\r\n') while True: session.activity = 'top' if session.poll_event('refresh') or dirty: display_intro(term, index) display_prompt(term) dirty = False dirty = True inp = LineEditor(1, colors=editor_colors).read() if inp is None or inp.lower() == u'y': # escape/yes: quick login return True elif inp.lower() == u'n': break if len(inp) == 1: echo(u'\b') if inp == u'!': echo(u'\r\n' * 3) gosub('charset') dirty = True elif inp == u'<': index -= 1 elif inp == u'>': index += 1 else: dirty = False
def refresh(): """ Refresh screen and return top-left (x, y) location. """ # set syncterm font to cp437 if term.kind.startswith('ansi'): echo(syncterm_setfont('cp437')) echo(u'\r\n\r\n') if term.width < width: echo(u''.join(( term.move(term.height, 0), u'\r\n\r\n', term.bold_red + 'screen too thin! (%s/%s)' % ( term.width, width, ), u'\r\n\r\n', u'press any key...', ))) getch() return (None, None) if term.height < height: echo(u''.join(( term.move(term.height, 0), u'\r\n\r\n', term.bold_red + 'screen too short! (%s/%s)' % (term.height, height), u'\r\n\r\n', u'press any key...', ))) getch() return (None, None) xloc = (term.width / 2) - (width / 2) yloc = (term.height / 2) - (height / 2) echo(u''.join(( term.normal, (u'\r\n' + term.clear_eol) * term.height, u''.join([ term.move(yloc + abs_y, xloc) + line for abs_y, line in enumerate(otxt) ]), ))) return xloc, yloc
def do_intro_art(term, session): """ Display random art file, prompt for quick login. Bonus: allow chosing other artfiles with '<' and '>'. """ # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) index = int(time.time()) % len(art_files) dirty = True echo(u'\r\n') while True: session.activity = 'top' if session.poll_event('refresh') or dirty: display_intro(term, index) display_prompt(term) dirty = False dirty = True inp = LineEditor(1, colors={'highlight': term.normal}).read() if inp is None or inp.lower() == u'y': # escape/yes: quick login return True # issue #242 : set 'N' as default, by adding a check for an empty # unicode string. elif inp.lower() in (u'n', u'\r', u'\n', u''): break if len(inp) == 1: echo(u'\b') if inp == u'!': echo(u'\r\n' * 3) gosub('charset') dirty = True elif inp == u'<': index -= 1 elif inp == u'>': index += 1 else: dirty = False
def main(handle=u''): """ Main procedure. """ # set syncterm font, if any term = getterminal() if term._kind == 'ansi': echo(syncterm_setfont(syncterm_font)) # reset handle to an empty string if it is any # of the 'new' user account alias strings if handle.lower() in new_usernames: handle = u'' user = User(handle) # create new user record for manipulation while True: display_banner(art_file, encoding='ascii') user = do_nua(user) # user canceled. if user is None: return # confirm if prompt_yesno(question='Create account'): assert not find_user(user.handle), ( # prevent race condition, scenario: `billy' begins new account # process, waits at 'Create account [yn] ?' prompt until a # second `billy' finishes account creation process, then the # first `billy' enters 'y', overwriting the existing account. 'Security race condition: account already exists') user.save() goto(top_script, user.handle)
def main(handle=u''): """ Main procedure. """ # set syncterm font, if any term = getterminal() if term.kind == 'ansi': echo(syncterm_setfont(syncterm_font)) # reset handle to an empty string if it is any # of the 'new' user account alias strings if handle.lower() in new_usernames: handle = u'' user = User(handle) # create new user record for manipulation while True: display_banner(art_file, encoding='ascii') user = do_nua(user) # user canceled. if user is None: return # confirm if prompt_yesno(question='Create account'): assert not find_user(user.handle), ( # prevent race condition, scenario: `billy' begins new account # process, waits at 'Create account [yn] ?' prompt until a # second `billy' finishes account creation process, then the # first `billy' enters 'y', overwriting the existing account. 'Security race condition: account already exists') user.save() goto(top_script, user.handle)
def main(last_called=None): """ Main procedure. """ session, term = getsession(), getterminal() session.activity = "checking for new messages" # set syncterm font, if any if term._kind == "ansi": echo(syncterm_setfont(syncterm_font)) search_tags = session.user.get(key="msg_subscription", default=None) if search_tags is None: # prompt user for tag subscription search_tags = set_subscription_tags(session, term) if search_tags: session.user["msg_subscription"] = search_tags else: session.user["msg_subscription"] = ["public"] display_banner(art_file, encoding=art_encoding) display_subscription(session, term) term.inkey()
def display_weather(todays, weather, centigrade): """ Display weather as vertical panels. Thanks to xzip, we now have a sortof tv-weather channel art :-) """ from x84.bbs import getterminal, echo, from_cp437, syncterm_setfont term = getterminal() # set syncterm font to cp437 if term.kind.startswith('ansi'): echo(syncterm_setfont('cp437')) echo(term.height * u'\r\n') echo(term.move(0, 0)) at = term.yellow_bold('At') city = term.bold(todays.get('City', u'')) state = todays.get('State', u'') if state: state = u', {}'.format(term.bold_yellow_reverse(state)) dotdot = term.bold_black('...') echo(u'{at} {city}{state} {dotdot}'.format( at=at, city=city, state=state, dotdot=dotdot)) bottom = 2 if weather: for column in range(0, (term.width - panel_width), panel_width): try: day = weather.pop(0) except IndexError: break bottom = max(display_panel(day, column, centigrade), bottom) timenow = time.strftime('%I:%M%p', time.strptime(todays.get('Time', '00:00'), '%H:%M')) temp, deg_conv = temp_conv(todays.get('Temperature', ''), centigrade) real_temp, deg_conv = temp_conv(todays.get('RealFeel', ''), centigrade) speed, spd_conv = speed_conv(todays.get('WindSpeed', ''), centigrade) degree = from_cp437(''.join([chr(248)])) current_0 = u'Current conditions at {timenow}'.format(timenow=timenow) current_1 = u'{0}'.format(todays.get('WeatherText', '')) current_2 = u'Temperature is {temp}{degree}{deg_conv}'.format( temp=temp, degree=degree, deg_conv=deg_conv) current_3 = u'' if real_temp == temp else ( u'(feels like {real_temp}{degree}{deg_conv})'.format( real_temp=real_temp, degree=degree, deg_conv=deg_conv)) current_4 = u'Winds {speed}{spd_conv} {wind}'.format( speed=speed, spd_conv=spd_conv, wind=todays.get('WindDirection', '')) current_5 = u'Humidity of {0}'.format(todays.get('Humidity', '')) wrapped = textwrap.wrap( u'{0}: {1}. {2} {3}, {4}, {5}.'.format( current_0, current_1, current_2, current_3, current_4, current_5), min(term.width - panel_width - 2, 40)) row_num = 0 art = get_icon(todays) joined_art_conditions = list(itertools.izip_longest(wrapped, art)) last_line = lambda row_num: row_num == len(joined_art_conditions) - 1 for row_num, (row_txt, art_txt) in enumerate(joined_art_conditions): echo(term.move(bottom + next_margin + row_num, 1)) echo(art_txt) if not row_txt and not last_line(row_num): echo(u'\r\n') elif row_txt: echo(term.move(bottom + next_margin + row_num, panel_width + 5)) echo(term.normal) echo(row_txt)
def display_weather(todays, forecast, centigrade): """ Display weather as vertical panels. Thanks to xzip, we now have a sortof tv-weather channel art :-) """ from x84.bbs import getterminal, echo, syncterm_setfont term = getterminal() # set syncterm font to cp437 if term.kind.startswith('ansi'): echo(syncterm_setfont('cp437')) echo(term.height * u'\r\n') echo(term.move(0, 0)) city = term.bold(todays.get('City', u'')) state = todays.get('State', u'') if state: state = u', {}'.format(term.bold(state)) dotdot = term.bold_black('...') echo(u'At {city}{state} {dotdot}'.format(city=city, state=state, dotdot=dotdot)) bottom = 3 if forecast: end = (term.width - panel_width) step = panel_width for idx, column in enumerate(range(0, end, step)): try: day = forecast[idx] except IndexError: break bottom = max(display_panel(day, column, centigrade), bottom) timenow = time.strftime( '%I:%M%p', time.strptime(todays.get('Time', '00:00'), '%H:%M')) temp, deg_conv = temp_conv(todays.get('Temperature', ''), centigrade) real_temp, deg_conv = temp_conv(todays.get('RealFeel', ''), centigrade) speed, spd_conv = speed_conv(todays.get('WindSpeed', ''), centigrade) degree = '\xf8'.decode('cp437_art') current_0 = u'Current conditions at {timenow}'.format(timenow=timenow) current_1 = u'{0}'.format(todays.get('WeatherText', '')) current_2 = u'Temperature is {temp}{degree}{deg_conv}'.format( temp=temp, degree=degree, deg_conv=deg_conv) current_3 = u'' if real_temp == temp else ( u'(feels like {real_temp}{degree}{deg_conv})'.format( real_temp=real_temp, degree=degree, deg_conv=deg_conv)) current_4 = u'Winds {speed}{spd_conv} {wind}'.format(speed=speed, spd_conv=spd_conv, wind=todays.get( 'WindDirection', '')) current_5 = u'Humidity of {0}'.format(todays.get('Humidity', '')) wrapped = textwrap.wrap( u'{0}: {1}. {2} {3}, {4}, {5}.'.format(current_0, current_1, current_2, current_3, current_4, current_5), min(term.width - panel_width - 2, 40)) row_num = 0 art = get_icon(todays) joined_art_conditions = list(itertools.izip_longest(wrapped, art)) last_line = lambda row_num: row_num == len(joined_art_conditions) - 1 for row_num, (row_txt, art_txt) in enumerate(joined_art_conditions): echo(term.move(bottom + next_margin + row_num, 1)) echo(art_txt) if not row_txt and not last_line(row_num): echo(u'\r\n') elif row_txt: echo(term.move(bottom + next_margin + row_num, panel_width + 5)) echo(term.normal) echo(row_txt)
def main(): """ Main menu entry point. """ import os, random, time from x84.bbs import showart session, term = getsession(), getterminal() global menutoggle global arttoggle global bgtoggle text, width, height, dirty = u'', -1, -1, 2 menu_items = get_menu_items(session) colors = {} if colored_menu_items: colors['backlight'] = getattr(term, color_backlight) colors['highlight'] = getattr(term, color_highlight) colors['lowlight'] = getattr(term, color_lowlight) editor = get_line_editor(term, menu_items) menumode = False tallmode = False widemode = False if term.width >= 132: widemode = True if term.height >= 43: tallmode = True #if session.user['bg'] is None: randombgset() starttime = time.time() while True: if dirty > 1: # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) if dirty == 2: menutoggle, arttoggle, bgtoggle = True, True, True if dirty: session.activity = 'main menu' if width != term.width or height != term.height: width, height = term.width, term.height renderscreen(menutoggle, arttoggle, bgtoggle) echo(term.move(term.height, 2)) echo(u''.join((text, display_prompt(term, colors), editor.refresh()+term.normal))) dirty = 0 event, data = session.read_events(('input', 'refresh'), 0.1) if event == 'refresh': dirty = True continue elif event == 'input': session.buffer_input(data, pushback=True) # we must loop over inkey(0), we received a 'data' # event, though there may be many keystrokes awaiting for our # decoding -- or none at all (multibyte sequence not yet complete). inp = term.inkey(0) while inp: if inp == u'*': menutoggle = not menutoggle dirty = True break if inp.code == term.KEY_TAB: starttime = time.time() randombgset() dirty = True break if inp.code == term.KEY_ENTER: # find matching menu item, for item in menu_items: if item.inp_key == editor.content.strip(): echo(term.normal + u'\r\n') gosub(item.script, *item.args, **item.kwargs) editor.content = u'' dirty = 3 break else: if editor.content: # command not found, clear prompt. echo(u''.join(( (u'\b' * len(editor.content)), (u' ' * len(editor.content)), (u'\b' * len(editor.content)),))) editor.content = u'' echo(editor.refresh()+term.normal) elif inp.is_sequence: echo(editor.process_keystroke(inp.code)) else: echo(editor.process_keystroke(inp)) inp = term.inkey(0) if time.time() - starttime > 1800: dirty = True starttime = time.time() randombgset() continue
def main(): session = getsession() session.activity = u'hanging out in voting script' term = getterminal() echo(syncterm_setfont('topaz')) db = DBProxy(databasename) if 'questions' not in db: generate_database() while True: # clears the screen and displays the vote art header echo(term.clear()) for line in showart( os.path.join(os.path.dirname(__file__), 'art', 'vote.ans'), 'cp437'): echo(term.cyan + term.move_x(max(0, (term.width / 2) - 40)) + line) if 'sysop' in session.user.groups: spacing = 1 else: spacing = 7 echo(' ') echo(term.magenta(u'\n (') + term.cyan(u'r') + term.magenta(u')') + term.white(u'esults') + ' ' * spacing + term.magenta(u'(') + term.cyan(u'v') + term.magenta(u')') + term.white(u'ote on a question') + u' ' * spacing + term.magenta(u'(') + term.cyan(u'a') + term.magenta(u')') + term.white(u'dd a new question') + u' ' * spacing) if 'sysop' in session.user.groups: echo(term.magenta(u'(') + term.cyan(u'd') + term.magenta(u')') + term.white(u'elete a question') + u' ' * spacing) echo(term.magenta(u'(') + term.cyan(u'q') + term.magenta(u')') + term.white(u'uit') + term.magenta(u'\r\n\r\nx/84 voting booth command: ')) le = LineEditor(10) le.colors['highlight'] = term.cyan inp = le.read() # makes the input indifferent to wheter you used lower case when typing # in a command or not.. inp = (inp or u'').lower() if 'sysop' in session.user.groups and inp == u'd': while True: questionnumber = query_question() if questionnumber == -1: break delete_question(questionnumber) elif inp == u'r': while True: questionnumber = query_question() if questionnumber == -1: break list_results(questionnumber) elif inp == u'v': while True: questionnumber = query_question() if questionnumber == -1: break vote(questionnumber) elif inp == u'a': add_question() elif inp == u'q': return else: # if no valid key is pressed then do some ami/x esthetics. echo(term.red(u'\r\nNo such command. Try again.\r\n')) waitprompt(term)
def main(quick=False): """ Main procedure. """ session, term = getsession(), getterminal() session.activity = 'checking for new messages' # set syncterm font, if any if term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) colors = dict( highlight=lambda txt: txt, lowlight=lambda txt: txt, backlight=lambda txt: txt, text=lambda txt: txt ) if not colored_menu_items else dict( highlight=getattr(term, color_highlight), lowlight=getattr(term, color_lowlight), backlight=getattr(term, color_backlight), text=getattr(term, color_text)) yloc = top_margin = 0 subscription = session.user.get('msg_subscription', []) dirty = 2 while True: if dirty == 2: # display header art, yloc = display_banner(art_file, encoding=art_encoding, center=True) xloc = max(0, (term.width // 2) - 40) echo(u'\r\n') top_margin = yloc = (yloc + 1) elif dirty: echo(term.move(top_margin, 0) + term.normal + term.clear_eos) echo(term.move(top_margin, xloc)) if dirty: if not subscription: # prompt the user for a tag subscription, and loop # back again when completed to re-draw and show new messages. subscription = session.user['msg_subscription'] = ( prompt_subscription( session=session, term=term, yloc=top_margin, subscription=subscription, colors=colors)) continue messages, messages_bytags = get_messages_by_subscription( session, subscription) # When quick login ('y') selected in top.py, return immediately # when no new messages are matched any longer. if quick and not messages['new']: echo(term.move_x(xloc) + u'\r\nNo new messages.\r\n') return waitprompt(term) txt = describe_message_area( term=term, subscription=subscription, messages_bytags=messages_bytags, colors=colors) yloc = top_margin + show_description( term=term, description=txt, color=None, subsequent_indent=' ' * len('message area: ')) echo(render_menu_entries( term=term, top_margin=yloc, menu_items=get_menu(messages), colors=colors, max_cols=2)) echo(display_prompt(term=term, colors=colors)) echo(colors['backlight'](u' \b')) dirty = False event, data = session.read_events(('refresh', 'newmsg', 'input')) if event == 'refresh': # screen resized, redraw. dirty = 2 continue elif event == 'newmsg': # When a new message is sent, 'newmsg' event is broadcasted. session.flush_event('newmsg') nxt_msgs, nxt_bytags = get_messages_by_subscription( session, subscription) if nxt_msgs['new'] - messages['new']: # beep and re-display when a new message has arrived. echo(u'\b') messages, messages_bytags = nxt_msgs, nxt_bytags dirty = True continue elif event == 'input': # on input, block until carriage return session.buffer_input(data, pushback=True) given_inp = LineEditor( 1, colors={'highlight': colors['backlight']} ).read() if given_inp is None: # escape/cancel continue inp = given_inp.strip() if inp.lower() in (u'n', 'a', 'v'): # read new/all/private messages message_indices = sorted(list( {'n': messages['new'], 'a': messages['all'], 'v': messages['private'], }[inp.lower()])) if message_indices: dirty = 2 read_messages(session=session, term=term, message_indices=message_indices, colors=colors) elif inp.lower() == u'm' and messages['new']: # mark all messages as read dirty = 1 do_mark_as_read(session, messages['new']) elif inp.lower() in (u'p', u'w'): # write new public/private message dirty = 2 public = bool(inp.lower() == u'p') msg = Msg() if ( not prompt_recipient( term=term, msg=msg, colors=colors, public=public ) or not prompt_subject( term=term, msg=msg, colors=colors ) or not prompt_body( term=term, msg=msg, colors=colors ) or not prompt_tags( session=session, term=term, msg=msg, colors=colors, public=public )): continue do_send_message(session=session, term=term, msg=msg, colors=colors) elif inp.lower() == u'c': # prompt for new tag subscription (at next loop) subscription = [] dirty = 1 elif inp.lower() == u'?': # help echo(term.move(top_margin, 0) + term.clear_eos) do_describe_message_system(term, colors) waitprompt(term) dirty = 1 elif inp.lower() == u'q': return if given_inp: # clear out line editor prompt echo(colors['backlight'](u'\b \b'))
def play(): import time from random import randint import os from x84.bbs import getterminal, from_cp437, AnsiWindow, syncterm_setfont from x84.bbs import echo as echo_unbuffered term = getterminal() field = [] global charcache charcache = u'' field_width = 10 field_height = 20 # Access scheme looks like this: # layout[p][r][ypox][xpos] # layoutcolor = [ 7,2,3,4,4,6,7 ] layout = [ # ## # ## [ [ [1, 1, ], [1, 1, ], ], ], # # # # # # # # [ [ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], ], [ [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0], ] ], # ### # # [ [ [0, 0, 0], [1, 1, 1], [0, 1, 0], ], [ [0, 1, 0], [0, 1, 1], [0, 1, 0], ], [ [0, 1, 0], [1, 1, 1], [0, 0, 0], ], [ [0, 1, 0], [1, 1, 0], [0, 1, 0], ], ], # # # # # ## [ [ [0, 1, 0], [0, 1, 0], [0, 1, 1], ], [ [0, 0, 1], [1, 1, 1], [0, 0, 0], ], [ [1, 1, 0], [0, 1, 0], [0, 1, 0], ], [ [0, 0, 0], [1, 1, 1], [1, 0, 0], ], ], # # # # # ## [ [ [0, 1, 0], [0, 1, 0], [1, 1, 0], ], [ [0, 0, 0], [1, 1, 1], [0, 0, 1], ], [ [0, 1, 1], [0, 1, 0], [0, 1, 0], ], [ [1, 0, 0], [1, 1, 1], [0, 0, 0], ], ], # ## # ## [ [ [0, 1, 0], [1, 1, 0], [1, 0, 0], ], [ [0, 0, 0], [1, 1, 0], [0, 1, 1], ], ], # ## # ## [ [ [0, 1, 0], [0, 1, 1], [0, 0, 1], ], [ [0, 0, 0], [0, 1, 1], [1, 1, 0], ], ], ] fieldx1 = 32 fieldy1 = 10 scorex1 = 11 scorey1 = 11 class RectRedraw: x1 = None y1 = None x2 = None y2 = None def max(r, val, valmax): if val > valmax: return valmax return val def min(r, val, valmin): if val < valmin: return valmin return val def merge(r, x1, y1, x2, y2): if r.x1 is None or r.x1 > x1: r.x1 = r.min(x1, 0) if r.y1 is None or r.y1 > y1: r.y1 = r.min(y1, 0) if r.x2 is None or r.x2 < x2: r.x2 = r.max(x2, field_width) if r.y2 is None or r.y2 < y2: r.y2 = r.max(y2, field_height) # print r.x1,r.y1,r.x2,r.y2 def clean(r): r.x1 = None r.y1 = None r.x2 = None r.y2 = None rr = RectRedraw() for _ in range(field_height): field.append([0] * field_width) def echo(s): global charcache charcache += s assert term.height > (field_height + 1) echo_unbuffered(u''.join(( u'\r\n\r\n', u'REAdY YOUR tERMiNAl %s ' % (term.bold_blue('(!)'),), u'\r\n\r\n', u'%s PRESS ANY kEY' % (term.bold_black('...'),), ))) term.inkey() # set syncterm font to cp437 if term.kind.startswith('ansi'): echo_unbuffered(syncterm_setfont('cp437')) artfile = os.path.join(os.path.dirname(__file__), 'art', 'tetris.ans') echo_unbuffered(u'\r\n' * term.height) # cls if os.path.exists(artfile): echo_unbuffered(from_cp437(open(artfile).read()).rstrip()) def gotoxy(x, y): echo(term.move(y, x)) def plotblock(color, lastcolor): if color: c = u'\u2588\u2588' # '\xDB\xDB' else: # both empty c = ' ' color = 0 # Output optimization if color % 8 == 0: color = color / 8 if color == lastcolor: echo(c) else: if color: fg = str(30 + color % 8) else: fg = '37' if color >= 8: bg = ';%d' % (40 + color / 8) else: bg = '' echo('\x1b[0;' + fg + bg + 'm') echo(c) lastcolor = color return lastcolor def drawfield(): lastcolor = '' for y in range(0, field_height, 2): # gotoxy(field_width,2+y/2) gotoxy(fieldx1 + 2, fieldy1 + 1 + y / 2) # Which block to show, full, half-up, half-down or empty. for x in range(field_width): color = field[y][x] + field[y + 1][x] * 8 if field[y][x] and field[y + 1][x]: c = u'\u2588' # '\xDB' if field[y][x] == field[y + 1][x]: color = color % 8 else: c = u'\u2580' # '\xDF' elif field[y][x] and not field[y + 1][x]: c = u'\u2580' # '\xDF' elif not field[y][x] and field[y + 1][x]: c = u'\u2584' # '\xDC' else: # both empty c = ' ' # Output optimization if color % 8 == 0: color = color / 8 if color == lastcolor: echo(c) else: if color: fg = str(30 + color % 8) else: fg = '37' if color >= 8: bg = ';%d' % (40 + color / 8) else: bg = '' echo('\x1b[0;' + fg + bg + 'm') echo(c) lastcolor = color echo(term.normal) layoutcolor = [7, 2, 7, 6, 3, 6, 3] # p = -1 # Current piece type nextpiece = randint(0, len(layout) - 1) p = randint(0, len(layout) - 1) p = 1 r = 0 # Current rotation xpos = 4 # X position # ypos = -2 # Y position ypos = -len(layout[p][0]) level = 1 score = 0 lines = 0 def flush(): global charcache echo_unbuffered(charcache) charcache = u'' def fillpiece(x, y, p, r, value): row = 0 for line in layout[p][r]: col = 0 for c in line: if c and (y + row) >= 0: field[y + row][x + col] = value col += 1 row += 1 def showpiece(x, y, p, r): fillpiece(x, y, p, r, layoutcolor[p]) def hidepiece(): fillpiece(xpos, ypos, p, r, 0) def testpiece(x, y, newr): hidepiece() # Space at the new location? row = 0 for line in layout[p][newr]: col = 0 for c in line: try: if c: if ((y + row) >= 0 and field[y + row][x + col] or (x + col) < 0 or (x + col) > 9): return 0 except IndexError: return 0 col += 1 row += 1 # Movement possible return 1 def movepiece(x, y, newr): if testpiece(x, y, newr): # Build redraw rectangle rr.merge(xpos, ypos, xpos + len(layout[p][0][0]), ypos + len(layout[p][0])) rr.merge(x, y, x + len(layout[p][0][0]), y + len(layout[p][0])) showpiece(x, y, p, newr) return (x, y, newr, 1) else: showpiece(xpos, ypos, p, r) return (xpos, ypos, r, 0) def shownext(p): r = 0 for y in range(4): gotoxy(26, 18 + y) echo(u' ' * 4) echo(term.color(layoutcolor[p])) yoffset = int(len(layout[p][r][0]) < 4) xoffset = int(len(layout[p][r]) < 3) for y in range(len(layout[p][r])): for x in range(len(layout[p][r][y])): val = layout[p][r][y][x] if val: gotoxy(26 + x + xoffset, 18 + y + yoffset) echo(u'\u2588\u2588') def drawstats(): echo(term.move(scorey1, scorex1) + '%d' % level) echo(term.move(scorey1 + 2, scorex1) + '%d' % lines) echo(term.move(scorey1 + 3, scorex1) + '%d' % score) drawstats() ticksize = 0.4 nexttick = time.time() + ticksize showpiece(xpos, ypos, p, r) gotoxy(26, 17) echo(term.blue_reverse('next')) shownext(nextpiece) # Full redraw first frame rr.merge(0, 0, field_width, field_height) buf = '' while True: drawfield() # gotoxy(0,0) # echo('\x1b[37mx: %d, y: %d, p: %d '%(xpos,ypos,p)) slice = nexttick - time.time() if slice < 0: slice = 0 echo(buf) buf = '' flush() key = term.inkey(slice + 0.01) now = time.time() # hidepiece() if key is not None: if key in (u'q', u'Q'): return (0, 0, 0) elif key.code == term.KEY_LEFT or key == u'h': xpos, ypos, r, m = movepiece(xpos - 1, ypos, r) elif key.code == term.KEY_RIGHT or key == u'l': xpos, ypos, r, m = movepiece(xpos + 1, ypos, r) elif key.code == term.KEY_UP or key == u'k': xpos, ypos, r, m = movepiece( xpos, ypos, (r + 1) % len(layout[p])) elif key.code == term.KEY_DOWN or key == u'j': xpos, ypos, r, m = movepiece(xpos, ypos + 1, r) elif key in (' ',): m = True c = 0 while m: xpos, ypos, r, m = movepiece(xpos, ypos + 1, r) if m: c += 1 if c: nexttick = time.time() + ticksize # New tick? if now > nexttick: nexttick += ticksize # Move down piece xpos, ypos, r, moved = movepiece(xpos, ypos + 1, r) # Piece has touched down? if not moved: # Is the player dead? if ypos <= -len(layout[p][0]): death_win = AnsiWindow(height=6, width=40, yloc=fieldy1 + 10 / 2, xloc=fieldx1 - 11) death_win.colors['border'] = term.bold_black echo_unbuffered(death_win.clear() + death_win.border()) echo_unbuffered( term.move(fieldy1 + 10 / 2 + 1, fieldx1 - 11)) echo_unbuffered(( u'!! gAME OVeR!! Score was: %i' % (score,)).center(40)) echo_unbuffered( term.move(fieldy1 + 10 / 2 + 3, fieldx1 - 11)) echo_unbuffered(u'press RETURN'.center(40)) while True: inp = term.inkey() if inp.code == term.KEY_ENTER: break return (score, level, lines) # Any complete rows to remove? complete = [] for y in range(field_height): x = 0 while x < field_width: if field[y][x] == 0: break x += 1 if x == field_width: complete.append(y) if len(complete) > 0: # Add score lines += len(complete) score += len(complete) * len(complete) * 100 # Shrink field for line in complete: del field[line] field.insert(0, [0] * field_width) if lines >= level * 10: level += 1 ticksize = 0.4 - level * 0.02 drawstats() # Redraw complete field rr.merge(0, 0, field_width, field_height) # Time for a new piece p = nextpiece nextpiece = randint(0, len(layout) - 1) r = 0 xpos = 4 ypos = -len(layout[p][0]) showpiece(xpos, ypos, p, r) shownext(nextpiece)
def main(): session = getsession() session.activity = u'hanging out in voting script' term = getterminal() echo(term.clear + syncterm_setfont('topaz')) db = DBProxy(databasename) if not 'questions' in db: generate_database() while True: # clears the screen and displays the vote art header echo(term.clear()) for line in showart( os.path.join(os.path.dirname(__file__), 'art', 'vote.ans'), 'cp437'): echo(term.cyan + term.move_x(max(0, (term.width / 2) - 40)) + line) if 'sysop' in session.user.groups: spacing = 1 else: spacing = 7 echo(' ') echo(term.magenta + '\n (' + term.cyan + 'r' + term.magenta + ')' + term.white + 'esults' + ' ' * spacing) echo(term.magenta + '(' + term.cyan + 'v' + term.magenta + ')' + term.white + 'ote on a question' + ' ' * spacing) echo(term.magenta + '(' + term.cyan + 'a' + term.magenta + ')' + term.white + 'dd a new question' + ' ' * spacing) if 'sysop' in session.user.groups: echo(term.magenta + '(' + term.cyan + 'd' + term.magenta + ')' + term.white + 'elete a question' + ' ' * spacing) echo( term.magenta + '(' + term.cyan + 'q' + term.magenta + ')' + term.white + 'uit') echo(term.magenta + '\r\n\r\n\r\nx/84 voting booth command: ') le = LineEditor(30) le.colors['highlight'] = term.cyan inp = le.read() # makes the input indifferent to wheter you used lower case when typing # in a command or not.. inp = inp.lower() if 'sysop' in session.user.groups and inp == 'd': while True: questionnumber = query_question() if questionnumber == 999: break delete_question(questionnumber) elif inp == 'r': while True: questionnumber = query_question() if questionnumber == 999: break list_results(questionnumber) elif inp == 'v': while True: questionnumber = query_question() if questionnumber == 999: break vote(questionnumber) elif inp == 'a': add_question() elif inp == 'q': return else: # if no valid key is pressed then do some ami/x esthetics. echo(term.red + '\r\nNo such command. Try again.\r\n') waitprompt()
def main(): """ Main procedure. """ # pylint: disable=R0912 # Too many branches import logging from x84.bbs import getsession, getterminal, ini, echo, getch, syncterm_setfont session, term = getsession(), getterminal() pager, selector = get_pager(), get_selector() log = logging.getLogger(__name__) thread = None if ini.CFG.has_section('bbs-scene'): log.info('starting bbs-scene.org oneliners thread...') thread = FetchUpdates() thread.start() elif ini.CFG.has_section('shroo-ms'): log.info('starting shroo.ms oneliners thread...') thread = FetchUpdatesShrooMs() thread.start() else: log.info('using built-in oneliners...') if thread is not None: session.activity = u'one-liners [%s]' % (thread.ident,) else: session.activity = u'one-liners' # flag a pager update, dirty = True # force screen clear on first loop, session.buffer_event('refresh', ('init',)) # makes syncterm switch back to the amiga topaz font if term._kind.startswith('ansi'): echo(syncterm_setfont('topaz')) while True: # 1. calculate and redraw screen, # or enter dumb pager mode (no scrolling) if session.poll_event('refresh'): pager, selector = get_pager(), get_selector(selector.selection) echo(banner()) dirty = True if chk_thread(thread): thread = None while session.read_event('oneliner_update', 0.15): dirty = True if dirty and (not session.user.get('expert', False) and term.width >= 78 and term.height >= 20): # smart terminal redraw(pager, selector) dirty = False elif dirty: # dumb terminal if thread is not None: wait_for(thread) if chk_thread(thread): thread = None echo(u'\r\n\r\n') return dummy_pager() # 2. detect and process keyboard input, inp = getch(1) if inp is not None: # input is multiplexed to both interfaces echo(pager.process_keystroke(inp)) echo(selector.process_keystroke(inp)) # selected 'yes' & return, 'say something' if (selector.selected and selector.selection == selector.left): # re-assign thread so that it is checked for updates thread = saysomething(dumb=False) # undo 'selected' state of yes/no bar, selector.selected = False # quit 'q', or selected 'no' & return elif (selector.selected and selector.selection == selector.right or pager.quit): # makes syncterm switch back to the cp437 font if term._kind.startswith('ansi'): echo(syncterm_setfont('cp437')) return
def main(save_key=None, continue_draft=False): """ Main Editor procedure. When argument ``save_key`` is non-None, the result is saved to the user attribute of the same name. When unset, the contents are returned to the caller. When argument ``continue_draft`` is non-None, the editor continues a previously saved draft, whose contents is its value. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements session, term = getsession(), getterminal() # set syncterm font, if any if term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) movement = (term.KEY_UP, term.KEY_DOWN, term.KEY_NPAGE, term.KEY_PPAGE, term.KEY_HOME, term.KEY_END, u'\r', term.KEY_ENTER) keyset = {'edit': ('\r', '\n'), 'command': (unichr(27),), 'kill': (u'K',), 'undo': (u'u', 'U',), 'goto': (u'G',), 'insert': (u'I',), 'insert-before': (u'O',), 'insert-after': (u'o',), 'join': (u'J',), 'rubout': (unichr(8), unichr(127), unichr(23)), } def merge(): """ Merges line editor content as a replacement for the currently selected lightbar row. Returns True if text inserted caused additional rows to be appended, which is meaningful in a window refresh context. """ lightbar.content[lightbar.index] = [ lightbar.selection[0], softwrap_join(wrap_rstrip(lneditor.content)) + HARDWRAP] prior_length = len(lightbar.content) prior_position = lightbar.position set_lbcontent(lightbar, get_lbcontent(lightbar)) if len(lightbar.content) - prior_length == 0: echo(lightbar.refresh_row(prior_position[0])) return False while len(lightbar.content) - prior_length > 0: # hidden move-down for each appended line lightbar.move_down() prior_length += 1 return True def statusline(lightbar): """ Display status line and command help on ``lightbar`` borders """ lightbar.colors['border'] = term.red if edit else term.yellow keyset_cmd = u'' if not edit: keyset_cmd = u''.join(( term.yellow(u'-( '), term.yellow_underline(u'S'), u':', term.bold(u'ave'), u' ', term.yellow_underline(u'A'), u':', term.bold(u'bort'), u' ', term.yellow_underline(u'?'), u':', term.bold(u'help'), term.yellow(u' )-'),)) keyset_xpos = max(0, lightbar.width - (term.length(keyset_cmd) + 3)) keyset_cmd = lightbar.pos(lightbar.yloc + lightbar.height - 1, keyset_xpos ) + keyset_cmd return u''.join(( lightbar.border(), keyset_cmd, lightbar.pos(lightbar.yloc + lightbar.height - 1, lightbar.xpadding), u''.join(( term.red(u'-[ '), u'EditiNG liNE ', term.reverse_red('%d' % (lightbar.index + 1,)), term.red(u' ]-'),)) if edit else u''.join(( term.yellow(u'-( '), u'liNE ', term.yellow('%d/%d ' % ( lightbar.index + 1, len(lightbar.content),)), '%3d%% ' % ( int((float(lightbar.index + 1) / max(1, len(lightbar.content))) * 100)), term.yellow(u' )-'),)), lightbar.title(u''.join(( term.red('-] '), term.bold(u'Escape'), u':', term.bold_red(u'command mode'), term.red(' [-'),) ) if edit else u''.join(( term.yellow('-( '), term.bold(u'Enter'), u':', term.bold_yellow(u'edit mode'), term.yellow(' )-'),))), lightbar.fixate(), )) def redraw_lneditor(lightbar, lneditor): """ Return ucs suitable for refreshing line editor. """ return ''.join(( term.normal, statusline(lightbar), lneditor.border(), lneditor.refresh())) def get_ui(ucs, lightbar=None): """ Returns Lightbar and ScrollingEditor instance. """ lbr = get_lightbar(ucs) lbr.position = (lightbar.position if lightbar is not None else (0, 0)) lne = get_lneditor(lbr) return lbr, lne def banner(): """ Returns string suitable clearing screen """ return u''.join(( term.move(0, 0), term.normal, term.clear)) def redraw(lightbar, lneditor): """ Returns ucs suitable for redrawing Lightbar and ScrollingEditor UI elements. """ return u''.join(( term.normal, redraw_lightbar(lightbar), redraw_lneditor(lightbar, lneditor) if edit else u'', )) def redraw_lightbar(lightbar): """ Returns ucs suitable for redrawing Lightbar. """ return u''.join(( statusline(lightbar), lightbar.refresh(),)) def resize(lightbar): """ Resize Lightbar. """ if edit: # always re-merge current line on resize, merge() lbr, lne = get_ui(get_lbcontent(lightbar), lightbar) echo(redraw(lbr, lne)) return lbr, lne if continue_draft: ucs = continue_draft else: ucs = u'' lightbar, lneditor = get_ui(ucs, None) echo(banner()) dirty = True edit = False digbuf, num_repeat = u'', -1 count_repeat = lambda: range(max(num_repeat, 1)) while True: # poll for refresh if session.poll_event('refresh'): echo(banner()) lightbar, lneditor = resize(lightbar) dirty = True if dirty: session.activity = 'editing %s' % (save_key,) echo(redraw(lightbar, lneditor)) dirty = False # poll for input inp = term.inkey() # buffer keystrokes for repeat if (not edit and inp and inp.isdigit()): digbuf += inp if len(digbuf) > 10: # overflow, echo(u'\a') digbuf = inp try: num_repeat = int(digbuf) except ValueError: try: num_repeat = int(inp) except ValueError: pass continue else: digbuf = u'' # toggle edit mode, if (inp in keyset['command']) or not edit and inp in keyset['edit']: edit = not edit # toggle if not edit: # switched to command mode, merge our lines echo(term.normal + lneditor.erase_border()) merge() lightbar.colors['highlight'] = term.yellow_reverse else: # switched to edit mode, save draft, # instantiate new line editor save_draft(save_key, get_lbcontent(lightbar)) lneditor = get_lneditor(lightbar) lightbar.colors['highlight'] = term.red_reverse dirty = True # command mode, kill line elif not edit and inp in keyset['kill']: # when 'killing' a line, make accomidations to clear # bottom-most row, otherwise a ghosting effect occurs for _ in count_repeat(): del lightbar.content[lightbar.index] set_lbcontent(lightbar, get_lbcontent(lightbar)) if lightbar.visible_bottom > len(lightbar.content): echo(lightbar.refresh_row(lightbar.visible_bottom + 1)) else: dirty = True save_draft(save_key, get_lbcontent(lightbar)) # command mode, insert line elif not edit and inp in keyset['insert']: for _ in count_repeat(): lightbar.content.insert(lightbar.index, (lightbar.index, HARDWRAP,)) set_lbcontent(lightbar, get_lbcontent(lightbar)) save_draft(save_key, get_lbcontent(lightbar)) dirty = True # command mode; goto line elif not edit and inp in keyset['goto']: if num_repeat == -1: # 'G' alone goes to end of file, num_repeat = len(lightbar.content) echo(lightbar.goto((num_repeat or 1) - 1)) echo(statusline(lightbar)) # command mode; insert-before (switch to edit mode) elif not edit and inp in keyset['insert-before']: lightbar.content.insert(lightbar.index, (lightbar.index, HARDWRAP,)) set_lbcontent(lightbar, get_lbcontent(lightbar)) edit = dirty = True # switched to edit mode, save draft, # instantiate new line editor lightbar.colors['highlight'] = term.red_reverse lneditor = get_lneditor(lightbar) save_draft(save_key, get_lbcontent(lightbar)) # command mode; insert-after (switch to edit mode) elif not edit and inp in keyset['insert-after']: lightbar.content.insert(lightbar.index + 1, (lightbar.index + 1, HARDWRAP,)) set_lbcontent(lightbar, get_lbcontent(lightbar)) edit = dirty = True # switched to edit mode, save draft, # instantiate new line editor lightbar.colors['highlight'] = term.red_reverse lightbar.move_down() lneditor = get_lneditor(lightbar) save_draft(save_key, get_lbcontent(lightbar)) # command mode, undo elif not edit and inp in keyset['undo']: for _ in count_repeat(): if len(UNDO): set_lbcontent(lightbar, UNDO.pop()) dirty = True else: echo(u'\a') break # command mode, join line elif not edit and inp in keyset['join']: for _ in count_repeat(): if lightbar.index + 1 < len(lightbar.content): idx = lightbar.index lightbar.content[idx] = ( idx, WHITESPACE.join(( lightbar.content[idx][1].rstrip(), lightbar.content[idx + 1][1].lstrip(),)) ) del lightbar.content[idx + 1] prior_length = len(lightbar.content) set_lbcontent(lightbar, get_lbcontent(lightbar)) if len(lightbar.content) - prior_length > 0: lightbar.move_down() dirty = True else: echo(u'\a') break if dirty: save_draft(save_key, get_lbcontent(lightbar)) # command mode, basic cmds & movement elif not edit and inp: if inp in (u'a', u'A',): if yes_no(lightbar, term.yellow(u'- ') + term.bold_red(u'AbORt') + term.yellow(u' -')): return False dirty = True elif inp in (u's', u'S',): if yes_no(lightbar, term.yellow(u'- ') + term.bold_green(u'SAVE') + term.yellow(u' -'), term.reverse_green): # save contents to user attribtue content = get_contents(lightbar) if not save_key: # return entire message body as return value return content save(save_key, content) return True dirty = True elif inp in (u'?',): show_help(term) term.inkey() dirty = True else: moved = False for _ in count_repeat(): echo(lightbar.process_keystroke(inp)) moved = lightbar.moved or moved if moved: echo(statusline(lightbar)) # edit mode; movement elif edit and (inp in movement or inp.code in movement): dirty = merge() if inp in (u'\r', u'\n') or inp.code == term.KEY_ENTER: lightbar.content.insert(lightbar.index + 1, [lightbar.selection[0] + 1, u'']) lightbar.move_down() dirty = True ucs = lightbar.process_keystroke(inp) #if lightbar.moved: # XXX optimize redraws echo(term.normal + lneditor.erase_border()) echo(ucs) lneditor = get_lneditor(lightbar) save_draft(save_key, get_lbcontent(lightbar)) echo(lneditor.border() + lneditor.refresh()) # edit mode -- append character / backspace elif edit and inp: if (inp in keyset['rubout'] and len(lneditor.content) == 0 and lightbar.index > 0): # erase past margin, echo(term.normal + lneditor.erase_border()) del lightbar.content[lightbar.index] lightbar.move_up() set_lbcontent(lightbar, get_lbcontent(lightbar)) lneditor = get_lneditor(lightbar) dirty = True else: # edit mode, add/delete ch echo(lneditor.process_keystroke(inp)) if lneditor.moved: echo(statusline(lightbar)) if inp and not inp.isdigit(): # commands were processed, reset num_repeat to 1 num_repeat = -1
def main(): """ Main procedure. """ # pylint: disable=R0912 # Too many branches import logging from x84.bbs import getsession, getterminal, ini, echo, getch, syncterm_setfont session, term = getsession(), getterminal() pager, selector = get_pager(), get_selector() log = logging.getLogger(__name__) thread = None if ini.CFG.has_section('bbs-scene'): log.info('starting bbs-scene.org oneliners thread...') thread = FetchUpdates() thread.start() elif ini.CFG.has_section('shroo-ms'): log.info('starting shroo.ms oneliners thread...') thread = FetchUpdatesShrooMs() thread.start() else: log.info('using built-in oneliners...') if thread is not None: session.activity = u'one-liners [%s]' % (thread.ident, ) else: session.activity = u'one-liners' # flag a pager update, dirty = True # force screen clear on first loop, session.buffer_event('refresh', ('init', )) # makes syncterm switch back to the amiga topaz font if term._kind.startswith('ansi'): echo(syncterm_setfont('topaz')) while True: # 1. calculate and redraw screen, # or enter dumb pager mode (no scrolling) if session.poll_event('refresh'): pager, selector = get_pager(), get_selector(selector.selection) echo(banner()) dirty = True if chk_thread(thread): thread = None while session.read_event('oneliner_update', 0.15): dirty = True if dirty and (not session.user.get('expert', False) and term.width >= 78 and term.height >= 20): # smart terminal redraw(pager, selector) dirty = False elif dirty: # dumb terminal if thread is not None: wait_for(thread) if chk_thread(thread): thread = None echo(u'\r\n\r\n') return dummy_pager() # 2. detect and process keyboard input, inp = getch(1) if inp is not None: # input is multiplexed to both interfaces echo(pager.process_keystroke(inp)) echo(selector.process_keystroke(inp)) # selected 'yes' & return, 'say something' if (selector.selected and selector.selection == selector.left): # re-assign thread so that it is checked for updates thread = saysomething(dumb=False) # undo 'selected' state of yes/no bar, selector.selected = False # quit 'q', or selected 'no' & return elif (selector.selected and selector.selection == selector.right or pager.quit): # makes syncterm switch back to the cp437 font if term._kind.startswith('ansi'): echo(syncterm_setfont('cp437')) return
def main(): """ Main menu entry point. """ session, term = getsession(), getterminal() text, width, height, dirty = u'', -1, -1, 2 menu_items = get_menu_items(session) editor = get_line_editor(term, menu_items) colors = {} if colored_menu_items: colors['backlight'] = getattr(term, color_backlight) colors['highlight'] = getattr(term, color_highlight) colors['lowlight'] = getattr(term, color_lowlight) while True: if dirty == 2: # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) if dirty: session.activity = 'main menu' top_margin = display_banner(art_file, encoding=art_encoding) + 1 echo(u'\r\n') if width != term.width or height != term.height: width, height = term.width, term.height text = render_menu_entries( term, top_margin, menu_items, colors) echo(u''.join((text, display_prompt(term, colors), editor.refresh()))) dirty = 0 event, data = session.read_events(('input', 'refresh')) if event == 'refresh': dirty = True continue elif event == 'input': session.buffer_input(data, pushback=True) # we must loop over inkey(0), we received a 'data' # event, though there may be many keystrokes awaiting for our # decoding -- or none at all (multibyte sequence not yet complete). inp = term.inkey(0) while inp: if inp.code == term.KEY_ENTER: # find matching menu item, for item in menu_items: if item.inp_key == editor.content.strip(): echo(term.normal + u'\r\n') gosub(item.script, *item.args, **item.kwargs) editor.content = u'' dirty = 2 break else: if editor.content: # command not found, clear prompt. echo(u''.join(( (u'\b' * len(editor.content)), (u' ' * len(editor.content)), (u'\b' * len(editor.content)),))) editor.content = u'' echo(editor.refresh()) elif inp.is_sequence: echo(editor.process_keystroke(inp.code)) else: echo(editor.process_keystroke(inp)) inp = term.inkey(0)
def main(quick=False): """ Main procedure. """ session, term = getsession(), getterminal() session.activity = 'checking for new messages' # set syncterm font, if any if term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) colors = dict(highlight=lambda txt: txt, lowlight=lambda txt: txt, backlight=lambda txt: txt, text=lambda txt: txt) if not colored_menu_items else dict( highlight=getattr(term, color_highlight), lowlight=getattr(term, color_lowlight), backlight=getattr(term, color_backlight), text=getattr(term, color_text)) yloc = top_margin = 0 subscription = session.user.get('msg_subscription', []) dirty = 2 while True: if dirty == 2: # display header art, yloc = display_banner(art_file, encoding=art_encoding, center=True) xloc = max(0, (term.width // 2) - 40) echo(u'\r\n') top_margin = yloc = (yloc + 1) elif dirty: echo(term.move(top_margin, 0) + term.normal + term.clear_eos) echo(term.move(top_margin, xloc)) if dirty: if not subscription: # prompt the user for a tag subscription, and loop # back again when completed to re-draw and show new messages. subscription = session.user['msg_subscription'] = ( prompt_subscription(session=session, term=term, yloc=top_margin, subscription=subscription, colors=colors)) continue messages, messages_bytags = get_messages_by_subscription( session, subscription) # When quick login ('y') selected in top.py, return immediately # when no new messages are matched any longer. if quick and not messages['new']: echo(term.move_x(xloc) + u'\r\nNo new messages.\r\n') return waitprompt(term) txt = describe_message_area(term=term, subscription=subscription, messages_bytags=messages_bytags, colors=colors) yloc = top_margin + show_description( term=term, description=txt, color=None, subsequent_indent=' ' * len('message area: ')) echo( render_menu_entries(term=term, top_margin=yloc, menu_items=get_menu(messages), colors=colors, max_cols=2)) echo(display_prompt(term=term, colors=colors)) echo(colors['backlight'](u' \b')) dirty = False event, data = session.read_events(('refresh', 'newmsg', 'input')) if event == 'refresh': # screen resized, redraw. dirty = 2 continue elif event == 'newmsg': # When a new message is sent, 'newmsg' event is broadcasted. session.flush_event('newmsg') nxt_msgs, nxt_bytags = get_messages_by_subscription( session, subscription) if nxt_msgs['new'] - messages['new']: # beep and re-display when a new message has arrived. echo(u'\b') messages, messages_bytags = nxt_msgs, nxt_bytags dirty = True continue elif event == 'input': # on input, block until carriage return session.buffer_input(data, pushback=True) given_inp = LineEditor(1, colors={ 'highlight': colors['backlight'] }).read() if given_inp is None: # escape/cancel continue inp = given_inp.strip() if inp.lower() in (u'n', 'a', 'v'): # read new/all/private messages message_indices = sorted( list({ 'n': messages['new'], 'a': messages['all'], 'v': messages['private'], }[inp.lower()])) if message_indices: dirty = 2 read_messages(session=session, term=term, message_indices=message_indices, colors=colors) elif inp.lower() == u'm' and messages['new']: # mark all messages as read dirty = 1 do_mark_as_read(session, messages['new']) elif inp.lower() in (u'p', u'w'): # write new public/private message dirty = 2 public = bool(inp.lower() == u'p') msg = Msg() if (not prompt_recipient( term=term, msg=msg, colors=colors, public=public) or not prompt_subject(term=term, msg=msg, colors=colors) or not prompt_body(term=term, msg=msg, colors=colors) or not prompt_tags(session=session, term=term, msg=msg, colors=colors, public=public)): continue do_send_message(session=session, term=term, msg=msg, colors=colors) elif inp.lower() == u'c': # prompt for new tag subscription (at next loop) subscription = [] dirty = 1 elif inp.lower() == u'?': # help echo(term.move(top_margin, 0) + term.clear_eos) do_describe_message_system(term, colors) waitprompt(term) dirty = 2 elif inp.lower() == u'q': return if given_inp: # clear out line editor prompt echo(colors['backlight'](u'\b \b'))
def play(): import time from random import randint import os from x84.bbs import getterminal, getch, from_cp437, AnsiWindow, syncterm_setfont from x84.bbs import echo as echo_unbuffered term = getterminal() field = [] global charcache charcache = u'' field_width = 10 field_height = 20 # Access scheme looks like this: # layout[p][r][ypox][xpos] # layoutcolor = [ 7,2,3,4,4,6,7 ] layout = [ # ## # ## [ [ [1, 1, ], [1, 1, ], ], ], # # # # # # # # [ [ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], ], [ [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0], ] ], # ### # # [ [ [0, 0, 0], [1, 1, 1], [0, 1, 0], ], [ [0, 1, 0], [0, 1, 1], [0, 1, 0], ], [ [0, 1, 0], [1, 1, 1], [0, 0, 0], ], [ [0, 1, 0], [1, 1, 0], [0, 1, 0], ], ], # # # # # ## [ [ [0, 1, 0], [0, 1, 0], [0, 1, 1], ], [ [0, 0, 1], [1, 1, 1], [0, 0, 0], ], [ [1, 1, 0], [0, 1, 0], [0, 1, 0], ], [ [0, 0, 0], [1, 1, 1], [1, 0, 0], ], ], # # # # # ## [ [ [0, 1, 0], [0, 1, 0], [1, 1, 0], ], [ [0, 0, 0], [1, 1, 1], [0, 0, 1], ], [ [0, 1, 1], [0, 1, 0], [0, 1, 0], ], [ [1, 0, 0], [1, 1, 1], [0, 0, 0], ], ], # ## # ## [ [ [0, 1, 0], [1, 1, 0], [1, 0, 0], ], [ [0, 0, 0], [1, 1, 0], [0, 1, 1], ], ], # ## # ## [ [ [0, 1, 0], [0, 1, 1], [0, 0, 1], ], [ [0, 0, 0], [0, 1, 1], [1, 1, 0], ], ], ] fieldx1 = 32 fieldy1 = 10 scorex1 = 11 scorey1 = 11 class RectRedraw: x1 = None y1 = None x2 = None y2 = None def max(r, val, valmax): if val > valmax: return valmax return val def min(r, val, valmin): if val < valmin: return valmin return val def merge(r, x1, y1, x2, y2): if r.x1 is None or r.x1 > x1: r.x1 = r.min(x1, 0) if r.y1 is None or r.y1 > y1: r.y1 = r.min(y1, 0) if r.x2 is None or r.x2 < x2: r.x2 = r.max(x2, field_width) if r.y2 is None or r.y2 < y2: r.y2 = r.max(y2, field_height) # print r.x1,r.y1,r.x2,r.y2 def clean(r): r.x1 = None r.y1 = None r.x2 = None r.y2 = None rr = RectRedraw() for _ in range(field_height): field.append([0] * field_width) def echo(s): global charcache charcache += s assert term.height > (field_height + 1) echo_unbuffered(u''.join(( u'\r\n\r\n', u'REAdY YOUR tERMiNAl %s ' % (term.bold_blue('(!)'),), u'\r\n\r\n', u'%s PRESS ANY kEY' % (term.bold_black('...'),), ))) getch() # set syncterm font to cp437 if term.kind.startswith('ansi'): echo_unbuffered(syncterm_setfont('cp437')) artfile = os.path.join(os.path.dirname(__file__), 'art', 'tetris.ans') echo_unbuffered(u'\r\n' * term.height) # cls if os.path.exists(artfile): echo_unbuffered(from_cp437(open(artfile).read()).rstrip()) def gotoxy(x, y): echo(term.move(y, x)) def plotblock(color, lastcolor): if color: c = u'\u2588\u2588' # '\xDB\xDB' else: # both empty c = ' ' color = 0 # Output optimization if color % 8 == 0: color = color / 8 if color == lastcolor: echo(c) else: if color: fg = str(30 + color % 8) else: fg = '37' if color >= 8: bg = ';%d' % (40 + color / 8) else: bg = '' echo('\x1b[0;' + fg + bg + 'm') echo(c) lastcolor = color return lastcolor def drawfield(): lastcolor = '' for y in range(0, field_height, 2): # gotoxy(field_width,2+y/2) gotoxy(fieldx1 + 2, fieldy1 + 1 + y / 2) # Which block to show, full, half-up, half-down or empty. for x in range(field_width): color = field[y][x] + field[y + 1][x] * 8 if field[y][x] and field[y + 1][x]: c = u'\u2588' # '\xDB' if field[y][x] == field[y + 1][x]: color = color % 8 else: c = u'\u2580' # '\xDF' elif field[y][x] and not field[y + 1][x]: c = u'\u2580' # '\xDF' elif not field[y][x] and field[y + 1][x]: c = u'\u2584' # '\xDC' else: # both empty c = ' ' # Output optimization if color % 8 == 0: color = color / 8 if color == lastcolor: echo(c) else: if color: fg = str(30 + color % 8) else: fg = '37' if color >= 8: bg = ';%d' % (40 + color / 8) else: bg = '' echo('\x1b[0;' + fg + bg + 'm') echo(c) lastcolor = color echo(term.normal) layoutcolor = [7, 2, 7, 6, 3, 6, 3] # p = -1 # Current piece type nextpiece = randint(0, len(layout) - 1) p = randint(0, len(layout) - 1) p = 1 r = 0 # Current rotation xpos = 4 # X position # ypos = -2 # Y position ypos = -len(layout[p][0]) level = 1 score = 0 lines = 0 def flush(): global charcache echo_unbuffered(charcache) charcache = u'' def fillpiece(x, y, p, r, value): row = 0 for line in layout[p][r]: col = 0 for c in line: if c and (y + row) >= 0: field[y + row][x + col] = value col += 1 row += 1 def showpiece(x, y, p, r): fillpiece(x, y, p, r, layoutcolor[p]) def hidepiece(): fillpiece(xpos, ypos, p, r, 0) def testpiece(x, y, newr): hidepiece() # Space at the new location? row = 0 for line in layout[p][newr]: col = 0 for c in line: try: if c: if ((y + row) >= 0 and field[y + row][x + col] or (x + col) < 0 or (x + col) > 9): return 0 except IndexError: return 0 col += 1 row += 1 # Movement possible return 1 def movepiece(x, y, newr): if testpiece(x, y, newr): # Build redraw rectangle rr.merge(xpos, ypos, xpos + len(layout[p][0][0]), ypos + len(layout[p][0])) rr.merge(x, y, x + len(layout[p][0][0]), y + len(layout[p][0])) showpiece(x, y, p, newr) return (x, y, newr, 1) else: showpiece(xpos, ypos, p, r) return (xpos, ypos, r, 0) def shownext(p): r = 0 for y in range(4): gotoxy(26, 18 + y) echo(u' ' * 4) echo(term.color(layoutcolor[p])) yoffset = int(len(layout[p][r][0]) < 4) xoffset = int(len(layout[p][r]) < 3) for y in range(len(layout[p][r])): for x in range(len(layout[p][r][y])): val = layout[p][r][y][x] if val: gotoxy(26 + x + xoffset, 18 + y + yoffset) echo(u'\u2588\u2588') def drawstats(): echo(term.move(scorey1, scorex1) + '%d' % level) echo(term.move(scorey1 + 2, scorex1) + '%d' % lines) echo(term.move(scorey1 + 3, scorex1) + '%d' % score) drawstats() ticksize = 0.4 nexttick = time.time() + ticksize showpiece(xpos, ypos, p, r) gotoxy(26, 17) echo(term.blue_reverse('next')) shownext(nextpiece) # Full redraw first frame rr.merge(0, 0, field_width, field_height) buf = '' while True: drawfield() # gotoxy(0,0) # echo('\x1b[37mx: %d, y: %d, p: %d '%(xpos,ypos,p)) slice = nexttick - time.time() if slice < 0: slice = 0 echo(buf) buf = '' flush() key = getch(slice + 0.01) now = time.time() # hidepiece() if key is not None: if key in (u'q', u'Q'): return (0, 0, 0) elif key in (term.KEY_LEFT, u'h',): xpos, ypos, r, m = movepiece(xpos - 1, ypos, r) elif key in (term.KEY_RIGHT, u'l',): xpos, ypos, r, m = movepiece(xpos + 1, ypos, r) elif key in (term.KEY_UP, u'k',): xpos, ypos, r, m = movepiece( xpos, ypos, (r + 1) % len(layout[p])) elif key in (term.KEY_DOWN, u'j',): xpos, ypos, r, m = movepiece(xpos, ypos + 1, r) elif key in (' ',): m = True c = 0 while m: xpos, ypos, r, m = movepiece(xpos, ypos + 1, r) if m: c += 1 if c: nexttick = time.time() + ticksize # New tick? if now > nexttick: nexttick += ticksize # Move down piece xpos, ypos, r, moved = movepiece(xpos, ypos + 1, r) # Piece has touched down? if not moved: # Is the player dead? if ypos <= -len(layout[p][0]): death_win = AnsiWindow(height=6, width=40, yloc=fieldy1 + 10 / 2, xloc=fieldx1 - 11) death_win.colors['border'] = term.bold_black echo_unbuffered(death_win.clear() + death_win.border()) echo_unbuffered( term.move(fieldy1 + 10 / 2 + 1, fieldx1 - 11)) echo_unbuffered(( u'!! gAME OVeR!! Score was: %i' % (score,)).center(40)) echo_unbuffered( term.move(fieldy1 + 10 / 2 + 3, fieldx1 - 11)) echo_unbuffered(u'press RETURN'.center(40)) while True: inp = getch() if inp in (u'\r', term.KEY_ENTER): break return (score, level, lines) # Any complete rows to remove? complete = [] for y in range(field_height): x = 0 while x < field_width: if field[y][x] == 0: break x += 1 if x == field_width: complete.append(y) if len(complete) > 0: # Add score lines += len(complete) score += len(complete) * len(complete) * 100 # Shrink field for line in complete: del field[line] field.insert(0, [0] * field_width) if lines >= level * 10: level += 1 ticksize = 0.4 - level * 0.02 drawstats() # Redraw complete field rr.merge(0, 0, field_width, field_height) # Time for a new piece p = nextpiece nextpiece = randint(0, len(layout) - 1) r = 0 xpos = 4 ypos = -len(layout[p][0]) showpiece(xpos, ypos, p, r) shownext(nextpiece)