Загрузка данных
"""
ПОДЗЕМЕЛЬЕ ТЁМНОГО МАГА v2
Текстовая RPG · Чистый Python · 0 библиотек
"""
# ═══════ Генератор случайных чисел (LCG) ═══════
_seed = 1
def srand(v):
global _seed
_seed = v & 0x7FFFFFFF
def rand(a, b):
global _seed
_seed = (_seed * 1103515245 + 12345) & 0x7FFFFFFF
if a > b:
a, b = b, a
return a + (_seed % (b - a + 1))
# ═══════ Утилиты ═══════
def cls():
print("\n" * 40)
def pause():
input("\n Нажмите Enter...")
def bar(cur, mx, w=10):
f = max(0, min(w, cur * w // mx)) if mx else 0
return "█" * f + "░" * (w - f)
# ═══════ Данные игры ═══════
MOBS = [
("Слайм", 12, 3, 10, 5),
("Гигантская крыса", 14, 4, 8, 4),
("Летучая мышь", 10, 5, 6, 3),
("Гоблин", 18, 6, 14, 10),
("Скелет", 22, 7, 18, 12),
("Паук-гигант", 16, 5, 10, 7),
("Зомби", 28, 8, 22, 15),
("Призрак", 20, 9, 25, 18),
("Тролль", 35, 10, 30, 22),
]
BOSSES = [
("Огненный элементаль", 60, 12, 100, 50),
("Некромант", 85, 15, 150, 80),
("Тёмный маг", 130, 20, 300, 200),
]
# Товары торговца: (название, цена-база, описание-эффекта)
# Цена растёт с этажем
SHOP_ITEMS = [
("Зелье лечения", 15, "+2 зелья в инвентарь"),
("Зелье здоровья", 25, "Полное восстановление HP"),
("Усилитель оружия", 40, "+4 к атаке"),
("Усилитель брони", 35, "+2 к защите"),
("Эликсир силы", 60, "+10 к макс. HP"),
]
SZ = 5
_EMPTY, _MOB, _POT, _GOLD = 0, 1, 2, 3
_TRAP, _BOSS, _START, _SEEN = 4, 5, 6, 7
_SHOP = 8
SYM = {
_EMPTY: "·", _MOB: "!", _POT: "+", _GOLD: "$",
_TRAP: "^", _BOSS: "☠", _START: "·", _SEEN: "·",
_SHOP: "S",
}
# ═══════ Класс героя ═══════
class Hero:
def __init__(self, name):
self.name = name
self.hp = 50; self.mhp = 50
self.atk = 8; self.df = 3
self.gold = 0; self.pot = 2
self.xp = 0; self.lv = 1
self.x = 0; self.y = 0
def need(self):
return self.lv * 50
def alive(self):
return self.hp > 0
def try_levelup(self):
ok = False
while self.xp >= self.need():
self.xp -= self.need()
self.lv += 1
self.mhp += 10
self.hp = self.mhp
self.atk += 3
self.df += 1
ok = True
return ok
# ═══════ Магазин бомжа-торговца ═══════
def shop(hero, floor):
markup = 1 + (floor - 1) * 0.3 # наценка за этаж
while True:
cls()
show_stats(hero, floor)
print()
print(" ╔════════════════════════════════════╗")
print(" ║ БОМЖ-ТОРГОВЕЦ ║")
print(" ║ \"Эй, путник! Глянь товар!\" ║")
print(" ╠════════════════════════════════════╣")
print(f" ║ Ваше золото: {hero.gold:<20}║")
print(" ╠════════════════════════════════════╣")
prices = []
for i, (name, base_price, desc) in enumerate(SHOP_ITEMS):
p = int(base_price * markup)
prices.append(p)
ok = "[✓]" if hero.gold >= p else "[✗]"
print(f" ║ {ok} [{i + 1}] {name:<18} {p:>3} зол. ║")
print(f" ║ {desc:<30}║")
print(f" ║ [0] Уйти ║")
print(" ╚════════════════════════════════════╝")
c = input("\n Что покупаем? > ").strip()
if c == "0":
print("\n Торговец: \"Удачи, путник! Не сдохни!\"")
pause()
return
if not c.isdigit() or int(c) < 1 or int(c) > len(SHOP_ITEMS):
continue
idx = int(c) - 1
price = prices[idx]
if hero.gold < price:
print(" Торговец: \"Денег нет? Иди убей кого-нибудь!\"")
pause()
continue
hero.gold -= price
if idx == 0: # Зелье лечения
hero.pot += 2
print(" Торговец: \"Держи два зельца, свежие!\"")
elif idx == 1: # Зелье здоровья
hero.hp = hero.mhp
print(" Торговец: \"Пей — и будь как огурчик!\"")
elif idx == 2: # Усилитель оружия
hero.atk += 4
print(" Торговец: \"Намажь на клинок — "
"режет как бритва!\"")
elif idx == 3: # Усилитель брони
hero.df += 2
print(" Торговец: \"Мажь на кожу — "
"каменная броня!\"")
elif idx == 4: # Эликсир силы
hero.mhp += 10
hero.hp += 10
print(" Торговец: \"Эликсир от бабки, "
"работает как надо!\"")
pause()
# ═══════ Генерация подземелья ═══════
def gen_dungeon(floor):
m = [[_EMPTY] * SZ for _ in range(SZ)]
m[0][0] = _START
m[SZ - 1][SZ - 1] = _BOSS
free = [(x, y) for y in range(SZ) for x in range(SZ)
if (x, y) not in ((0, 0), (SZ - 1, SZ - 1))]
for i in range(len(free) - 1, 0, -1):
j = rand(0, i)
free[i], free[j] = free[j], free[i]
k = 0
# 3 зелья (было 2)
for _ in range(3):
if k < len(free):
m[free[k][1]][free[k][0]] = _POT; k += 1
# 3 сундука (было 2)
for _ in range(3):
if k < len(free):
m[free[k][1]][free[k][0]] = _GOLD; k += 1
# 1 ловушка + бонусные за этаж
for _ in range(1 + floor):
if k < len(free):
m[free[k][1]][free[k][0]] = _TRAP; k += 1
# 1 торговец на этаж
if k < len(free):
m[free[k][1]][free[k][0]] = _SHOP; k += 1
# Остальное — враги (было 100%, стало ~75%)
# примерно каждый 4-й оставшийся — пустая комната
while k < len(free):
if rand(1, 100) <= 25:
m[free[k][1]][free[k][0]] = _EMPTY
else:
m[free[k][1]][free[k][0]] = _MOB
k += 1
return m
# ═══════ Отображение ═══════
def show_map(m, h, vis):
line = " +" + "---+" * SZ
print(line)
for y in range(SZ):
row = " |"
for x in range(SZ):
if x == h.x and y == h.y:
ch = "@"
elif vis[y][x]:
ch = SYM.get(m[y][x], "?")
else:
ch = "?"
row += f" {ch} |"
print(row)
print(line)
def show_stats(h, fl):
hb = bar(h.hp, h.mhp)
print(" ┌──────────────────────────────────┐")
print(f" │ {h.name:<14} Ур.{h.lv:<2} Этаж {fl} │")
print(f" │ HP [{hb}] {h.hp:>3}/{h.mhp:<3} │")
print(f" │ ATK:{h.atk:<3} DEF:{h.df:<3}"
f" Gold:{h.gold:<4} Pot:{h.pot} │")
print(f" │ XP: {h.xp}/{h.need():<25} │")
print(" └──────────────────────────────────┘")
def legend():
print(" Легенда: ! враг + зелье $ золото")
print(" ^ ловушка S торговец ☠ босс")
# ═══════ Боевая система ═══════
def combat(hero, mob, boss=False):
name, m_hp, m_atk, m_xp, m_gold = mob
e_hp = m_hp
tag = "БОСС" if boss else "БОЙ"
print(f"\n {'=' * 36}")
print(f" {tag}: {name}")
print(f" HP: {e_hp} Атака: {m_atk}")
print(f" {'=' * 36}")
while hero.alive() and e_hp > 0:
print(f"\n Вы: {hero.hp}/{hero.mhp}"
f" | {name}: {e_hp}/{m_hp}")
opts = f" [1] Атака [2] Зелье(x{hero.pot})"
if not boss:
opts += " [3] Бегство"
print(opts)
c = input(" > ").strip()
if c == "1":
d = max(1, rand(hero.atk - 2, hero.atk + 3))
e_hp -= d
print(f" Вы наносите {d} урона!")
if e_hp <= 0:
print(f"\n {name} повержен!")
print(f" +{m_xp} XP +{m_gold} золота")
hero.xp += m_xp
hero.gold += m_gold
if hero.try_levelup():
print(f" >>> УРОВЕНЬ {hero.lv}! "
f"HP восстановлено! <<<")
return True
elif c == "2":
if hero.pot > 0:
hero.pot -= 1
heal = rand(18, 25)
old = hero.hp
hero.hp = min(hero.mhp, hero.hp + heal)
print(f" Зелье: +{hero.hp - old} HP")
else:
print(" Зельев нет!")
continue
elif c == "3" and not boss:
if rand(1, 100) <= 40:
print(" Вы сбежали!")
return False
print(" Побег не удался!")
else:
continue
if e_hp > 0:
ed = max(1, rand(m_atk - 2, m_atk + 3) - hero.df)
hero.hp -= ed
print(f" {name} наносит {ed} урона!")
if hero.hp <= 0:
hero.hp = 0
return False
# ═══════ Основной цикл ═══════
def main():
cls()
print("""
╔══════════════════════════════════════╗
║ ПОДЗЕМЕЛЬЕ ТЁМНОГО МАГА ║
║ ~ Текстовая RPG ~ ║
╚══════════════════════════════════════╝
Вы — искатель приключений.
Пройдите 3 этажа подземелья
и победите Тёмного мага!
Управление: W вверх A влево
S вниз D вправо
""")
name = input(" Имя героя: ").strip() or "Герой"
h = 0
for ch in name:
h = (h * 131 + ord(ch)) & 0x7FFFFFFF
srand(h)
hero = Hero(name)
print(f"\n Добро пожаловать, {hero.name}!")
print(f" HP:{hero.hp} ATK:{hero.atk} "
f"DEF:{hero.df} Зелья:{hero.pot}")
pause()
floor = 1
while floor <= 3 and hero.alive():
dungeon = gen_dungeon(floor)
vis = [[False] * SZ for _ in range(SZ)]
hero.x, hero.y = 0, 0
vis[0][0] = True
cleared = False
cls()
print(f"\n {'=' * 36}")
print(f" ЭТАЖ {floor}")
print(f" {'=' * 36}")
pause()
while hero.alive() and not cleared:
cls()
show_stats(hero, floor)
print()
show_map(dungeon, hero, vis)
legend()
rt = dungeon[hero.y][hero.x]
if rt == _START:
print("\n Вы у входа. Путь назад отрезан.")
elif rt == _SEEN:
print("\n Здесь уже ничего нет.")
print("\n [W] вверх [A] влево "
"[S] вниз [D] вправо [Q] выход")
c = input(" > ").strip().upper()
dx = dy = 0
if c == "W": dy = -1
elif c == "S": dy = 1
elif c == "A": dx = -1
elif c == "D": dx = 1
elif c == "Q":
print("\n До встречи, герой!")
return
else:
continue
nx, ny = hero.x + dx, hero.y + dy
if not (0 <= nx < SZ and 0 <= ny < SZ):
print(" Стена! Туда нельзя.")
pause()
continue
hero.x, hero.y = nx, ny
vis[ny][nx] = True
rt = dungeon[ny][nx]
# ——— Обработка комнаты ———
if rt == _MOB:
base = list(MOBS[rand(0, len(MOBS) - 1)])
base[1] += (floor - 1) * 8
base[2] += (floor - 1) * 2
base[3] += (floor - 1) * 5
base[4] += (floor - 1) * 5
combat(hero, tuple(base))
if hero.alive():
dungeon[ny][nx] = _SEEN
elif rt == _POT:
n = rand(1, 2)
hero.pot += n
cls(); show_stats(hero, floor)
print(f"\n Найдено {n} зелье(й)!")
dungeon[ny][nx] = _SEEN
pause()
elif rt == _GOLD:
g = rand(15, 30) + floor * 10
hero.gold += g
cls(); show_stats(hero, floor)
print(f"\n Сундук: +{g} золота!")
dungeon[ny][nx] = _SEEN
pause()
elif rt == _TRAP:
d = rand(8, 15) + floor * 3
hero.hp = max(0, hero.hp - d)
cls(); show_stats(hero, floor)
print(f"\n ЛОВУШКА! -{d} HP!")
dungeon[ny][nx] = _SEEN
pause()
elif rt == _SHOP:
shop(hero, floor)
dungeon[ny][nx] = _SEEN
elif rt == _BOSS:
cls()
print("\n Тёмная энергия сгущается вокруг...")
pause()
boss = BOSSES[floor - 1]
won = combat(hero, boss, boss=True)
if won:
cleared = True
dungeon[ny][nx] = _SEEN
elif hero.alive():
print(" Вы отступаете к входу...")
hero.x, hero.y = 0, 0
pause()
# ——— Конец этажа ———
if hero.alive() and floor < 3:
cls()
print(f"\n {'=' * 36}")
print(f" Этаж {floor} пройден!")
heal = 15
hero.hp = min(hero.mhp, hero.hp + heal)
print(f" Отдых: +{heal} HP")
print(f" Спуск на этаж {floor + 1}...")
print(f" {'=' * 36}")
pause()
floor += 1
# ═══════ Финал ═══════
cls()
if hero.alive():
score = hero.gold + hero.lv * 100
print(f"""
╔══════════════════════════════════════╗
║ П О Б Е Д А ! ║
║ ║
║ Вы победили Тёмного мага и ║
║ очистили подземелье от тьмы! ║
║ ║
║ Счёт: {score:<6} ║
║ Уровень: {hero.lv:<3} Золото: {hero.gold:<5} ║
╚══════════════════════════════════════╝""")
else:
print(f"""
╔══════════════════════════════════════╗
║ КОНЕЦ ИГРЫ ║
║ ║
║ Вы пали на этаже {floor}... ║
║ ║
║ Уровень: {hero.lv:<3} Золото: {hero.gold:<5} ║
╚══════════════════════════════════════╝""")
print("\n Спасибо за игру!\n")
if __name__ == "__main__":
main()