Files
pysaver/pysaver/screensavers/fang.py
Tommy Parnell 1be4095e04 the fang works
2025-07-02 21:57:21 -04:00

165 lines
6.5 KiB
Python

import time
import random
from blessed import Terminal
import pyfiglet
def run():
"""A multi-scene animation involving a knife thrower and a target."""
term = Terminal()
# --- ASCII Art Definitions ---
thrower = [" O ", "/|\\->", "/ \\ "]
side_victim = [" O ", " | ", "/ \\ "]
side_target = ["/-\\", "|O|", "\\-/"]
front_victim = [
" \\ O / ",
" | ",
" --+-- ",
" | ",
" / \\ ",
" / \\ "
]
front_target = [
" .---''''---. ",
" .-' '-. ",
" .' '. ",
" / \ ",
" / \ ",
" | | ",
" \ / ",
" \ / ",
" '. .' ",
" '-. .-' ",
" '---....---' "
]
fig = pyfiglet.Figlet(font='standard')
banner_art = fig.renderText('FANG')
# CORRECTED: Split by newline character '\n' instead of literal '\\n'
banner_lines = banner_art.split('\n')
banner_height = len(banner_lines)
banner_width = len(banner_lines[0]) if banner_height > 0 else 0
knife_char = "'"
colors = [term.red, term.yellow, term.blue, term.magenta, term.cyan]
with term.fullscreen(), term.cbreak(), term.hidden_cursor():
while True:
# --- SCENE 1: SIDE VIEW & MULTIPLE THROWS --- #
print(term.home + term.clear)
thrower_x, thrower_y = 5, term.height // 2 - 1
target_x, target_y = term.width - 15, term.height // 2 - 1
victim_x, victim_y = target_x - 5, term.height // 2 - 1
# Draw static elements
for i, line in enumerate(thrower):
print(term.move_xy(thrower_x, thrower_y + i) + line)
for i, line in enumerate(side_target):
print(term.move_xy(target_x, target_y + i) + line)
for i, line in enumerate(side_victim):
print(term.move_xy(victim_x, victim_y + i) + line)
# Animate 5 rapid, overlapping knife throws
knife_y = thrower_y + 1
knives = [] # stores x-positions of active knives
knives_thrown_count = 0
max_knives = 5
frame = 0
while True:
# Add a new knife every 4 frames until we've thrown 5
if frame % 4 == 0 and knives_thrown_count < max_knives:
knives.append(thrower_x + len(thrower[1]))
knives_thrown_count += 1
# Move and draw all active knives
next_knives = []
for x in knives:
# Erase old position
print(term.move_xy(x, knife_y) + " ")
# Move forward
new_x = x + 1
# If knife is still on screen before victim
if new_x < victim_x - 2:
print(term.move_xy(new_x, knife_y) + term.red("-"))
next_knives.append(new_x)
knives = next_knives
# Exit condition: all 5 knives thrown and all have disappeared
if knives_thrown_count == max_knives and not knives:
break
frame += 1
time.sleep(0.04)
if term.inkey(timeout=0): return
time.sleep(1.0)
if term.inkey(timeout=0): return
# --- SCENE 2: FRONT VIEW & KNIFE LANDING --- #
print(term.home + term.clear)
center_x, center_y = term.width // 2, term.height // 2
# Draw Banner
banner_x = center_x - banner_width // 2
banner_y = center_y - (len(front_victim) // 2) - banner_height - 3
for i, line in enumerate(banner_lines):
if line.strip():
print(term.move_xy(banner_x, banner_y + i) + line)
# Draw Target (background)
target_height = len(front_target)
target_width = len(front_target[0])
target_x = center_x - target_width // 2
target_y = center_y - target_height // 2
for i, line in enumerate(front_target):
print(term.move_xy(target_x, target_y + i) + term.bright_black(line))
# Draw Victim (foreground)
victim_height = len(front_victim)
victim_width = len(front_victim[0])
victim_x = center_x - victim_width // 2
victim_y = center_y - victim_height // 2
for i, line in enumerate(front_victim):
print(term.move_xy(victim_x, victim_y + i) + line)
def update_banner_color():
color = random.choice(colors)
for i, line in enumerate(banner_lines):
if line.strip():
print(term.move_xy(banner_x, banner_y + i) + color(line))
# Initial pause with color changing
end_time = time.time() + 1.5
while time.time() < end_time:
update_banner_color()
time.sleep(0.15) # Faster color change
if term.inkey(timeout=0): return
# Knife landing with interleaved color changing
knife_positions = [
(victim_x + 2, victim_y), # Between head and left arm
(victim_x + 4, victim_y), # Between head and right arm
(victim_x + 1, victim_y + 4), # By left leg
(victim_x + 5, victim_y + 4), # By right leg
(center_x, victim_y + 5), # Between feet
]
for kx, ky in knife_positions:
print(term.move_xy(kx, ky) + term.red(knife_char))
end_time_knife = time.time() + 0.5
while time.time() < end_time_knife:
update_banner_color()
time.sleep(0.15)
if term.inkey(timeout=0): return
# Final pause before restart, with continued color change
end_time_final = time.time() + 4.0
while time.time() < end_time_final:
update_banner_color()
time.sleep(0.15)
if term.inkey(timeout=0): return
time.sleep(2.5)
if term.inkey(timeout=0): return