Repository: plaaosert/credits_public
Branch: main
Commit: b0f09e1116d7
Files: 22
Total size: 142.8 KB
Directory structure:
gitextract_b3wq7xz6/
├── .gitattributes
├── .gitignore
├── CLIRender/
│ ├── classes.py
│ └── dat.py
├── README.md
├── animation_classes.py
├── animation_functions.py
├── animation_scenes.py
├── animator.py
├── colorama/
│ ├── __init__.py
│ ├── ansi.py
│ ├── ansitowin32.py
│ ├── initialise.py
│ ├── win32.py
│ └── winterm.py
├── credits.py
├── credits_pynput.py
├── media/
│ ├── README.txt
│ └── credits.txt
├── ocean.py
├── requirements.txt
└── string_defs.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: .gitignore
================================================
**/__pycache__
media/*.wav
media/*.WAV
media/*.mp3
media/*.MP3
venv
================================================
FILE: CLIRender/classes.py
================================================
import os
from platform import system as system_type
from bisect import insort_right, bisect_right
from CLIRender.dat import Vector2
class RenderSection:
id_inc = 0
def __init__(self, string, start, code):
self.id = RenderSection.id_inc
RenderSection.id_inc += 1
self.string = string
self.start = start
self.length = len(self.string)
self.end = self.start + self.length
self.code = code
def __lt__(self, other):
return self.start < other
def __gt__(self, other):
return self.start > other
def add_char(self, char):
self.string += char
self.end += 2
self.length += 2
def mod_char(self, char, loc):
if loc == self.end:
self.add_char(char)
else:
self.string = self.string[:loc] + char + self.string[loc + 2:]
# The addition operation adds the other section to this section. The other section takes precedence.
# This only works with text and discards the other section's code.
def add_section(self, other):
diff = other.start - self.start
self.string = self.string[:diff] + other.string + self.string[diff + other.length:]
self.length = len(self.string)
self.start = min(other.start, self.start)
self.end = self.start + self.length
# The addition operation adds the other section to this section. The self section takes precedence.
# This only works with text and discards the other section's code.
def add_section_below(self, other):
diff = self.start - other.start
self.string = other.string[:diff] + self.string + other.string[diff + self.length:]
self.length = len(self.string)
self.start = min(other.start, self.start)
self.end = self.start + self.length
# Same as section subtraction but only one char.
def subtract_char(self, loc):
first = None
last = None
if loc > self.start:
diff = loc - self.start
first = RenderSection(self.string[:diff], self.start, self.code)
if loc < self.end:
diff = self.end - loc
last = RenderSection(self.string[diff:], loc + 2, self.code)
return first, last
# Subtracts another section's length from this section. This returns a 2-tuple containing the two new subsections.
def subtract_section(self, other):
first = None
last = None
if other.start > self.start:
# if the other string starts later, there's still a part of the victim string remaining
diff = other.start - self.start
first = RenderSection(self.string[:diff], self.start, self.code)
if other.end < self.end:
# if the other string ends before us, the latter part needs something too
diff = self.end - other.end
last = RenderSection(self.string[self.length - diff:], other.end, self.code)
return first, last
class Canvas:
# TODO write multi-layer support. shouldn't be too hard, just merge down layers as we need
# but not right now. plaao tired
def __init__(self, dimensions, num_layers, merge_rules):
self.dimensions = Vector2(dimensions.x * 2, dimensions.y)
self.num_layers = num_layers
self.layers = [Layer(i, self.dimensions) for i in range(num_layers)]
self.merge_rules = merge_rules
self.edits_this_frame = 0
def set_char(self, layer, location, char, code):
self.layers[layer].set_char(int(location.x * 2) + (location.y * self.dimensions.x), char, code)
self.edits_this_frame += 1
def set_string(self, layer, location, string, code):
self.layers[layer].set_string(int(location.x * 2) + (location.y * self.dimensions.x), string, code)
self.edits_this_frame += 1
def clear_layer(self, layer):
self.layers[layer].set_string(0, " " * self.dimensions.x * self.dimensions.y, "")
def render_blank(self):
print("\033[1;1H\033[1;37;40m" + ((" " * self.dimensions.x + "\n") * self.dimensions.y))
def render_all(self):
# Merge layers from bottom to top then render the resulting group list.
# Here is the only point we even think about line lengths.
total_string = "\033[1;1H\033[1;39m"
for group in self.layers[0].new_groups:
lineno = group.start // self.dimensions.x
add_string = ""
add_string += "\033[{};{}H".format(
lineno + 1, group.start % self.dimensions.x + 1
)
add_string += group.code
offset = group.start % self.dimensions.x
# If overrun is greater than x, then it breaks a line boundary.
# So, for every x overrun, we add a \n between lines.
split = 0
stop = 0
while stop <= group.length:
if lineno >= self.dimensions.y:
break
stop = self.dimensions.x - offset + split
add_string += group.string[split:stop] + ("\n" if stop <= group.length else "")
offset = 0
lineno += 1
split += stop - split
# We're done! How simple ...
total_string += add_string
self.layers[0].new_groups.clear()
self.edits_this_frame = 0
print(total_string + "\033[27;0H", end="\n")
class Layer:
def __init__(self, layer_id, dimensions):
self.dimensions = Vector2(dimensions.x * 2, dimensions.y)
self.max_loc = self.dimensions.x * self.dimensions.y
self.id = layer_id
# new_groups contains a list of groups of text that need to be rendered next time this layer is flattened.
self.new_groups = []
self.full_str = ["" for i in range(self.dimensions.x * self.dimensions.y)]
def set_char(self, loc, char, code):
# Set a single char in the layer.
# Step 1: binary search through new_groups to see if we need to make a new group
# Step 2: make a new group or mod the found group
#
# We want to find the rightmost value less than or equal to loc,
# then check if it encompasses the given position.
i = bisect_right(self.new_groups, loc) - 1
if i >= len(self.new_groups) or i < 0:
i = None
else:
# Also check backwards for things with the SAME start location.
while i >= 1 and self.new_groups[i - 1].start == loc:
i -= 1
if i is not None:
# If a group already exists, we might need to split it.
# This happens when codes are not equal.
# In that situation, split our insert group in two and add a new one as normal.
insert_group = self.new_groups[i]
# This is only ever relevant when our found group actually reaches loc.
if insert_group.end >= loc:
if insert_group.code != code:
sub_groups = insert_group.subtract_char(loc)
self.new_groups.pop(i)
if sub_groups[0]:
insort_right(self.new_groups, sub_groups[0])
if sub_groups[1]:
insort_right(self.new_groups, sub_groups[1])
i = None
else:
insert_group.mod_char(char, loc)
else:
i = None
if i is None:
# Add this char as a new group.
insort_right(self.new_groups, RenderSection(char, loc, code))
# Then replace the full string at location with our new thing.
# This is only as a contingency if our console crashes / burns / explodes / vanishes without a trace.
# It should be disableable if necessary.
# print("\n".join("".join(char for char in canvas.layers[0].full_str[line * 40:(line + 1) * 40]) for line in range(10)))
self.full_str[loc] = code + char
def has_duplicate_starts(self):
non_dupe_list = []
for group in self.new_groups:
if group in non_dupe_list:
return False
non_dupe_list.append(group)
return True
def set_string(self, loc, string, code):
# Find the two groups that are closest to the start and end points of the group.
# Perform the add function on both if they exist, or the sub function if their code is different.
# Remove all groups in between.
# Find the rightmost section with start less than or equal to loc; so, the closest element that can intersect.
# IT MAY NOT INTERSECT. CHECK. IF IT DOESN'T, THEN NOTHING INTERSECTS START.
# If we are out of bounds, leave instantly
if loc >= self.max_loc or loc < 0:
return
start_i = bisect_right(self.new_groups, loc) - 1
if start_i < 0:
start_i = 0
# Also check backwards for things with the SAME start location.
while start_i >= 1 and self.new_groups[start_i - 1].start == loc:
start_i -= 1
# Cut the string down to the maximum possible length it could be.
cut_string = string[:self.max_loc - loc]
add_group = RenderSection(cut_string, loc, code)
add_groups = [None, add_group, None]
remove = []
for mid_i in range(start_i, len(self.new_groups)):
# If the group is the same, add. If it's different, subtract.
# Fill up add_groups with subtracted items.
mid_group = self.new_groups[mid_i]
# If it starts after our end, break. We're out.
if mid_group.start >= add_group.end:
break
# If it ends before our start, discard. We don't need it.
if mid_group.end > add_group.start:
# If it is eclipsed, we don't need it at all.
if mid_group.start >= add_group.start and mid_group.end <= add_group.end:
remove.append(mid_i)
else:
# Otherwise, run either subtract or add on it.
if mid_group.code == add_group.code:
# Add the mid group to the code. Delete the mid group.
add_group.add_section_below(mid_group)
remove.append(mid_i)
else:
# Subtract the add group from the mid group. Remove previous mid group.
sub_groups = mid_group.subtract_section(add_group)
if sub_groups[0]:
add_groups[0] = sub_groups[0]
if sub_groups[1]:
add_groups[2] = sub_groups[1]
remove.append(mid_i)
remove.reverse()
for index in remove:
self.new_groups.pop(index)
# THERE'S A BETTER WAY OF DOING THIS; I JUST DONT KNOW WHAT RIGHT NOW :(
add_index = bisect_right(self.new_groups, loc)
for group in add_groups:
if group:
self.new_groups.insert(start_i + add_index, group)
add_index += 1
# For full string usage.
for index, char in enumerate(string):
self.full_str[index] = code + char
def enable_ansi():
"""
Uses a hack to enable ANSI mode in the Windows console. Does nothing on Linux.
"""
if system_type() == "Windows":
# might fuck around
os.system("")
"""
enable_ansi()
canvas = Canvas(Vector2(40, 26), 1, ())
canvas.render_blank()
import time
import random
ind = 0
for j in range(50):
canvas.render_all()
canvas.layers[0].set_char(
ind % (40 * 26) * 2, "##", "\033[{}m".format(31 + (ind % 12) // 2)
)
ind += random.randint(0, 80 * 26)
canvas.layers[0].set_char(
ind % (40 * 26) * 2, "##", "\033[{}m".format(31 + (ind % 12) // 2)
)
ind += random.randint(0, 80 * 26)
input("")
ind = 0
while True:
canvas.render_all()
for yval in range(26):
if ind % 14 == 13:
canvas.layers[0].set_string(
0 + (80 * yval), "---------|" if ind % 2 == 0 else "~~~~~~~~~/", "\033[{}m".format(32)
)
canvas.layers[0].set_string(
20 + (80 * yval), "|---------" if ind % 2 == 0 else "\~~~~~~~~~", "\033[{}m".format(32)
)
canvas.layers[0].set_string(
10 + (80 * yval), " ", "\033[{}m".format(32)
)
else:
canvas.layers[0].set_string(
0 + (80 * yval), "---------|" if ind % 2 == 0 else "~~~~~~~~~/", "\033[{}m".format(32)
)
canvas.layers[0].set_string(
20 + (80 * yval), "|---------" if ind % 2 == 0 else "\~~~~~~~~~", "\033[{}m".format(32)
)
canvas.layers[0].set_string(
14 - (1 * (ind % 14)) + (80 * yval), "<{}>".format("--" * (ind % 14)), "\033[{}m".format((34, 32, 33, 31)[int((ind % 14) / 14 * 4)])
)
# canvas.layers[0].set_string(
# i % (40 * 26), "abcdefghijklmnopqrstuvwxyz", "\033[{}m".format(31 + (i % 12) // 2)
# )
ind += 1
# TODO write nicer functions and multilayer support
# multilayer entails searching upwards for groups that intersect; if so, adding them to the layer
# nicer functions means an actual set_char for the canvas that takes in x, y rather than absolute loc
# also add set_string which can take in a longer string, subtracting any intersecting groups
"""
================================================
FILE: CLIRender/dat.py
================================================
# contains:
#
# x position (generic typing because python but should be an int in most cases)
# y position (the same)
#
class Vector2: # to be honest this is me showing off
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self): # returns a formatted string for the vector2
return "({v.x}, {v.y})".format(v=self)
def __add__(self, other): # allows adding of vector2s, and ints
if isinstance(other, Vector2):
return Vector2(self.x + other.x, self.y + other.y)
elif isinstance(other, (int, float)):
return Vector2(self.x + other, self.y + other)
else:
raise ValueError("Accepted data types are float, int and Vector2.")
def __mul__(self, other): # multiplies a vector2 by an int, or by another vector2
if isinstance(other, Vector2):
return Vector2(self.x * other.x, self.y * other.y)
elif isinstance(other, (int, float)):
return Vector2(self.x * other, self.y * other)
else:
raise ValueError("Accepted data types are float, int and Vector2.")
def __truediv__(self, other): # returns a FLOAT value (true div)
if isinstance(other, Vector2):
return Vector2(self.x / other.x, self.y / other.y)
elif isinstance(other, (int, float)):
return Vector2(self.x / other, self.y / other)
else:
raise ValueError("Accepted data types are float, int and Vector2.")
def __floordiv__(self, other): # returns an INT value (floor div)
if isinstance(other, Vector2):
return Vector2(self.x // other.x, self.y // other.y)
elif isinstance(other, (int, float)):
return Vector2(self.x // other, self.y // other)
else:
raise ValueError("Accepted data types are float, int and Vector2.")
def __pos__(self):
return Vector2(abs(self.x), abs(self.y))
def __neg__(self):
return Vector2(-self.x, -self.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def Magnitude(self): # returns the magnitude of the vector2. (length of the vector)
return ((self.x ** 2) + (self.y ** 2)) ** (1/2) #sqrt
class Vector3: # to be honest this is me showing off
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __str__(self): # returns a formatted string for the Vector3
return "({v.x}, {v.y}, {v.z})".format(v=self)
def __add__(self, other): # allows adding of Vector3s, and ints
if isinstance(other, Vector3):
return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)
elif isinstance(other, (int, float)):
return Vector3(self.x + other, self.y + other, self.z + other)
else:
raise ValueError("Accepted data types are float, int and Vector3.")
def __mul__(self, other): # multiplies a Vector3 by an int, or by another Vector3
if isinstance(other, Vector3):
return Vector3(self.x * other.x, self.y * other.y, self.z * other.z)
elif isinstance(other, (int, float)):
return Vector3(self.x * other, self.y * other, self.z * other)
else:
raise ValueError("Accepted data types are float, int and Vector3.")
def __truediv__(self, other): # returns a FLOAT value (true div)
if isinstance(other, Vector3):
return Vector3(self.x / other.x, self.y / other.y, self.z / other.z)
elif isinstance(other, (int, float)):
return Vector3(self.x / other, self.y / other, self.z / other)
else:
raise ValueError("Accepted data types are float, int and Vector3.")
def __floordiv__(self, other): # returns an INT value (floor div)
if isinstance(other, Vector3):
return Vector3(self.x // other.x, self.y // other.y, self.z // other.z)
elif isinstance(other, (int, float)):
return Vector3(self.x // other, self.y // other, self.z // other)
else:
raise ValueError("Accepted data types are float, int and Vector3.")
def __pos__(self):
return Vector3(abs(self.x), abs(self.y), abs(self.z))
def __neg__(self):
return Vector3(-self.x, -self.y, -self.z)
def __eq__(self, other):
return self.x == other.x and self.y == other.y and self.z == other.z
def Magnitude(self): # returns the magnitude of the Vector3. (length of the vector)
return ((self.x ** 2) + (self.y ** 2) + (self.z ** 2)) ** (1 / 2) # sqrt
================================================
FILE: README.md
================================================
# credits_public
- Public version of Frums - Credits animation repository.
- Should be multiplatform. Feel free to raise an issue if it isn't. Feel free to raise an issue for anything.
- Tested on clean Python 3.6 (Windows 10) with minimal modules installed.
# media credits
- All animation work done by me (plaaosert)
- Renderer used is an in-progress command line rendering library for which a separate repository will be created... eventually.
- Song credit: Frums - Credits EX https://soundcloud.com/frums/credits-ex
- Song is not included in this repository. Read /media/README.txt.
# how to see
- https://youtu.be/o3cKQzrtFgQ
# how to run
Run `credits.py`. Required libraries:
- just-playback https://github.com/cheofusi/just_playback
- keyboard https://github.com/boppreh/keyboard
- **important**: if you're running **linux** or **macos**, you might have trouble with this module. if so, try using `credits_pynput.py` instead (and install pynput -- https://pypi.org/project/pynput/)
- colorama https://github.com/tartley/colorama -
the version of colorama used is also included inside this repository.
You can install all required libraries by running:
```
pip install -r requirements.txt
```
# misc
## start-of-song skips
before the animation starts, a menu will appear with options to skip to specific parts of the song. i used this a lot while debugging and left it in because i ~forgot~ felt i should include it. input nothing to let the song start normally, else hold a digit key on the keyboard to skip:
- 1 | start _(equivalent to pressing no button but slightly faster)_
- 2 | title _(flashing square in center + artist and self credits)_
- 3 | funding _(start of first "Funding for this program was made possible..." section)_
- 4 | loading _(loading bar before fake error and second typography "searching for access point" segment)_
- 5 | break _(hell ocean, second weather forecast scene)_
- 6 | final _(return of the flashing square - ending sequence)_
## generic hotkeys
| hotkey | effect |
| ------------------- | ------------------------ |
| `p` | play/pause toggle |
| `,` | small fast forward (4x) |
| `.` | medium fast forward (8x) |
| `/` | large fast forward (16x) |
================================================
FILE: animation_classes.py
================================================
# Contains all classes (just Weather)
import random
import math
class Weather:
def __init__(self, precip, temp, wind, gust, wind_dir, humidity, days=2):
self.precip = precip
self.temp = temp
self.wind = wind
self.gust = gust
self.wind_dir = wind_dir
self.humidity = humidity
self.weather_name = self.get_weather_name()
self.days = days
def __str__(self):
return "{}% precipitation\n" \
"{}F temperature\n" \
"{}mph wind\n" \
"{}mph gust\n" \
"{} wind direction\n" \
"{}% humidity\n" \
"{}\n".format(
round(self.precip * 100, 2),
int(self.temp),
int(self.wind),
int(self.gust),
int(self.wind_dir),
round(self.humidity * 100, 2),
self.weather_name
)
def get_weather_name(self):
# Clear/Sunny <> Cloudy/Rainy
if self.humidity > 0.5:
# Cloudy or rainy
if self.precip > 0.4:
if self.wind > 43:
return "Blizzard" if self.temp < 32 else "Hurricane"
elif self.wind > 25:
return "Snowstorm" if self.temp < 32 else "Storm"
else:
return "Snow" if self.temp < 32 else "Rain"
elif self.precip > 0.25:
return "Sleet" if self.temp < 32 else "Drizzle"
if self.humidity > 0.8 or self.precip > 0.5:
return "Overcast"
elif self.humidity > 0.65 or self.precip > 0.3:
return "Cloudy"
else:
return "Partly cloudy"
else:
if self.precip > 0.4:
return "Snow" if self.temp < 32 else "Rain"
elif self.precip > 0.2:
return "Sleet" if self.temp < 32 else "Drizzle"
return ("Sunny" if self.humidity < 0.1 else "Partly sunny") if self.humidity < 0.2 else "Clear"
def mutate(self, steps=1):
for i in range(steps):
# Prefer 33% precip, move wind dir by +-3 each day, gust = speed x 2.1 - 2.6
precip_move = random.randint(-100, 100) / 400.0
precip_move += (random.randint(0, int(100 * abs(0.33 - self.precip))) / 200) * (-1 if 0.33 - self.precip < 0 else 1)
self.precip = min(1, max(0, self.precip + precip_move))
self.wind_dir = (self.wind_dir + random.randint(-3, 3)) % 8
wind_move = random.randint(-100, 100) / 13
wind_move += (random.randint(0, int(abs(15 - self.wind))) / 3) * (-1 if 15 - self.wind < 0 else 1)
self.wind = max(0, self.wind + wind_move)
adjusted_days = self.days - 282
temp_target = 40 * (math.sin((2 * math.pi * adjusted_days) / 365 - math.pi / 3) + 1) + 20
temp_move = random.randint(-100, 100) / 20
temp_move += (random.randint(0, int(abs(temp_target - self.temp))) / 5) * (-1 if temp_target - self.temp < 0 else 1)
self.temp = max(0, self.temp + temp_move)
humidity_move = random.randint(-100, 100) / 500.0
humidity_move += (random.randint(0, int(abs(0.2 - self.humidity))) / 200) * (-1 if 0.5 - self.humidity < 0 else 1)
self.humidity = max(0, min(1, self.humidity + humidity_move))
self.gust = self.wind * random.randint(210, 260) * 0.01
self.days += 1
self.weather_name = self.get_weather_name()
# 22.10.2009: Cloudy, precip 20%, temp 43, wind dir 6, 13 (25)
# 23.10.2009: Sunny, precip 4%, temp 52, wind dir 7, 12 (25)
# 24.10.2009: Partly sunny, precip 7%, temp 48, wind dir 1, 8 (20)
known_weathers = (
Weather(0.203, 43, 13, 25, 6, 0.66),
Weather(0.04, 52, 12, 25, 7, 0.1),
Weather(0.07, 48, 8, 20, 1, 0.1, 200),
Weather(0.07, 48, 8, 20, 1, 0.1, 528 + 200),
Weather(-1, -1, -1, -1, -1, -1)
)
known_weathers[4].weather_name = "Connection lost... "
================================================
FILE: animation_functions.py
================================================
# Contains functions used inside credits.py.
# Reduce clutter. Reuse clutter. Recycle clutter.
import random
from CLIRender.dat import Vector2
from colorama import Fore, Style
def generate_random_hex(length):
return ('%0' + str(length) + 'x') % random.randrange(16 ** length)
def replace_text_with_spaces(string, chance):
return "".join((" " if random.randint(0, 100) < chance else char) for char in string)
def render_weather(c, layer, x, y, weather, mutations_after=0, spc_chance=0):
# . .
if weather.precip != -1:
c.set_string(
layer, Vector2(x + 5, y - 2),
replace_text_with_spaces("{:>14}".format(weather.weather_name), spc_chance),
Fore.YELLOW + Style.NORMAL
)
else:
c.set_string(
layer, Vector2(x, y - 2),
replace_text_with_spaces("{:>14}".format(weather.weather_name), spc_chance),
Fore.RED + Style.BRIGHT
)
temp_colour = (Fore.WHITE, Fore.CYAN, Fore.YELLOW, Fore.RED)[min(3, int(weather.temp) // 23)]
c.set_string(
layer, Vector2(x, y),
replace_text_with_spaces("{:2}°F ".format(int(weather.temp)), spc_chance),
temp_colour + Style.BRIGHT
)
wind_dirs = ("N ", "NE", "E ", "SE", "S ", "SW", "W ", "NW")
c.set_string(
layer, Vector2(x + 5, y),
replace_text_with_spaces("Wind {:2} mph {}".format(int(weather.wind), wind_dirs[weather.wind_dir]), spc_chance),
Fore.CYAN + Style.BRIGHT
)
c.set_string(
layer, Vector2(x + 5, y + 2),
replace_text_with_spaces("Precipitation ", spc_chance),
Fore.BLUE + Style.BRIGHT
)
c.set_string(
layer, Vector2(x + 5, y + 3),
replace_text_with_spaces("{:^13} ".format(str(round(weather.precip * 100, 2)) + "%"), spc_chance),
Fore.BLUE + Style.BRIGHT
)
weather.mutate(mutations_after)
def noise(c, layer, amount, chars, colours):
for n in range(amount):
location = Vector2(random.randint(0, c.dimensions.x - 1), random.randint(0, c.dimensions.y - 1))
c.set_char(
layer, location, random.choice(chars), random.choice(colours)
)
def set_multiline_string(c, layer, x, y, string, col):
for offset, line in enumerate(string.split("\n")):
c.set_string(
layer, Vector2(x, y + offset), line, col
),
def type_text(c, generator, layer, x, y, col, render=True):
# pop a char off the manager's text if there is one
text_get = generator.get_data("text")
offset = generator.get_data("offset")
total_chars = 0
add_offset = 0
if text_get:
if text_get.startswith("[##CLEAR|"):
clear_bounds = text_get.split("|")[1].split(";")
for yclear in range(int(clear_bounds[1])):
location = Vector2(x, y + yclear)
if render:
c.set_string(
layer, location, " " * int(clear_bounds[0]), col
)
else:
for linecount, text_line in enumerate(text_get.split("\n")):
local_offset = offset - total_chars
if 0 <= local_offset < len(text_get):
place_typer = local_offset < len(text_line) - 1
string = text_line[:local_offset] + ("_" if place_typer else "")
if local_offset < len(text_line) and text_line[local_offset] == "@":
add_offset += 3
string = string.replace("~", "").replace("@", "")
total_chars += len(text_line)
location = Vector2(x, y + linecount)
if render:
c.set_string(
layer, location, string, col
)
generator.oper_data("offset", lambda t: t + 1 + add_offset)
def fuck_up_text(string, chance, also_ignore=""):
new_str = ""
fucks = (
".", ".", ".", " ", " ", "`", "=", "/", "?", "-", "$", "%"
)
for char in string:
if char == "\n":
new_str += char
else:
if random.randint(1, 1000) < chance and char not in "@~\n" + also_ignore:
new_str += random.choice(fucks)
else:
new_str += char
return new_str
def debug_info(c, g, b, frames):
c.set_string(
0, Vector2(32, 1), "{:4} g | {:4} l".format(g.parent.cur_beat, g.parent.active_scene[0].internal_beat), Style.BRIGHT + Fore.YELLOW
),
counted_scenes = 0
for index, scene in enumerate(filter(lambda s: s.name != "debug_counter", g.parent.active_scene)):
c.set_string(
0, Vector2(32, index + 2), "{:^17}".format(
scene.name + " ({})".format(len(list(filter(lambda g: g.start_beat <= b, scene.generators))))
), Style.NORMAL + Fore.GREEN
),
counted_scenes += 1
for index2 in range(counted_scenes, 6):
c.set_string(
0, Vector2(32, index2 + 2), " ", Style.NORMAL + Fore.GREEN
),
c.set_string(
0, Vector2(32, 8), " {:4} e/s".format(c.edits_this_frame), Style.BRIGHT + Fore.YELLOW
),
avg_differences = sum(frames[i] - frames[i - 1] for i in range(len(frames) - 1, 0, -1))
if avg_differences:
avg_differences /= 10
else:
avg_differences = 60
c.set_string(
0, Vector2(32, 9), " {:6} fps".format(round(1 / avg_differences, 1)), Style.BRIGHT + Fore.YELLOW
),
cols = (
Fore.BLACK,
Fore.RED,
Fore.GREEN,
Fore.YELLOW,
Fore.BLUE,
Fore.MAGENTA,
Fore.CYAN,
Fore.WHITE,
)
styles = (
Style.NORMAL,
Style.BRIGHT
)
for index in range(16):
c.set_char(
0, Vector2(32 + (index % 8), 11 + (index // 8)), "##", cols[index % 8] + styles[index // 8]
),
def clear(c, layer):
c.clear_layer(layer)
def beat_toggle(c, g, layer, x, x2, y, y2, char, col):
tog = g.get_data("beat_toggle")
chars = char if tog else ".."
x_diff = x2 - x
for yn in range(y, y2):
c.set_string(
layer, Vector2(x, yn), chars * x_diff, col
),
g.set_data("beat_toggle", not tog)
def work_out_date(b, day_offset=0):
# "22.10.2009"
lengths = (
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
)
# One day passes every 64 beats.
days_needed = (b // 64) + day_offset
month_loc = 9
day_loc = 22
year = 2009
while days_needed > 0:
leap_year = (1 if year % 4 == 0 and month_loc == 1 else 0) # leap year
until_end_month = lengths[month_loc] + 1 - day_loc + leap_year
day_loc += min(days_needed, until_end_month)
days_needed -= min(days_needed, until_end_month)
if day_loc > lengths[month_loc] + leap_year:
month_loc += 1
day_loc = 1
if month_loc >= 12:
month_loc = 0
year += 1
return "{:02}.{:02}.{:04}".format(day_loc, month_loc + 1, year)
def split_word_template(string):
return [sp.split("#") for sp in string.split("\n")]
def typewrite_by_word(c, generator, layer, x, y, col, render=True, history_var="history"):
# Show the text up to offset words at line lineno
text_get = generator.get_data("text")
offset = generator.get_data("offset")
lineno = generator.get_data("lineno")
if text_get:
if lineno < len(text_get):
line_get = text_get[lineno]
line_total = "".join(line for line in line_get[:offset])
if line_get:
if line_get[0].startswith("[~~CLEAR|"):
clear_bounds = line_get[0].split("|")[1]
location = Vector2(x, y)
if render:
c.set_string(
layer, location, " " * int(clear_bounds), col
)
else:
# print line_total and increment offset by 1.
# if offset is > lineno, reset offset and increment lineno
# if line_total is empty (offset == 0), print a clear
if render:
if line_total:
c.set_string(
layer, Vector2(x, y), line_total.replace("~", ""), col
),
else:
c.set_string(
layer, Vector2(x, y), " " * 60, col
),
if offset >= len(line_get):
history = generator.parent.get_data(history_var)
is_fluff = line_total.startswith(" ") or not line_total
is_important = line_total.endswith("~")
colour_select = Fore.YELLOW + Style.NORMAL
prefix = "- "
if is_fluff:
prefix = " "
colour_select = Fore.BLACK + Style.BRIGHT
elif is_important:
prefix = "> "
colour_select = Fore.GREEN + Style.NORMAL
if not history:
history = [(
prefix + line_total.strip(" ").replace("~", ""), colour_select
)]
generator.parent.set_data(history_var, history)
else:
history.append((
prefix + line_total.strip(" ").replace("~", ""), colour_select
))
generator.parent.set_data("refresh", True)
generator.set_data("offset", 0)
generator.set_data("lineno", lineno + 1)
else:
generator.set_data("offset", offset + 1)
else:
generator.set_data("offset", offset + 1)
def write_history(c, generator, layer, x, y, col, stop, var="history"):
# Write history from y position going upwards until 0
history = generator.parent.get_data(var)
need_refresh = generator.parent.get_data("refresh")
if need_refresh:
generator.parent.set_data("refresh", False)
if history:
lineid = 0
for ypos in range(y, stop - 1, -1):
line = history[len(history) - 1 - lineid] if lineid < len(history) else ("", Fore.BLACK + Style.BRIGHT)
lineid += 1
location = Vector2(x, ypos)
c.set_string(
layer, location, "{:50}".format(line[0]), line[1]
),
else:
for ypos in range(y, stop - 1, -1):
c.set_string(
layer, Vector2(x, ypos), " " * 50, Fore.BLACK + Style.NORMAL
),
def show_access_point_visual(c, generator, layer, x, y):
# Increment counter. If counter > 8, reset it, increment the bigger counter
counter = generator.get_data("counter")
block_counter = generator.get_data("block")
location_x = 5 * (block_counter % 6) + x
location_y = 4 * (block_counter // 6) + y
if counter < 8:
set_multiline_string(
c, layer, location_x, location_y,
" ### \nPBS #{:02}\nPing {}".format(block_counter + 1, counter + 1), Fore.YELLOW + Style.NORMAL
)
generator.oper_data("counter", lambda t: t + 1)
else:
set_multiline_string(
c, layer, location_x, location_y,
" ... \nPBS #{:02}\n-------".format(block_counter + 1), Fore.BLACK + Style.BRIGHT
)
location_x_next = 5 * ((block_counter + 1) % 6) + x
location_y_next = 4 * ((block_counter + 1) // 6) + y
set_multiline_string(
c, layer, location_x_next, location_y_next,
" ### \nPBS #{:02}\nPing {}".format(block_counter + 2, 1), Fore.YELLOW + Style.NORMAL
)
generator.set_data("counter", 1)
generator.oper_data("block", lambda t: t + 1)
def make_poweroff_bars(c, b, layer, col):
# at b=1, full screen
# then lerp height on both ends down to 0
height = int(24 / (b ** 1.3))
location = Vector2(0, 12 - (height // 2))
c.set_string(
layer, location, ("##" * 40) * height, col
)
================================================
FILE: animation_scenes.py
================================================
# Contains all animation scenes except for debug_counter.
# Use variable "all_scenes" which contains all scenes defined here.
# This file also creates the canvas.
import animator as am
from animation_functions import *
from animation_classes import known_weathers
from ocean import begin_ocean, update_ocean_slices
from CLIRender.classes import Canvas
canvas = Canvas(Vector2(40, 24), 1, ())
wipe = am.Scene(
"wipe",
(
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: noise(
canvas, 0, int(b ** 1.4), ("##", "@@", " "),
(
*((Style.BRIGHT + Fore.WHITE,) * b),
*((Style.NORMAL + Fore.WHITE,) * (70 - b)),
*((Style.BRIGHT + Fore.BLACK,) * 4 * (40 - b)),
)
),
am.Generator.no_request()
),
)
)
clear_wipe = am.Scene(
"clear_wipe",
(
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: noise(
canvas, 0, int(b ** 2.2), (" ",), (Fore.WHITE + Style.BRIGHT,)
),
am.Generator.no_request()
),
)
)
clear_scene = am.Scene(
"clear",
(
#am.Generator(
# 0, am.Generator.at_beat(0),
# lambda g: noise(
# canvas, 0, 40 * 24, ("##",), (Style.BRIGHT + Fore.WHITE,)
# ),
# am.Generator.no_request(), am.Generator.no_request()
#),
am.Generator(
0, am.Generator.always(),
lambda g: clear(canvas, 0),
am.Generator.no_request(), am.Generator.no_request()
),
)
)
ocean = am.Scene(
"ocean_b",
(
am.Generator(
0, am.Generator.every_n_beats(2),
lambda g: g.set_data("ocean", begin_ocean(), "ocean_glitch", 1, "ocean_col", Style.BRIGHT + Fore.BLUE),
lambda g, b: canvas.set_string(
0, Vector2(0, 14), update_ocean_slices(g.get_data("ocean"),
g.get_data("ocean_glitch")), g.get_data("ocean_col")
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", "", "offset", 0),
lambda g, b: type_text(canvas, g, 0, 1, 1, Style.BRIGHT + Fore.WHITE),
am.Generator.no_request()
),
)
)
ocean2 = am.Scene(
"ocean_c",
(
am.Generator(
0, am.Generator.every_n_beats(2),
lambda g: g.set_data("ocean", begin_ocean(), "ocean_glitch", 16, "ocean_col", Style.BRIGHT + Fore.BLACK),
lambda g, b: canvas.set_string(
0, Vector2(0, 14), update_ocean_slices(g.get_data("ocean"),
g.get_data("ocean_glitch")), g.get_data("ocean_col")
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", "", "offset", 0),
lambda g, b: type_text(canvas, g, 0, 1, 1, Style.BRIGHT + Fore.RED, int(b ** 1.143) % 20 not in (0, 8, 17, 15)),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", "", "offset", 0),
lambda g, b: type_text(canvas, g, 0, 1, 1, Style.BRIGHT + Fore.RED, int(b ** 1.2) % 20 in (0, 15)),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", "", "offset", 0),
lambda g, b: type_text(canvas, g, 0, 1, 1, Style.BRIGHT + Fore.RED, int(b ** 1.2) % 20 == 8),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", "", "offset", 0),
lambda g, b: type_text(canvas, g, 0, 1, 1, Style.BRIGHT + Fore.RED, int(b ** 1.2) % 20 == 17),
am.Generator.no_request()
),
)
)
ocean3 = am.Scene(
"ocean_d",
(
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("ocean", begin_ocean(), "ocean_glitch", 100, "ocean_col", Style.NORMAL + Fore.MAGENTA),
lambda g, b: canvas.set_string(
0, Vector2(0, 14), update_ocean_slices(g.get_data("ocean"),
g.get_data("ocean_glitch")), g.get_data("ocean_col")
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: set_multiline_string(canvas, 0, 1, 1,
"The system has encountered a fatal error. Please wait.\n\n"
"[ERR: 801]\n\n" + "\n".join(
" ".join(generate_random_hex(4) for _ in range(8)) for _ in range(4)
),
Style.BRIGHT + Fore.RED),
am.Generator.no_request()
),
)
)
text = am.Scene(
"typewrite",
(
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", "", "offset", 0),
lambda g, b: type_text(canvas, g, 0, 1, 1, Style.BRIGHT + Fore.WHITE),
am.Generator.no_request()
),
)
)
title = am.Scene(
"title",
(
# We have 12 beat-ends to map to:
# ' - plaaosert
# ' - frums
# ' - python 3.6
# ' - command line
# drums
# ' -
# ' -
# ' -
# ' -
# small moog
# ' -
# ' -
# ' -
# ' -
am.Generator(
64, am.Generator.at_beat(64),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(1, 1), "animation | plaaosert", Fore.CYAN + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
128, am.Generator.at_beat(128),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(1, 2), "bgm | Frums - Credits", Fore.CYAN + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
192, am.Generator.at_beat(192),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(1, 4), "running pure Python 3.6", Fore.CYAN + Style.NORMAL
),
am.Generator.no_request()
),
am.Generator(
256, am.Generator.at_beat(256),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(1, 5), "in the command line", Fore.CYAN + Style.NORMAL
),
am.Generator.no_request()
),
am.Generator(
320, am.Generator.at_beat(320),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(0, 21), "--" * 40, Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
384, am.Generator.at_beat(384),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(1, 22), "> _ ", Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
448, am.Generator.at_beat(448),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 26, 14, "----------------------------\n" +
"| |\n" * 6, Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
512, am.Generator.at_beat(512),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 27, 15, "22.10.2009", Fore.YELLOW + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
576, am.Generator.at_beat(576),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 26, 16, "----------------------------", Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
640, am.Generator.at_beat(640),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 27, 17, "43°F Wind 13 mph W \n"
" ", Fore.CYAN + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
704, am.Generator.at_beat(704),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 32, 19, "Precipitation \n"
" 20.3% ", Fore.BLUE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
768, am.Generator.at_beat(768),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 36, 15, "Cloudy", Fore.YELLOW + Style.NORMAL
),
am.Generator.no_request()
),
)
)
beats = am.Scene(
"beats",
(
# beat manager
am.Generator(
0, am.Generator.combine_conditions(am.Generator.every_on_off(48, 16), am.Generator.every_n_beats(4)),
lambda g: g.set_data("beat_toggle", True),
lambda g, b: beat_toggle(canvas, g, 0, 18, 22, 11, 15, "@@", Style.BRIGHT + Fore.YELLOW),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.combine_conditions(am.Generator.every_off_on(48, 16), am.Generator.every_n_beats(2)),
lambda g: g.set_data("beat_toggle", True),
lambda g, b: beat_toggle(canvas, g, 0, 18, 22, 11, 15, "##", Style.BRIGHT + Fore.GREEN),
am.Generator.no_request()
),
)
)
beats_lr = am.Scene(
"beats_lr",
(
# beat manager
am.Generator(
0, am.Generator.combine_conditions(am.Generator.every_on_off(48, 16), am.Generator.every_n_beats(4)),
lambda g: g.set_data("beat_toggle", True),
lambda g, b: beat_toggle(canvas, g, 0, 18, 20, 11, 15, "@@", Style.BRIGHT + Fore.YELLOW),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.combine_conditions(am.Generator.every_off_on(48, 16), am.Generator.every_n_beats(2)),
lambda g: g.set_data("beat_toggle", True),
lambda g, b: beat_toggle(canvas, g, 0, 20, 22, 11, 15, "##", Style.BRIGHT + Fore.GREEN),
am.Generator.no_request()
),
)
)
beats_side = am.Scene(
"beats_side",
(
# beat manager
am.Generator(
0, am.Generator.combine_conditions(am.Generator.every_on_off(48, 16), am.Generator.every_n_beats(4)),
lambda g: g.set_data("beat_toggle", True),
lambda g, b: beat_toggle(canvas, g, 0, 18, 20, 11, 15, "@@", Style.BRIGHT + Fore.YELLOW),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.combine_conditions(am.Generator.every_off_on(48, 16), am.Generator.every_n_beats(2)),
lambda g: g.set_data("beat_toggle", True),
lambda g, b: beat_toggle(canvas, g, 0, 20, 22, 11, 15, "##", Style.BRIGHT + Fore.GREEN),
am.Generator.no_request()
),
)
)
date_ticker = am.Scene(
"dates",
(
# TODO change this shit to every n beats, use a data variable to store the current date index PLEASE
#
# Run at normal speed
# Run at double speed
# Run with slight randomness forwards
# Skip forwards, go every step
# At crazy part, switch off this and go to a glitchy display
#
am.Generator(
0, am.Generator.before_n(64 * 8),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(27, 15), work_out_date(b), Fore.YELLOW + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
64 * 8, am.Generator.before_n(64 * 12 - 4),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(27, 15), work_out_date((64 * 8) + (b - (64 * 8)) * 2), Fore.YELLOW + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
64 * 12 - 4, am.Generator.at_beat(64 * 12 - 4),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(27, 15), "??.??.????", Fore.YELLOW + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
64 * 12 + 4, am.Generator.combine_conditions(am.Generator.every_n_beats(4), am.Generator.before_n(64 * 16)),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(27, 15), work_out_date(random.randint(64 * 12 + b * 8, 64 * 12 + b * 24)), Fore.YELLOW + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
64 * 16, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(27, 15), work_out_date(64 * 16 + b * 64 - 64 * 16 * 32), Fore.YELLOW + Style.BRIGHT
),
am.Generator.no_request()
),
)
)
redraw_ui = am.Scene(
"redraw_ui",
(
am.Generator(
0, am.Generator.at_beat(0),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(0, 21), "--" * 40, Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(0),
am.Generator.no_create(),
lambda g, b: canvas.set_string(
0, Vector2(1, 22), "> _ ", Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(2),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 26, 14, "----------------------------\n" +
"| |\n" * 6, Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(3),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 27, 15, "22.10.2009", Fore.YELLOW + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(4),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 26, 16, "----------------------------", Fore.WHITE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(5),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 27, 17, "43°F Wind 13 mph W ", Fore.CYAN + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(6),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 32, 19, "Precipitation \n"
" 20.3% ", Fore.BLUE + Style.BRIGHT
),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(7),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 36, 15, "Cloudy", Fore.YELLOW + Style.NORMAL
),
am.Generator.no_request()
),
)
)
weather = am.Scene(
"weather",
(
am.Generator(
0, am.Generator.combine_conditions(am.Generator.every_n_beats(64), am.Generator.before_n(64 * 8)),
am.Generator.no_create(),
lambda g, b: render_weather(canvas, 0, 27, 17, known_weathers[min(2, b // 64)], 0 if b < 128 else 1),
am.Generator.no_request()
),
am.Generator(
64 * 8, am.Generator.combine_conditions(am.Generator.every_n_beats(32), am.Generator.before_n(64 * 12)),
am.Generator.no_create(),
lambda g, b: render_weather(canvas, 0, 27, 17, known_weathers[2], 1),
am.Generator.no_request()
),
am.Generator(
64 * 12 - 4, am.Generator.at_beat(64 * 12 - 4),
am.Generator.no_create(),
lambda g, b: render_weather(canvas, 0, 27, 17, known_weathers[4], 1),
am.Generator.no_request()
),
am.Generator(
64 * 12 + 4, am.Generator.combine_conditions(am.Generator.every_n_beats(4), am.Generator.before_n(64 * 16)),
am.Generator.no_create(),
lambda g, b: render_weather(canvas, 0, 27, 17, known_weathers[2], 14),
am.Generator.no_request()
),
am.Generator(
64 * 16, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: render_weather(canvas, 0, 27, 17, known_weathers[3], 1, max(0, (b - 1080) * 2.2)),
am.Generator.no_request()
),
)
)
funding = am.Scene(
"funding",
(
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.WHITE + Style.BRIGHT),
lambda g, b: typewrite_by_word(canvas, g, 0, 2, 22, g.get_data("type_col")),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: write_history(canvas, g, 0, 1, 19, Fore.BLACK + Style.BRIGHT, 1),
am.Generator.no_request()
),
)
)
loading = am.Scene(
"loadingbar",
(
am.Generator(
0, am.Generator.at_beat(0),
lambda g: g.scene.set_data("progress", 0),
lambda g, b: set_multiline_string(canvas, 0, 2, 9,
"----------------------------------\n"
"| |\n"
"----------------------------------",
Fore.WHITE + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
1, am.Generator.at_beat(1),
lambda g: g.scene.set_data("progress", 0),
lambda g, b: set_multiline_string(canvas, 0, 3, 10,
" Loading... \n",
Fore.BLACK + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.combine_conditions(am.Generator.before_n(240), am.Generator.every_n_beats(8)),
am.Generator.no_create(),
lambda g, b: g.scene.oper_data("progress", lambda t: t + 1),
am.Generator.no_request()
),
am.Generator(
240, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: g.scene.oper_data("progress", lambda t: t + random.randint(40, 70)),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.before_n(240),
am.Generator.no_create(),
lambda g, b: canvas.set_string(0, Vector2(3, 10), "#" * g.scene.get_data("progress"),
Fore.YELLOW + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
240, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: canvas.set_string(0, Vector2(3, 10), fuck_up_text("#" * g.scene.get_data("progress"), 400),
Fore.RED + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.before_n(240),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.BLACK + Style.BRIGHT),
lambda g, b: typewrite_by_word(canvas, g, 0, 3, 12, g.get_data("type_col")),
am.Generator.no_request()
),
)
)
quick_loading = am.Scene(
"fastload",
(
am.Generator(
0, am.Generator.at_beat(0),
lambda g: g.scene.set_data("progress", 0),
lambda g, b: set_multiline_string(canvas, 0, 2, 9,
"----------------------------------\n"
"| |\n"
"----------------------------------",
Fore.WHITE + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
1, am.Generator.at_beat(1),
lambda g: g.scene.set_data("progress", 0),
lambda g, b: set_multiline_string(canvas, 0, 3, 10,
" Please wait... \n",
Fore.BLACK + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: g.scene.oper_data("progress", lambda t: t + random.randint(4, 6)),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: canvas.set_string(0, Vector2(3, 10), "#" * g.scene.get_data("progress"),
Fore.GREEN + Style.BRIGHT),
am.Generator.no_request()
),
)
)
error_screen = am.Scene(
"error",
(
am.Generator(
0, am.Generator.at_beat(0),
lambda g: g.scene.set_data("progress", 0),
lambda g, b: set_multiline_string(canvas, 0, 0, 14, "--" * 40 + "\n" * 8 + " $ ", Fore.WHITE + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(0),
lambda g: g.scene.set_data("progress", 0),
lambda g, b: set_multiline_string(canvas, 0, 1, 1,
"Automatic diagnosis unsuccessful. Please wait.\n> ",
Fore.BLACK + Style.BRIGHT),
am.Generator.no_request()
),
)
)
funding_double = am.Scene(
"fundingx2",
(
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.RED + Style.NORMAL),
lambda g, b: typewrite_by_word(canvas, g, 0, 2, 2, g.get_data("type_col")),
am.Generator.no_request()
),
# am.Generator(
# 0, am.Generator.always(),
# am.Generator.no_create(),
# lambda g, b: write_history(canvas, g, 0, 1, 19, Fore.BLACK + Style.BRIGHT, 1),
# am.Generator.no_request()
# ),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.CYAN + Style.BRIGHT),
lambda g, b: typewrite_by_word(canvas, g, 0, 2, 22, g.get_data("type_col"), history_var="history2"),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: write_history(canvas, g, 0, 1, 21, Fore.BLACK + Style.BRIGHT, 15, var="history2"),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.YELLOW + Style.BRIGHT),
lambda g, b: typewrite_by_word(canvas, g, 0, 4, 5, g.get_data("type_col"), history_var="history3"),
am.Generator.no_request()
),
)
)
access_points = am.Scene(
"accesspoints",
(
am.Generator(
0, am.Generator.combine_conditions(am.Generator.before_n(20), am.Generator.every_n_beats(2)),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 1, 1,
"\n\n".join(
"\n".join(
" ".join(
("PBS #{:02}".format((yblock * 6) + x + 1) if yline == 1 else (" ### ", "", "Unknown")[yline]) if random.randint(0, max(1, 32 - int(b ** 1.2))) < 4 else " "
for x in range(6)
) for yline in range(3)
) for yblock in range(4)
),
Fore.BLACK + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
20, am.Generator.at_beat(20),
am.Generator.no_create(),
lambda g, b: set_multiline_string(
canvas, 0, 1, 1,
"\n\n".join(
"\n".join(
" ".join(
("PBS #{:02}".format((yblock * 6) + x + 1) if yline == 1 else (" ### ", "", "Unknown")[yline])
for x in range(6)
) for yline in range(3)
) for yblock in range(4)
),
Fore.RED + Style.NORMAL),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.at_beat(0),
am.Generator.no_create(),
lambda g, b: set_multiline_string(canvas, 0, 1, 17,
"No access points are broadcasting.\n"
"Manual search in progress.\n"
"Last search 27.02.2019 (532 days ago)",
Fore.BLACK + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
80, am.Generator.combine_conditions(am.Generator.every_n_beats(8), am.Generator.before_n(976)),
lambda g: g.set_data("counter", 0, "block", 0),
lambda g, b: show_access_point_visual(canvas, g, 0, 1, 1),
am.Generator.no_request()
),
am.Generator(
968, am.Generator.at_beat(968),
am.Generator.no_create(),
lambda g, b: set_multiline_string(canvas, 0, 6, 9, " @@@ \nPBS #14\n Active", Fore.GREEN + Style.BRIGHT),
am.Generator.no_request()
)
)
)
funding_single = am.Scene(
"fdg_single",
(
am.Generator(
0, am.Generator.at_beat(0),
lambda g: g.scene.set_data("progress", 0),
lambda g, b: set_multiline_string(canvas, 0, 0, 20, "--" * 40 + "\n" + " Sending > ",
Fore.WHITE + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.YELLOW + Style.NORMAL),
lambda g, b: typewrite_by_word(canvas, g, 0, 6, 21, g.get_data("type_col")),
am.Generator.no_request()
),
)
)
funding_down = am.Scene(
"fdg_down",
(
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.YELLOW + Style.NORMAL),
lambda g, b: typewrite_by_word(canvas, g, 0, 1, 1 + g.get_data("lineno"), g.get_data("type_col")),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
lambda g: g.set_data("text", [], "offset", 0, "lineno", 0, "type_col", Fore.YELLOW + Style.NORMAL),
lambda g, b: typewrite_by_word(canvas, g, 0, 1, 20 + g.get_data("lineno"), g.get_data("type_col")),
am.Generator.no_request()
),
)
)
poweroff = am.Scene(
"poweroff",
(
am.Generator(
3, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: make_poweroff_bars(canvas, b - 2, 0, Fore.BLACK + Style.NORMAL),
am.Generator.no_request()
),
am.Generator(
2, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: make_poweroff_bars(canvas, b - 1, 0, Fore.BLACK + Style.BRIGHT),
am.Generator.no_request()
),
am.Generator(
1, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: make_poweroff_bars(canvas, b, 0, Fore.WHITE + Style.NORMAL),
am.Generator.no_request()
),
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: make_poweroff_bars(canvas, b + 1, 0, Fore.WHITE + Style.BRIGHT),
am.Generator.no_request()
),
)
)
all_scenes = (
wipe, clear_wipe, clear_scene, ocean, ocean2, ocean3, text, title, beats, beats_lr, funding, date_ticker,
weather, redraw_ui, loading, quick_loading, error_screen, funding_double, access_points, funding_single,
funding_down, poweroff
)
================================================
FILE: animator.py
================================================
class DataStoringObject:
def __init__(self):
self.data = {}
def set_data(self, *ident):
for i in range(0, len(ident), 2):
self.data[ident[i]] = ident[i + 1]
def get_data(self, ident):
if ident in self.data:
return self.data[ident]
def oper_data(self, ident, oper):
self.data[ident] = oper(self.data[ident])
class SceneManager(DataStoringObject):
def __init__(self, scenes, events):
super().__init__()
self.scenes = {scene.name: scene for scene in scenes}
self.events = {event.beat: [ev for ev in events if ev.beat == event.beat] for event in events}
for scene in scenes:
scene.set_parent(self)
self.active_scene = []
self.cur_beat = -1
self.data = {}
def start_scene(self, scene, at=0):
if len(self.active_scene) == 0:
self.active_scene.append(None)
self.active_scene[0] = self.scenes[scene]
self.active_scene[0].start(at)
def add_scene(self, scene, at=0):
self.active_scene.append(self.scenes[scene])
self.active_scene[-1].start(at)
def remove_scene(self, scene):
if self.scenes[scene] in self.active_scene:
self.active_scene.remove(self.scenes[scene])
def request_next(self, render=True):
for scene in self.active_scene:
scene.request_frame(render)
self.next_beat()
def next_beat(self):
self.cur_beat += 1
if self.cur_beat in self.events:
for event in self.events[self.cur_beat]:
event.do(self)
def set_scene_data(self, scene, *ident):
self.scenes[scene].set_data(*ident)
def set_generator_data(self, scene, generator, *ident):
self.scenes[scene].generators[generator].set_data(*ident)
class Event:
def __init__(self, beat, do):
self.beat = beat
self.do = do
@staticmethod
def swap_scene(sc, at=0):
return lambda sm: sm.start_scene(sc, at)
@staticmethod
def layer_scene(sc, at=0):
return lambda sm: sm.add_scene(sc, at)
@staticmethod
def remove_scene(sc):
return lambda sm: sm.remove_scene(sc)
class Scene(DataStoringObject):
def __init__(self, name, generators):
super().__init__()
self.parent = None
self.name = name
self.generators = generators
self.start_beat = 0
self.internal_beat = 0
def set_parent(self, parent):
self.parent = parent
# Requests a frame. This basically calls the request() and request_clear() functions in every generator.
def request_frame(self, render=True):
beat = self.internal_beat
if render:
for generator in self.generators:
if beat >= generator.start_beat and generator.condition(beat):
if beat != self.start_beat and beat != generator.start_beat:
# Clear previous beat
generator.request_clear(generator, beat - 1)
# Make current
generator.request(generator, beat)
self.internal_beat += 1
# Starts the scene at the beat given.
def start(self, at):
for generator in self.generators:
generator.set_parent(self.parent)
generator.set_scene(self)
generator.on_create(generator)
self.start_beat = at
self.internal_beat = at
self.request_frame()
class Generator(DataStoringObject):
def __init__(self, start_beat, condition, on_create, request, request_clear):
super().__init__()
self.parent = None
self.scene = None
self.data = {}
self.start_beat = start_beat
self.condition = condition
self.on_create = on_create
self.request = request
self.request_clear = request_clear
def set_parent(self, parent):
self.parent = parent
def set_scene(self, scene):
self.scene = scene
@staticmethod
def combine_conditions(*cond):
return lambda b: all(c(b) for c in cond)
@staticmethod
def always():
return lambda b: True
@staticmethod
def every_n_beats(beat):
return lambda b: b % beat == 0
@staticmethod
def every_on_off(on, off):
return lambda b: (b % (on + off)) < on
@staticmethod
def every_off_on(off, on):
return lambda b: (b % (on + off)) >= off
@staticmethod
def before_n(beat):
return lambda b: b < beat
@staticmethod
def at_beat(beat):
return lambda b: b == beat
@staticmethod
def no_create():
return lambda g: None
@staticmethod
def no_request():
return lambda g, b: None
================================================
FILE: colorama/__init__.py
================================================
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
from .initialise import init, deinit, reinit, colorama_text
from .ansi import Fore, Back, Style, Cursor
from .ansitowin32 import AnsiToWin32
__version__ = '0.3.7'
================================================
FILE: colorama/ansi.py
================================================
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
'''
This module generates ANSI character codes to printing colors to terminals.
See: http://en.wikipedia.org/wiki/ANSI_escape_code
'''
CSI = '\033['
OSC = '\033]'
BEL = '\007'
def code_to_chars(code):
return CSI + str(code) + 'm'
def set_title(title):
return OSC + '2;' + title + BEL
def clear_screen(mode=2):
return CSI + str(mode) + 'J'
def clear_line(mode=2):
return CSI + str(mode) + 'K'
class AnsiCodes(object):
def __init__(self):
# the subclasses declare class attributes which are numbers.
# Upon instantiation we define instance attributes, which are the same
# as the class attributes but wrapped with the ANSI escape sequence
for name in dir(self):
if not name.startswith('_'):
value = getattr(self, name)
setattr(self, name, code_to_chars(value))
class AnsiCursor(object):
def UP(self, n=1):
return CSI + str(n) + 'A'
def DOWN(self, n=1):
return CSI + str(n) + 'B'
def FORWARD(self, n=1):
return CSI + str(n) + 'C'
def BACK(self, n=1):
return CSI + str(n) + 'D'
def POS(self, x=1, y=1):
return CSI + str(y) + ';' + str(x) + 'H'
class AnsiFore(AnsiCodes):
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
WHITE = 37
RESET = 39
# These are fairly well supported, but not part of the standard.
LIGHTBLACK_EX = 90
LIGHTRED_EX = 91
LIGHTGREEN_EX = 92
LIGHTYELLOW_EX = 93
LIGHTBLUE_EX = 94
LIGHTMAGENTA_EX = 95
LIGHTCYAN_EX = 96
LIGHTWHITE_EX = 97
class AnsiBack(AnsiCodes):
BLACK = 40
RED = 41
GREEN = 42
YELLOW = 43
BLUE = 44
MAGENTA = 45
CYAN = 46
WHITE = 47
RESET = 49
# These are fairly well supported, but not part of the standard.
LIGHTBLACK_EX = 100
LIGHTRED_EX = 101
LIGHTGREEN_EX = 102
LIGHTYELLOW_EX = 103
LIGHTBLUE_EX = 104
LIGHTMAGENTA_EX = 105
LIGHTCYAN_EX = 106
LIGHTWHITE_EX = 107
class AnsiStyle(AnsiCodes):
BRIGHT = 1
DIM = 2
NORMAL = 22
RESET_ALL = 0
Fore = AnsiFore()
Back = AnsiBack()
Style = AnsiStyle()
Cursor = AnsiCursor()
================================================
FILE: colorama/ansitowin32.py
================================================
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import re
import sys
import os
from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style
from .winterm import WinTerm, WinColor, WinStyle
from .win32 import windll, winapi_test
winterm = None
if windll is not None:
winterm = WinTerm()
def is_stream_closed(stream):
return not hasattr(stream, 'closed') or stream.closed
def is_a_tty(stream):
return hasattr(stream, 'isatty') and stream.isatty()
class StreamWrapper(object):
'''
Wraps a stream (such as stdout), acting as a transparent proxy for all
attribute access apart from method 'write()', which is delegated to our
Converter instance.
'''
def __init__(self, wrapped, converter):
# double-underscore everything to prevent clashes with names of
# attributes on the wrapped stream object.
self.__wrapped = wrapped
self.__convertor = converter
def __getattr__(self, name):
return getattr(self.__wrapped, name)
def write(self, text):
self.__convertor.write(text)
class AnsiToWin32(object):
'''
Implements a 'write()' method which, on Windows, will strip ANSI character
sequences from the text, and if outputting to a tty, will convert them into
win32 function calls.
'''
ANSI_CSI_RE = re.compile('\001?\033\[((?:\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer
ANSI_OSC_RE = re.compile('\001?\033\]((?:.|;)*?)(\x07)\002?') # Operating System Command
def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
# The wrapped stream (normally sys.stdout or sys.stderr)
self.wrapped = wrapped
# should we reset colors to defaults after every .write()
self.autoreset = autoreset
# create the proxy wrapping our output stream
self.stream = StreamWrapper(wrapped, self)
on_windows = os.name == 'nt'
# We test if the WinAPI works, because even if we are on Windows
# we may be using a terminal that doesn't support the WinAPI
# (e.g. Cygwin Terminal). In this case it's up to the terminal
# to support the ANSI codes.
conversion_supported = on_windows and winapi_test()
# should we strip ANSI sequences from our output?
if strip is None:
strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped))
self.strip = strip
# should we should convert ANSI sequences into win32 calls?
if convert is None:
convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped)
self.convert = convert
# dict of ansi codes to win32 functions and parameters
self.win32_calls = self.get_win32_calls()
# are we wrapping stderr?
self.on_stderr = self.wrapped is sys.stderr
def should_wrap(self):
'''
True if this class is actually needed. If false, then the output
stream will not be affected, nor will win32 calls be issued, so
wrapping stdout is not actually required. This will generally be
False on non-Windows platforms, unless optional functionality like
autoreset has been requested using kwargs to init()
'''
return self.convert or self.strip or self.autoreset
def get_win32_calls(self):
if self.convert and winterm:
return {
AnsiStyle.RESET_ALL: (winterm.reset_all, ),
AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT),
AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL),
AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL),
AnsiFore.BLACK: (winterm.fore, WinColor.BLACK),
AnsiFore.RED: (winterm.fore, WinColor.RED),
AnsiFore.GREEN: (winterm.fore, WinColor.GREEN),
AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW),
AnsiFore.BLUE: (winterm.fore, WinColor.BLUE),
AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA),
AnsiFore.CYAN: (winterm.fore, WinColor.CYAN),
AnsiFore.WHITE: (winterm.fore, WinColor.GREY),
AnsiFore.RESET: (winterm.fore, ),
AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True),
AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True),
AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True),
AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True),
AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True),
AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True),
AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True),
AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True),
AnsiBack.BLACK: (winterm.back, WinColor.BLACK),
AnsiBack.RED: (winterm.back, WinColor.RED),
AnsiBack.GREEN: (winterm.back, WinColor.GREEN),
AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW),
AnsiBack.BLUE: (winterm.back, WinColor.BLUE),
AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA),
AnsiBack.CYAN: (winterm.back, WinColor.CYAN),
AnsiBack.WHITE: (winterm.back, WinColor.GREY),
AnsiBack.RESET: (winterm.back, ),
AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True),
AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True),
AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True),
AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True),
AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True),
AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True),
AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True),
AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True),
}
return dict()
def write(self, text):
if self.strip or self.convert:
self.write_and_convert(text)
else:
self.wrapped.write(text)
self.wrapped.flush()
if self.autoreset:
self.reset_all()
def reset_all(self):
if self.convert:
self.call_win32('m', (0,))
elif not self.strip and not is_stream_closed(self.wrapped):
self.wrapped.write(Style.RESET_ALL)
def write_and_convert(self, text):
'''
Write the given text to our wrapped stream, stripping any ANSI
sequences from the text, and optionally converting them into win32
calls.
'''
cursor = 0
text = self.convert_osc(text)
for match in self.ANSI_CSI_RE.finditer(text):
start, end = match.span()
self.write_plain_text(text, cursor, start)
self.convert_ansi(*match.groups())
cursor = end
self.write_plain_text(text, cursor, len(text))
def write_plain_text(self, text, start, end):
if start < end:
self.wrapped.write(text[start:end])
self.wrapped.flush()
def convert_ansi(self, paramstring, command):
if self.convert:
params = self.extract_params(command, paramstring)
self.call_win32(command, params)
def extract_params(self, command, paramstring):
if command in 'Hf':
params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';'))
while len(params) < 2:
# defaults:
params = params + (1,)
else:
params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0)
if len(params) == 0:
# defaults:
if command in 'JKm':
params = (0,)
elif command in 'ABCD':
params = (1,)
return params
def call_win32(self, command, params):
if command == 'm':
for param in params:
if param in self.win32_calls:
func_args = self.win32_calls[param]
func = func_args[0]
args = func_args[1:]
kwargs = dict(on_stderr=self.on_stderr)
func(*args, **kwargs)
elif command in 'J':
winterm.erase_screen(params[0], on_stderr=self.on_stderr)
elif command in 'K':
winterm.erase_line(params[0], on_stderr=self.on_stderr)
elif command in 'Hf': # cursor position - absolute
winterm.set_cursor_position(params, on_stderr=self.on_stderr)
elif command in 'ABCD': # cursor position - relative
n = params[0]
# A - up, B - down, C - forward, D - back
x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command]
winterm.cursor_adjust(x, y, on_stderr=self.on_stderr)
def convert_osc(self, text):
for match in self.ANSI_OSC_RE.finditer(text):
start, end = match.span()
text = text[:start] + text[end:]
paramstring, command = match.groups()
if command in '\x07': # \x07 = BEL
params = paramstring.split(";")
# 0 - change title and icon (we will only change title)
# 1 - change icon (we don't support this)
# 2 - change title
if params[0] in '02':
winterm.set_title(params[1])
return text
================================================
FILE: colorama/initialise.py
================================================
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import atexit
import contextlib
import sys
from .ansitowin32 import AnsiToWin32
orig_stdout = None
orig_stderr = None
wrapped_stdout = None
wrapped_stderr = None
atexit_done = False
def reset_all():
if AnsiToWin32 is not None: # Issue #74: objects might become None at exit
AnsiToWin32(orig_stdout).reset_all()
def init(autoreset=False, convert=None, strip=None, wrap=True):
if not wrap and any([autoreset, convert, strip]):
raise ValueError('wrap=False conflicts with any other arg=True')
global wrapped_stdout, wrapped_stderr
global orig_stdout, orig_stderr
orig_stdout = sys.stdout
orig_stderr = sys.stderr
if sys.stdout is None:
wrapped_stdout = None
else:
sys.stdout = wrapped_stdout = \
wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
if sys.stderr is None:
wrapped_stderr = None
else:
sys.stderr = wrapped_stderr = \
wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
global atexit_done
if not atexit_done:
atexit.register(reset_all)
atexit_done = True
def deinit():
if orig_stdout is not None:
sys.stdout = orig_stdout
if orig_stderr is not None:
sys.stderr = orig_stderr
@contextlib.contextmanager
def colorama_text(*args, **kwargs):
init(*args, **kwargs)
try:
yield
finally:
deinit()
def reinit():
if wrapped_stdout is not None:
sys.stdout = wrapped_stdout
if wrapped_stderr is not None:
sys.stderr = wrapped_stderr
def wrap_stream(stream, convert, strip, autoreset, wrap):
if wrap:
wrapper = AnsiToWin32(stream,
convert=convert, strip=strip, autoreset=autoreset)
if wrapper.should_wrap():
stream = wrapper.stream
return stream
================================================
FILE: colorama/win32.py
================================================
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
# from winbase.h
STDOUT = -11
STDERR = -12
try:
import ctypes
from ctypes import LibraryLoader
windll = LibraryLoader(ctypes.WinDLL)
from ctypes import wintypes
except (AttributeError, ImportError):
windll = None
SetConsoleTextAttribute = lambda *_: None
winapi_test = lambda *_: None
else:
from ctypes import byref, Structure, c_char, POINTER
COORD = wintypes._COORD
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
"""struct in wincon.h."""
_fields_ = [
("dwSize", COORD),
("dwCursorPosition", COORD),
("wAttributes", wintypes.WORD),
("srWindow", wintypes.SMALL_RECT),
("dwMaximumWindowSize", COORD),
]
def __str__(self):
return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
self.dwSize.Y, self.dwSize.X
, self.dwCursorPosition.Y, self.dwCursorPosition.X
, self.wAttributes
, self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
, self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
)
_GetStdHandle = windll.kernel32.GetStdHandle
_GetStdHandle.argtypes = [
wintypes.DWORD,
]
_GetStdHandle.restype = wintypes.HANDLE
_GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
_GetConsoleScreenBufferInfo.argtypes = [
wintypes.HANDLE,
POINTER(CONSOLE_SCREEN_BUFFER_INFO),
]
_GetConsoleScreenBufferInfo.restype = wintypes.BOOL
_SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
_SetConsoleTextAttribute.argtypes = [
wintypes.HANDLE,
wintypes.WORD,
]
_SetConsoleTextAttribute.restype = wintypes.BOOL
_SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition
_SetConsoleCursorPosition.argtypes = [
wintypes.HANDLE,
COORD,
]
_SetConsoleCursorPosition.restype = wintypes.BOOL
_FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA
_FillConsoleOutputCharacterA.argtypes = [
wintypes.HANDLE,
c_char,
wintypes.DWORD,
COORD,
POINTER(wintypes.DWORD),
]
_FillConsoleOutputCharacterA.restype = wintypes.BOOL
_FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute
_FillConsoleOutputAttribute.argtypes = [
wintypes.HANDLE,
wintypes.WORD,
wintypes.DWORD,
COORD,
POINTER(wintypes.DWORD),
]
_FillConsoleOutputAttribute.restype = wintypes.BOOL
_SetConsoleTitleW = windll.kernel32.SetConsoleTitleA
_SetConsoleTitleW.argtypes = [
wintypes.LPCSTR
]
_SetConsoleTitleW.restype = wintypes.BOOL
handles = {
STDOUT: _GetStdHandle(STDOUT),
STDERR: _GetStdHandle(STDERR),
}
def winapi_test():
handle = handles[STDOUT]
csbi = CONSOLE_SCREEN_BUFFER_INFO()
success = _GetConsoleScreenBufferInfo(
handle, byref(csbi))
return bool(success)
def GetConsoleScreenBufferInfo(stream_id=STDOUT):
handle = handles[stream_id]
csbi = CONSOLE_SCREEN_BUFFER_INFO()
success = _GetConsoleScreenBufferInfo(
handle, byref(csbi))
return csbi
def SetConsoleTextAttribute(stream_id, attrs):
handle = handles[stream_id]
return _SetConsoleTextAttribute(handle, attrs)
def SetConsoleCursorPosition(stream_id, position, adjust=True):
position = COORD(*position)
# If the position is out of range, do nothing.
if position.Y <= 0 or position.X <= 0:
return
# Adjust for Windows' SetConsoleCursorPosition:
# 1. being 0-based, while ANSI is 1-based.
# 2. expecting (x,y), while ANSI uses (y,x).
adjusted_position = COORD(position.Y - 1, position.X - 1)
if adjust:
# Adjust for viewport's scroll position
sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
adjusted_position.Y += sr.Top
adjusted_position.X += sr.Left
# Resume normal processing
handle = handles[stream_id]
return _SetConsoleCursorPosition(handle, adjusted_position)
def FillConsoleOutputCharacter(stream_id, char, length, start):
handle = handles[stream_id]
char = c_char(char.encode())
length = wintypes.DWORD(length)
num_written = wintypes.DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
success = _FillConsoleOutputCharacterA(
handle, char, length, start, byref(num_written))
return num_written.value
def FillConsoleOutputAttribute(stream_id, attr, length, start):
''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
handle = handles[stream_id]
attribute = wintypes.WORD(attr)
length = wintypes.DWORD(length)
num_written = wintypes.DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
return _FillConsoleOutputAttribute(
handle, attribute, length, start, byref(num_written))
def SetConsoleTitle(title):
return _SetConsoleTitleW(title)
================================================
FILE: colorama/winterm.py
================================================
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
from . import win32
# from wincon.h
class WinColor(object):
BLACK = 0
BLUE = 1
GREEN = 2
CYAN = 3
RED = 4
MAGENTA = 5
YELLOW = 6
GREY = 7
# from wincon.h
class WinStyle(object):
NORMAL = 0x00 # dim text, dim background
BRIGHT = 0x08 # bright text, dim background
BRIGHT_BACKGROUND = 0x80 # dim text, bright background
class WinTerm(object):
def __init__(self):
self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes
self.set_attrs(self._default)
self._default_fore = self._fore
self._default_back = self._back
self._default_style = self._style
# In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style.
# So that LIGHT_EX colors and BRIGHT style do not clobber each other,
# we track them separately, since LIGHT_EX is overwritten by Fore/Back
# and BRIGHT is overwritten by Style codes.
self._light = 0
def get_attrs(self):
return self._fore + self._back * 16 + (self._style | self._light)
def set_attrs(self, value):
self._fore = value & 7
self._back = (value >> 4) & 7
self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND)
def reset_all(self, on_stderr=None):
self.set_attrs(self._default)
self.set_console(attrs=self._default)
def fore(self, fore=None, light=False, on_stderr=False):
if fore is None:
fore = self._default_fore
self._fore = fore
# Emulate LIGHT_EX with BRIGHT Style
if light:
self._light |= WinStyle.BRIGHT
else:
self._light &= ~WinStyle.BRIGHT
self.set_console(on_stderr=on_stderr)
def back(self, back=None, light=False, on_stderr=False):
if back is None:
back = self._default_back
self._back = back
# Emulate LIGHT_EX with BRIGHT_BACKGROUND Style
if light:
self._light |= WinStyle.BRIGHT_BACKGROUND
else:
self._light &= ~WinStyle.BRIGHT_BACKGROUND
self.set_console(on_stderr=on_stderr)
def style(self, style=None, on_stderr=False):
if style is None:
style = self._default_style
self._style = style
self.set_console(on_stderr=on_stderr)
def set_console(self, attrs=None, on_stderr=False):
if attrs is None:
attrs = self.get_attrs()
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
win32.SetConsoleTextAttribute(handle, attrs)
def get_position(self, handle):
position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition
# Because Windows coordinates are 0-based,
# and win32.SetConsoleCursorPosition expects 1-based.
position.X += 1
position.Y += 1
return position
def set_cursor_position(self, position=None, on_stderr=False):
if position is None:
# I'm not currently tracking the position, so there is no default.
# position = self.get_position()
return
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
win32.SetConsoleCursorPosition(handle, position)
def cursor_adjust(self, x, y, on_stderr=False):
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
position = self.get_position(handle)
adjusted_position = (position.Y + y, position.X + x)
win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False)
def erase_screen(self, mode=0, on_stderr=False):
# 0 should clear from the cursor to the end of the screen.
# 1 should clear from the cursor to the beginning of the screen.
# 2 should clear the entire screen, and move cursor to (1,1)
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
csbi = win32.GetConsoleScreenBufferInfo(handle)
# get the number of character cells in the current buffer
cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y
# get number of character cells before current cursor position
cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X
if mode == 0:
from_coord = csbi.dwCursorPosition
cells_to_erase = cells_in_screen - cells_before_cursor
if mode == 1:
from_coord = win32.COORD(0, 0)
cells_to_erase = cells_before_cursor
elif mode == 2:
from_coord = win32.COORD(0, 0)
cells_to_erase = cells_in_screen
# fill the entire screen with blanks
win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord)
# now set the buffer's attributes accordingly
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord)
if mode == 2:
# put the cursor where needed
win32.SetConsoleCursorPosition(handle, (1, 1))
def erase_line(self, mode=0, on_stderr=False):
# 0 should clear from the cursor to the end of the line.
# 1 should clear from the cursor to the beginning of the line.
# 2 should clear the entire line.
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
csbi = win32.GetConsoleScreenBufferInfo(handle)
if mode == 0:
from_coord = csbi.dwCursorPosition
cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X
if mode == 1:
from_coord = win32.COORD(0, csbi.dwCursorPosition.Y)
cells_to_erase = csbi.dwCursorPosition.X
elif mode == 2:
from_coord = win32.COORD(0, csbi.dwCursorPosition.Y)
cells_to_erase = csbi.dwSize.X
# fill the entire screen with blanks
win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord)
# now set the buffer's attributes accordingly
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord)
def set_title(self, title):
win32.SetConsoleTitle(title)
================================================
FILE: credits.py
================================================
from animation_functions import debug_info
from CLIRender.classes import enable_ansi
from colorama import Fore, Style
import keyboard
import time
import os
import random
from just_playback import Playback
from animation_scenes import all_scenes, canvas
from string_defs import data_strings
import animator as am
enable_ansi()
# canvas.render_blank()
delay = 60.0 / 179.0 / 8.0
beat = -60
offset = 5.492
# print((delay * 980) + offset)
skip_by = 0
debug = False
last_frames = []
def skip_beats(ctr, amount, next_debug):
global beat
global skip_by
ctr.cur_beat += amount
beat += amount
if debug:
controller.events[next_debug] = (am.Event(next_debug, am.Event.layer_scene("debug_counter")),)
skip_by = offset + (delay * amount)
counter = am.Scene(
"debug_counter",
(
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: debug_info(canvas, g, b, last_frames),
am.Generator.no_request()
),
)
)
ocean_events = (
am.Event(60, lambda c: c.set_generator_data(
"ocean_b", 1, "text", data_strings["ocean_b_0"]
)),
am.Event(310, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", "[##CLEAR|60;6"
)),
am.Event(310, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 3
)),
am.Event(310, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.BLUE
)),
am.Event(312, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.BLUE
)),
am.Event(314, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.BLUE
)),
am.Event(320, lambda c: c.set_generator_data(
"ocean_b", 1, "text", data_strings["ocean_b_1"], "offset", 0
)),
am.Event(590, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.BLACK
)),
am.Event(646, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", "[##CLEAR|60;8"
)),
am.Event(652, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", data_strings["ocean_b_2"], "offset", 0
)),
am.Event(656, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.YELLOW
)),
am.Event(666, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.YELLOW
)),
am.Event(666, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 6
)),
am.Event(850, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.YELLOW
)),
am.Event(999, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", "[##CLEAR|60;10"
)),
am.Event(1000, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.BLACK
)),
am.Event(1000, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 13
)),
am.Event(1000, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", data_strings["ocean_b_3"],
"offset", 0
)),
am.Event(1044, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 102
)),
am.Event(1048, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 230
)),
am.Event(1052, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 500
)),
am.Event(1056, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 760
)),
am.Event(1060, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 1600
)),
am.Event(1064, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 2500
))
)
ocean2_events = (
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 1, "text", data_strings["ocean_c_0"]
)
),
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 2, "text", data_strings["ocean_c_1"]
)
),
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 3, "text", data_strings["ocean_c_2"]
)
),
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 4, "text", data_strings["ocean_c_3"]
)
),
am.Event(4400, lambda c: c.set_generator_data(
"ocean_c", 1,
"text", "[##CLEAR|60;10"
)),
*(
am.Event(4401 + i * 2, lambda c: c.set_generator_data(
"ocean_c", 0, "ocean_col", random.choice((Style.BRIGHT, Style.NORMAL)) + Fore.BLACK
)) for i in range(5)
),
am.Event(4411, lambda c: c.set_generator_data(
"ocean_c", 0, "ocean_col", Style.NORMAL + Fore.BLACK
)),
)
controller = am.SceneManager((*all_scenes, counter), (
am.Event(0, am.Event.swap_scene("wipe")),
# am.Event(1, am.Event.layer_scene("debug_counter")),
am.Event(58, am.Event.swap_scene("clear")),
am.Event(60, am.Event.swap_scene("ocean_b")),
# am.Event(60, am.Event.layer_scene("typewrite")),
*ocean_events,
am.Event(1079, am.Event.swap_scene("clear")),
am.Event(1080, am.Event.swap_scene("beats")),
am.Event(1080, am.Event.layer_scene("title")),
am.Event(1080, am.Event.swap_scene("beats")),
am.Event(1336, am.Event.swap_scene("beats_lr")),
am.Event(1844, am.Event.remove_scene("title")),
am.Event(1848, am.Event.swap_scene("funding")),
am.Event(1848, am.Event.layer_scene("dates")),
am.Event(1848, am.Event.layer_scene("weather")),
am.Event(1848, lambda c: c.set_data(
"history", [], "refresh", True
)),
am.Event(1848, lambda c: c.set_generator_data(
"funding", 0, "text", data_strings["funding_0"]
)),
am.Event(2348, lambda c: c.set_generator_data(
"funding", 0, "text", (('',), ('',))
)),
am.Event(2348, lambda c: c.set_data(
"history", [], "refresh", True
)),
am.Event(2352, lambda c: c.set_generator_data(
"funding", 0, "text", data_strings["funding_1"], "offset", 0, "lineno", 0
)),
am.Event(2976, am.Event.remove_scene("dates")),
am.Event(2976, am.Event.remove_scene("weather")),
am.Event(2976, am.Event.swap_scene("clear_wipe")),
am.Event(3007, am.Event.swap_scene("clear")),
# idk what to do here. some sort of bootup sequence?
am.Event(3132, am.Event.swap_scene("loadingbar")),
am.Event(3132, lambda c: c.set_generator_data(
"loadingbar", 6, "text", data_strings["funding_2"]
)),
am.Event(3376, am.Event.swap_scene("ocean_d")),
am.Event(3380, am.Event.swap_scene("clear")),
am.Event(3380, am.Event.swap_scene("fastload")),
am.Event(3388, am.Event.swap_scene("clear")),
# Crazy part. Go wild
am.Event(3390, am.Event.swap_scene("error")),
am.Event(3390, am.Event.layer_scene("fundingx2")),
am.Event(3390, lambda c: c.set_data(
"history", [], "refresh", True
)),
am.Event(3390, lambda c: c.set_generator_data(
"fundingx2", 0,
"text", data_strings["fundingx2_0"]
)),
am.Event(3390, lambda c: c.set_generator_data(
"fundingx2", 1,
"text", data_strings["fundingx2_1"]
)),
am.Event(3390, lambda c: c.set_generator_data(
"fundingx2", 3,
"text", data_strings["fundingx2_2"]
)),
am.Event(3895, am.Event.remove_scene("fundingx2")),
am.Event(3895, am.Event.swap_scene("clear")),
am.Event(3896, am.Event.swap_scene("ocean_c")),
*ocean2_events,
# remember to clean the ocean_c events up, or it will stay in the screen. At frame 4413.
am.Event(4413, am.Event.swap_scene("clear")),
am.Event(4460, am.Event.swap_scene("accesspoints")),
am.Event(4460, am.Event.layer_scene("fdg_single")),
am.Event(4534, lambda c: c.set_generator_data(
"fdg_single", 1, "text", data_strings["fdg_single_0"]
)),
am.Event(5500, am.Event.remove_scene("fdg_single")),
am.Event(5500, am.Event.swap_scene("clear")),
am.Event(5500, am.Event.swap_scene("beats")),
am.Event(5500, am.Event.layer_scene("fdg_down")),
am.Event(5788, lambda c: c.set_generator_data(
"fdg_down", 0, "text", data_strings["fdg_down_0"]
)),
am.Event(5916, lambda c: c.set_generator_data(
"fdg_down", 0,
"text", data_strings["fdg_down_1"], "lineno", 0, "offset", 0
)),
am.Event(5916, lambda c: c.set_generator_data(
"fdg_down", 1,
"text", data_strings["fdg_down_2"]
)),
am.Event(6270, am.Event.swap_scene("beats_lr")),
am.Event(6508, am.Event.remove_scene("fdg_down")),
# am.Event(6508, am.Event.remove_scene("debug_counter")),
am.Event(6508, am.Event.swap_scene("clear"))
))
# class MixerWrapper:
# def __init__(self):
# self.is_paused = False
#
# def toggle_music(self):
# if self.is_paused:
# pygame.mixer.music.unpause()
# self.is_paused = False
# else:
# pygame.mixer.music.pause()
# self.is_paused = True
#
#
# ffwing = MixerWrapper()
paused_this_frame = False
ff_this_frame = False
filename = "media/credits.wav"
playback = Playback()
playback.load_file(filename)
# Clear the console before showing the skip menu
if os.name == "nt":
os.system("cls")
elif os.name == "posix":
os.system("clear")
else:
print("\033[2J")
print("\033[1;1Hskips\n\n1 | start\n2 | title\n3 | funding\n4 | loading\n5 | break\n6 | final")
# Skips forward to the title scene
time_menu = time.time()
while time.time() - 2 < time_menu:
if keyboard.is_pressed("1"):
time_menu = 99999999999999999999
break
elif keyboard.is_pressed("2"):
skip_beats(controller, 1000, 1081)
time_menu = 99999999999999999999
break
elif keyboard.is_pressed("3"):
skip_beats(controller, 1770, 1851)
controller.events[1849] = am.Event(1849, am.Event.layer_scene("redraw_ui")),
controller.events[1860] = am.Event(1860, am.Event.remove_scene("redraw_ui")),
time_menu = 99999999999999999999
break
elif keyboard.is_pressed("4"):
skip_beats(controller, 3040, 3133)
time_menu = 99999999999999999999
break
elif keyboard.is_pressed("5"):
skip_beats(controller, 3780, 3898)
time_menu = 99999999999999999999
break
elif keyboard.is_pressed("6"):
skip_beats(controller, 5420, 5501)
time_menu = 99999999999999999999
break
time.sleep(0.01)
if os.name == "nt":
os.system("cls")
elif os.name == "posix":
os.system("clear")
else:
print("\033[2J")
# wave_obj = sa.WaveObject.from_wave_file(filename)
# play_obj = wave_obj.play()
playback.play()
playback.seek(skip_by)
time_start = time.time()
last_update = time.time()
prev_pos = 0
while playback.active:
# (17.06.21) might have broken, i used a -1 beat offset here to try and sync up everything better
# since i originally used 1-indexed beats
#
# (24.06.21) update chat it didnt break
# next_beat = (time.time() - time_start - offset) > ((beat - 1) * delay)
next_beat = (playback.curr_pos - offset) > ((beat - 1) * delay)
need_update = time.time() - (1/30) > last_update
# print(pygame.mixer.music.get_pos())
if next_beat:
controller.request_next()
canvas.render_all()
last_frames.append(time.time())
if len(last_frames) > 10:
last_frames.pop(0)
beat += 1
if need_update:
if keyboard.is_pressed("p"):
if not paused_this_frame:
if playback.paused:
playback.resume()
else:
playback.pause()
paused_this_frame = True
else:
paused_this_frame = False
if keyboard.is_pressed(","):
if not ff_this_frame:
ff_this_frame = True
else:
playback.seek(playback.curr_pos + delay * 3)
if keyboard.is_pressed("."):
if not ff_this_frame:
ff_this_frame = True
else:
playback.seek(playback.curr_pos + delay * 7)
if keyboard.is_pressed("/"):
if not ff_this_frame:
ff_this_frame = True
else:
playback.seek(playback.curr_pos + delay * 15)
# else:
# # print("n", ff_this_frame, pygame.mixer.music.get_pos() + prev_pos, prev_pos)
# if ff_this_frame:
# # print("unpausing now")
# ff_this_frame = False
# ffwing.toggle_music()
last_update = time.time()
# Add a final clear at the end to prevent the last frame from sticking around when the program ends.
if os.name == "nt":
os.system("cls")
elif os.name == "posix":
os.system("clear")
else:
print("\033[2J")
================================================
FILE: credits_pynput.py
================================================
from animation_functions import debug_info
from CLIRender.classes import enable_ansi
from colorama import Fore, Style
from pynput import keyboard
import time
import os
import random
from just_playback import Playback
from animation_scenes import all_scenes, canvas
from string_defs import data_strings
import animator as am
enable_ansi()
# canvas.render_blank()
delay = 60.0 / 179.0 / 8.0
beat = -60
offset = 5.492
# print((delay * 980) + offset)
skip_by = 0
debug = False
last_frames = []
def skip_beats(ctr, amount, next_debug):
global beat
global skip_by
ctr.cur_beat += amount
beat += amount
if debug:
controller.events[next_debug] = (am.Event(next_debug, am.Event.layer_scene("debug_counter")),)
skip_by = offset + (delay * amount)
counter = am.Scene(
"debug_counter",
(
am.Generator(
0, am.Generator.always(),
am.Generator.no_create(),
lambda g, b: debug_info(canvas, g, b, last_frames),
am.Generator.no_request()
),
)
)
ocean_events = (
am.Event(60, lambda c: c.set_generator_data(
"ocean_b", 1, "text", data_strings["ocean_b_0"]
)),
am.Event(310, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", "[##CLEAR|60;6"
)),
am.Event(310, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 3
)),
am.Event(310, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.BLUE
)),
am.Event(312, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.BLUE
)),
am.Event(314, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.BLUE
)),
am.Event(320, lambda c: c.set_generator_data(
"ocean_b", 1, "text", data_strings["ocean_b_1"], "offset", 0
)),
am.Event(590, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.BLACK
)),
am.Event(646, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", "[##CLEAR|60;8"
)),
am.Event(652, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", data_strings["ocean_b_2"], "offset", 0
)),
am.Event(656, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.YELLOW
)),
am.Event(666, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.YELLOW
)),
am.Event(666, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 6
)),
am.Event(850, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.NORMAL + Fore.YELLOW
)),
am.Event(999, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", "[##CLEAR|60;10"
)),
am.Event(1000, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_col", Style.BRIGHT + Fore.BLACK
)),
am.Event(1000, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 13
)),
am.Event(1000, lambda c: c.set_generator_data(
"ocean_b", 1,
"text", data_strings["ocean_b_3"],
"offset", 0
)),
am.Event(1044, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 102
)),
am.Event(1048, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 230
)),
am.Event(1052, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 500
)),
am.Event(1056, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 760
)),
am.Event(1060, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 1600
)),
am.Event(1064, lambda c: c.set_generator_data(
"ocean_b", 0, "ocean_glitch", 2500
))
)
ocean2_events = (
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 1, "text", data_strings["ocean_c_0"]
)
),
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 2, "text", data_strings["ocean_c_1"]
)
),
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 3, "text", data_strings["ocean_c_2"]
)
),
am.Event(3896, lambda c: c.set_generator_data(
"ocean_c", 4, "text", data_strings["ocean_c_3"]
)
),
am.Event(4400, lambda c: c.set_generator_data(
"ocean_c", 1,
"text", "[##CLEAR|60;10"
)),
*(
am.Event(4401 + i * 2, lambda c: c.set_generator_data(
"ocean_c", 0, "ocean_col", random.choice((Style.BRIGHT, Style.NORMAL)) + Fore.BLACK
)) for i in range(5)
),
am.Event(4411, lambda c: c.set_generator_data(
"ocean_c", 0, "ocean_col", Style.NORMAL + Fore.BLACK
)),
)
controller = am.SceneManager((*all_scenes, counter), (
am.Event(0, am.Event.swap_scene("wipe")),
# am.Event(1, am.Event.layer_scene("debug_counter")),
am.Event(58, am.Event.swap_scene("clear")),
am.Event(60, am.Event.swap_scene("ocean_b")),
# am.Event(60, am.Event.layer_scene("typewrite")),
*ocean_events,
am.Event(1079, am.Event.swap_scene("clear")),
am.Event(1080, am.Event.swap_scene("beats")),
am.Event(1080, am.Event.layer_scene("title")),
am.Event(1080, am.Event.swap_scene("beats")),
am.Event(1336, am.Event.swap_scene("beats_lr")),
am.Event(1844, am.Event.remove_scene("title")),
am.Event(1848, am.Event.swap_scene("funding")),
am.Event(1848, am.Event.layer_scene("dates")),
am.Event(1848, am.Event.layer_scene("weather")),
am.Event(1848, lambda c: c.set_data(
"history", [], "refresh", True
)),
am.Event(1848, lambda c: c.set_generator_data(
"funding", 0, "text", data_strings["funding_0"]
)),
am.Event(2348, lambda c: c.set_generator_data(
"funding", 0, "text", (('',), ('',))
)),
am.Event(2348, lambda c: c.set_data(
"history", [], "refresh", True
)),
am.Event(2352, lambda c: c.set_generator_data(
"funding", 0, "text", data_strings["funding_1"], "offset", 0, "lineno", 0
)),
am.Event(2976, am.Event.remove_scene("dates")),
am.Event(2976, am.Event.remove_scene("weather")),
am.Event(2976, am.Event.swap_scene("clear_wipe")),
am.Event(3007, am.Event.swap_scene("clear")),
# idk what to do here. some sort of bootup sequence?
am.Event(3132, am.Event.swap_scene("loadingbar")),
am.Event(3132, lambda c: c.set_generator_data(
"loadingbar", 6, "text", data_strings["funding_2"]
)),
am.Event(3376, am.Event.swap_scene("ocean_d")),
am.Event(3380, am.Event.swap_scene("clear")),
am.Event(3380, am.Event.swap_scene("fastload")),
am.Event(3388, am.Event.swap_scene("clear")),
# Crazy part. Go wild
am.Event(3390, am.Event.swap_scene("error")),
am.Event(3390, am.Event.layer_scene("fundingx2")),
am.Event(3390, lambda c: c.set_data(
"history", [], "refresh", True
)),
am.Event(3390, lambda c: c.set_generator_data(
"fundingx2", 0,
"text", data_strings["fundingx2_0"]
)),
am.Event(3390, lambda c: c.set_generator_data(
"fundingx2", 1,
"text", data_strings["fundingx2_1"]
)),
am.Event(3390, lambda c: c.set_generator_data(
"fundingx2", 3,
"text", data_strings["fundingx2_2"]
)),
am.Event(3895, am.Event.remove_scene("fundingx2")),
am.Event(3895, am.Event.swap_scene("clear")),
am.Event(3896, am.Event.swap_scene("ocean_c")),
*ocean2_events,
# remember to clean the ocean_c events up, or it will stay in the screen. At frame 4413.
am.Event(4413, am.Event.swap_scene("clear")),
am.Event(4460, am.Event.swap_scene("accesspoints")),
am.Event(4460, am.Event.layer_scene("fdg_single")),
am.Event(4534, lambda c: c.set_generator_data(
"fdg_single", 1, "text", data_strings["fdg_single_0"]
)),
am.Event(5500, am.Event.remove_scene("fdg_single")),
am.Event(5500, am.Event.swap_scene("clear")),
am.Event(5500, am.Event.swap_scene("beats")),
am.Event(5500, am.Event.layer_scene("fdg_down")),
am.Event(5788, lambda c: c.set_generator_data(
"fdg_down", 0, "text", data_strings["fdg_down_0"]
)),
am.Event(5916, lambda c: c.set_generator_data(
"fdg_down", 0,
"text", data_strings["fdg_down_1"], "lineno", 0, "offset", 0
)),
am.Event(5916, lambda c: c.set_generator_data(
"fdg_down", 1,
"text", data_strings["fdg_down_2"]
)),
am.Event(6270, am.Event.swap_scene("beats_lr")),
am.Event(6508, am.Event.remove_scene("fdg_down")),
# am.Event(6508, am.Event.remove_scene("debug_counter")),
am.Event(6508, am.Event.swap_scene("clear"))
))
# class MixerWrapper:
# def __init__(self):
# self.is_paused = False
#
# def toggle_music(self):
# if self.is_paused:
# pygame.mixer.music.unpause()
# self.is_paused = False
# else:
# pygame.mixer.music.pause()
# self.is_paused = True
#
#
# ffwing = MixerWrapper()
paused_this_frame = False
ff_this_frame = False
filename = "media/credits.wav"
playback = Playback()
playback.load_file(filename)
# Clear the console before showing the skip menu
if os.name == "nt":
os.system("cls")
elif os.name == "posix":
os.system("clear")
else:
print("\033[2J")
print("\033[1;1Hskips\n\n1 | start\n2 | title\n3 | funding\n4 | loading\n5 | break\n6 | final")
# Skips forward to the title scene
key_states = {
'1': False,
'2': False,
'3': False,
'4': False,
'5': False,
'6': False,
'p': False,
',': False,
'.': False,
'/': False
}
def on_press(key):
try:
if key.char in key_states:
key_states[key.char] = True
except AttributeError:
pass
def on_release(key):
try:
if key.char in key_states:
key_states[key.char] = False
except AttributeError:
pass
listener = keyboard.Listener(on_press=on_press, on_release=on_release)
listener.start()
time_menu = time.time()
while time.time() - 2 < time_menu:
if key_states['1']:
time_menu = 99999999999999999999
break
elif key_states['2']:
skip_beats(controller, 1000, 1081)
time_menu = 99999999999999999999
break
elif key_states['3']:
skip_beats(controller, 1770, 1851)
controller.events[1849] = am.Event(1849, am.Event.layer_scene("redraw_ui")),
controller.events[1860] = am.Event(1860, am.Event.remove_scene("redraw_ui")),
time_menu = 99999999999999999999
break
elif key_states['4']:
skip_beats(controller, 3040, 3133)
time_menu = 99999999999999999999
break
elif key_states['5']:
skip_beats(controller, 3780, 3898)
time_menu = 99999999999999999999
break
elif key_states['6']:
skip_beats(controller, 5420, 5501)
time_menu = 99999999999999999999
break
time.sleep(0.01)
if os.name == "nt":
os.system("cls")
elif os.name == "posix":
os.system("clear")
else:
print("\033[2J")
# wave_obj = sa.WaveObject.from_wave_file(filename)
# play_obj = wave_obj.play()
playback.play()
playback.seek(skip_by)
time_start = time.time()
last_update = time.time()
prev_pos = 0
while playback.active:
# (17.06.21) might have broken, i used a -1 beat offset here to try and sync up everything better
# since i originally used 1-indexed beats
#
# (24.06.21) update chat it didnt break
# next_beat = (time.time() - time_start - offset) > ((beat - 1) * delay)
next_beat = (playback.curr_pos - offset) > ((beat - 1) * delay)
need_update = time.time() - (1/30) > last_update
# print(pygame.mixer.music.get_pos())
if next_beat:
controller.request_next()
canvas.render_all()
last_frames.append(time.time())
if len(last_frames) > 10:
last_frames.pop(0)
beat += 1
if need_update:
if key_states['p']:
if not paused_this_frame:
if playback.paused:
playback.resume()
else:
playback.pause()
paused_this_frame = True
else:
paused_this_frame = False
if key_states[',']:
if not ff_this_frame:
ff_this_frame = True
else:
playback.seek(playback.curr_pos + delay * 3)
if key_states['.']:
if not ff_this_frame:
ff_this_frame = True
else:
playback.seek(playback.curr_pos + delay * 7)
if key_states['/']:
if not ff_this_frame:
ff_this_frame = True
else:
playback.seek(playback.curr_pos + delay * 15)
# else:
# # print("n", ff_this_frame, pygame.mixer.music.get_pos() + prev_pos, prev_pos)
# if ff_this_frame:
# # print("unpausing now")
# ff_this_frame = False
# ffwing.toggle_music()
last_update = time.time()
# Add a final clear at the end to prevent the last frame from sticking around when the program ends.
if os.name == "nt":
os.system("cls")
elif os.name == "posix":
os.system("clear")
else:
print("\033[2J")
================================================
FILE: media/README.txt
================================================
I can't really distribute a full .wav file of an entire song that I don't own the rights to.
That would be disrespectful.
If you want to run this on your own device, you'll need to find yourself a copy of
Frums 「Credits LONG」
for yourself.
Sorry.
-----------
If you do find a copy, convert it to "credits.wav" and drop it in this /media folder.
================================================
FILE: media/credits.txt
================================================
Now for the official national weather service forecast for Eastern Massachusets inside of I-495,
including Boston, issued at 7:21 PM, Thursday, October 22nd.
Tonight: Mostly cloudy with isolated showers until midight,
then mostly clear after midnight.
Lows in the lower 40s.
West winds 10-15 mph with gusts up to 25 mph.
Chance of rain: 20 percent.
Friday: Sunny. Lush colour with highs in the lower 50s.
Northwest winds 10-15mph with gusts up to 25mph.
Friday night, mostly clear.
Lows in the mid-30s.
North winds 10-15mph.
Saturday: Partly sunny.
High-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh-igh...
22.10.2009: Cloudy, precip 20%, temp 43, wind dir 6, 13 (25)
23.10.2009: Sunny, precip 4%, temp 52, wind dir 7, 12 (25)
24.10.2009: Partly sunny, precip 7%, temp 48, wind dir 1, 8 (20)
25.10.2009 and beyond: randomly mutate value.
Prefer 33% precip, move wind dir by +-3 each day, gust = speed x 2.1 - 2.6
Funding for this program was made possible by by by by by
Fun-by-by-by-by-ding by-by-by-by-for thiiiii
Program. Program. Pro-pro-pro-pro-pro-gram.
Funding for-by-by-made possible by viewers like you.
like you. like you. like you. like you. like you. like you
...
...
Annual financial suppor-
Annual financial suppor-
Annual financial suppor-
Annual financial suppor-
Annual financial suppor-
Annual financial suppor-
Annual financial suppor-
Annual financial suppor-
Annu- Annu- Th-th-th-thank you.
By-ci-po-po-cor-cor-by-by-rrrrrrroooooaaaaaa-
-wers-ble-b-b-F-f-fi-i-naaaaaaaa-
Fun-funding, fu-fun-fu-fun-funding
Fu-fu-fun-funding, fu-fun-fu-funding
F-i-n-a-n--po-po-cor-by-por-portio-portio-portion-nnn
B-b-b-by b-by b-by b-by
>>>>>
By-by-finan-b-b-nc-nc-
Corrrrrr
Viewers like you. like you. like you.
Funding-Funding-Fun-fu-funding
Fu-fu-fu-fu-Fu-fu-fu-fu-
Corporationnnn
The corportation for public broadcasting and bi-annual fiii-
of-nan-for-financial su-for financial asssss-
in-viewers-you-
This is PBS.
...
...
Here are the 7 PM observations for the Boston metropolitan area.
At Logan Airport, it was cloudy.
The temperature as 68 degrees.
The dew point, 47 -
and the relative humidity, 46 percent.
The wind was southwest at 13 miles an hour.
The pressure was 29.99 inches and rising.
Elsewherrrrrrrrrrrrr
...
...
Funding for this program was made possible by viewers...
================================================
FILE: ocean.py
================================================
# adapted from the-sea.js by plaao (me)
# The ocean is stored as a list of strings which is combined into one string when rendered.
# It is rendered internally in 40x8 resolution.
import math
import random
ocean_time = math.floor(random.random() * 2000)
alphabet = "abcdefghijklmnopqrstuvwxyz"
def init_populate_ocean():
global ocean_time
# Create 12 lists of 80 chars each and get an ocean slice for every ocean time value needed.
ocean_base = get_ocean_slices(ocean_time, ocean_time + 80)
ocean_time += 80
return ocean_base
def get_ocean_slice(xr, glitch):
x = xr / 5
c = math.cos(0.2 * x) + math.sin(0.3 * x) * math.sin(0.23 * x)
y = -math.floor(2 * c * math.sin(x)) + 3
# Returns a list of chars which can then be populated into the ocean.
cont_list = []
for i in range(10):
if random.random() <= 0.002 * glitch:
cont_list.append(alphabet[math.floor(random.random() * len(alphabet))])
else:
if i == y:
cont_list.append("#")
elif i > y:
cont_list.append(".")
else:
cont_list.append(" ")
return cont_list
def mutate_text(txt, glitch):
for i in range(len(txt)):
ch = txt[i]
if ch in "#. " and random.random() <= (0.0002 + ((ocean_time % 1200) / 1200000)) * glitch:
txt = txt[:i] + alphabet[math.floor(random.random() * len(alphabet))] + txt[i + 1:]
return txt
def get_ocean_slices(x1, x2):
cont_list = [
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
]
for xr in range(x1, x2):
x = xr / 5
c = math.cos(0.2 * x) + math.sin(0.3 * x) * math.sin(0.23 * x)
y = -math.floor(2 * c * math.sin(x)) + 3
# Returns a list of chars which can then be populated into the ocean.
for i in range(10):
if random.random() <= 0.002:
cont_list[i] += alphabet[math.floor(random.random() * len(alphabet))]
else:
if i == y:
cont_list[i] += "#"
elif i > y:
cont_list[i] += "."
else:
cont_list[i] += " "
return cont_list
def update_ocean_slices(ocean_content, ocean_glitch):
global ocean_time
# edits in place
# get the new slice
ocean_slice = get_ocean_slice(ocean_time, ocean_glitch)
ocean_time += 1
# for every line in content, remove the first char and add the slice char
for i in range(10):
ocean_content[i] = ocean_content[i][1:] + ocean_slice[i]
raw_txt = unpack_content_to_text(ocean_content)
return mutate_text(raw_txt, ocean_glitch)
def unpack_content_to_text(content):
# Join every line with \n
return "".join(line for line in content)
def begin_ocean():
return init_populate_ocean()
================================================
FILE: requirements.txt
================================================
just_playback
pynput; sys_platform == "darwin"
keyboard; sys_platform != "darwin"
================================================
FILE: string_defs.py
================================================
# Contains strings used inside credits.py.
# Kept inside this file to reduce clutter.
# Implemented as a dictionary of in-memory strings.
from animation_functions import split_word_template, fuck_up_text, work_out_date
data_strings = {}
data_strings["ocean_b_0"] = (
"Now for the official national~ weather~ service~ forecast\n"
"~~~~for~~ Eastern Massachusetts~ inside of~~ I-~~~~4~~~~9~~~~~~~5~~,\n"
"~~~~~~~~ including Boston,\n\n"
"~~~~~~~~issued at 7~~~~:2~~1~~~~ PM~~~~, ~~~~~~~~~~~~~~Thursday, October~~ 2~~2~~nd."
)
data_strings["ocean_b_1"] = (
"Tonight:\n\n~~~~~Mostly cloudy with isolated~ showers~ until~~ mid~~~~night,\n"
"~~~~~~~~~then mostly clear~~ after~~ mid~night.\n"
"~~~~~~~~~Lows in the lower 4~~~~0~~~~s.\n"
"~~~~~~~~~West winds 10~ to~~ 1~~5~~ miles~~ an~~ hour\n"
"~~~~~with~ gusts~~ up~ to~ 2~~~~5~~~~ miles~~ an~~ hour~~.\n"
"~~~~~~~~~~Chance of rain:~~~~ 2~~0~~~~ per~cent."
)
data_strings["ocean_b_2"] = (
"Friday:\n\n~~Sunny.\n~~~~~~~~~~~~~~~~Lush colour with highs in the low~er 5~~~0~s.\n"
"~~~~~~~~~~Northwest~~ winds~~ 10~~-~1~~5~~ miles~~ an~~ hour\n"
"~~~~with gusts up to~~ 2~~~~5~~~~ miles~~ an~~ hour~~.\n"
"~~~~~~~~~~~~~~~~Friday night,~~ mostly~ clear.\n"
"~~~~~~~~~~~~~~Lows in the mid-3~~~~0~~s.\n"
"~~~~~~~~~~~~~~~~North winds 10-1~~~5~~ miles~~ an~~ hour~~."
)
data_strings["ocean_b_3"] = (
"Saturday:\n\n~~~~~~~~Partly sunny.\n"
"~~~~~~~~High-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-@igh-i"
)
data_strings["ocean_c_0"] = (
"Here~ are~ the 7~~~~ P~~~~M~~~~ ob~ser~va~tions for~~ the\n"
"~~~Bos~ton~~ metro~po~li~tan~~~ ar~ea.\n\n"
"~~~~~~~~~~~~~~~At Logan~~~~ Airport,~~~~~~ it was clou~~~~dy.\n"
"~~~~~~~~~~~~~~~The tem~per~a~ture was 6~~~~8~~~~ de~grees,\n"
"~~~~~~~~the dew point,~~ 4~~~~7~~ -\n"
"~~~~~~and~ the~ re~la~tive~~ hu~mi~di~ty,~~~~ 4~~~~6~~~~ per~~cent.\n"
"~~~~~~~~~~~~~~~~The~ wind~ was~ south~~west~ at 1~~~~3~ miles~~~~ an~~~~ ho~ur.\n"
"~~~~~~~~~~~~The~ pres~~sure~~ was~~ 2~~~~9~~~~.~~~~~~~~9~~~~~~9~~~~~~ in~ches and ri~sing.\n"
"~~~~~~~~Elsewher" + fuck_up_text(
"rrrrrrrrr\n", 800
)
)
data_strings["ocean_c_1"] = (
fuck_up_text(
"Here~ are~ the 7~~~~ P~~~~M~~~~ ob~ser~va~tions for~~ the\n"
"~~~Bos~ton~~ metro~po~li~tan~~~ ar~ea.\n\n"
"~~~~~~~~~~~~~~~At Logan~~~~ Airport,~~~~~~ it was clou~~~~dy.\n"
"~~~~~~~~~~~~~~~The tem~per~a~ture was 6~~~~8~~~~ de~grees,\n"
"~~~~~~~~the dew point,~~ 4~~~~7~~ -\n"
"~~~~~~and~ the~ re~la~tive~~ hu~mi~di~ty,~~~~ 4~~~~6~~~~ per~~cent.\n"
"~~~~~~~~~~~~~~~~The~ wind~ was~ south~~west~ at 1~~~~3~ miles~~~~ an~~~~ ho~ur.\n"
"~~~~~~~~~~~~The~ pres~~sure~~ was~~ 2~~~~9~~~~.~~~~~~~~9~~~~~~9~~~~~~ in~ches and ri~sing.\n"
"~~~~~~~~Elsewher", 100
) + fuck_up_text(
"rrrrrrrrr\n", 900
)
)
data_strings["ocean_c_2"] = (
fuck_up_text(
"Here~ are~ the 7~~~~ P~~~~M~~~~ ob~ser~va~tions for~~ the\n"
"~~~Bos~ton~~ metro~po~li~tan~~~ ar~ea.\n\n"
"~~~~~~~~~~~~~~~At Logan~~~~ Airport,~~~~~~ it was clou~~~~dy.\n"
"~~~~~~~~~~~~~~~The tem~per~a~ture was 6~~~~8~~~~ de~grees,\n"
"~~~~~~~~the dew point,~~ 4~~~~7~~ -\n"
"~~~~~~and~ the~ re~la~tive~~ hu~mi~di~ty,~~~~ 4~~~~6~~~~ per~~cent.\n"
"~~~~~~~~~~~~~~~~The~ wind~ was~ south~~west~ at 1~~~~3~ miles~~~~ an~~~~ ho~ur.\n"
"~~~~~~~~~~~~The~ pres~~sure~~ was~~ 2~~~~9~~~~.~~~~~~~~9~~~~~~9~~~~~~ in~ches and ri~sing.\n"
"~~~~~~~~Elsewher", 200
) + fuck_up_text(
"rrrrrrrrr\n", 1000
)
)
data_strings["ocean_c_3"] = (
fuck_up_text(
"Here~ are~ the 7~~~~ P~~~~M~~~~ ob~ser~va~tions for~~ the\n"
"~~~Bos~ton~~ metro~po~li~tan~~~ ar~ea.\n\n"
"~~~~~~~~~~~~~~~At Logan~~~~ Airport,~~~~~~ it was clou~~~~dy.\n"
"~~~~~~~~~~~~~~~The tem~per~a~ture was 6~~~~8~~~~ de~grees,\n"
"~~~~~~~~the dew point,~~ 4~~~~7~~ -\n"
"~~~~~~and~ the~ re~la~tive~~ hu~mi~di~ty,~~~~ 4~~~~6~~~~ per~~cent.\n"
"~~~~~~~~~~~~~~~~The~ wind~ was~ south~~west~ at 1~~~~3~ miles~~~~ an~~~~ ho~ur.\n"
"~~~~~~~~~~~~The~ pres~~sure~~ was~~ 2~~~~9~~~~.~~~~~~~~9~~~~~~9~~~~~~ in~ches and ri~sing.\n"
"~~~~~~~~Elsewher", 250
) + fuck_up_text(
"rrrrrrrrr\n", 1000
)
)
data_strings["funding_0"] = (
split_word_template(
"Fun####ding#### for#### this#### pro####gram#### was#### made#### pos####si####ble###~\n"
" by###\n"
" by###\n"
" by###\n"
" by###\n"
" by#\n"
"Fun#\n"
" by\n"
" by\n"
" by\n"
" by\n"
"Funding#\n"
" by\n"
" by\n"
" by\n"
" by\n"
"Funding for\n"
"Funding for thi#i#i#i#i#\n"
"Funding for this pro####gram###\n"
"Funding for this pro####gram###\n"
" pro\n"
" pro\n"
" pro\n"
"Funding for this pro#gram.#~\n"
"Fun####ding#### for#\n"
" by#\n"
" by#\n"
"Funding made#### pos####si####ble#### by#### view####ers#### like#### you.###~\n"
"####like#### you.##\n"
"####like#### you.##\n"
"####like#### you.##\n"
"####like#### you.##\n"
"####like#### you.##\n"
"####like#### you.\n"
" Fu\n"
" Fu\n"
) * 2
)
data_strings["funding_1"] = (
split_word_template(
"Broad####cast####\n"
"Broadcast Cor####por##a####tion.~#####\n"
"Cor####po##ra####tion.#####\n"
"Cor####po##ra####tion.#####\n"
" Cor###po\n"
" Cor###po\n"
" Co\n"
" Co\n"
"Cor####po##ra####tion.#####\n"
"Cor####po##ra####tion.#####\n"
"Cor####po##ra####tion.#####\n"
" Cor###po\n"
" Cor###po\n"
" Co\n"
" Co\n"
"Cor####po##ra###tion.#\n"
" Co\n"
" Co\n"
"Cor####po##ra###tion.#\n"
" Co\n"
" Co\n"
"Cor####po##ra###tion.#\n"
" Co\n"
" Co\n"
"Cor####po##ra###tion.#\n"
" Co\n"
" Co\n"
"Cor####po##ra###tion.#\n"
" Co\n"
" Co\n"
"Cor####po##ra###tion.#\n"
" Co\n"
" Co\n"
" Cor###po\n"
" Cor###po\n"
" Cor###po\n"
" Cor###po\n"
"...#######\n"
" Cor###po#\n"
" cor##\n"
" cor###po#\n"
" cor###po#\n"
" cor##\n"
" cor###po#\n"
" cor###po#\n"
" cor##\n"
" cor###po#\n"
" cor##\n"
" cor##\n"
" cor##\n"
" co#\n"
" co#\n"
" cor###po#\n"
" cor##\n"
" cor###po#\n"
" cor###po#\n"
" cor##\n"
" cor##\n"
" cor###po#\n" + fuck_up_text(
" cor###po#\n"
" cor#\n"
" cor###po#\n"
" cor#\n"
" cor#\n", 100, "# "
) + " ...#\n" + fuck_up_text(
" co#\n"
" co#\n"
" cor###po#\n"
" cor##\n"
" cor###po#\n"
" cor###po#\n"
" cor##\n"
" cor###po#\n", 280, "# "
) + fuck_up_text(
" cor###po#\n"
" cor##\n"
" cor###po#\n"
" cor#\n"
" cor#\n"
" cor#\n", 500, "# "
) + fuck_up_text(
" co#\n"
" co#\n"
" cor###po#\n"
" cor#\n"
" cor###po#\n"
" cor###po#\n"
" cor#\n"
" cor###po#\n", 650, "# "
) +
" ???###p?#\n"
" ??r#\n"
" ???###??#\n"
" co?#\n"
" ???#\n"
"....#....#....#....#....#....#....#....#...#...#...#...#..#..\n"
" <##C##O##N##N##E##C##T##I##O##N## ##L##O##S##T##>"
"##########################################################################################################"
"##########################################################################################################"
"##########################################################################################################"
"##########################################################################################################"
)
)
data_strings["funding_2"] = (
split_word_template(
"--####--####-- ####-i####-a-####---- ####-up####-o-#\n" +
"-n####nu####-l ####fi####nan####cial ####sup####por#\n" +
"An####nu####al ####fi####nan####cial ####sup####por#\n" * 5 +
"An####nu###\nAn####nu###\n"
)
)
data_strings["fundingx2_0"] = (
split_word_template(
" By\n"
" ci\n"
" po\n"
" po\n"
" cor#\n"
" cor#\n"
" by#\n"
" by#\n"
"rr#rr#rr#ro#oo#oo#aa#aa#aa#\n##"
" wers#\n"
" ble#\n"
" b\n"
" b\n"
" F#\n"
" f\n"
" fi\n"
" i\n"
"na#aa#aa#aa#aa#aa#aa#aa#\n"
" Fun\n"
"Fun####ding#\n"
" Fu#\n"
" Fun#\n"
" fu#\n"
"Fun####ding#\n"
" Fu#\n"
" Fun#\n"
" fu#\n"
"Fun####ding#\n"
" Fu#\n"
" Fun#\n"
" fu#\n"
"Fun####ding#\n"
"F\n"
" Fi\n"
" Fin\n"
" Fina\n"
" Finan\n"
"po\n"
"po\n"
"cor#\n"
"by#\n"
" por\n"
"Por#tio##\n"
"Por#tio##\n"
"Por#tion# nn#nn#nn\n"
"b\n"
" b\n"
"by###\n"
"---- by###\n"
"-------- by###\n"
"------------ by###\n"
"---------------- by#######\n"
">>#>>###\n"
"By#\n"
" by#\n"
"fi#nan#\n"
" b#\n"
" b#\n"
" nc#\n"
" nc#\n"
"Corr#rr#rr#\n"
"View####ers#### like#### you.#\n"
" like#### you.#\n"
" like## you.#\n"
"Fun####ding###\n"
"Fun####ding###\n"
" Fun###\n"
" Fu#\n"
"Fun####ding###\n"
" fu#\n"
" fu#\n"
" fu#\n"
" fu#\n"
" fu#\n"
"Cor####por####a####tion\n"
"The#### cor####por####a####tion#### for#### pub####lic####"
" broad####cast####ing#### and#### bi####-an####nual#### fii#ii#i\n"
"of#\n"
"nan#\n"
"for#\n"
"fin####an####cial#### su#\n"
"for#### fin####an####cial#### ass#ss#ss\n"
"in#\n"
"view####ers###\n"
"you#####\n"
"| ########This######## is######## P####B####S!############~\n"
)
)
data_strings["fundingx2_1"] = (
split_word_template("\n".join(
"{}#### Unknown###".format(
work_out_date((64 * 3390) + i * 64)).replace(".", ".####") for i in range(26)
) + "\n| ########This######## is######## P####B####S!############~\n")
)
data_strings["fundingx2_2"] = (
split_word_template(
"S#e#a#r#c#h#i#n#g# #f#o#r# #a#c#c#e#s##s## ##p##o##i##n##t"
"########.########.########.########\n" +
"Searching for access point########.########.########.########\n" * 11 +
"Found:################"
" P#B#S# #O#f#f#i#c#i#a#l# #1#1#.#### #R#e#s#t#a#r#t#i#n#g#.####.####.####"
)
)
data_strings["fdg_single_0"] = (
split_word_template(
"########.########.########.########.########.########.########.#######\n"
"########.########.########.########.########.########.########.#######\n"
"########.########.########.########.########.########.########.#######\n"
"########.########.########.########.########.########.########.#######\n"
"########.########.########.########.########.########.########.#######\n"
"########.########.########.########.########.########.########.#######\n"
"Fun####ding#### for#### this#### pro####gram#### was#### made#### pos####sible#\n"
" 7 > > > by###\n"
" 7 > > > > by###\n"
" 8 > > > by###\n"
" 8 > > > > by###\n"
" 9 > > > by###\n"
"Fun##\n"
" by\n"
" by\n"
" by\n"
" by\n"
"Funding#\n"
" by\n"
" by\n"
" by\n"
" by\n"
"for\n"
"thi#i#i#i\n"
"Pro####gram.#\n"
"Pro####gram.#\n"
"Pro\n"
" pro\n"
" pro\n"
" pro\n"
"Pro####gram.###\n"
"Fun####ding#### for####\n"
" by#\n"
" by#\n"
"Funding for made#### pos####sible#### by#### view####ers#### like#### you.###\n"
"like#### you.#####\n"
"##like#### you.#####\n"
"##like#### you.#####\n"
"##like#### you.#####\n"
"##like#### you.#####\n"
"##like#### you.###\n"
"Fu\n"
" Fu\n"
"Fun####ding#### for#### this#### pro####gram#### was#### made#### pos####sible#### by#\n"
" by###\n"
" by###\n"
" by###\n"
" by#\n"
"Fun###\n"
" by\n"
" by\n"
" by\n"
" by\n"
"Funding#\n"
" by\n"
" by\n"
" by\n"
" by\n"
"for\n"
"thi#i#i#i\n"
"Pro####gram.###\n"
"Pro####gram.###\n"
"Pro\n"
" pro\n"
" pro\n"
" pro\n"
"Pro####gram.#\n"
"Fun####ding#### for####\n"
" by#\n"
" by#\n"
"Funding for made#### pos####sible#### by#### view####ers#### like#### you.###\n"
"like#### you.#####\n"
"##like#### you.#####\n"
"##like#### you.#####\n"
"##like#### you.#####\n"
"##like#### you.#####\n"
"####< RET 200################################################################\n"
)
)
data_strings["fdg_down_0"] = (
split_word_template(
"Fun####ding#### for#### this#### pro####gram#### was#\n"
"made#### made#### made#### made#### made#### made#### made#### made#### made###\n"
"pos####sible#### by#### view####ers#### like#### you.#######"
)
)
data_strings["fdg_down_1"] = (
split_word_template(
"---####----#### ---#### ----#### ---####----#### ---#\n"
"----#### ----#### ----#### ----#### ----#### ----#### ----#### ----#### ----###\n"
"---####-----#### --#### ----####---###### ----######## -##-##-##.#######"
)
)
data_strings["fdg_down_2"] = (
split_word_template(
"Fun####ding#### for#### this#### pro####gram#### was#\n"
"made#### made#### made#### made#### made#### made#### made#### made#### made###\n"
"pos####sible#### by#### view####ers###### like######## y##o##u##.#######"
)
)
gitextract_b3wq7xz6/ ├── .gitattributes ├── .gitignore ├── CLIRender/ │ ├── classes.py │ └── dat.py ├── README.md ├── animation_classes.py ├── animation_functions.py ├── animation_scenes.py ├── animator.py ├── colorama/ │ ├── __init__.py │ ├── ansi.py │ ├── ansitowin32.py │ ├── initialise.py │ ├── win32.py │ └── winterm.py ├── credits.py ├── credits_pynput.py ├── media/ │ ├── README.txt │ └── credits.txt ├── ocean.py ├── requirements.txt └── string_defs.py
SYMBOL INDEX (179 symbols across 13 files)
FILE: CLIRender/classes.py
class RenderSection (line 8) | class RenderSection:
method __init__ (line 11) | def __init__(self, string, start, code):
method __lt__ (line 21) | def __lt__(self, other):
method __gt__ (line 24) | def __gt__(self, other):
method add_char (line 27) | def add_char(self, char):
method mod_char (line 32) | def mod_char(self, char, loc):
method add_section (line 40) | def add_section(self, other):
method add_section_below (line 49) | def add_section_below(self, other):
method subtract_char (line 57) | def subtract_char(self, loc):
method subtract_section (line 71) | def subtract_section(self, other):
class Canvas (line 87) | class Canvas:
method __init__ (line 91) | def __init__(self, dimensions, num_layers, merge_rules):
method set_char (line 98) | def set_char(self, layer, location, char, code):
method set_string (line 102) | def set_string(self, layer, location, string, code):
method clear_layer (line 106) | def clear_layer(self, layer):
method render_blank (line 109) | def render_blank(self):
method render_all (line 112) | def render_all(self):
class Layer (line 148) | class Layer:
method __init__ (line 149) | def __init__(self, layer_id, dimensions):
method set_char (line 158) | def set_char(self, loc, char, code):
method has_duplicate_starts (line 207) | def has_duplicate_starts(self):
method set_string (line 217) | def set_string(self, loc, string, code):
function enable_ansi (line 287) | def enable_ansi():
FILE: CLIRender/dat.py
class Vector2 (line 6) | class Vector2: # to be honest this is me showing off
method __init__ (line 7) | def __init__(self, x, y):
method __str__ (line 11) | def __str__(self): # returns a formatted string for the vector2
method __add__ (line 14) | def __add__(self, other): # allows adding of vector2s, and ints
method __mul__ (line 22) | def __mul__(self, other): # multiplies a vector2 by an int, or by ano...
method __truediv__ (line 30) | def __truediv__(self, other): # returns a FLOAT value (true div)
method __floordiv__ (line 38) | def __floordiv__(self, other): # returns an INT value (floor div)
method __pos__ (line 46) | def __pos__(self):
method __neg__ (line 49) | def __neg__(self):
method __eq__ (line 52) | def __eq__(self, other):
method Magnitude (line 55) | def Magnitude(self): # returns the magnitude of the vector2. (length ...
class Vector3 (line 59) | class Vector3: # to be honest this is me showing off
method __init__ (line 60) | def __init__(self, x, y, z):
method __str__ (line 65) | def __str__(self): # returns a formatted string for the Vector3
method __add__ (line 68) | def __add__(self, other): # allows adding of Vector3s, and ints
method __mul__ (line 76) | def __mul__(self, other): # multiplies a Vector3 by an int, or by ano...
method __truediv__ (line 84) | def __truediv__(self, other): # returns a FLOAT value (true div)
method __floordiv__ (line 92) | def __floordiv__(self, other): # returns an INT value (floor div)
method __pos__ (line 100) | def __pos__(self):
method __neg__ (line 103) | def __neg__(self):
method __eq__ (line 106) | def __eq__(self, other):
method Magnitude (line 109) | def Magnitude(self): # returns the magnitude of the Vector3. (length ...
FILE: animation_classes.py
class Weather (line 6) | class Weather:
method __init__ (line 7) | def __init__(self, precip, temp, wind, gust, wind_dir, humidity, days=2):
method __str__ (line 17) | def __str__(self):
method get_weather_name (line 34) | def get_weather_name(self):
method mutate (line 62) | def mutate(self, steps=1):
FILE: animation_functions.py
function generate_random_hex (line 8) | def generate_random_hex(length):
function replace_text_with_spaces (line 12) | def replace_text_with_spaces(string, chance):
function render_weather (line 16) | def render_weather(c, layer, x, y, weather, mutations_after=0, spc_chanc...
function noise (line 60) | def noise(c, layer, amount, chars, colours):
function set_multiline_string (line 68) | def set_multiline_string(c, layer, x, y, string, col):
function type_text (line 75) | def type_text(c, generator, layer, x, y, col, render=True):
function fuck_up_text (line 112) | def fuck_up_text(string, chance, also_ignore=""):
function debug_info (line 129) | def debug_info(c, g, b, frames):
function clear (line 183) | def clear(c, layer):
function beat_toggle (line 187) | def beat_toggle(c, g, layer, x, x2, y, y2, char, col):
function work_out_date (line 199) | def work_out_date(b, day_offset=0):
function split_word_template (line 227) | def split_word_template(string):
function typewrite_by_word (line 231) | def typewrite_by_word(c, generator, layer, x, y, col, render=True, histo...
function write_history (line 298) | def write_history(c, generator, layer, x, y, col, stop, var="history"):
function show_access_point_visual (line 324) | def show_access_point_visual(c, generator, layer, x, y):
function make_poweroff_bars (line 356) | def make_poweroff_bars(c, b, layer, col):
FILE: animator.py
class DataStoringObject (line 1) | class DataStoringObject:
method __init__ (line 2) | def __init__(self):
method set_data (line 5) | def set_data(self, *ident):
method get_data (line 9) | def get_data(self, ident):
method oper_data (line 13) | def oper_data(self, ident, oper):
class SceneManager (line 17) | class SceneManager(DataStoringObject):
method __init__ (line 18) | def __init__(self, scenes, events):
method start_scene (line 31) | def start_scene(self, scene, at=0):
method add_scene (line 38) | def add_scene(self, scene, at=0):
method remove_scene (line 42) | def remove_scene(self, scene):
method request_next (line 46) | def request_next(self, render=True):
method next_beat (line 52) | def next_beat(self):
method set_scene_data (line 58) | def set_scene_data(self, scene, *ident):
method set_generator_data (line 61) | def set_generator_data(self, scene, generator, *ident):
class Event (line 65) | class Event:
method __init__ (line 66) | def __init__(self, beat, do):
method swap_scene (line 71) | def swap_scene(sc, at=0):
method layer_scene (line 75) | def layer_scene(sc, at=0):
method remove_scene (line 79) | def remove_scene(sc):
class Scene (line 83) | class Scene(DataStoringObject):
method __init__ (line 84) | def __init__(self, name, generators):
method set_parent (line 93) | def set_parent(self, parent):
method request_frame (line 97) | def request_frame(self, render=True):
method start (line 112) | def start(self, at):
class Generator (line 123) | class Generator(DataStoringObject):
method __init__ (line 124) | def __init__(self, start_beat, condition, on_create, request, request_...
method set_parent (line 137) | def set_parent(self, parent):
method set_scene (line 140) | def set_scene(self, scene):
method combine_conditions (line 144) | def combine_conditions(*cond):
method always (line 148) | def always():
method every_n_beats (line 152) | def every_n_beats(beat):
method every_on_off (line 156) | def every_on_off(on, off):
method every_off_on (line 160) | def every_off_on(off, on):
method before_n (line 164) | def before_n(beat):
method at_beat (line 168) | def at_beat(beat):
method no_create (line 172) | def no_create():
method no_request (line 176) | def no_request():
FILE: colorama/ansi.py
function code_to_chars (line 12) | def code_to_chars(code):
function set_title (line 15) | def set_title(title):
function clear_screen (line 18) | def clear_screen(mode=2):
function clear_line (line 21) | def clear_line(mode=2):
class AnsiCodes (line 25) | class AnsiCodes(object):
method __init__ (line 26) | def __init__(self):
class AnsiCursor (line 36) | class AnsiCursor(object):
method UP (line 37) | def UP(self, n=1):
method DOWN (line 39) | def DOWN(self, n=1):
method FORWARD (line 41) | def FORWARD(self, n=1):
method BACK (line 43) | def BACK(self, n=1):
method POS (line 45) | def POS(self, x=1, y=1):
class AnsiFore (line 49) | class AnsiFore(AnsiCodes):
class AnsiBack (line 71) | class AnsiBack(AnsiCodes):
class AnsiStyle (line 93) | class AnsiStyle(AnsiCodes):
FILE: colorama/ansitowin32.py
function is_stream_closed (line 16) | def is_stream_closed(stream):
function is_a_tty (line 20) | def is_a_tty(stream):
class StreamWrapper (line 24) | class StreamWrapper(object):
method __init__ (line 30) | def __init__(self, wrapped, converter):
method __getattr__ (line 36) | def __getattr__(self, name):
method write (line 39) | def write(self, text):
class AnsiToWin32 (line 43) | class AnsiToWin32(object):
method __init__ (line 52) | def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
method should_wrap (line 85) | def should_wrap(self):
method get_win32_calls (line 95) | def get_win32_calls(self):
method write (line 139) | def write(self, text):
method reset_all (line 149) | def reset_all(self):
method write_and_convert (line 156) | def write_and_convert(self, text):
method write_plain_text (line 172) | def write_plain_text(self, text, start, end):
method convert_ansi (line 178) | def convert_ansi(self, paramstring, command):
method extract_params (line 184) | def extract_params(self, command, paramstring):
method call_win32 (line 202) | def call_win32(self, command, params):
method convert_osc (line 224) | def convert_osc(self, text):
FILE: colorama/initialise.py
function reset_all (line 18) | def reset_all():
function init (line 23) | def init(autoreset=False, convert=None, strip=None, wrap=True):
function deinit (line 51) | def deinit():
function colorama_text (line 59) | def colorama_text(*args, **kwargs):
function reinit (line 67) | def reinit():
function wrap_stream (line 74) | def wrap_stream(stream, convert, strip, autoreset, wrap):
FILE: colorama/win32.py
class CONSOLE_SCREEN_BUFFER_INFO (line 21) | class CONSOLE_SCREEN_BUFFER_INFO(Structure):
method __str__ (line 30) | def __str__(self):
function winapi_test (line 97) | def winapi_test():
function GetConsoleScreenBufferInfo (line 104) | def GetConsoleScreenBufferInfo(stream_id=STDOUT):
function SetConsoleTextAttribute (line 111) | def SetConsoleTextAttribute(stream_id, attrs):
function SetConsoleCursorPosition (line 115) | def SetConsoleCursorPosition(stream_id, position, adjust=True):
function FillConsoleOutputCharacter (line 133) | def FillConsoleOutputCharacter(stream_id, char, length, start):
function FillConsoleOutputAttribute (line 143) | def FillConsoleOutputAttribute(stream_id, attr, length, start):
function SetConsoleTitle (line 153) | def SetConsoleTitle(title):
FILE: colorama/winterm.py
class WinColor (line 6) | class WinColor(object):
class WinStyle (line 17) | class WinStyle(object):
class WinTerm (line 22) | class WinTerm(object):
method __init__ (line 24) | def __init__(self):
method get_attrs (line 36) | def get_attrs(self):
method set_attrs (line 39) | def set_attrs(self, value):
method reset_all (line 44) | def reset_all(self, on_stderr=None):
method fore (line 48) | def fore(self, fore=None, light=False, on_stderr=False):
method back (line 59) | def back(self, back=None, light=False, on_stderr=False):
method style (line 70) | def style(self, style=None, on_stderr=False):
method set_console (line 76) | def set_console(self, attrs=None, on_stderr=False):
method get_position (line 84) | def get_position(self, handle):
method set_cursor_position (line 92) | def set_cursor_position(self, position=None, on_stderr=False):
method cursor_adjust (line 102) | def cursor_adjust(self, x, y, on_stderr=False):
method erase_screen (line 110) | def erase_screen(self, mode=0, on_stderr=False):
method erase_line (line 139) | def erase_line(self, mode=0, on_stderr=False):
method set_title (line 161) | def set_title(self, title):
FILE: credits.py
function skip_beats (line 28) | def skip_beats(ctr, amount, next_debug):
FILE: credits_pynput.py
function skip_beats (line 28) | def skip_beats(ctr, amount, next_debug):
function on_press (line 335) | def on_press(key):
function on_release (line 342) | def on_release(key):
FILE: ocean.py
function init_populate_ocean (line 12) | def init_populate_ocean():
function get_ocean_slice (line 22) | def get_ocean_slice(xr, glitch):
function mutate_text (line 44) | def mutate_text(txt, glitch):
function get_ocean_slices (line 53) | def get_ocean_slices(x1, x2):
function update_ocean_slices (line 88) | def update_ocean_slices(ocean_content, ocean_glitch):
function unpack_content_to_text (line 105) | def unpack_content_to_text(content):
function begin_ocean (line 110) | def begin_ocean():
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (154K chars).
[
{
"path": ".gitattributes",
"chars": 66,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
},
{
"path": ".gitignore",
"chars": 67,
"preview": "**/__pycache__\nmedia/*.wav\nmedia/*.WAV\nmedia/*.mp3\nmedia/*.MP3\nvenv"
},
{
"path": "CLIRender/classes.py",
"chars": 13597,
"preview": "import os\nfrom platform import system as system_type\nfrom bisect import insort_right, bisect_right\n\nfrom CLIRender.dat i"
},
{
"path": "CLIRender/dat.py",
"chars": 4617,
"preview": "# contains:\n#\n# x position (generic typing because python but should be an int in most cases)\n# y position (the sa"
},
{
"path": "README.md",
"chars": 2326,
"preview": "# credits_public\n- Public version of Frums - Credits animation repository.\n- Should be multiplatform. Feel free to raise"
},
{
"path": "animation_classes.py",
"chars": 4087,
"preview": "# Contains all classes (just Weather)\nimport random\nimport math\n\n\nclass Weather:\n def __init__(self, precip, temp, wi"
},
{
"path": "animation_functions.py",
"chars": 12547,
"preview": "# Contains functions used inside credits.py.\n# Reduce clutter. Reuse clutter. Recycle clutter.\nimport random\nfrom CLIRen"
},
{
"path": "animation_scenes.py",
"chars": 30380,
"preview": "# Contains all animation scenes except for debug_counter.\n# Use variable \"all_scenes\" which contains all scenes defined "
},
{
"path": "animator.py",
"chars": 4793,
"preview": "class DataStoringObject:\n def __init__(self):\n self.data = {}\n\n def set_data(self, *ident):\n for i i"
},
{
"path": "colorama/__init__.py",
"chars": 240,
"preview": "# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.\nfrom .initialise import init, deinit, reinit,"
},
{
"path": "colorama/ansi.py",
"chars": 2524,
"preview": "# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.\n'''\nThis module generates ANSI character code"
},
{
"path": "colorama/ansitowin32.py",
"chars": 9668,
"preview": "# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.\nimport re\nimport sys\nimport os\n\nfrom .ansi im"
},
{
"path": "colorama/initialise.py",
"chars": 1917,
"preview": "# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.\nimport atexit\nimport contextlib\nimport sys\n\nf"
},
{
"path": "colorama/win32.py",
"chars": 5365,
"preview": "# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.\n\n# from winbase.h\nSTDOUT = -11\nSTDERR = -12\n\n"
},
{
"path": "colorama/winterm.py",
"chars": 6290,
"preview": "# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.\nfrom . import win32\n\n\n# from wincon.h\nclass W"
},
{
"path": "credits.py",
"chars": 12880,
"preview": "from animation_functions import debug_info\nfrom CLIRender.classes import enable_ansi\nfrom colorama import Fore, Style\n\ni"
},
{
"path": "credits_pynput.py",
"chars": 13380,
"preview": "from animation_functions import debug_info\nfrom CLIRender.classes import enable_ansi\nfrom colorama import Fore, Style\n\nf"
},
{
"path": "media/README.txt",
"chars": 347,
"preview": "I can't really distribute a full .wav file of an entire song that I don't own the rights to.\nThat would be disrespectful"
},
{
"path": "media/credits.txt",
"chars": 2323,
"preview": "Now for the official national weather service forecast for Eastern Massachusets inside of I-495,\nincluding Boston, issue"
},
{
"path": "ocean.py",
"chars": 2939,
"preview": "# adapted from the-sea.js by plaao (me)\n\n# The ocean is stored as a list of strings which is combined into one string wh"
},
{
"path": "requirements.txt",
"chars": 82,
"preview": "just_playback\npynput; sys_platform == \"darwin\"\nkeyboard; sys_platform != \"darwin\"\n"
},
{
"path": "string_defs.py",
"chars": 15758,
"preview": "# Contains strings used inside credits.py.\n# Kept inside this file to reduce clutter.\n# Implemented as a dictionary of i"
}
]
About this extraction
This page contains the full source code of the plaaosert/credits_public GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (142.8 KB), approximately 39.2k tokens, and a symbol index with 179 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.