Skip to content

Instantly share code, notes, and snippets.

@Pinacolada64
Created November 17, 2023 20:19
Show Gist options
  • Save Pinacolada64/ed5a7c7a57dd65b46ef8a250a8bb1a5c to your computer and use it in GitHub Desktop.
Save Pinacolada64/ed5a7c7a57dd65b46ef8a250a8bb1a5c to your computer and use it in GitHub Desktop.
Output various player character information using a Character subclass
import logging
from dataclasses import dataclass, field
import datetime
import doctest
from typing import Optional
# Totally Awesome Dungeon Adventure modules:
from server import Player, Room
def random_number(limit: int = 65535) -> int:
import random
return random.randrange(1, limit)
class Message:
def __init__(self, message_list: str | list):
logging.info("Running native Message.__init__()")
self.message_list = message_list
def __str__(self):
# FIXME: if a list is passed, returns <BLANKLINE> as last line
"""
>>> test_message = Message("line 1") # string
>>> print(test_message)
line 1
>>> test_message = Message(["line 1", "line 2"]) # list
>>> print(test_message)
line 1
line 2
>>> # test of squashing "test_message = Message(...)" & "print(test_message)
>>> print(Message(["line 1", "line 2"])) # list
line 1
line 2
"""
"""
:return: _: \n delimited string of message_list
"""
_ = ""
if isinstance(self.message_list, str):
logging.info("self.message_list: string")
return self.message_list
else:
logging.info("self.message_list: list")
for line in self.message_list:
_ += f"{line}\n"
return _
@dataclass
class Player(object):
name: str
connection_id: Optional[int | None]
flag: Optional[dict] # dict[str: bool] # {"expert_mode": True}
class_name: str
race: str
experience: Optional[int]
client: dict[str: int | str] = field(default_factory=dict) # {"name": "ANSI", "columns": 40}
def __str__(self):
"""
>>> rulan = Player(name="Rulan", class_name="German", race="polarfuchs",
... connection_id=1, flag={'xx': True}, experience=None)
>>> print(rulan)
Rulan is a German polarfuchs.
"""
return f"{self.name} is a {self.class_name} {self.race}."
def output(self, text: str | list, bracket_coloring: bool = True) -> None:
"""
Word-wrap string (or list of strings) to Player.client['cols'] width.
If a line break in the string is needed, make two separate calls to output(), one per line.
Ending a string with a CR or specifying CR in the join() call won't do what you want.
:param text: string (or list of strings) to output
:param bracket_coloring: if False, do not recolor text within brackets
(e.g., set to False when drawing bar so as to not color bar '[] ... []' table graphics)
:return Message: list object
"""
"""
>>> rulan = Player(name="Rulan", class_name="polarfuchs", race="German",
... {'client': {"cols": 40, "name": "Commodore 64"}},
... room=1, map_level=1)
>>> rulan.output(["line 1", "line 2"])
line 1
line 2
>>> print(rulan)
Rulan is a German polarfuchs.
"""
from colorama import Fore as foreground
import re
from net_server import Message
import textwrap
# from tada_utilities import input_prompt
"""
We want to wrap the un-substituted text first. substituting ANSI
color codes adds 5-6 characters per substitution, and that wraps
text in the wrong places.
"""
wrapped_text = []
for i, v in enumerate(text):
# returns wrapped_text[]
wrapped_text.append(textwrap.wrap(v, width=self.client['cols']))
if self.flag['debug']:
print(f"{i:3}: {wrapped_text[i]}")
new_lines = wrapped_text
# color text inside brackets using re and colorama:
# '.+?' is a non-greedy match (finds multiple matches, not just '[World...a]')
# >>> re.sub(r'\[(.+?)]', r'!\1!', string="Hello [World] this [is a] test.")
# 'Hello !World! this !is a! test.'
translation = self.client['translation']
if bracket_coloring:
colored_lines = []
temp = ""
for line, text in enumerate(wrapped_text):
# TODO: configurable normal/highlight colors in PREFS
if translation == "ANSI":
temp = re.sub(pattern=r'\[(.+?)\]',
repl=f'{foreground.RED}' + r'\1' + f'{foreground.RESET}',
string=text)
elif translation == "PETSCII":
pass
colored_lines.append(temp)
new_lines = colored_lines
elif translation == "ASCII":
# for ASCII clients, no color substitution for [bracketed text]:
new_lines = wrapped_text
# put output in list, otherwise enumerate() goes through individual
# characters of a single string
output = []
for k, v in enumerate(new_lines):
if self.flag['debug']:
logging.info(f"{k:>3}: {v}")
output.append(v)
if k % self.client['rows'] == 0 and self.flag['more_prompt'] is True:
logging.info(f'{k=} {self.client["rows"]=} {k % self.client["rows"]=}')
temp, _ = input_prompt(prompt=f"[A]bort or {self.client['return_key']} to continue: ")
if temp.lower() == 'a':
output.append("[Aborted.]")
break # out of the loop
# pause test:
rows = 25
for i in range(1, rows * 2):
print(f'{i=}', end='')
if i % rows == 0:
print(f' [pause]', end='')
print()
print(Message(lines=wrapped_text))
class RoomMessage(Message):
"""
Notify all players in room of something happening.
"""
def output(self, level, room: int, message: str):
"""
:param level: map level
:param room: room number
:param message: Message object to output
:return:
"""
# TODO: caller: str # <player who initiated action?> param,
# room_notify: bool # False: notify players in room?
pass
if __name__ == '__main__':
doctest.testmod(verbose=True)
"""
>>> rulan = Player(name="Rulan", class_name="German", race="polarfuchs",
... {'client': {"cols": 40, "rows": 25, "name": "Commodore 64"}},
... 'flag': {'debug': True}},
... room=1, map_level=1)
>>> rulan.output(["line 1", "line 2"])
line 1
line 2
>>> print(rulan)
Rulan is a German polarfuchs.
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment