Велогрибник 2.0: Лесное Метро
Материал из Абсурдопедии
Перейти к навигацииПерейти к поискуВелогрибник 2.0 — долгожданное продолжение легендарной игры Велогрибник: Заводской Дрифт. Категорически не рекомендуется геймерам с топографическим кретинизмом. Данный шедевр слишком нишевый, чтобы проводить ликбез для случайных нубов, поэтому ограничимся ответами на частые вопросы.
ЧаВо[править]
- Почему хозяин лесных заводов живёт у чёрта на рогах? Если Москва далеко от Мухосранска, то это проблема жителей Мухосранска, а не москвичей.
- А почему он не живёт хотя бы рядом со станцией метро? Жильё в двух шагах от метро слишком дорогое, не каждому миллиардеру по карману.
- Зачем вообще нужен метрополитен в лесу? А где вы видели в лесу трамвай или троллейбус? Как они проедут между деревьями по бездорожью?
- 5 грибов за проезд! Почему так дорого?! Ну не гнать же машинисту состав порожняком ЛесМетроЭлектротрансу в убыток. А другие люди на платформе — это не пассажиры. Они живут в метро, потому что под землёй немножко безопаснее, чем в лесу.
- Где общая схема метро? Откуда я знаю, куда мне ехать? Спросите у местных жителей — они подскажут. Ах да, подземные диалоги в код не поместились, всё ушло на красивое граффити на стене над поездом.
- Что ещё за бустеры и почему они вечно спавнятся не там где надо? Опытные велогрибники уже научились ездить по лесу, ловко объезжая препятствия. Чтобы дать этим гонщикам возможность разбиться, нужно придать им дополнительное ускорение.
- Почему бустеры так странно спавнятся? А если я набью 10 комбо подряд, весь лес будет завален бустерами? Да, это чтобы вы улетели в космос и приземлились оттуда прямо на крышу особняка.
- Почему пистолеты появляются только тогда, когда против стаи волков уже требуется пулемёт? Скажите спасибо, что велогрибник в моменте лутает пестик и хедшотит, а не как в случае с Трампом.
- Почему волки обходят пистолет стороной? У них же лапки, как волк подберёт пистолет и нажмёт на спусковой крючок? Ну и страх перед огнестрелом небольшой есть — для волков это будто ма-а-аленький костёр.
- В жопу метро, я и так доеду! Удачи.
Маленький скромненький кодик[править]
import os
import sys
import random
import shutil
import time
import textwrap
import math
import re
if os.name == 'nt':
os.system('chcp 65001 >nul')
def clear_screen():
if os.name == 'nt':
os.system('cls')
else:
print("\033[H\033[J", end="")
def visible_len(s):
return len(re.sub(r'\033\[[0-9;]*m', '', s))
def center_ansi(text, width):
vis_len = visible_len(text)
pad = max(0, (width - vis_len) // 2)
return " " * pad + text
def get_input(menu_mode=False):
move_map = {
'е': (-1, -1), 't': (-1, -1),
'н': (0, -1), 'y': (0, -1),
'г': (1, -1), 'u': (1, -1),
'п': (-1, 0), 'g': (-1, 0),
'о': (1, 0), 'j': (1, 0),
'м': (-1, 1), 'v': (-1, 1),
'и': (0, 1), 'b': (0, 1),
'т': (1, 1), 'n': (1, 1),
'7': (-1, -1), '8': (0, -1), '9': (1, -1),
'4': (-1, 0), '6': (1, 0),
'1': (-1, 1), '2': (0, 1), '3': (1, 1),
'5': (0, 0)
}
if os.name == 'nt':
import msvcrt
while True:
key = msvcrt.getwch()
if key in ('\xe0', '\x00'):
arr = msvcrt.getwch()
if arr == 'H': return (0, -1)
if arr == 'P': return (0, 1)
if arr == 'K': return (-1, 0)
if arr == 'M': return (1, 0)
elif key == '\x03': return None
else:
k = key.lower()
if k in ['q', 'й']: return None
if k in ['р', 'h']: return 'blow'
if menu_mode:
return k
if k in move_map:
return move_map[k]
else:
import tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
if ch == '\x1b':
sys.stdin.read(1)
arr = sys.stdin.read(1)
if arr == 'A': return (0, -1)
if arr == 'B': return (0, 1)
if arr == 'D': return (-1, 0)
if arr == 'C': return (1, 0)
elif ch == '\x03': return None
else:
k = ch.lower()
if k in ['q', 'й']: return None
if k in ['р', 'h']: return 'blow'
if menu_mode:
return k
if k in move_map:
return move_map[k]
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return (0, 0)
def main():
player_x, player_y = 0, 0
moves = 0
speed = 0
last_dx, last_dy = 0, 0
mushrooms = 0
dead_wolves = 0
total_combos = 0
combo_streak = 0
turns_without_mushrooms = 0
diagonal_unlocked = False
mansion_visited = False
given_mushrooms = 0
diamonds = 0
last_hint_tier = 0
grid = {}
wolves = []
burning_trees_cells = set()
turn_events = []
combo_msg = ""
feedback_msg = ""
dead = False
death_msg = ""
is_igniting = False
recent_combos = []
boosters_active = 0
# === ГЕНЕРАЦИЯ МЕТРО ===
METRO_NAMES = [
"Грибная", "Лесная", "Волчья", "Заводская", "Алмазная", "Дождливая",
"Кислотная", "Велосипедная", "Скоростная", "Диагональная", "Комбовая",
"Координатная", "Особняковая", "Хозяйская", "Смертельная", "Деревянная",
"Костровая", "Пожарная", "Подутая", "Разгонная", "Разворотная", "Поворотная",
"Генераторная", "Вероятностная", "Случайная", "Рандомная", "Поджигательная",
"Собирательная", "Сбивательная", "Рекордная", "Счётчиковая", "Ходовая",
"Подсказная", "Горизонтальная", "Вертикальная", "Бесконечная"
]
random.shuffle(METRO_NAMES)
name_iter = iter(METRO_NAMES)
metro_lines = {'Красная': [], 'Жёлтая': [], 'Зелёная': [], 'Синяя': []}
all_stops = []
unique_metros = set()
metro_exclusion_zones = set()
def add_stop(line, idx, rx, ry, is_t=False):
name = next(name_iter)
stop = {'line': line, 'idx': idx, 'name': name, 'x': rx, 'y': ry, 'graffiti_seed': random.randint(0, 10000)}
metro_lines[line].append(stop)
all_stops.append(stop)
unique_metros.add((rx, ry))
t1_x = -50 + random.randint(-15, 15); t1_y = 50 + random.randint(-15, 15)
t2_x = 50 + random.randint(-15, 15); t2_y = 50 + random.randint(-15, 15)
t3_x = -50 + random.randint(-15, 15); t3_y = -50 + random.randint(-15, 15)
t4_x = 50 + random.randint(-15, 15); t4_y = -50 + random.randint(-15, 15)
for i, y_nom in enumerate([200, 150, 100, 50, 0, -50, -100, -150, -200]):
if y_nom == 50: add_stop('Красная', i, t1_x, t1_y, True)
elif y_nom == -50: add_stop('Красная', i, t3_x, t3_y, True)
else: add_stop('Красная', i, -50 + random.randint(-15, 15), y_nom + random.randint(-15, 15))
for i, y_nom in enumerate([200, 150, 100, 50, 0, -50, -100, -150, -200]):
if y_nom == 50: add_stop('Жёлтая', i, t2_x, t2_y, True)
elif y_nom == -50: add_stop('Жёлтая', i, t4_x, t4_y, True)
else: add_stop('Жёлтая', i, 50 + random.randint(-15, 15), y_nom + random.randint(-15, 15))
for i, x_nom in enumerate([-200, -150, -100, -50, 0, 50, 100, 150, 200]):
if x_nom == -50: add_stop('Зелёная', i, t1_x, t1_y, True)
elif x_nom == 50: add_stop('Зелёная', i, t2_x, t2_y, True)
else: add_stop('Зелёная', i, x_nom + random.randint(-15, 15), 50 + random.randint(-15, 15))
for i, x_nom in enumerate([-200, -150, -100, -50, 0, 50, 100, 150, 200]):
if x_nom == -50: add_stop('Синяя', i, t3_x, t3_y, True)
elif x_nom == 50: add_stop('Синяя', i, t4_x, t4_y, True)
else: add_stop('Синяя', i, x_nom + random.randint(-15, 15), -50 + random.randint(-15, 15))
for mx, my in unique_metros:
for dy in range(-4, 5):
for dx in range(-4, 5):
tx, ty = mx + dx, my + dy
metro_exclusion_zones.add((tx, ty))
if abs(dx) <= 1 and abs(dy) <= 1:
if dx == 0 and dy == 0:
grid[(tx, ty)] = 'Ⓜ️'
else:
grid[(tx, ty)] = '..'
def get_metros_at(x, y):
return [s for s in all_stops if s['x'] == x and s['y'] == y]
# === ГЕНЕРАЦИЯ ОСОБНЯКА ===
while True:
mx = random.randint(0, 250)
my = 250 - mx
mx *= random.choice([-1, 1])
my *= random.choice([-1, 1])
valid = True
for sx, sy in unique_metros:
if math.hypot(mx - sx, my - sy) < 25:
valid = False
break
if valid:
mansion_x, mansion_y = mx, my
break
# === ФУНКЦИИ ===
def get_wolf_emoji(w):
stage = w.get('acid_stage', -1)
if stage == 1: return '👽'
elif stage == 2: return '👺'
elif stage == 3: return '👾'
return '🐺'
def is_visible(dx, dy):
return abs(dx) <= 7 and abs(dy) <= 7
def is_on_leading_edge(x, y, px, py, mdx, mdy, R=7):
if mdx == 0 and mdy == -1: return y == py - R and abs(x - px) <= R
elif mdx == 0 and mdy == 1: return y == py + R and abs(x - px) <= R
elif mdx == -1 and mdy == 0: return x == px - R and abs(y - py) <= R
elif mdx == 1 and mdy == 0: return x == px + R and abs(y - py) <= R
return False
def trigger_mansion_scene():
nonlocal mansion_visited, given_mushrooms, mushrooms, wolves, dead_wolves
clear_screen()
term_size = shutil.get_terminal_size((80, 24))
term_width = term_size.columns
if mushrooms == 0: msg = "Хозяин лесных заводов багровеет от ярости! «Ни одного гриба?! Ты смеешь тратить моё время?!» Он обрушивает на вас трёхэтажный мат, а его охрана жестоко избивает вас, после чего вышвыривает вон."
elif mushrooms < 10: msg = f"Хозяин лесных заводов брезгливо морщится. «Всего {mushrooms}? Жалкое зрелище, ты убожество. Убирайся, пока я не спустил собак.» Вас грубо выталкивают за дверь."
elif mushrooms < 20: msg = f"Хозяин лесных заводов холодно смотрит на вас сверху вниз. «Что ж, {mushrooms} грибов. Положи на стол и уходи. И не топчи ковры.»"
elif mushrooms < 30: msg = f"Хозяин лесных заводов кивает. «{mushrooms} грибов. Неплохо. Оставь их прислуге. Мы в расчёте.» Обычная, формальная встреча."
elif mushrooms < 40: msg = f"Хозяин лесных заводов уважительно жмёт вам руку. «О, {mushrooms} отличных грибов! Вижу в тебе перспективного и надёжного партнёра по бизнесу. Заходи ещё!»"
else: msg = f"Хозяин лесных заводов сияет от радости и обнимает вас! «Браво! {mushrooms} грибов! Мой дорогой гость, мой лучший друг! Закатим пир!» Вас принимают по высшему разряду."
wrapped = textwrap.wrap(msg, width=min(term_width - 4, 60))
print("\n" * max(0, term_size.lines // 2 - len(wrapped) // 2 - 2))
for line in wrapped:
print(" " * max(0, (term_width - len(line)) // 2) + line)
prompt = "[Нажмите любую клавишу для выхода из особняка]"
print("\n\n" + " " * max(0, (term_width - len(prompt)) // 2) + prompt)
get_input(menu_mode=True)
given_mushrooms = mushrooms
mansion_visited = True
mushrooms = 0
wolves.clear()
for pos in list(grid.keys()):
if grid[pos] == '🍄':
grid[pos] = '..'
def ignite_tree_group(start_x, start_y):
nonlocal dead_wolves, is_igniting
if is_igniting: return 0, 0
is_igniting = True
try:
burned_count, ignited_trees = 0, 0
visited = set([(start_x, start_y)])
stack = [(start_x, start_y)]
while stack:
cx, cy = stack.pop()
if grid.get((cx, cy)) == '🌲':
grid[(cx, cy)] = '🔥'
burning_trees_cells.add((cx, cy))
ignited_trees += 1
for w in list(wolves):
if abs(w['x'] - cx) <= 1 and abs(w['y'] - cy) <= 1:
wolves.remove(w)
dead_wolves += 1
burned_count += 1
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if dx == 0 and dy == 0: continue
nx, ny = cx + dx, cy + dy
if (nx, ny) not in visited:
if (nx, ny) not in grid: generate_cell(nx, ny)
if grid.get((nx, ny)) == '🌲':
visited.add((nx, ny))
stack.append((nx, ny))
return ignited_trees, burned_count
finally:
is_igniting = False
def generate_cell(x, y, move_dx=0, move_dy=0):
nonlocal is_igniting
if (x, y) in grid: return
dx_m = abs(x - mansion_x)
dy_m = abs(y - mansion_y)
if dx_m <= 2 and dy_m <= 2:
if dx_m == 0 and dy_m == 0: grid[(x, y)] = '🏯'
elif dx_m == 1 and dy_m == 1: grid[(x, y)] = '🏮'
else: grid[(x, y)] = '..'
return
on_leading_edge = is_on_leading_edge(x, y, player_x, player_y, move_dx, move_dy, R=7)
wolf_prob = max(0.0, (moves * 0.0005) - (total_combos * 0.003)) if on_leading_edge else 0.0
if x == 0 and y == 0:
grid[(x, y)] = '..'
return
in_exclusion = (x, y) in metro_exclusion_zones
if mansion_visited and not in_exclusion:
diamond_prob = 0.00001 * (given_mushrooms ** 2)
if random.random() < diamond_prob:
grid[(x, y)] = '💎'
return
r = random.random()
if r < 0.20:
has_factory = any(grid.get((x+dx, y+dy)) == '🏭' for dx in range(-2, 3) for dy in range(-2, 3))
if not has_factory:
grid[(x, y)] = '🌲'
if not is_igniting and any((x+adx, y+ady) in burning_trees_cells for adx in [-1,0,1] for ady in [-1,0,1] if adx!=0 or ady!=0):
_, w_b = ignite_tree_group(x, y)
if w_b > 0: turn_events.append(f"🔥 Распространяющийся пожар поглотил волков: {w_b}!")
else:
grid[(x, y)] = '..'
elif r < 0.25:
has_factory = any(grid.get((x+dx, y+dy)) == '🏭' for dx in range(-2, 3) for dy in range(-2, 3))
if not mansion_visited and not has_factory and not in_exclusion:
grid[(x, y)] = '🍄'
else:
grid[(x, y)] = '..'
elif r < 0.27:
has_factory = any(grid.get((x+dx, y+dy)) == '🏭' for dx in range(-2, 3) for dy in range(-2, 3))
if not has_factory:
is_near_wolf = any(abs(w['x'] - x) <= 1 and abs(w['y'] - y) <= 1 for w in wolves)
grid[(x, y)] = '..' if is_near_wolf else '🔥'
else:
grid[(x, y)] = '..'
elif r < 0.32:
has_nature = any(grid.get((x+dx, y+dy)) in ['🌲', '🍄', '🔥'] for dx in range(-2, 3) for dy in range(-2, 3))
grid[(x, y)] = '🏭' if not has_nature else '..'
else:
grid[(x, y)] = '..'
if grid[(x, y)] == '..' and wolf_prob > 0:
has_wolf = any(w['x'] == x and w['y'] == y for w in wolves)
if not has_wolf:
is_near_fire = any(grid.get((x + adx, y + ady)) == '🔥' for adx in [-1, 0, 1] for ady in [-1, 0, 1])
if not is_near_fire and random.random() < wolf_prob:
wolves.append({'x': x, 'y': y, 'just_spawned': True})
if grid[(x, y)] == '..':
booster_prob = 0.004 * (sum(recent_combos)**2)
if random.random() < booster_prob:
grid[(x, y)] = '🚀'
else:
gun_prob = 0.002 * dead_wolves
if random.random() < gun_prob:
grid[(x, y)] = '🔫'
def generate_viewport(move_dx=0, move_dy=0):
R = 7
for y in range(player_y - R, player_y + R + 1):
for x in range(player_x - R, player_x + R + 1):
if is_visible(x - player_x, y - player_y):
generate_cell(x, y, move_dx, move_dy)
def is_safe_for_wolf(nx, ny, current_wolf=None):
if grid.get((nx, ny)) in ['🌲', '🏭', '🔥', '🏯', '🏮', '💎', 'Ⓜ️', '🔫']: return False
for adx in [-1, 0, 1]:
for ady in [-1, 0, 1]:
if grid.get((nx + adx, ny + ady)) == '🔥': return False
for other in wolves:
if current_wolf and other is current_wolf: continue
if other['x'] == nx and other['y'] == ny: return False
if current_wolf and 'old_x' in current_wolf and 'old_x' in other:
if nx == other['old_x'] and ny == other['old_y'] and other['x'] == current_wolf['old_x'] and other['y'] == current_wolf['old_y']:
return False
return True
def run_metro(entry_dx, entry_dy):
nonlocal player_x, player_y, moves, mushrooms, turns_without_mushrooms, wolves, dead, last_hint_tier
COLORS = {'Красная': '\033[91m', 'Жёлтая': '\033[93m', 'Зелёная': '\033[92m', 'Синяя': '\033[94m'}
RESET = '\033[0m'
passengers_list = ['🧍', '🕴️', '🧍♂️', '🧍♀️', '🧑🦽']
platform_passengers = " ".join(random.choices(passengers_list, k=random.randint(2, 3)))
GRAFFITI_LIST = [
[
"\033[32m /\\ \033[0m \033[92m /\\ \033[0m \033[32m /\\ \033[0m \033[92m /\\ \033[0m",
"\033[32m //\\\\ \033[0m \033[92m //\\\\ \033[0m \033[32m //\\\\ \033[0m \033[92m //\\\\ \033[0m",
"\033[33m || \033[0m \033[33m || \033[0m \033[33m || \033[0m \033[33m || \033[0m"
],
[
"\033[91m .---. \033[0m \033[95m .---. \033[0m \033[91m .---. \033[0m",
"\033[91m / o \\ \033[0m \033[95m / o \\ \033[0m \033[91m / o \\ \033[0m",
"\033[97m | | \033[0m \033[97m | | \033[0m \033[97m | | \033[0m"
],
[
"\033[96m /\\ \033[0m \033[94m /\\ \033[0m \033[96m /\\ \033[0m",
"\033[96m / \\ \033[0m \033[94m / \\ \033[0m \033[96m / \\ \033[0m",
"\033[96m \\ / \033[0m \033[94m \\ / \033[0m \033[96m \\ / \033[0m"
],
[
"\033[90m _ _ \033[0m \033[90m _ _ \033[0m",
"\033[90m | | | | \033[0m \033[90m | | | | \033[0m",
"\033[91m _|_|_|_|_ \033[0m \033[91m _|_|_|_|_ \033[0m"
],
[
"\033[33m \\|||/ \033[0m \033[33m \\|||/ \033[0m",
"\033[33m - 0 - \033[0m \033[33m - 0 - \033[0m",
"\033[33m /|||\\ \033[0m \033[33m /|||\\ \033[0m"
]
]
def map_qwerty_ru_to_en(ch):
if not ch: return ch
mapping = {'ф':'a', 'и':'b', 'с':'c', 'в':'d', 'у':'e', 'а':'f', 'ч':'x'}
return mapping.get(ch, ch)
stops_here = get_metros_at(player_x, player_y)
if len(stops_here) > 1:
while True:
clear_screen()
term_width = shutil.get_terminal_size((80, 24)).columns
title = "Пересадочный узел"
print("\n" * (shutil.get_terminal_size().lines // 4))
print(title.center(term_width))
print("Выберите линию:".center(term_width) + "\n")
letters = 'abcdef'
opt_map = {}
for i, st in enumerate(stops_here):
letter = letters[i]
opt = f"{letter.upper()}. {COLORS[st['line']]}{st['line']} линия ({st['name']}){RESET}"
vis_len = len(f"{letter.upper()}. {st['line']} линия ({st['name']})")
pad = max(0, (term_width - vis_len) // 2)
print(" " * pad + opt)
opt_map[letter] = st
exit_opt = "X. Выйти обратно в лес (входной билет сгорел)"
print("\n" + exit_opt.center(term_width))
ch = map_qwerty_ru_to_en(get_input(menu_mode=True))
if ch is None: sys.exit(0)
if ch in opt_map:
cur_stop = opt_map[ch]
break
elif ch == 'x':
moves += 1
player_x -= entry_dx
player_y -= entry_dy
turns_without_mushrooms = 0
wolves.clear()
return
else:
cur_stop = stops_here[0]
current_graffiti = GRAFFITI_LIST[cur_stop['graffiti_seed'] % len(GRAFFITI_LIST)]
state = "PLATFORM"
train_dir = 1
track_edge = "=================================================="
def animate_subway_travel(t_dir):
term_size = shutil.get_terminal_size((80, 24))
term_width = term_size.columns
fps = 10
duration = 3
total_frames = int(fps * duration)
sleep_time = 1.0 / fps
pattern = "- = - - = = - = " * (term_width // 4 + 2)
tunnel_wall = [
"\033[90m/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|\033[0m",
"\033[90m|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/\033[0m",
"\033[90m/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|/|\033[0m"
]
for frame in range(total_frames):
clear_screen()
if t_dir == 1:
offset = (frame * 2) % 16
else:
offset = 16 - ((frame * 2) % 16)
top_dashes = pattern[offset : offset + term_width - 10]
bottom_dashes = pattern[offset + 2 : offset + term_width - 8]
print("\n" * max(0, term_size.lines // 4))
for line in tunnel_wall:
print(center_ansi(line, term_width))
print(center_ansi(track_edge, term_width))
print(top_dashes.center(term_width))
print(" 🚃🚃🚃🚃🚃🚃🚃🚃🚃 ".center(term_width))
print(bottom_dashes.center(term_width))
print(center_ansi(track_edge, term_width))
time.sleep(sleep_time)
while True:
clear_screen()
term_width = shutil.get_terminal_size((80, 24)).columns
c = COLORS[cur_stop['line']]
line_arr = metro_lines[cur_stop['line']]
idx = cur_stop['idx']
prev_s = line_arr[idx-1]['name'].lower() if idx > 0 else "конечная"
next_s = line_arr[idx+1]['name'].lower() if idx < len(line_arr)-1 else "конечная"
header_line = "-"*56
name_len = len(cur_stop['name'])
name_pad_left = (24 - name_len) // 2
name_pad_right = 24 - name_len - name_pad_left
name_disp = " " * name_pad_left + f"{c}{cur_stop['name'].upper()}{RESET}" + " " * name_pad_right
print("\n" * max(0, shutil.get_terminal_size().lines // 5))
print(header_line.center(term_width))
pad_h = max(0, (term_width - 56) // 2)
print(" " * pad_h + f" {prev_s:<15} {name_disp} {next_s:>15}")
transfers = [s for s in get_metros_at(cur_stop['x'], cur_stop['y']) if s['line'] != cur_stop['line']]
if transfers:
t = transfers[0]
tc = COLORS[t['line']]
trans_str = f"Переход: {tc}{t['line']} линия ({t['name']}){RESET}"
trans_vis_len = len(f"Переход: {t['line']} линия ({t['name']})")
print(" " * max(0, (term_width - trans_vis_len) // 2) + trans_str)
print(header_line.center(term_width))
print()
for line in current_graffiti:
print(center_ansi(line, term_width))
print(center_ansi(track_edge, term_width))
if state == "PLATFORM":
scene = " 🚃🚃🚃🚃🚃🚃🚃🚃🚃 "
print(scene.center(term_width))
print(center_ansi(track_edge, term_width))
platform = "🪑 🗑️ 🎫 🎫 🗑️ 🪑"
print(platform.center(term_width))
player_row = f"🚴♀️ {platform_passengers}"
print(player_row.center(term_width))
print()
options = []
opt_map = {}
letters = 'abcdef'
cnt = 0
if idx < len(line_arr) - 1:
l = letters[cnt]
options.append(f"{l.upper()}. Сесть в поезд (к ст. {line_arr[idx+1]['name']})")
opt_map[l] = ('BOARD', 1)
cnt += 1
if idx > 0:
l = letters[cnt]
options.append(f"{l.upper()}. Сесть в поезд (к ст. {line_arr[idx-1]['name']})")
opt_map[l] = ('BOARD', -1)
cnt += 1
for t in transfers:
l = letters[cnt]
tc = COLORS[t['line']]
options.append((f"{l.upper()}. Перейти на {tc}{t['line']} линия ({t['name']}){RESET}", len(f"{l.upper()}. Перейти на {t['line']} линия ({t['name']})")))
opt_map[l] = ('TRANSFER', t)
cnt += 1
options.append("X. Выйти на поверхность")
opt_map['x'] = ('EXIT', None)
for o in options:
if isinstance(o, tuple):
text, vlen = o
print(" " * max(0, (term_width - vlen) // 2) + text)
else:
print(o.center(term_width))
ch = map_qwerty_ru_to_en(get_input(menu_mode=True))
if ch is None: sys.exit(0)
if ch in opt_map:
action, arg = opt_map[ch]
if action == 'EXIT':
moves += 1
player_x = cur_stop['x'] - entry_dx
player_y = cur_stop['y'] - entry_dy
turns_without_mushrooms = 0
wolves.clear()
return
elif action == 'TRANSFER':
moves += 1
cur_stop = arg
current_graffiti = GRAFFITI_LIST[cur_stop['graffiti_seed'] % len(GRAFFITI_LIST)]
platform_passengers = " ".join(random.choices(passengers_list, k=random.randint(2, 3)))
elif action == 'BOARD':
moves += 1
train_dir = arg
state = "TRAIN"
elif state == "TRAIN":
scene = " (вы внутри) 🚃🚃🚃🚃🚃🚃🚃🚃🚃 "
print(scene.center(term_width))
print(center_ansi(track_edge, term_width))
platform = "🪑 🗑️ 🎫 🎫 🗑️ 🪑"
print(platform.center(term_width))
print(f" {platform_passengers}".center(term_width))
print()
animate_subway_travel(train_dir)
cur_stop = line_arr[cur_stop['idx'] + train_dir]
current_graffiti = GRAFFITI_LIST[cur_stop['graffiti_seed'] % len(GRAFFITI_LIST)]
platform_passengers = " ".join(random.choices(passengers_list, k=random.randint(2, 3)))
is_terminal = (train_dir == 1 and cur_stop['idx'] == len(line_arr)-1) or \
(train_dir == -1 and cur_stop['idx'] == 0)
clear_screen()
c = COLORS[cur_stop['line']]
idx = cur_stop['idx']
prev_s = line_arr[idx-1]['name'].lower() if idx > 0 else "конечная"
next_s = line_arr[idx+1]['name'].lower() if idx < len(line_arr)-1 else "конечная"
name_len = len(cur_stop['name'])
name_pad_left = (24 - name_len) // 2
name_pad_right = 24 - name_len - name_pad_left
name_disp = " " * name_pad_left + f"{c}{cur_stop['name'].upper()}{RESET}" + " " * name_pad_right
print("\n" * max(0, shutil.get_terminal_size().lines // 5))
print(header_line.center(term_width))
print(" " * pad_h + f" {prev_s:<15} {name_disp} {next_s:>15}")
transfers = [s for s in get_metros_at(cur_stop['x'], cur_stop['y']) if s['line'] != cur_stop['line']]
if transfers:
t = transfers[0]
tc = COLORS[t['line']]
trans_str = f"Переход: {tc}{t['line']} линия ({t['name']}){RESET}"
trans_vis_len = len(f"Переход: {t['line']} линия ({t['name']})")
print(" " * max(0, (term_width - trans_vis_len) // 2) + trans_str)
print(header_line.center(term_width))
print()
for line in current_graffiti:
print(center_ansi(line, term_width))
print(center_ansi(track_edge, term_width))
print(scene.center(term_width))
print(center_ansi(track_edge, term_width))
platform = "🪑 🗑️ 🎫 🎫 🗑️ 🪑"
print(platform.center(term_width))
print(f" {platform_passengers}".center(term_width))
print()
if is_terminal:
msg = "Конечная станция. Выходим на платформу..."
print(msg.center(term_width))
get_input(menu_mode=True)
state = "PLATFORM"
else:
next_st = line_arr[cur_stop['idx'] + train_dir]
msg_next = f"Следующая: {next_st['name']}"
print(msg_next.center(term_width))
print("A. Ехать дальше".center(term_width))
print("B. Выйти на платформе".center(term_width))
ch = map_qwerty_ru_to_en(get_input(menu_mode=True))
if ch is None: sys.exit(0)
if ch == 'a':
moves += 1
elif ch == 'b':
state = "PLATFORM"
def render_rain(is_acid_rain):
clear_screen()
term_size = shutil.get_terminal_size((80, 24))
term_width = term_size.columns
term_height = term_size.lines
if mansion_visited:
h1 = f"\033[90m🍄 Грибов: 0 (Сдано: {given_mushrooms})\033[0m | 💎 Алмазов: {diamonds}"
else:
h1 = f"🍄 Грибов: {mushrooms}"
h2 = f"💀 Волков: {dead_wolves} | 🔥 Комбо: {total_combos} | ⏱ Ходы: {moves} | 💠 8-way: {'ВКЛ' if diagonal_unlocked else 'ВЫКЛ'}"
h3 = f"🚀 Скор: 0 🛑 | 💨 Дуть: Р | 🧭 Ход: Е Н Г / П О / М И Т | Выход: Й/Q"
feedback = "🧪 КИСЛОТНЫЙ ДОЖДЬ (9x9)!" if is_acid_rain else "🌧️ ЛОКАЛЬНЫЙ ДОЖДЬ (9x9)!"
wrapped_feedback = textwrap.wrap(feedback, width=min(term_width, 45))
R = 7
grid_width_visual = (2 * R + 1) * 3
total_height = 3 + len(wrapped_feedback) + 1 + (2 * R + 1)
v_pad = max(0, (term_height - total_height) // 2)
h_pad_grid = max(0, (term_width - grid_width_visual) // 2)
print("\n" * v_pad, end="")
print(" " * max(0, (term_width - visible_len(h1)) // 2) + h1)
print(" " * max(0, (term_width - visible_len(h2)) // 2) + h2)
print(" " * max(0, (term_width - visible_len(h3)) // 2) + h3)
for line in wrapped_feedback: print(" " * max(0, (term_width - visible_len(line)) // 2) + line)
print()
for y in range(player_y - R, player_y + R + 1):
row_str = ""
for x in range(player_x - R, player_x + R + 1):
if not is_visible(x - player_x, y - player_y): row_str += " "
elif x == player_x and y == player_y: row_str += "🚴♀️ "
elif abs(x - player_x) <= 4 and abs(y - player_y) <= 4: row_str += "🧪 " if is_acid_rain else "🌧️ "
else:
is_wolf = next((w for w in wolves if w['x'] == x and w['y'] == y), None)
if is_wolf: row_str += get_wolf_emoji(is_wolf) + " "
else: row_str += grid.get((x, y), '..') + " "
print(" " * h_pad_grid + row_str)
def render():
clear_screen()
term_size = shutil.get_terminal_size((80, 24))
term_width = term_size.columns
term_height = term_size.lines
dir_emoji = "🛑"
if speed > 0:
if last_dx == 0 and last_dy == -1: dir_emoji = "⬆️"
elif last_dx == 0 and last_dy == 1: dir_emoji = "⬇️"
elif last_dx == -1 and last_dy == 0: dir_emoji = "⬅️"
elif last_dx == 1 and last_dy == 0: dir_emoji = "➡️"
elif last_dx == -1 and last_dy == -1: dir_emoji = "↖️"
elif last_dx == 1 and last_dy == -1: dir_emoji = "↗️"
elif last_dx == -1 and last_dy == 1: dir_emoji = "↙️"
elif last_dx == 1 and last_dy == 1: dir_emoji = "↘️"
speed_str = f"{speed} {dir_emoji}".strip()
if mansion_visited:
h1 = f"\033[90m🍄 Грибов: 0 (Сдано: {given_mushrooms})\033[0m | 💎 Алмазов: {diamonds}"
else:
h1 = f"🍄 Грибов: {mushrooms}"
h2 = f"💀 Волков: {dead_wolves} | 🔥 Комбо: {total_combos} | ⏱ Ходы: {moves} | 💠 8-way: {'ВКЛ' if diagonal_unlocked else 'ВЫКЛ'}"
h3 = f"🚀 Скор: {speed_str} | 💨 Дуть: Р | 🧭 Ход: Е Н Г / П О / М И Т | Выход: Й/Q"
wrapped_feedback = textwrap.wrap(feedback_msg, width=min(term_width, 60)) if feedback_msg else []
R = 7
grid_width_visual = (2 * R + 1) * 3
total_height = 3 + max(1, len(wrapped_feedback)) + 1 + (2 * R + 1) + (15 if dead else 0)
v_pad = max(0, (term_height - total_height) // 2)
h_pad_grid = max(0, (term_width - grid_width_visual) // 2)
print("\n" * v_pad, end="")
print(" " * max(0, (term_width - visible_len(h1)) // 2) + h1)
print(" " * max(0, (term_width - visible_len(h2)) // 2) + h2)
print(" " * max(0, (term_width - visible_len(h3)) // 2) + h3)
if wrapped_feedback:
for line in wrapped_feedback: print(" " * max(0, (term_width - visible_len(line)) // 2) + line)
else: print()
print()
for y in range(player_y - R, player_y + R + 1):
row_str = ""
for x in range(player_x - R, player_x + R + 1):
if not is_visible(x - player_x, y - player_y): row_str += " "
elif dead and x == player_x and y == player_y: row_str += "💀 "
elif not dead and x == player_x and y == player_y: row_str += "🚴♀️ "
else:
is_wolf = next((w for w in wolves if w['x'] == x and w['y'] == y), None)
if is_wolf: row_str += get_wolf_emoji(is_wolf) + " "
else: row_str += grid.get((x, y), '..') + " "
print(" " * h_pad_grid + row_str)
if dead:
screamer = [
r" ▄████▄ ██▀███ ▄▄▄ ██████ ██░ ██ ",
r"▒██▀ ▀█ ▓██ ▒ ██▒▒████▄ ▒██ ▒ ▓██░ ██▒",
r"▒▓█ ▄ ▓██ ░▄█ ▒▒██ ▀█▄ ░ ▓██▄ ▒██▀▀██░",
r"▒▓▓▄ ▄██▒▒██▀▀█▄ ░██▄▄▄▄██ ▒ ██▒░▓█ ░██ ",
r"▒ ▓███▀ ░░██▓ ▒██▒ ▓█ ▓██▒▒██████▒▒░▓█▒░██▓",
r"░ ░▒ ▒ ░░ ▒▓ ░▒▓░ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒",
r" ░ ▒ ░▒ ░ ▒░ ▒ ▒▒ ░░ ░▒ ░ ░ ▒ ░▒░ ░",
r"░ ░░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░",
r"░ ░ ░ ░ ░ ░ ░ ░ ░",
r"░ "
]
msg1 = f"💀 ИГРА ОКОНЧЕНА! {death_msg}"
wrapped_death = textwrap.wrap(msg1, width=min(term_width, 45))
msg2 = "Нажмите любую клавишу для выхода..."
print("\n", end="")
for line in screamer: print(" " * max(0, (term_width - visible_len(line)) // 2) + line)
print()
for line in wrapped_death: print(" " * max(0, (term_width - visible_len(line)) // 2) + line)
print("\n" + " " * max(0, (term_width - visible_len(msg2)) // 2) + msg2)
generate_viewport()
while True:
ignited_this_turn = False
if turn_events or combo_msg:
feedback_msg = " | ".join(turn_events)
if combo_msg: feedback_msg = f"{feedback_msg} {combo_msg}".strip(" | ")
else:
feedback_msg = ""
render()
turn_events = []
combo_msg = ""
if dead:
get_input()
break
inp = get_input()
if inp is None: break
if inp == (0, 0): continue
combo_action_this_turn = False
boosters_collected_this_turn = 0
if inp == 'blow':
fires = []
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if dx == 0 and dy == 0: continue
if grid.get((player_x + dx, player_y + dy)) == '🔥': fires.append((dx, dy))
target_fire = None
fires_around = len(fires)
if fires_around == 1: target_fire = fires[0]
elif fires_around > 1:
dir_names = {(0,-1): "вверх", (0,1): "вниз", (-1,0): "влево", (1,0): "вправо", (-1,-1): "вверх-влево", (1,-1): "вверх-вправо", (-1,1): "вниз-влево", (1,1): "вниз-вправо"}
dir_keys_display = {(0,-1): "Н", (0,1): "И", (-1,0): "П", (1,0): "О", (-1,-1): "Е", (1,-1): "Г", (-1,1): "М", (1,1): "Т"}
options_str = [f"{dir_keys_display.get(f)} ({dir_names.get(f)})" for f in fires]
feedback_msg = f"🔥 Укажите направление костра: " + ", ".join(options_str)
render()
while True:
choice = get_input(menu_mode=False)
if isinstance(choice, tuple) and choice in fires:
target_fire = choice
break
elif choice is None: return
trees_ignited_by_blow = 0
wolves_burned_by_blow = 0
if target_fire:
fdx, fdy = target_fire
tx, ty = player_x + 2*fdx, player_y + 2*fdy
generate_cell(tx, ty)
if grid.get((tx, ty)) == '🌲':
i_t, w_b = ignite_tree_group(tx, ty)
trees_ignited_by_blow += i_t
wolves_burned_by_blow += w_b
speed = 0
last_dx, last_dy = 0, 0
diagonal_unlocked = False
moves += 1
turns_without_mushrooms += 1
boosters_active = 0
if fires_around == 0: turn_events.append("💨 Вы подули, но костра рядом нет.")
elif trees_ignited_by_blow > 0:
combo_action_this_turn = True
msg = f"🌲 Вы успешно подожгли лес!"
if wolves_burned_by_blow > 0: msg += f" Волки сгорели: {wolves_burned_by_blow}!"
turn_events.append(msg)
ignited_this_turn = True
else: turn_events.append("💨 Вы подули на костёр, но ни одно дерево не загорелось.")
generate_viewport(0, 0)
elif isinstance(inp, tuple):
dx, dy = inp
if abs(dx) == 1 and abs(dy) == 1 and not diagonal_unlocked:
turn_events.append("❌ Диагональный ход недоступен! Нужно собрать/сбить 2+ объекта за 1 ход.")
continue
was_speed_zero = (speed == 0)
if speed > 0:
if dx == last_dx and dy == last_dy: base_speed = speed + 1
elif (dx - last_dx)**2 + (dy - last_dy)**2 == 1: base_speed = speed
else: base_speed = 1
else:
base_speed = 1
current_speed = base_speed + boosters_active
next_x, next_y = player_x + dx, player_y + dy
generate_cell(next_x, next_y, dx, dy)
if grid[(next_x, next_y)] in ['🌲', '🏭', '🏯', '🏮', 'Ⓜ️']:
angle_valid = was_speed_zero or (last_dx*dx + last_dy*dy <= 0)
if grid[(next_x, next_y)] == '🏯' and not mansion_visited and was_speed_zero and current_speed == 1 and next_x == mansion_x and next_y == mansion_y: pass
elif grid[(next_x, next_y)] == 'Ⓜ️' and current_speed == 1 and angle_valid: pass
else: continue
mushrooms_this_turn = 0
diamonds_this_turn = 0
wolves_killed_this_turn = 0
entered_mansion = False
entered_metro = False
picked_up_gun = False
for step in range(1, current_speed + 1):
cx, cy = player_x + dx * step, player_y + dy * step
generate_cell(cx, cy, dx, dy)
if grid[(cx, cy)] == '🔥':
dead, death_msg, player_x, player_y = True, "Вы сдуру заехали прямо в костёр и сгорели заживо!", cx, cy
break
if grid[(cx, cy)] == '🏯':
if not mansion_visited and was_speed_zero and current_speed == 1 and cx == mansion_x and cy == mansion_y: entered_mansion = True; break
else:
dead, death_msg, player_x, player_y = True, "Вы врезались в стену роскошного особняка и разбились!", cx, cy
break
if grid[(cx, cy)] == 'Ⓜ️':
angle_valid = was_speed_zero or (last_dx*dx + last_dy*dy <= 0)
if current_speed == 1 and angle_valid:
if mushrooms >= 5:
mushrooms -= 5
last_hint_tier = mushrooms // 5
player_x, player_y = cx, cy
entered_metro = True
break
else:
turn_events.append("❌ Не хватает грибов для оплаты проезда в метро! (Нужно 5)")
player_x, player_y = cx - dx, cy - dy
current_speed = step - 1
break
else:
dead, death_msg, player_x, player_y = True, "Вы на скорости влетели в бетонный спуск станции метро и разбились!", cx, cy
break
if grid[(cx, cy)] in ['🏮', '🌲', '🏭']:
obst = {"🏮": "красный фонарь", "🌲": "дерево", "🏭": "заводскую стену"}
dead, death_msg, player_x, player_y = True, f"Вы на огромной скорости влетели в {obst[grid[(cx, cy)]]} и разбились!", cx, cy
break
wolf_here = next((w for w in wolves if w['x'] == cx and w['y'] == cy), None)
if wolf_here:
if step == current_speed:
dead, death_msg, player_x, player_y = True, "Вы остановились прямо перед волком, и он вас загрыз!", cx, cy
wolves.remove(wolf_here)
break
else:
wolves.remove(wolf_here)
dead_wolves += 1
wolves_killed_this_turn += 1
if grid[(cx, cy)] == '🍄':
mushrooms += 1
mushrooms_this_turn += 1
grid[(cx, cy)] = '..'
elif grid[(cx, cy)] == '💎':
diamonds += 1
diamonds_this_turn += 1
grid[(cx, cy)] = '..'
elif grid[(cx, cy)] == '🚀':
boosters_collected_this_turn += 1
grid[(cx, cy)] = '..'
elif grid[(cx, cy)] == '🔫':
picked_up_gun = True
grid[(cx, cy)] = '..'
current_speed = step
break
if entered_mansion:
trigger_mansion_scene()
speed, last_dx, last_dy, turns_without_mushrooms, diagonal_unlocked, moves = 0, 0, 0, 0, False, moves + 1
boosters_active = 0
generate_viewport(0, 0)
continue
if entered_metro:
moves += 1
run_metro(dx, dy)
speed, last_dx, last_dy, diagonal_unlocked = 0, 0, 0, False
boosters_active = 0
generate_viewport(0, 0)
continue
if not dead:
if wolves_killed_this_turn > 0: turn_events.append(f"🐺 Вы сбили волков: {wolves_killed_this_turn}!")
if boosters_collected_this_turn > 0: turn_events.append(f"🚀 Вы подобрали бустер! Скорость на следующем ходу +{boosters_collected_this_turn}")
items_collected = mushrooms_this_turn + diamonds_this_turn + wolves_killed_this_turn + boosters_collected_this_turn
if items_collected >= 2:
diagonal_unlocked = True
turn_events.append("✨ Доступен ход по диагонали на следующий ход! (Е, Г, М, Т)")
else: diagonal_unlocked = False
if items_collected > 0: combo_action_this_turn = True
turns_without_mushrooms = 0 if items_collected > 0 else turns_without_mushrooms + 1
player_x += dx * current_speed
player_y += dy * current_speed
last_dx, last_dy = dx, dy
speed = current_speed
moves += 1
boosters_active = boosters_collected_this_turn
if picked_up_gun:
targets = {}
dirs = [(-1,-1), (0,-1), (1,-1), (-1,0), (1,0), (-1,1), (0,1), (1,1)]
for dir_dx, dir_dy in dirs:
tx, ty = player_x, player_y
while True:
tx += dir_dx
ty += dir_dy
if not is_visible(tx - player_x, ty - player_y):
break
generate_cell(tx, ty)
wolf_hit = next((w for w in wolves if w['x'] == tx and w['y'] == ty), None)
if wolf_hit:
targets[(dir_dx, dir_dy)] = wolf_hit
break
cell = grid.get((tx, ty), '..')
if cell not in ['..', '🍄', '🚀', '🔥', '🔫']:
break
if len(targets) == 0:
turn_events.append("🔫 Вы подобрали пистолет и выстрелили в воздух, но ни в кого не попали.")
elif len(targets) == 1:
dir_key = list(targets.keys())[0]
wolf_hit = targets[dir_key]
wolves.remove(wolf_hit)
dead_wolves += 1
combo_action_this_turn = True
turns_without_mushrooms = 0
turn_events.append("🔫 Вы метким выстрелом убили волка!")
else:
dir_names = {(0,-1): "вверх", (0,1): "вниз", (-1,0): "влево", (1,0): "вправо", (-1,-1): "вверх-влево", (1,-1): "вверх-вправо", (-1,1): "вниз-влево", (1,1): "вниз-вправо"}
dir_keys_display = {(0,-1): "Н", (0,1): "И", (-1,0): "П", (1,0): "О", (-1,-1): "Е", (1,-1): "Г", (-1,1): "М", (1,1): "Т"}
options_str = [f"{dir_keys_display.get(d)} ({dir_names.get(d)})" for d in targets.keys()]
feedback_msg = f"🔫 Укажите направление выстрела: " + ", ".join(options_str)
render()
chosen_dir = None
while True:
choice = get_input(menu_mode=False)
if isinstance(choice, tuple) and choice in targets:
chosen_dir = choice
break
elif choice is None: sys.exit(0)
wolf_hit = targets[chosen_dir]
wolves.remove(wolf_hit)
dead_wolves += 1
combo_action_this_turn = True
turns_without_mushrooms = 0
turn_events.append(f"🔫 Вы прицелились и застрелили волка ({dir_names[chosen_dir]})!")
speed = 0
last_dx, last_dy = 0, 0
diagonal_unlocked = False
boosters_active = 0
if "✨ Доступен ход по диагонали на следующий ход! (Е, Г, М, Т)" in turn_events:
turn_events.remove("✨ Доступен ход по диагонали на следующий ход! (Е, Г, М, Т)")
current_hint_tier = mushrooms // 5
if not mansion_visited and current_hint_tier > last_hint_tier:
last_hint_tier = current_hint_tier
dist = round(math.hypot(mansion_x - player_x, mansion_y - player_y), 1)
turn_events.append(f"🗺️ ПОДСКАЗКА: Особняк хозяина лесных заводов находится на расстоянии {dist} клеток.")
generate_viewport(dx, dy)
if not dead:
if combo_action_this_turn:
combo_streak += 1
if combo_streak >= 2:
total_combos += 1
recent_combos.append(1)
combo_msg = f"🔥 {random.choice(['Супер!', 'Огонь!', 'Отлично!', 'Безумие!', 'Невероятно!', 'Мощно!'])} Комбо x{combo_streak}! 🔥"
else:
recent_combos.append(0)
else:
combo_streak = 0
recent_combos.append(0)
if len(recent_combos) > 10:
recent_combos.pop(0)
died_from_acid = 0
for w in list(wolves):
if 'acid_stage' in w:
w['acid_stage'] += 1
if w['acid_stage'] >= 4:
wolves.remove(w)
dead_wolves += 1
died_from_acid += 1
if died_from_acid > 0: turn_events.append(f"💀 Кислота разъела скелеты волков (👾 -> ☠️): {died_from_acid} шт!")
for w in wolves: w['old_x'], w['old_y'] = w['x'], w['y']
if not dead:
for w in wolves:
if w.get('has_booster'):
w['has_booster'] = False
wdx, wdy = player_x - w['x'], player_y - w['y']
if max(abs(wdx), abs(wdy)) == 2 and (abs(wdx) == 2 or wdx == 0) and (abs(wdy) == 2 or wdy == 0):
step_x, step_y = wdx // 2, wdy // 2
mid_x, mid_y = w['x'] + step_x, w['y'] + step_y
if grid.get((mid_x, mid_y), '..') in ['..', '🍄']:
is_player_near_fire = any(grid.get((player_x + adx, player_y + ady)) == '🔥' for adx in [-1, 0, 1] for ady in [-1, 0, 1])
if not is_player_near_fire:
w['x'], w['y'] = player_x, player_y
dead = True
death_msg = "Волк под бустером 🚀 совершил молниеносный прыжок на 2 клетки и загрыз вас!"
wolves.remove(w)
break
for w in wolves:
if dead: break
if w['just_spawned']:
w['just_spawned'] = False
continue
wx, wy = w['x'], w['y']
wdx, wdy = (player_x > wx) - (player_x < wx), (player_y > wy) - (player_y < wy)
candidates = [(wdx, wdy), (wdx, 0), (0, wdy)] if wdx != 0 and wdy != 0 else ([(wdx, 0), (wdx, 1), (wdx, -1)] if wdx != 0 else [(0, wdy), (1, wdy), (-1, wdy)])
for cdx, cdy in candidates:
tx, ty = wx + cdx, wy + cdy
generate_cell(tx, ty)
if not is_safe_for_wolf(tx, ty, w): continue
w['x'], w['y'] = tx, ty
break
if w['x'] == player_x and w['y'] == player_y:
dead, death_msg = True, "Голодный волк догнал вас и загрыз!"
wolves.remove(w)
break
if not dead and grid.get((w['x'], w['y'])) in ['🍄', '💎', '🚀']:
if grid.get((w['x'], w['y'])) == '🚀':
w['has_booster'] = True
grid[(w['x'], w['y'])] = '..'
elif grid.get((w['x'], w['y'])) == '🍄':
grid[(w['x'], w['y'])] = '..'
if not dead and turns_without_mushrooms >= 10:
combo_streak, diagonal_unlocked = 0, False
if "✨ Доступен ход по диагонали на следующий ход! (Е, Г, М, Т)" in turn_events: turn_events.remove("✨ Доступен ход по диагонали на следующий ход! (Е, Г, М, Т)")
is_acid_rain = any(grid.get((player_x + dx, player_y + dy)) == '🏭' for dy in range(-4, 5) for dx in range(-4, 5))
# Показываем результат поджога, если он произошел в этот самый ход перед дождем
if ignited_this_turn:
current_feedback = " | ".join(turn_events)
if combo_msg: current_feedback = f"{current_feedback} {combo_msg}".strip(" | ")
original_feedback = feedback_msg
feedback_msg = current_feedback
render()
time.sleep(1.0)
feedback_msg = original_feedback
render_rain(is_acid_rain)
time.sleep(3.5)
for dy in range(-4, 5):
for dx in range(-4, 5):
pos = (player_x + dx, player_y + dy)
if grid.get(pos) == '🔥':
grid[pos] = '..'
if pos in burning_trees_cells: burning_trees_cells.remove(pos)
if is_acid_rain:
for w in wolves:
if abs(w['x'] - player_x) <= 4 and abs(w['y'] - player_y) <= 4: w['acid_stage'] = 0
speed, last_dx, last_dy, turns_without_mushrooms = 0, 0, 0, 0
boosters_active = 0
turn_events.append("🧪 Прошёл КИСЛОТНЫЙ дождь! Костры в зоне 9x9 потухли, волки облучены." if is_acid_rain else "🌧️ Прошёл локальный дождь! Костры в зоне 9x9 потухли, комбо сброшено.")
if __name__ == "__main__":
main()
Игровая комната |
||
|---|---|---|
| Собранные игрушки | Second Hand · SimCity 2000 · QTE · Wikigacha · Весёлый работодатель · Казино «Флэш Рояль» · Маленький человечек в большой квартире: Яичница · Отшей блондинку · Пустыня · Путешествие куда-нибудь и не только · Сказка про белого бычка | |
| Разобранные игрушки | AI Adventures · Бездна · Интерактивное кино · Крестики-нолики · Самый сложный экзамен · Симулятор динозавра | |
| Игрушечный питон | Велогрибник: Заводской Дрифт · Велогрибник 2.0: Лесное Метро | |
| Ещё чего: Портал «Игры Абсурдопедии» | Компьютерные игры | Ролевая игра Абсурдопедии | ||