This commit is contained in:
sShemet
2025-12-22 14:03:10 +05:00
commit ade2833df7
74 changed files with 42924 additions and 0 deletions

26
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/csharp/Chapter01/HelloCS/bin/Debug/net7.0/HelloCS.dll",
"args": [],
"cwd": "${workspaceFolder}/csharp/Chapter01/HelloCS",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

41
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/csharp/Chapter01/HelloCS/HelloCS.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/csharp/Chapter01/HelloCS/HelloCS.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/csharp/Chapter01/HelloCS/HelloCS.csproj"
],
"problemMatcher": "$msCompile"
}
]
}

191
GigaPong/pong.py Normal file
View File

@@ -0,0 +1,191 @@
import pygame
import sys
# Инициализация pygame
pygame.init()
# Константы
WIDTH, HEIGHT = 800, 600
PADDLE_WIDTH, PADDLE_HEIGHT = 10, 100
BALL_SIZE = 15
WHITE = (255, 255, 255)
FPS = 60
WINNING_SCORE = 10 # Основной счёт для победы
TIE_BREAK_REQUIRED_DIFFERENCE = 2 # Разница для победы в тай-брейке
AI_SPEED = 0.7 # Уровень "умения" ИИ (0.5 - очень медленный, 1.0 - идеальный)
# Создание экрана
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pong с ИИ")
clock = pygame.time.Clock()
# Функция для сброса игры
def reset_game():
return {
"player_paddle": pygame.Rect(20, HEIGHT//2 - PADDLE_HEIGHT//2, PADDLE_WIDTH, PADDLE_HEIGHT),
"ai_paddle": pygame.Rect(WIDTH - 30, HEIGHT//2 - PADDLE_HEIGHT//2, PADDLE_WIDTH, PADDLE_HEIGHT),
"ball": pygame.Rect(WIDTH//2 - BALL_SIZE//2, HEIGHT//2 - BALL_SIZE//2, BALL_SIZE, BALL_SIZE),
"ball_speed_x": 5,
"ball_speed_y": 5,
"player_score": 0,
"ai_score": 0,
"game_over": False,
"tie_break_active": False,
"win_message": None,
"show_win_screen": False,
"restart_timer": 0
}
# Состояние игры
game_state = reset_game()
# Шрифты
score_font = pygame.font.Font(None, 74)
win_font = pygame.font.Font(None, 100)
def move_ai_paddle(paddle, ball):
"""Логика ИИ: ракетка следует за мячом с задержкой"""
if ball.centerx > WIDTH/2: # Реагируем только на мяч, приближающийся к ИИ
if paddle.centery < ball.centery:
paddle.y += min(7 * AI_SPEED, ball.centery - paddle.centery)
elif paddle.centery > ball.centery:
paddle.y -= min(7 * AI_SPEED, paddle.centery - ball.centery)
# Ограничение границ экрана
paddle.y = max(0, min(HEIGHT - PADDLE_HEIGHT, paddle.y))
def calculate_ball_angle(contact_point, paddle_center):
"""Рассчитывает угол отскока мяча в зависимости от точки контакта"""
contact_diff = contact_point - paddle_center
angle_factor = contact_diff / (PADDLE_HEIGHT/2) # От -1 до +1
# Более резкий угол для ударов по краям ракетки
return angle_factor * 0.5 # 0.5 - коэффициент максимального изменения угла
# Основной цикл игры
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if not game_state["show_win_screen"]:
# Обработка управления
keys = pygame.key.get_pressed()
if keys[pygame.K_w] and game_state["player_paddle"].top > 0:
game_state["player_paddle"].y -= 7
if keys[pygame.K_s] and game_state["player_paddle"].bottom < HEIGHT:
game_state["player_paddle"].y += 7
# Движение мяча
game_state["ball"].x += game_state["ball_speed_x"]
game_state["ball"].y += game_state["ball_speed_y"]
# Отскок от стен
if game_state["ball"].top <= 0 or game_state["ball"].bottom >= HEIGHT:
game_state["ball_speed_y"] *= -1
# Проверка на гол
if game_state["ball"].left <= 0:
game_state["ai_score"] += 1
# Проверка условий победы после гола
if game_state["ai_score"] == WINNING_SCORE:
if game_state["player_score"] == WINNING_SCORE - 1:
game_state["tie_break_active"] = True
elif game_state["player_score"] <= WINNING_SCORE - 2:
game_state["win_message"] = "КОМПЬЮТЕР ПОБЕДИЛ!"
game_state["show_win_screen"] = True
game_state["game_over"] = True
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
# Проверка условий победы в тай-брейке
if game_state["tie_break_active"] and abs(game_state["ai_score"] - game_state["player_score"]) >= TIE_BREAK_REQUIRED_DIFFERENCE:
game_state["win_message"] = "КОМПЬЮТЕР ПОБЕДИЛ!"
game_state["show_win_screen"] = True
game_state["game_over"] = True
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
game_state["ball"].center = (WIDTH//2, HEIGHT//2)
game_state["ball_speed_x"] = 5
game_state["ball_speed_y"] = 5 * random.choice([-1, 1])
pygame.time.delay(500)
elif game_state["ball"].right >= WIDTH:
game_state["player_score"] += 1
# Проверка условий победы после гола
if game_state["player_score"] == WINNING_SCORE:
if game_state["ai_score"] == WINNING_SCORE - 1:
game_state["tie_break_active"] = True
elif game_state["ai_score"] <= WINNING_SCORE - 2:
game_state["win_message"] = "ТЫ ПОБЕДИЛ!"
game_state["show_win_screen"] = True
game_state["game_over"] = True
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
# Проверка условий победы в тай-брейке
if game_state["tie_break_active"] and abs(game_state["player_score"] - game_state["ai_score"]) >= TIE_BREAK_REQUIRED_DIFFERENCE:
game_state["win_message"] = "ТЫ ПОБЕДИЛ!"
game_state["show_win_screen"] = True
game_state["game_over"] = True
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
game_state["ball"].center = (WIDTH//2, HEIGHT//2)
game_state["ball_speed_x"] = -5
game_state["ball_speed_y"] = 5 * random.choice([-1, 1])
pygame.time.delay(500)
# Отскок от ракеток с учётом угла
if game_state["ball"].colliderect(game_state["player_paddle"]):
contact_point = game_state["ball"].centery
paddle_center = game_state["player_paddle"].centery
angle_change = calculate_ball_angle(contact_point, paddle_center)
game_state["ball_speed_y"] += angle_change
game_state["ball_speed_x"] *= -1.1
elif game_state["ball"].colliderect(game_state["ai_paddle"]):
contact_point = game_state["ball"].centery
paddle_center = game_state["ai_paddle"].centery
angle_change = calculate_ball_angle(contact_point, paddle_center)
game_state["ball_speed_y"] += angle_change
game_state["ball_speed_x"] *= -1.1
# Обновление позиции ИИ
if not game_state["game_over"]:
move_ai_paddle(game_state["ai_paddle"], game_state["ball"])
# Обработка события нажатия клавиши для перезапуска
if game_state["show_win_screen"]:
keys = pygame.key.get_pressed()
if any(keys): # Любая клавиша
game_state = reset_game()
# Отрисовка
screen.fill((0, 0, 0))
if not game_state["show_win_screen"]:
# Отображение счета
score_text = score_font.render(f"{game_state['player_score']} {game_state['ai_score']}", True, WHITE)
screen.blit(score_text, (WIDTH//2 - 50, 10))
# Текст тай-брейка
if game_state["tie_break_active"]:
tie_text = score_font.render("TIE BREAK!", True, WHITE)
screen.blit(tie_text, (WIDTH//2 - 100, HEIGHT//2))
# Основные элементы игры
pygame.draw.rect(screen, WHITE, game_state["player_paddle"])
pygame.draw.rect(screen, WHITE, game_state["ai_paddle"])
pygame.draw.ellipse(screen, WHITE, game_state["ball"])
pygame.draw.aaline(screen, WHITE, (WIDTH//2, 0), (WIDTH//2, HEIGHT))
else:
# Экран победы
win_text = win_font.render(game_state["win_message"], True, WHITE)
text_rect = win_text.get_rect(center=(WIDTH//2, HEIGHT//2))
screen.blit(win_text, text_rect)
pygame.display.flip()
clock.tick(FPS)

14
UltraChat.code-workspace Normal file
View File

@@ -0,0 +1,14 @@
{
"folders": [
{
"path": "."
},
{
"path": "csharp/Chapter01/HelloCS"
},
{
"path": "repos"
}
],
"settings": {}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
back-coin.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 KiB

BIN
clannad_parser/00414.scr Normal file

Binary file not shown.

BIN
clannad_parser/00416.scr Normal file

Binary file not shown.

BIN
clannad_parser/00417.scr Normal file

Binary file not shown.

BIN
clannad_parser/00418.scr Normal file

Binary file not shown.

BIN
clannad_parser/00419.scr Normal file

Binary file not shown.

BIN
clannad_parser/00420.scr Normal file

Binary file not shown.

BIN
clannad_parser/00421.scr Normal file

Binary file not shown.

BIN
clannad_parser/00422.scr Normal file

Binary file not shown.

BIN
clannad_parser/00423.scr Normal file

Binary file not shown.

BIN
clannad_parser/00424.scr Normal file

Binary file not shown.

BIN
clannad_parser/00425.scr Normal file

Binary file not shown.

BIN
clannad_parser/00429.scr Normal file

Binary file not shown.

BIN
clannad_parser/02426.scr Normal file

Binary file not shown.

BIN
clannad_parser/02509.scr Normal file

Binary file not shown.

BIN
clannad_parser/04425.scr Normal file

Binary file not shown.

BIN
clannad_parser/04503.scr Normal file

Binary file not shown.

BIN
clannad_parser/04508.scr Normal file

Binary file not shown.

BIN
clannad_parser/05424.scr Normal file

Binary file not shown.

BIN
clannad_parser/05430.scr Normal file

Binary file not shown.

BIN
clannad_parser/07400.scr Normal file

Binary file not shown.

BIN
clannad_parser/07401.scr Normal file

Binary file not shown.

BIN
clannad_parser/07500.scr Normal file

Binary file not shown.

BIN
clannad_parser/07600.scr Normal file

Binary file not shown.

74
clannad_parser/parser.py Normal file
View File

@@ -0,0 +1,74 @@
import sys
def parse_text_command(data, pos):
# Читаем параметры в Little Endian
text_id = int.from_bytes(data[pos:pos+2], 'little')
voice_id = int.from_bytes(data[pos+2:pos+6], 'little')
pos += 6
# Собираем текст до 0000
text_bytes = bytearray()
while pos + 2 <= len(data):
char_bytes = data[pos:pos+2]
if char_bytes == b'\x00\x00':
break
text_bytes.extend(char_bytes)
pos += 2
# Декодируем UTF-16LE текст
text = text_bytes.decode('utf-16le', errors='replace')
total_size = 8 + len(text_bytes) + 2 # 8 байт заголовка + текст + 0000
return f"TextID: {text_id}, VoiceID: {voice_id}, Text: {text}", total_size
# База команд (идентификаторы в Big Endian)
command_db = {
0x1401: {
"name": "PlayBGM",
"size": 2,
"handler": lambda data, pos: (f"BGM Track: {int.from_bytes(data[pos:pos+2], 'little')}", 2)
},
0x0A00: {
"name": "ShowText",
"size": 8,
"handler": parse_text_command
}
}
def parse_script(file_path):
with open(file_path, 'rb') as f:
data = f.read()
pos = 0
output = []
while pos + 2 <= len(data):
# Определяем команду в Big Endian
cmd = int.from_bytes(data[pos:pos+2], 'big')
if cmd in command_db:
cmd_info = command_db[cmd]
result, size = cmd_info["handler"](data, pos + 2)
output.append(f"[0x{pos:08X}][0x{cmd:04X}] {cmd_info['name']}: {result}")
pos += 2 + size # 2 байта команды + размер данных
# Выравнивание по 4 байтам
while pos % 4 != 0:
pos += 1
else:
# output.append(f"[0x{pos:08X}][0x{cmd:04X}] UNKNOWN COMMAND")
pos += 2
# Сохраняем в файл
with open("script" + file_path + ".txt", "w", encoding="utf-8") as f:
f.write("\n".join(output))
return output
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python parser.py <script.bin>")
sys.exit(1)
results = parse_script(sys.argv[1])
for line in results:
print(line)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

13
config.ini Normal file
View File

@@ -0,0 +1,13 @@
[Telegram]
bot_secret = 6454033742:AAFj2rUoVb2jJ_Lew4eiIecdr7s7xbrqeNU
enabled = 1
[Youtube]
video_id = coYw-eVU0Ks
[Twitch]
channel = wanderbraun
[Alerts]
app_id = 12554
api_key = 7P95Bm7StPjosxSoD9GVQRykqy9J61MdiNn9sdMP

14
govno/async_test.py Normal file
View File

@@ -0,0 +1,14 @@
# First we need the asyncio library
import asyncio
# Then we need a loop to work with
loop = asyncio.get_event_loop()
# We also need something to run
async def main():
for char in 'Hello, world!\n':
print(char, end='', flush=True)
await asyncio.sleep(0.5)
# Then, we need to run the loop with a task
loop.run_until_complete(main())

29
govno/import.blade.php Normal file
View File

@@ -0,0 +1,29 @@
@extends('layout')
@section('title')Главная страница@endsection
@section('content')
<div class="bg-dark p-5 rounded">
@auth
<p class="lead">{{ Auth::user()->name }}, Вы залогинены. Поздравляем.</p>
@endauth
</div>
<br>
<p>Дорогие друзья!</p>
<p>Спасибо, что посетили эту страницу.</p>
<p>Если вы залогинены, то можете просматривать книги и оставлять комментарии как обычный пользователь.</p>
<p>Если Администратор включил вашей учётной записи опцию "сотрудник", то можете редактировать и добавлять книги и категории.</p>
<p>Вы можете войти как Администратор, используя admin@domain.com / password</p>
<p>Или просто выбрать нужную категорию книг:</p>
<ul>
@foreach ($cats as $el)
<li><a class="nav-link px-2 text-white" href={{ route('categories.show', $el->slug) }}>{{ $el->title }}</a></li>
@endforeach
</ul>
@endsection

1
govno/messages.json Normal file
View File

@@ -0,0 +1 @@
[{"id": 10921, "type": "tg", "date": "2023-01-22T11:57:37+05:00", "sendr": "\u0410\u0440\u0442\u0451\u043c \u0410\u0440\u0442\u0451\u043c\u043e\u0432", "msg": "\u041a\u0440\u0443\u0442\u043e\u0439 \u0441\u0442\u0440\u0438\u043c, \u0440\u0435\u0441\u043f\u0435\u043a\u0442"}, {"id": 10922, "type": "tg", "date": "2023-01-22T12:08:24+05:00", "sendr": "\u0418\u0433\u043e\u0440\u044c \u0413\u043e\u0440\u043d\u043e\u0441\u0442\u0430\u0435\u0432", "msg": "\ud83d\udcaa"}, {"id": 10923, "type": "tg", "date": "2023-01-22T12:49:31+05:00", "sendr": "\u0414\u0456\u043c\u0430", "msg": "\u0421\u043f\u0430\u0441\u0438\u0431\u043e, \u0434\u043e\u0436\u0434\u0430\u043b\u0441\u044f."}, {"id": 10924, "type": "tg", "date": "2023-01-22T12:59:13+05:00", "sendr": "Heliand", "msg": "\u041e! \u042f \u043f\u043e\u043c\u043d\u044e \u044d\u0442\u043e\u0442 \u0434\u0435\u043d\u044c!"}, {"id": 10926, "type": "tg", "date": "2023-01-22T13:19:42+05:00", "sendr": "Taburet", "msg": "\u0416\u0434\u0451\u043c ep"}, {"id": 11026, "type": "tg", "date": "2023-01-25T12:06:07+05:00", "sendr": "\u041c\u0438\u0445\u0430\u0438\u043b \u0410\u0440\u0437\u044f\u0435\u0432", "msg": "\u0428\u0435\u043c\u0435\u0442, \u0440\u0430\u0434\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0430 \u043f\u043e\u0441\u043b\u0435 \u0435\u0440 \u0437\u0430\u0439\u043c\u0435\u0448\u044c\u0441\u044f \u0438\u043d\u044b\u043c\u0438 \u0442\u0430\u0439\u0442\u043b\u0430\u043c\u0438 \u0430\u0442\u043b\u0443\u0441 \u043d\u0430 \u043f\u04411?"}, {"id": 11027, "type": "tg", "date": "2023-01-25T15:40:19+05:00", "sendr": "P2 IS EP RUS", "msg": "\u041f\u043e\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0435\u0449\u0451 \u043f2 \u0434\u043b\u044f psp, \u0442\u0430\u043c \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u044b :)"}, {"id": 11051, "type": "tg", "date": "2023-01-26T15:01:22+05:00", "sendr": "\u041c\u0438\u0445\u0430\u0438\u043b \u0410\u0440\u0437\u044f\u0435\u0432", "msg": "\u041d\u0443 \u0443 \u0432\u0441\u0435\u0445 \u0438\u0445 \u043f\u0441\u043f \u0442\u0430\u0439\u0442\u043b\u043e\u0432 \u0432\u0440\u043e\u0434\u0435 \u043a\u0430\u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u043b\u0438\u0437\u043a\u0430\u044f. \u0414\u0430\u0436\u0435 \u0443 \u0434\u0435\u0432\u0438\u043b\u0441\u0430\u043c\u043c\u043e\u043d\u0435\u0440\u0430."}, {"id": 11052, "type": "tg", "date": "2023-01-26T15:01:37+05:00", "sendr": "\u041c\u0438\u0445\u0430\u0438\u043b \u0410\u0440\u0437\u044f\u0435\u0432", "msg": "\u041a\u0441\u0442\u0430\u0442\u0438, \u0428\u0435\u043c\u0435\u0442. \u0421\u043b\u0430\u0431\u043e \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u0441\u0430\u043c\u043c\u043e\u043d\u0435\u0440\u0430 \u0440\u0430\u043d\u044c\u0448\u0435 \u0418\u0432\u0430\u043a\u0443\u0440\u044b?"}]

39
govno/messages_yt.json Normal file
View File

@@ -0,0 +1,39 @@
[
{
"author": {
"badgeUrl": "",
"type": "",
"isVerified": false,
"isChatOwner": false,
"isChatSponsor": false,
"isChatModerator": false,
"channelId": "UCUM4JfsjCQW25ZtDYq75Wkw",
"channelUrl": "http://www.youtube.com/channel/UCUM4JfsjCQW25ZtDYq75Wkw",
"name": "さんなー",
"imageUrl": "https://yt4.ggpht.com/ytc/AL5GRJVIdNw2w_SquPxEXWws9mBggNNUNWTGAb1WeHok=s64-c-k-c0x00ffffff-no-rj"
},
"type": "textMessage",
"id": "CjsKGkNKem5tWjdkM2Z3Q0ZjRUJmUW9kV080SklBEh1DT0cxMmVDNDNmd0NGYUpMblFrZDQtWUtEZy03NA%3D%3D",
"timestamp": 1674478157776,
"elapsedTime": "",
"datetime": "2023-01-23 17:49:17",
"message": "雪の日出勤には危険手当てだせ:megaphone::rabbit2:",
"messageEx": [
"雪の日出勤には危険手当てだせ",
{
"id": "📣",
"txt": ":megaphone:",
"url": "https://www.youtube.com/s/gaming/emoji/0f0cae22/emoji_u1f4e3.svg"
},
{
"id": "🐇",
"txt": ":rabbit2:",
"url": "https://www.youtube.com/s/gaming/emoji/0f0cae22/emoji_u1f407.svg"
}
],
"amountValue": 0,
"amountString": "",
"currency": "",
"bgColor": 0
}
]

49
govno/mychat.py Normal file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/python
import configparser
import json
from telethon import TelegramClient
from telethon.errors import SessionPasswordNeededError
# Reading Configs
config = configparser.ConfigParser()
config.read("E:/Games/cgi-bin/config.ini")
# Setting configuration values
api_id = config['Telegram']['api_id']
api_hash = config['Telegram']['api_hash']
api_hash = str(api_hash)
phone = config['Telegram']['phone']
username = config['Telegram']['username']
# Create the client and connect
client = TelegramClient(username, api_id, api_hash)
client.start()
print("Client Created")
# Ensure you're authorized
""" if not client.is_user_authorized():
client.send_code_request(phone)
try:
client.sign_in(phone, input('Enter the code: '))
except SessionPasswordNeededError:
client.sign_in(password=input('Password: ')) """
print('Content-type:text/html')
print('\r\n\r\n')
print('<html>')
print('<head>')
print('<title>Hello World - First CGI Program</title>')
print('</head>')
print('<body>')
print('<h2>Hello World! This is my first CGI program</h2>')
print(api_hash)
print('</body>')
print('</html>')

7
govno/pytchat___.py Normal file
View File

@@ -0,0 +1,7 @@
import pytchat
import time
chat = pytchat.create(video_id="uIx8l2xlYVY")
while chat.is_alive():
print(chat.get().json())
time.sleep(5)

7
govno/readfile.php Normal file
View File

@@ -0,0 +1,7 @@
<?
$file = 'D:\Games\Tecmo Cup - Football Game (Europe).nes';
header('Content-Type: application/x-binary');
header('Content-Disposition: attachment; filename="govno.nes');
print(' GOVNO ');
//readfile($file);

16
govno/server.conf Normal file
View File

@@ -0,0 +1,16 @@
description "Example JSON HTTP server"
author "nitaku - matteo.abrate@gmail.com"
start on started mountall
stop on shutdown
respawn
respawn limit 99 5
script
exec sudo -u www-data /usr/bin/python /data/examples/python_minimal_http/server.py 8009 >> /dev/null 2>> /dev/null
end script
post-start script
end script

55
govno/server.py Normal file
View File

@@ -0,0 +1,55 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
#import SocketServer
import json
import cgi
class Server(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_HEAD(self):
self._set_headers()
# GET sends back a Hello world message
def do_GET(self):
self._set_headers()
self.wfile.write(json.dumps({'hello': 'world', 'received': 'ok'}).encode('utf-8'))
# self.wfile.write('GET request for {}'.format(self.path).encode('utf-8'))
# POST echoes the message adding a JSON field
def do_POST(self):
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
# refuse to receive non-json content
if ctype != 'application/json':
self.send_response(400)
self.end_headers()
return
# read the message and convert it into a python dictionary
length = int(self.headers.getheader('content-length'))
message = json.loads(self.rfile.read(length))
# add a property to the object, just to mess with data
message['received'] = 'ok'
# send the message back
self._set_headers()
self.wfile.write(json.dumps(message))
def run(server_class=HTTPServer, handler_class=Server, port=8008):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print('Starting httpd on port %d...' % port)
httpd.serve_forever()
if __name__ == "__main__":
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()

BIN
govno/sshemet.session Normal file

Binary file not shown.

View File

@@ -0,0 +1,32 @@
import pytchat
import time
import json
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
if isinstance(o, bytes):
return list(o)
return json.JSONEncoder.default(self, o)
chat = pytchat.create(video_id="coYw-eVU0Ks")
while chat.is_alive():
#msg = chat.get().json()
'''with open('E:/Games/cgi-bin/messages_yt.json', 'w') as outfile:
json.dump(msg, outfile, cls=DateTimeEncoder)
break'''
time.sleep(2)
for c in chat.get().items:
#print(c.json())
print(c.author.name + ': ' + c.message)
'''
# Each chat item can also be output in JSON format.
for c in chat.get().items:
print(c.json())
'''

32
govno/yt.py Normal file
View File

@@ -0,0 +1,32 @@
import pytchat
import time
import json
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
if isinstance(o, bytes):
return list(o)
return json.JSONEncoder.default(self, o)
chat = pytchat.create(video_id="coYw-eVU0Ks")
while chat.is_alive():
#msg = chat.get().json()
'''with open('E:/Games/cgi-bin/messages_yt.json', 'w') as outfile:
json.dump(msg, outfile, cls=DateTimeEncoder)
break'''
time.sleep(2)
for c in chat.get().items:
#print(c.json())
print(c.author.name + ': ' + c.message)
'''
# Each chat item can also be output in JSON format.
for c in chat.get().items:
print(c.json())
'''

343
huy.py Normal file
View File

@@ -0,0 +1,343 @@
#Alerts autorization API
#https://www.donationalerts.com/oauth/authorize?redirect_uri=http://127.0.0.1/logined&response_type=code&scope=oauth-donation-index&client_id=12552
#http://127.0.0.1/logined?code=def5020000c8c717bd3993ac0bc29b903eb910fcabac108c2ac9dcaf4c3858b8ba61057915c4a2dd2599b83bebe509a2c771e2a3f4f2581d1db3a6ef5f01331aefdd8956610115e0ec0a6b1292cce0e285c5d38400ff83f79f02f402c2c73f2bde29214728229f2a2580fd36cc269bdbd75d8d2bade73eb8baa04844e0e437e5a1b856abfd4309580b6999d92d4529774289b409a72d81aada4ce4f3164febdab347372c2f9ea6a2038d9fbfef6c2942328b6187c4e6967eaa52530a6183cb1529bcee61279e43c176fcfff291d6f5d410c3648bf2f7497370ccf1bbf21298148f42e93fbcf9821ed307b97070cda02942c4ee7a552e61d3501718d8895da0631745cb3988d37fd73770d9112e56e84b431e80463efa21d6b73a59b5c176ad4adb55a85ff24e9981765ae48c2431e068f77b2982327b4e7dc9535c3045fb8ad6abab2167fd1dcf7144f5752dc517392822d509d7f342266ec24acfac1f0b6c3cb3beb9769168a5a4167cf067c27eabebf0fe79bdd6e59cf6
#https://www.donationalerts.com/oauth/token?grant_type=authorization_code&client_id=12552&client_secret=EwOBapII6syZy0k9z7AkEVhtUNDRe1VzTHW4AcmZ&redirect_uri=http://127.0.0.1/logined?code=def5020000c8c717bd3993ac0bc29b903eb910fcabac108c2ac9dcaf4c3858b8ba61057915c4a2dd2599b83bebe509a2c771e2a3f4f2581d1db3a6ef5f01331aefdd8956610115e0ec0a6b1292cce0e285c5d38400ff83f79f02f402c2c73f2bde29214728229f2a2580fd36cc269bdbd75d8d2bade73eb8baa04844e0e437e5a1b856abfd4309580b6999d92d4529774289b409a72d81aada4ce4f3164febdab347372c2f9ea6a2038d9fbfef6c2942328b6187c4e6967eaa52530a6183cb1529bcee61279e43c176fcfff291d6f5d410c3648bf2f7497370ccf1bbf21298148f42e93fbcf9821ed307b97070cda02942c4ee7a552e61d3501718d8895da0631745cb3988d37fd73770d9112e56e84b431e80463efa21d6b73a59b5c176ad4adb55a85ff24e9981765ae48c2431e068f77b2982327b4e7dc9535c3045fb8ad6abab2167fd1dcf7144f5752dc517392822d509d7f342266ec24acfac1f0b6c3cb3beb9769168a5a4167cf067c27eabebf0fe79bdd6e59cf6
import configparser
import random
import keyboard
import json
import os
import sys
import threading
import asyncio
import socket
import emoji
from datetime import date, datetime, timedelta
import time
import tzlocal
from zoneinfo import *
from http.server import BaseHTTPRequestHandler, HTTPServer
import pytchat
import telegram
from donationalerts import DonationAlertsAPI, Scope
from urllib import parse
sys.path.append('twitchchatirc')
import twitch
# Reading Configs
config = configparser.ConfigParser()
config.read("E:/Games/cgi-bin/config.ini")
alerts = DonationAlertsAPI(
config['Alerts']['app_id'],
config['Alerts']['api_key'],
"http://127.0.0.1:8008/login",
[
Scope.OAUTH_USER_SHOW,
Scope.OAUTH_DONATION_INDEX
]
)
# some functions to parse json date
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
if isinstance(o, bytes):
return list(o)
return json.JSONEncoder.default(self, o)
chat = pytchat.create(video_id=config['Youtube']['video_id'])
# twitchConn = twitch_chat_irc.TwitchChatIRC()
TGenabled = config['Telegram']['enabled']
if TGenabled:
bot = telegram.Bot(config['Telegram']['bot_secret']) #our nice Telegram eikichiBot
all_comments = []
all_old_comments = []
is_changed = False
yt_comments = []
tg_comments = []
tw_comments = []
alerts_comments = []
ytJSON = []
overallcount = 0
access_token = '' #alerts_access_token
LOCAL_TIMEZONE = tzlocal.get_localzone_name()
tz = ZoneInfo('Asia/Yekaterinburg')
#gett DonationAlerts
def get_alerts():
global access_token
global alerts_comments
alerts_comments = []
if not access_token:
print('Waiting for Alerts auth...')
return
repr(access_token)
al = alerts.donations.get(access_token.access_token)
#print(al.items)
for item in al.items:
u = item.username if item.username else 'Аноним'
m = item.message if item.message else ' --- '
amount = format(item.amount, '.2f') if item.amount != int(item.amount) else int(item.amount) #Если без десятичных, то удаляем их
amount = f"<br>{amount} {item.currency}"
#dt = item.created_at(ZoneInfo('UTC'))
if item.is_shown:
dt = datetime.fromisoformat(item.shown_at) + timedelta(hours=5)
else:
continue
dtM = datetime.now() - timedelta(days=30)
if dt > dtM: #Донаты за последний месяц...
dt = dt.replace().astimezone(tz)
comm = dict({'id': item.id, 'type': 'donate', 'amount': amount, 'date': dt , 'sendr': u, 'msg': emoji.emojize(m)})
alerts_comments.append(comm)
#Get telegram comments...
async def get_tg():
global tg_comments
tg_comments = []
async with bot:
try:
updates = await bot.get_updates(allowed_updates=['message', 'edited_message'], timeout=None)
except telegram.error.TimedOut:
print('TG connection timeout 2')
time.sleep(5)
except:
print('TG connection timeout...')
else:
for upd in updates:
msg = upd.message
if upd.edited_message:
msg = upd.edited_message
#tg_comments = list(filter(lambda x: (hasattr(msg,'message_id') & x['id'] != msg.message_id), tg_comments)) #если это сообщение редактирования, то удаляем все предыдущие
if not hasattr(msg, 'text'):
continue
if not msg.text:
continue
sendr = msg.from_user.first_name
if msg.from_user.last_name:
sendr = sendr + ' ' + msg.from_user.last_name
if sendr == "Group":
sendr = 'Админ'
#corricting TG time +timezone!!!!3
netdatetime = msg.date.replace(tzinfo=tz)
#print (repr(dt))
comm = dict({'id': msg.message_id, 'type': 'tg', 'date': netdatetime, 'sendr': sendr, 'msg': msg.text})
tg_comments.append(comm)
#Get youtube new comments...
def get_yt():
global yt_comments
global chat
itms = chat.get()
if not hasattr(itms, 'items'):
print('YT has no items attribute! (Empty?). Reconnecting...') #Catching YT empty object exception
time.sleep(5)
chat = pytchat.create(video_id=config['Youtube']['video_id']) #Reconnect YT
return
for c in itms.items:
dt = datetime.fromisoformat(c.datetime).replace(tzinfo=tz)
comm = dict({'id': c.id, 'type': 'yt', 'date': dt , 'sendr': c.author.name, 'msg': emoji.emojize(c.message)})
yt_comments.append(comm)
def makeJSONObject(): #we are parsing TG and YT
global all_comments
global yt_comments
global tg_comments
global tw_comments
global alerts_comments
global all_old_comments
global overallcount
global twitch_socket
tw_comments = twitch_socket.all_messages
get_yt() #Get YouTube
try:
get_alerts() #Get Donations
except:
print('ALERTS TIMEOUNT BLYAT!')
if TGenabled: #& int(time.time()) % 4 == 0:
try:
asyncio.run(get_tg()) #Get Telegram Comments
#print('')
except:
print('TG TIMEOUNT BLYAT!')
time.sleep(2)
if len(yt_comments) > 15:
yt_comments = yt_comments[-15:]
if len(tg_comments) > 15:
tg_comments = tg_comments[-15:]
if len(tw_comments) > 15:
tw_comments = tw_comments[-15:]
dt = datetime.now(ZoneInfo('UTC'))
dt = dt.replace().astimezone(tz)
hello_txt = dict({'id': random.randint(100000, 999999), 'type': 'hello', 'date': dt, 'sendr': 'Eikichi-bot', 'msg': '🔥 Спасибо всем на стриме за интерес к переводу и поддержку! 🔥'})
if int(time.time()) % 600 == 0: #Выдавать сообщение каждые 45 минут
all_comments.append(hello_txt)
updateAllComments(hello_txt)
overallcount += 1
print(datetime.now().strftime('%H:%M:%S') + ' TG And YouTube checked.... ' + str(len(all_comments)) + ' elements (' + str(overallcount) + ')')
#------------------------------------------------------------
def sortdate(e):
return e['date']
def updateAllComments(hello):
global all_comments
global tg_comments
global yt_comments
global tw_comments
global alerts_comments
for i in tg_comments:
if not i in all_comments:
all_comments.append(i)
for i in yt_comments:
if not i in all_comments:
all_comments.append(i)
for i in tw_comments:
if not i in all_comments:
all_comments.append(i)
for i in alerts_comments:
if not i in all_comments:
all_comments.append(i)
all_comments.sort(key=sortdate) #Sort objects by time
all_comments = all_comments[-150:] #Пул сообщений 150
# searchAndAddHello(hello)
def searchAndAddHello(hello):
global all_comments
for i in all_comments:
if i['type'] == 'hello':
return True
all_comments.append(hello)
return False
def printAllComments():
global all_comments
print('----------')
print(all_comments)
print('----------')
class Server(BaseHTTPRequestHandler):
global access_token
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
def do_HEAD(self):
self._set_headers()
def log_message(self, format, *args): #Disable server log!!!
return
def do_GET(self):
global access_token
if self.path == '/alert_auth':
self.send_response(301)
self.send_header('Location', alerts.authorize.login())
self.end_headers()
if self.path.startswith('/login'):
url = dict(parse.parse_qsl(parse.urlsplit(self.path).query))
code = url['code']
access_token = alerts.authorize.get_access_token(code)
print("Access token Success!")
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write(b'Access token success!')
return
self._set_headers()
self.wfile.write(json.dumps(all_comments, cls=DateTimeEncoder).encode('utf-8'))
def run(server_class=HTTPServer, handler_class=Server, port=8008):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print('Starting httpd on http://127.0.0.1:%d ...' % port)
print()
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
sys.exit(1)
print()
print('--- TelegramYoutubeTwitch Simple Chat parser --- Sergey Shemet (C) 2025 ---')
print()
print('Please, autorize your DonationAlerts at http://127.0.0.1:8008/alert_auth')
print('...Hold Ctrl-Alt-Shift-C for exit and C to clear console...')
twitch_socket = twitch.TwitchChatIRC(config['Twitch']['channel'])
# init the thread as daemon for HTTPServer
d = threading.Thread(target=run, name='Daemon')
d.daemon = True
d.start()
# init twitch socket reader
tw = threading.Thread(target=twitch_socket.listen, name='twitchirc')
tw.daemon = True
tw.start()
print('Starting YT DA TG subsystems...')
polTime = 2 # Secs to run check routine
while True:
if keyboard.is_pressed('Ctrl+Shift+Alt+c'):
sys.exit(1)
if keyboard.is_pressed('Ctrl+Shift+Alt+z'):
printAllComments()
if keyboard.is_pressed('c'):
os.system("cls")
thisSecond = int(time.time())
if thisSecond % polTime == 0: # every X seconds
makeJSONObject()
time.sleep(1)

378
huySeek.py Normal file
View File

@@ -0,0 +1,378 @@
import configparser
import random
import keyboard
import json
import os
import sys
import threading
import asyncio
from datetime import datetime, timedelta
import time
from zoneinfo import ZoneInfo
from http.server import BaseHTTPRequestHandler, HTTPServer
import pytchat
import telegram
from donationalerts import DonationAlertsAPI, Scope
from urllib import parse
import emoji
sys.path.append('twitchchatirc')
import twitch
# ====================
# Конфигурация
# ====================
class Config:
def __init__(self):
self.config = configparser.ConfigParser()
self.config.read("config.ini")
# Настройки
self.timezone = ZoneInfo('Asia/Yekaterinburg')
self.poll_interval = 2 # seconds
self.max_comments_per_source = 15
self.max_total_comments = 150
self.hello_message_interval = 600 # seconds
# API keys
self.alerts_app_id = self.config['Alerts']['app_id']
self.alerts_api_key = self.config['Alerts']['api_key']
self.telegram_enabled = self.config['Telegram']['enabled']
self.telegram_bot_secret = self.config['Telegram']['bot_secret']
self.youtube_video_id = self.config['Youtube']['video_id']
self.twitch_channel = self.config['Twitch']['channel']
# ====================
# Модели данных
# ====================
class Comment:
def __init__(self, comment_id, comment_type, sender, message, date, amount=None):
self.id = comment_id
self.type = comment_type
self.sender = sender
self.message = message
self.date = date
self.amount = amount
def to_dict(self):
return {
'id': self.id,
'type': self.type,
'sender': self.sender,
'message': emoji.emojize(self.message),
'date': self.date,
'amount': self.amount
}
# ====================
# Сервисы
# ====================
class DonationAlertsService:
def __init__(self, config):
self.config = config
self.api = DonationAlertsAPI(
config.alerts_app_id,
config.alerts_api_key,
"http://127.0.0.1:8008/login",
[Scope.OAUTH_USER_SHOW, Scope.OAUTH_DONATION_INDEX]
)
self.access_token = None
def get_donations(self):
if not self.access_token:
print('Waiting for Alerts auth...')
return []
try:
donations = self.api.donations.get(self.access_token.access_token)
return self._process_donations(donations.items)
except Exception as e:
print(f'Alerts error: {str(e)}')
return []
def _process_donations(self, items):
result = []
for item in items:
if not item.is_shown:
continue
sender = item.username or 'Аноним'
message = item.message or '---'
amount = self._format_amount(item.amount, item.currency)
date = self._parse_donation_date(item.shown_at)
result.append(
Comment(
comment_id=item.id,
comment_type='donate',
sender=sender,
message=message,
date=date,
amount=amount
)
)
return result
def _format_amount(self, amount, currency):
if amount != int(amount):
return f"{format(amount, '.2f')} {currency}"
return f"{int(amount)} {currency}"
def _parse_donation_date(self, date_str):
dt = datetime.fromisoformat(date_str).astimezone(self.config.timezone)
# Фильтр донатов за последний месяц
if dt > datetime.now(self.config.timezone) - timedelta(days=30):
return dt
return None
class TelegramService:
def __init__(self, config):
self.config = config
self.bot = telegram.Bot(config.telegram_bot_secret) if config.telegram_enabled else None
async def get_messages(self):
if not self.bot:
return []
try:
updates = await self.bot.get_updates(
allowed_updates=['message', 'edited_message'],
timeout=None
)
return self._process_updates(updates)
except Exception as e:
print(f'Telegram error: {str(e)}')
return []
def _process_updates(self, updates):
messages = []
for upd in updates:
msg = upd.edited_message if upd.edited_message else upd.message
if not hasattr(msg, 'text') or not msg.text:
continue
sender = self._get_sender_name(msg.from_user)
date = msg.date.replace(tzinfo=self.config.timezone)
messages.append(
Comment(
comment_id=msg.message_id,
comment_type='tg',
sender=sender,
message=msg.text,
date=date
)
)
return messages
def _get_sender_name(self, user):
if user.first_name and user.last_name:
return f"{user.first_name} {user.last_name}"
return user.first_name or "Админ"
class YouTubeService:
def __init__(self, config):
self.config = config
self.chat = pytchat.create(video_id=config.youtube_video_id)
def get_messages(self):
try:
items = self.chat.get()
if not hasattr(items, 'items'):
print('YT reconnecting...')
self.chat = pytchat.create(video_id=self.config.youtube_video_id)
return []
return self._process_messages(items.items)
except Exception as e:
print(f'YouTube error: {str(e)}')
return []
def _process_messages(self, items):
messages = []
for item in items:
date = datetime.fromisoformat(item.datetime).replace(tzinfo=self.config.timezone)
messages.append(
Comment(
comment_id=item.id,
comment_type='yt',
sender=item.author.name,
message=item.message,
date=date
)
)
return messages
class TwitchService:
def __init__(self, config):
self.config = config
self.socket = twitch.TwitchChatIRC(config.twitch_channel)
def get_messages(self):
# Предполагаем, что сообщения добавляются в self.socket.all_messages
# в отдельном потоке (как в оригинальном коде)
return getattr(self.socket, 'all_messages', [])
# ====================
# Ядро приложения
# ====================
class ChatAggregator:
def __init__(self):
self.config = Config()
self.services = {
'alerts': DonationAlertsService(self.config),
'telegram': TelegramService(self.config),
'youtube': YouTubeService(self.config),
'twitch': TwitchService(self.config)
}
self.comments = []
self.lock = threading.Lock()
self.hello_message = Comment(
comment_id=random.randint(100000, 999999),
comment_type='hello',
sender='Eikichi-bot',
message='🔥 Спасибо всем на стриме за интерес к переводу и поддержку! 🔥',
date=datetime.now(self.config.timezone)
)
def run(self):
# Запуск сервера в отдельном потоке
server_thread = threading.Thread(target=self._run_server)
server_thread.daemon = True
server_thread.start()
# Запуск Twitch в отдельном потоке
twitch_thread = threading.Thread(target=self.services['twitch'].socket.listen)
twitch_thread.daemon = True
twitch_thread.start()
print('System started. Press Ctrl+Shift+Alt+C to exit.')
# Главный цикл
while True:
if keyboard.is_pressed('Ctrl+Shift+Alt+C'):
sys.exit(0)
if int(time.time()) % self.config.poll_interval == 0:
self.update_comments()
time.sleep(1)
def update_comments(self):
# Сбор сообщений со всех сервисов
new_comments = []
# DonationAlerts
new_comments.extend(self.services['alerts'].get_donations())
# YouTube
new_comments.extend(self.services['youtube'].get_messages())
# Telegram
if self.config.telegram_enabled:
try:
telegram_comments = asyncio.run(self.services['telegram'].get_messages())
new_comments.extend(telegram_comments)
except Exception as e:
print(f'Telegram error: {e}')
# Twitch
new_comments.extend(self.services['twitch'].get_messages())
# Добавление приветственного сообщения
if int(time.time()) % self.config.hello_message_interval == 0:
new_comments.append(self.hello_message)
# Обновление основного списка комментариев
with self.lock:
# Добавление новых уникальных комментариев
existing_ids = {c.id for c in self.comments}
self.comments.extend(
c for c in new_comments
if c.id not in existing_ids
)
# Сортировка по дате
self.comments.sort(key=lambda x: x.date)
# Ограничение общего количества
self.comments = self.comments[-self.config.max_total_comments:]
print(f"{datetime.now().strftime('%H:%M:%S')} Updated. Total comments: {len(self.comments)}")
def get_comments_json(self):
with self.lock:
return json.dumps(
[c.to_dict() for c in self.comments],
cls=DateTimeEncoder,
ensure_ascii=False
)
def _run_server(self):
class Handler(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self.aggregator = kwargs.pop('aggregator')
super().__init__(*args, **kwargs)
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
def do_GET(self):
if self.path == '/alert_auth':
self.send_response(301)
self.send_header('Location', self.aggregator.services['alerts'].api.authorize.login())
self.end_headers()
elif self.path.startswith('/login'):
self._handle_alerts_login()
else:
self._set_headers()
self.wfile.write(self.aggregator.get_comments_json().encode('utf-8'))
def _handle_alerts_login(self):
url = dict(parse.parse_qsl(parse.urlsplit(self.path).query))
code = url.get('code')
if code:
try:
self.aggregator.services['alerts'].access_token = (
self.aggregator.services['alerts'].api.authorize.get_access_token(code)
)
print("DonationAlerts authorized successfully!")
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b'Authorization successful! You can close this page.')
except Exception as e:
print(f'Alerts auth error: {str(e)}')
self.send_error(500, 'Authorization failed')
else:
self.send_error(400, 'Missing code parameter')
def log_message(self, format, *args):
return
server_address = ('', 8008)
httpd = HTTPServer(server_address, lambda *args: Handler(*args, aggregator=self))
print(f'Starting HTTP server on port 8008...')
httpd.serve_forever()
# ====================
# Вспомогательные классы
# ====================
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
return super().default(o)
# ====================
# Точка входа
# ====================
if __name__ == '__main__':
print('\n--- Telegram/YouTube/Twitch Chat Aggregator ---\n')
print('For DonationAlerts authorization visit: http://127.0.0.1:8008/alert_auth')
print('Press Ctrl+Shift+Alt+C to exit\n')
aggregator = ChatAggregator()
aggregator.run()

125
index.html Normal file
View File

@@ -0,0 +1,125 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>template</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Condensed">
<style>
body {
background-color: #494949;
display: flex;
align-items: center;
justify-content: center;
align-content: flex-end;
font-family: "Roboto Condensed", sans-serif;
font-size: 1em;
letter-spacing: 0.1px;
color: lighter;
text-rendering: optimizeLegibility;
text-shadow: 1px 1px 1px rgba(0,0,0,0.004);
-webkit-font-smoothing: antialiased;
}
#chatwin {
/* color: white; */
height: 100%;
min-width: 150px;
max-width: 500px;
display: flex;
flex-direction: column;
}
.chatRow {
display: flex;
flex-direction: row;
margin-bottom: 1px;
}
.nameline {
color: white;
padding: 5px;
width: 25%;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
flex-direction: column;
vertical-align: auto;
}
.yt {
background-image: url('data:image/svg+xml,<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><g fill="%239C92AC" fill-opacity="0.4" fill-rule="evenodd"><path d="M0 40L40 0H20L0 20M40 40V20L20 40"/></g></svg>');
background-color: #E53935A0;
}
.tg {
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><g fill-rule="evenodd"><g fill="%239C92AC" fill-opacity="0.4"><path opacity=".5" d="M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z"/><path d="M6 5V0H5v5H0v1h5v94h1V6h94V5H6z"/></g></g></svg>');
background-color: #2196F3A0;
}
.tw {
background-color: #6034b2A0 ;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='60' viewBox='0 0 20 12'><g fill-rule='evenodd'><g id='charlie-brown' fill='%236441a5' fill-opacity='0.35'><path d='M9.8 12L0 2.2V.8l10 10 10-10v1.4L10.2 12h-.4zm-4 0L0 6.2V4.8L7.2 12H5.8zm8.4 0L20 6.2V4.8L12.8 12h1.4zM9.8 0l.2.2.2-.2h-.4zm-4 0L10 4.2 14.2 0h-1.4L10 2.8 7.2 0H5.8z'/></g></g></svg>");
}
/* <svg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'><rect fill='#6441A5' width='120' height='120'/><polygon fill='#5C3C98' fill-opacity='1' points='120 120 60 120 90 90 120 60 120 0 120 0 60 60 0 0 0 60 30 90 60 120 120 120 '/></svg> */
.donate {
background-image: url('back-coin.jpg');
/* background-size: 500px; */
color: black !important;
}
.hello {
background-color: #00bb77;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='59' height='59' viewBox='0 0 120 120'><polygon fill='%23000' fill-opacity='0.11' points='120 0 120 60 90 30 60 0 0 0 0 0 60 60 0 120 60 120 90 90 120 60 120 0'/></svg>");
}
.msgline {
padding: 5px;
width: 75%;
color: #fff;
}
</style>
</head>
<body>
<div id="chatwin">
<!--
<div idd="1" class="chatRow">
<div class="nameline tg">Edvard Force</div>
<div class="msgline">вот Тенчу Великому зашла , он в ней быстро разобрался и втащил за один стрим )))) ждем когда до нее доберется ))))</div>
</div>
<div idd="2" class="chatRow">
<div class="nameline tg" >Диванный Воин</div>
<div class="msgline">dc или если ты действительно решишь дать бан то мышкой два клика не сделаешь?</div>
</div>
<div idd="3" class="chatRow">
<div class="nameline tg">Yoshka's Cat</div>
<div class="msgline">великий ну эта часть ванпис лутьше чем вариорсы надо признать</div>
</div>
<div idd="4" class="chatRow">
<div class="nameline yt">XAOSHammer</div>
<div class="msgline">Великий а куда друг твой пропал спец по японскому языку ?))))</div>
</div>
<div idd="5" class="chatRow">
<div class="nameline tg">Kino Konformist</div>
<div class="msgline">вот Тенчу Великому зашла , он в ней быстро разобрался и втащил за один стрим )))) ждем когда до нее доберется ))))</div>
</div>
-->
<div id="anchor"></div>
</div>
<script src="script.js"></script>
</body>

148
script.js Normal file
View File

@@ -0,0 +1,148 @@
let messages = [
"I wondered why the baseball was getting bigger. Then it hit me.",
"Police were called to a day care, where a three-year-old was resisting a rest.",
"Did you hear about the guy whose whole left side was cut off? Hes all right now.",
"The roundest knight at King Arthurs round table was Sir Cumference.",
"To write with a broken pencil is pointless.",
"When fish are in schools they sometimes take debate.",
"The short fortune teller who escaped from prison was a small medium at large.",
"A thief who stole a calendar… got twelve months.",
"A thief fell and broke his leg in wet cement. He became a hardened criminal.",
"Thieves who steal corn from a garden could be charged with stalking.",
"When the smog lifts in Los Angeles , U. C. L. A.",
"The math professor went crazy with the blackboard. He did a number on it.",
"The professor discovered that his theory of earthquakes was on shaky ground.",
"The dead batteries were given out free of charge.",
"If you take a laptop computer for a run you could jog your memory.",
"A dentist and a manicurist fought tooth and nail.",
"A bicycle cant stand alone; it is two tired.",
"A will is a dead giveaway.",
"Time flies like an arrow; fruit flies like a banana.",
"A backward poet writes inverse.",
"In a democracy its your vote that counts; in feudalism, its your Count that votes.",
"A chicken crossing the road: poultry in motion.",
"If you dont pay your exorcist you can get repossessed.",
"With her marriage she got a new name and a dress.",
"Show me a piano falling down a mine shaft and Ill show you A-flat miner.",
"When a clock is hungry it goes back four seconds.",
"The guy who fell onto an upholstery machine was fully recovered.",
"A grenade fell onto a kitchen floor in France and resulted in Linoleum Blownapart.",
"You are stuck with your debt if you cant budge it.",
"Local Area Network in Australia : The LAN down under.",
"He broke into song because he couldnt find the key.",
"A calendars days are numbered."
];
let nicks = [
"Edvard Force",
"Диванный Воин",
"Yoshka's Cat",
"XAOSHammer",
"Kino Konformist" ];
const chatwin = document.getElementById("chatwin");
const anchor = document.getElementById("anchor");
function randomMessage() {
return messages[(Math.random() * messages.length) | 0];
}
function randomNick() {
return nicks[(Math.random() * nicks.length) | 0];
}
function randomChat() { if (Math.random() * 2 > 1) {return "tg"} else { return "yt" } }
function goDown() {
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
}
function removeElementsByClass(className){
const elements = document.getElementsByClassName(className);
while(elements.length > 15){
elements[0].parentNode.removeChild(elements[0]);
}
}
function createChatLine() {
const nm = document.createElement("div");
nm.className = "nameline " + randomChat();
nm.innerHTML = randomNick();
const msg = document.createElement("div");
msg.className = "msgline";
msg.innerHTML = randomMessage();
const rw = document.createElement("div");
rw.className = "chatRow";
rw.appendChild(nm);
rw.appendChild(msg);
console.log(rw);
chatwin.insertBefore(rw, anchor);
goDown();
}
function createNewLine(json) {
json.forEach(element => {
//checking new IDs on screen and print
//const elements = document.getElementsByName(element["id"]);
//if (elements.length > 0) { //if this id is present on screen
let curline = document.getElementById(element["id"])
if (curline) {
curline.innerHTML = element["msg"]
return;
}; //Updating text...
const nm = document.createElement("div");
nm.className = "nameline " + element["type"];
nm.innerHTML = element["sendr"];
if (element["type"] == "donate") { nm.innerHTML = nm.innerHTML + '<br><p style="color: red">' + element['amount']+"</p>" }
const msg = document.createElement("div");
msg.className = "msgline";
msg.innerHTML = element["msg"];
msg.setAttribute("id", element["id"]);
if (element["type"] == "donate") { msg.style="background-color: #0000FF20" }
const rw = document.createElement("div");
rw.className = "chatRow";
rw.setAttribute("name", element["id"]);
rw.appendChild(nm);
rw.appendChild(msg);
//console.log(rw);
chatwin.insertBefore(rw, anchor);
});
}
function requestNewLines() {
var request = new XMLHttpRequest();
request.open('GET', "http://localhost:8008/");
request.responseType = 'json';
request.send();
request.onload = function() {
var chatJSON = request.response;
createNewLine(chatJSON);
goDown();
}
}
setInterval(requestNewLines,1000);

55
style.css Normal file
View File

@@ -0,0 +1,55 @@
body {
display: flex;
align-items: center;
justify-content: center;
font-family: "Roboto", sans-serif;
font-size: 1em;
letter-spacing: 0.1px;
color: lighter;
text-rendering: optimizeLegibility;
text-shadow: 1px 1px 1px rgba(0,0,0,0.004);
-webkit-font-smoothing: antialiased;
}
#chatwin {
color: white;
min-width: 150px;
max-width: 500px;
}
.chatRow {
display: flex;
flex-direction: row;
margin-bottom: 1px;
}
.nameline {
color: light-grey;
padding: 10px;
width: 25%;
text-align: center;
font-weight: bold;
}
.yt {
background-image: url('data:image/svg+xml,%3Csvg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"%3E%3Cg fill="%239C92AC" fill-opacity="0.4" fill-rule="evenodd"%3E%3Cpath d="M0 40L40 0H20L0 20M40 40V20L20 40"/%3E%3C/g%3E%3C/svg%3E');
background-color: #E53935A0;
}
/* background-color: #DFDBE5;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='152' height='152' viewBox='0 0 152 152'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='temple' fill='%239C92AC' fill-opacity='0.4'%3E%3Cpath d='M152 150v2H0v-2h28v-8H8v-20H0v-2h8V80h42v20h20v42H30v8h90v-8H80v-42h20V80h42v40h8V30h-8v40h-42V50H80V8h40V0h2v8h20v20h8V0h2v150zm-2 0v-28h-8v20h-20v8h28zM82 30v18h18V30H82zm20 18h20v20h18V30h-20V10H82v18h20v20zm0 2v18h18V50h-18zm20-22h18V10h-18v18zm-54 92v-18H50v18h18zm-20-18H28V82H10v38h20v20h38v-18H48v-20zm0-2V82H30v18h18zm-20 22H10v18h18v-18zm54 0v18h38v-20h20V82h-18v20h-20v20H82zm18-20H82v18h18v-18zm2-2h18V82h-18v18zm20 40v-18h18v18h-18zM30 0h-2v8H8v20H0v2h8v40h42V50h20V8H30V0zm20 48h18V30H50v18zm18-20H48v20H28v20H10V30h20V10h38v18zM30 50h18v18H30V50zm-2-40H10v18h18V10z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); */
.tg {
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"%3E%3Cg fill-rule="evenodd"%3E%3Cg fill="%239C92AC" fill-opacity="0.4"%3E%3Cpath opacity=".5" d="M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z"/%3E%3Cpath d="M6 5V0H5v5H0v1h5v94h1V6h94V5H6z"/%3E%3C/g%3E%3C/g%3E%3C/svg%3E');
background-color: #2196F3A0;
}
.msgline {
padding: 10px;
width: 75%;
}

12
tet/camera.reg Normal file
View File

@@ -0,0 +1,12 @@
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\camera]
@="URL:Camera Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\camera\shell]
[HKEY_CLASSES_ROOT\camera\shell\open]
[HKEY_CLASSES_ROOT\camera\shell\open\command]
@="\"C:\\Program Files (x86)\\SATVISION\\Satvision V.2.0\\Satvision V.2.0.exe\" \"%1\""

3
tet/camera_del.reg Normal file
View File

@@ -0,0 +1,3 @@
Windows Registry Editor Version 5.00
[-HKEY_CLASSES_ROOT\camera]

202
tet/island_script.txt Normal file
View File

@@ -0,0 +1,202 @@
# Инициализация персонажей
@char yui:Юи|Каштановые волосы|Энергичная, но напуганная|Пахнет цитрусами
@char himitsu:Химицу|Черные волосы|Загадочная художница|Пахнет лавандой
@char mitsuhа:Мицуха|Розовые волосы|Ранимая певица|Пахнет ванилью
# Инициализация очков
@set yui_points = 0
@set himitsu_points = 0
@set mitsuha_points = 0
# --- ДЕНЬ 1: ТЕРРИТОРИЯ ТЕПЛА ---
@label start
@bg morning
*УТРО. Холод в пустой квартире стал почти осязаемым, пробираясь под самую одежду. Вы находите Юи в гостиной — она дрожит, и её кожа покрылась крупными мурашками.*
yui: Я скоро превращусь в лед... Можно мне хоть немного твоего тепла?
choice Прижать её к себе всем телом=>goto d1_yui_warm|Отстраниться и принести плед=>goto d1_yui_cold|Пошутить, что она преувеличивает=>goto d1_yui_none
@label d1_yui_warm
@bg day
*ДЕНЬ. Вы обхватываете её за талию и вжимаете в себя. Юи стонет, её соски отчетливо твердеют под тонкой тканью, царапая вашу грудь.*
*Она жадно ловит ваше дыхание, прижимаясь бедрами так плотно, что вы чувствуете каждый её изгиб.*
@set yui_points += 15
@goto d1_himitsu_scene
@label d1_yui_cold
*Юи разочарованно кутается в плед. Атмосфера между вами становится холоднее метели за окном.*
@set yui_points -= 5
@goto d1_himitsu_scene
@label d1_yui_none
*Она обиженно отворачивается. Вы явно выбрали неудачный момент для шуток.*
@set yui_points -= 10
@goto d1_himitsu_scene
@label d1_himitsu_scene
@bg evening
*ВЕЧЕР. Химицу сидит у окна, рисуя пальцем на запотевшем стекле символы, напоминающие сплетения тел.*
himitsu: Ты слышишь, как бьется моё сердце? Оно требует чего-то большего, чем просто тишина.
choice Положить руку ей на грудь=>goto d1_himi_hot|Просто слушать её слова=>goto d1_himi_soft|Сказать, что слышите только ветер=>goto d1_himi_none
@label d1_himi_hot
@bg night
*НОЧЬ. Ваша ладонь накрывает её грудь, чувствуя бешеный ритм. Химицу прижимает вашу руку сильнее, её дыхание становится тяжелым и прерывистым.*
*Она смотрит на вас затуманенным взглядом, и её тело под вашими пальцами кажется обжигающим.*
@set himitsu_points += 15
@goto d1_mitsuha_scene
@label d1_himi_soft
*Она лишь слегка улыбается, оценив ваше внимание, но искры не происходит.*
@set himitsu_points += 5
@goto d1_mitsuha_scene
@label d1_himi_none
*Химицу замыкается в себе. Вы упустили шанс стать к ней ближе.*
@set himitsu_points -= 10
@goto d1_mitsuha_scene
@label d1_mitsuha_scene
@bg morning
*УТРО (День 1-2). Мицуха зажигает свечи, её розовые волосы светятся в полумраке.*
mitsuhа: Кажется, метель заберет меня, если рядом никого не будет... Побудь со мной.
choice Обнять её со спины=>goto d1_mitsu_close|Взять её за руку=>goto d1_mitsu_hold|Посоветовать ей не бояться=>goto d1_mitsu_none
@label d1_mitsu_close
@bg day
*ДЕНЬ. Вы смыкаете руки на её талии. Мицуха выгибается, её ягодицы плотно прижимаются к вам, а дыхание сбивается на тихий стон.*
*Вы чувствуете мягкость её тела и сладкий аромат ванили, который кружит голову.*
@set mitsuha_points += 15
@goto d1_night_together
@label d1_mitsu_hold
*Она благодарно сжимает ваши пальцы, но ожидала более смелого шага.*
@set mitsuha_points += 5
@goto d1_night_together
@label d1_mitsu_none
*Мицуха опускает глаза. Ей не нужны советы, ей нужно было ваше тепло.*
@set mitsuha_points -= 10
@goto d1_night_together
@label d1_night_together
@bg night
*НОЧЬ. Чтобы не замерзнуть, вы спите на одном матрасе. Юи закидывает на вас ногу, а Мицуха обнимает за талию.*
*Вы засыпаете в коконе из женских тел, чувствуя их жар и слыша мерное, возбуждающее дыхание.*
@goto d2_start
# --- ДЕНЬ 2: ОБНАЖЕННЫЕ ЧУВСТВА ---
@label d2_start
@bg morning
*УТРО. Вы находите Юи на кухне. Она заспанная, её пижама сползла с плеча, открывая вид на нежную кожу.*
yui: Мне всю ночь снилось, как ты меня касаешься... Это было слишком реально.
choice Поцеловать её, углубляя контакт=>goto d2_yui_sex|Погладить её по плечу=>goto d2_yui_touch|Сказать, что это просто сны=>goto d2_yui_none
@label d2_yui_sex
@bg day
*ДЕНЬ. Поцелуй превращается в жадное исследование. Юи сплетается с вами, её горячий язык ищет вашего.*
*Она прижимается бедрами так яростно, что вы чувствуете её влажное желание сквозь тонкую ткань.*
@set yui_points += 15
@goto d2_himitsu_scene
@label d2_yui_touch
*Она улыбается, но в её глазах читается неудовлетворенное ожидание.*
@set yui_points += 5
@goto d2_himitsu_scene
@label d2_yui_none
*Юи разочарованно отстраняется. Момент близости безвозвратно утерян.*
@set yui_points -= 15
@goto d2_himitsu_scene
@label d2_himitsu_scene
@bg evening
*ВЕЧЕР. Химицу приглашает вас в свою комнату. Воздух здесь пропитан лавандой и тайной.*
himitsu: Сними рубашку... Я хочу запечатлеть твою силуэт, прежде чем всё закончится.
choice Раздеться и подойти вплотную=>goto d2_himi_naked|Снять только рубашку и стоять=>goto d2_himi_half|Отказаться раздеваться=>goto d2_himi_none
@label d2_himi_naked
@bg night
*НОЧЬ. Она ведет холодными пальцами по вашей коже, спускаясь всё ниже. Её вздохи становятся лихорадочными.*
*Химицу прижимается щекой к вашей груди, и вы чувствуете, как её собственное тело дрожит от нетерпения.*
@set himitsu_points += 15
@goto d2_mitsuha_scene
@label d2_himi_half
*Она рисует, но между вами остается дистанция, которую она не решается сократить.*
@set himitsu_points += 5
@goto d2_mitsuha_scene
@label d2_himi_none
*«Ты слишком скучный для музы», — холодно бросает она.*
@set himitsu_points -= 20
@goto d2_mitsuha_scene
@label d2_mitsuha_scene
@bg morning
*УТРО (День 2-3). Мицуха поет тихую балладу, её голос вибрирует глубоко в вашей груди.*
mitsuhа: Я хочу быть твоей... хотя бы пока бушует эта метель.
choice Поцеловать её в шею, лаская изгибы=>goto d2_mitsu_neck|Крепко обнять за плечи=>goto d2_mitsu_soft|Просто похвалить вокал=>goto d2_mitsu_none
@label d2_mitsu_neck
@bg day
*ДЕНЬ. Мицуха стонет, откидывая голову назад. Ваши губы находят её самую чувствительную точку.*
*Вы чувствуете нежную тяжесть её груди в своих руках и то, как она жадно ловит воздух ртом.*
@set mitsuha_points += 15
@goto d2_night_logic
@label d2_mitsu_soft
*Она прижимается к вам, ища защиты, но не страсти.*
@set mitsuha_points += 5
@goto d2_night_logic
@label d2_mitsu_none
*Мицуха замолкает. Вы разбили магию момента своей обыденностью.*
@set mitsuha_points -= 15
@goto d2_night_logic
@label d2_night_logic
@bg night
*НОЧЬ. Напряжение достигло пика. В темноте слышны лишь вздохи и шорох простыней.*
@if yui_points == 30 then *Юи вжимается в вас, её бедра двигаются в такт вашему дыханию, ища спасения от желания.*
@if himitsu_points == 30 then *Рука Химицу скользит под одеяло, её ладони обжигают вашу кожу лихорадочным жаром.*
@if mitsuha_points == 30 then *Мицуха обвивает вас, вы чувствуете её грудь и то, как она дрожит от каждого касания.*
*Остальные девушки, чувствуя этот жар, начинают ласкать друг друга в поисках утешения.*
@goto d3_final
# --- ДЕНЬ 3: ПОСЛЕДНЯЯ НОЧЬ ---
@label d3_final
@bg morning
*УТРО. Метель стихла, но внутри вас бушует шторм. Вы ловите их томные взгляды.*
@bg day
*ДЕНЬ. Каждое случайное касание теперь обжигает как разряд тока.*
@bg evening
*ВЕЧЕР. Пора решить, чьё тепло станет вашим навсегда.*
@if yui_points >= 30 then goto end_yui
@if himitsu_points >= 30 then goto end_himitsu
@if mitsuha_points >= 30 then goto end_mitsuha
@goto end_lonely
@label end_yui
*Юи уводит вас в свою комнату. Её поцелуй сбивает с ног, а руки жадно срывают одежду.*
@goto credits
@label end_himitsu
*Химицу забирает вашу волю в темноте мастерской. Её дыхание — единственное, что теперь имеет значение.*
@goto credits
@label end_mitsuha
*Мицуха шепчет слова любви, её тело пахнет ванилью и страстью, когда она тянет вас в постель.*
@goto credits
@label end_lonely
*Вы выходите на мороз один. Конец.*
@label credits
*Игра завершена.*

629
tet/island_script_ds.txt Normal file
View File

@@ -0,0 +1,629 @@
# Романтическая визуальная новелла "Запертые вместе"
# Главный герой оказывается в квартире с тремя девушками
# и должен строить отношения, чтобы выжить
# Инициализация персонажей
@char yui:Юи|Каштановые волосы, зеленые глаза, спортивная фигура|Студентка, занимается танцами|Пахнет цитрусами
@char himitsu:Химицу|Черные волосы, фиолетовые глаза, готический стиль|Художница, любит читать|Пахнет лавандой
@char mitsuhа:Мицуха|Розовые волосы, голубые глаза, кудрявая|Певица в караоке-клубе|Пахнет ванилью
# Инициализация переменных
@set yui_points = 0
@set himitsu_points = 0
@set mitsuhа_points = 0
@set day = 1
@set time = "утро"
@set sanity = 100
@set killed = 0
# Начало игры
@label start
@bg morning
*Вы просыпаетесь в незнакомой квартире после сильной метели. За окном белая пелена, дороги замело, связь не работает. В квартире кроме вас находятся три девушки.*
# Первая встреча
@label day1_morning
@bg morning
*Лёгкий солнечный свет пробивается через шторы. Вы слышите голоса из кухни.*
choice Подойти познакомиться=>goto meet_girls|Осмотреть квартиру=>goto explore_house|Попробовать найти выход=>goto try_exit
@label meet_girls
@bg morning
yui: О, ты наконец проснулся! Мы уже начали волноваться.
himitsu: *пристально смотрит* Ты вообще помнишь, как сюда попал?
mitsuhа: Не пугай его! Он же только что очнулся.
choice Извиниться за беспокойство=>goto polite_start|Спросить, где вы=>goto direct_question|Пошутить=>goto joke_response
@label polite_start
@set sanity+=5
*Девушки выглядят довольными вашими манерами*
yui: Ничего страшного! Метель всех застала врасплох.
himitsu: Да, мы тоже здесь застряли. Похоже, придётся пережидать.
@set yui_points+=5
@set himitsu_points+=5
@goto day1_breakfast
@label direct_question
@set sanity-=3
*Девушки переглядываются*
mitsuhа: Это моя квартира... ну, точнее, съёмная.
himitsu: А ты просто лежал у подъезда, мы не могли оставить тебя в метель.
@set mitsuhа_points+=3
@goto day1_breakfast
@label joke_response
@set sanity+=10
*Девушки смеются*
yui: О, весельчак! Это хорошо, в заточении пригодится.
mitsuhа: *хихикает* Ты забавный!
himitsu: *саркастично* Надеюсь, твои шутки не закончатся вместе с едой.
@set yui_points+=7
@set mitsuhа_points+=10
@set himitsu_points+=3
@goto day1_breakfast
@label explore_house
@bg grey
*Вы осматриваете квартиру. Небольшая гостиная, кухня, две спальни и ванная. Окна плотно закрыты, на балконной двери висит замок.*
himitsu: *появляется в дверях* Искал выход? Бесполезно, я уже пробовала.
@set himitsu_points+=5
@goto day1_breakfast
@label try_exit
@bg grey
*Вы пытаетесь открыть входную дверь, но она не поддаётся. Слышен голос за спиной.*
yui: Эй, не трать силы! Мы уже пробовали - снег завалил дверь снаружи.
@set yui_points+=5
@goto day1_breakfast
# Завтрак первого дня
@label day1_breakfast
@bg morning
mitsuhа: Ну что, будем завтракать? У меня есть рис и немного овощей.
yui: Я могу приготовить омлет!
himitsu: *вздыхает* Ладно, помогу накрыть на стол.
choice Помочь Юи с готовкой=>goto help_yui|Помочь Химицу с сервировкой=>goto help_himitsu|Поболтать с Мицухой=>goto talk_mitsuhа
@label help_yui
@bg morning
*Вы помогаете Юи готовить омлет. Она улыбается вашей помощи.*
yui: Ты неплохо справляешься! Часто готовишь?
choice Да, люблю готовить=>goto cooking_skill|Нет, просто повезло=>goto cooking_luck
@label cooking_skill
yui: Круто! Может, потом научишь меня чему-нибудь?
@set yui_points+=10
@goto breakfast_common
@label cooking_luck
yui: Скромничаешь, я вижу!
@set yui_points+=5
@goto breakfast_common
@label help_himitsu
@bg morning
*Вы помогаете Химицу расставлять посуду. Она наблюдает за вами.*
himitsu: Ты... не такой, как я ожидала.
choice Что ты ожидала?=>goto himitsu_expectations|Просто стараюсь помочь=>goto himitsu_help
@label himitsu_expectations
himitsu: Не знаю... Кого-то более напуганного или агрессивного.
@set himitsu_points+=8
@goto breakfast_common
@label himitsu_help
himitsu: Это... мило с твоей стороны.
@set himitsu_points+=5
@goto breakfast_common
@label talk_mitsuhа
@bg morning
*Вы садитесь рядом с Мицухой, которая нарезает овощи.*
mitsuhа: О! Хочешь помочь? Можешь нарезать огурец.
*Вы начинаете резать огурец, но получается неровно*
mitsuhа: *смеётся* Ничего, для первого раза сойдёт!
@set mitsuhа_points+=7
@goto breakfast_common
@label breakfast_common
@bg morning
*Вы все вместе завтракаете. В квартире царит дружеская атмосфера.*
yui: Так... что будем делать, пока не кончилась метель?
himitsu: У меня есть колода карт.
mitsuhа: А я могу петь! *смущённо* Если хотите, конечно...
choice Предложить играть в карты=>goto play_cards|Попросить Мицуху спеть=>goto ask_sing|Предложить рассказывать истории=>goto tell_stories
@label play_cards
@bg day
*Вы играете в карты с девушками. Юи азартна, Химицу хладнокровна, а Мицуха постоянно путает правила.*
@if himitsu_points>yui_points then goto himitsu_wins
@if himitsu_points>mitsuhа_points then goto himitsu_wins
@if yui_points>himitsu_points then goto yui_wins
@if yui_points>mitsuhа_points then goto yui_wins
@goto mitsuhа_wins
@label himitsu_wins
himitsu: *ухмыляется* Кажется, я выигрываю. Опять.
@set himitsu_points+=10
@goto day1_afternoon
@label yui_wins
yui: Да! Ещё одна победа! *радостно подпрыгивает*
@set yui_points+=10
@goto day1_afternoon
@label mitsuhа_wins
mitsuhа: Ой, я выиграла? Неожиданно!
@set mitsuhа_points+=10
@goto day1_afternoon
@label ask_sing
@bg day
mitsuhа: *радостно* Правда хочешь послушать? Ну ладно...
*Мицуха берёт гитару и исполняет красивую балладу*
choice Похвалить её голос=>goto praise_voice|Спросить, где научилась=>goto ask_learning|Аплодировать стоя=>goto standing_ovation
@label praise_voice
mitsuhа: Спасибо! *краснеет* Я редко пою для других.
@set mitsuhа_points+=10
@goto day1_afternoon
@label ask_learning
mitsuhа: Я работаю в караоке-клубе... но это секрет, ладно?
@set mitsuhа_points+=7
@goto day1_afternoon
@label standing_ovation
mitsuhа: *смущённо* Ой, ну что ты! *но явно рада*
@set mitsuhа_points+=15
@goto day1_afternoon
@label tell_stories
@bg day
*Вы рассказываете интересную историю из своей жизни. Девушки слушают с интересом.*
choice Рассказать смешную историю=>goto funny_story|Рассказать трогательную историю=>goto touching_story|Рассказать страшную историю=>goto scary_story
@label funny_story
yui: *смеётся* О боже, это же так глупо!
himitsu: *подавляет улыбку* Да уж...
@set yui_points+=10
@set himitsu_points+=5
@goto day1_afternoon
@label touching_story
mitsuhа: *глаза влажные* Это так... трогательно.
himitsu: *кивает* Сильная история.
@set mitsuhа_points+=12
@set himitsu_points+=8
@goto day1_afternoon
@label scary_story
yui: *вздрагивает* Брр, не люблю такие истории!
himitsu: *заинтересованно* Хороший рассказчик...
@set yui_points-=5
@set himitsu_points+=15
@goto day1_afternoon
# День 1 - Послеобеденное время
@label day1_afternoon
@bg day
*После совместного времяпрепровождения атмосфера в квартире стала более дружелюбной.*
yui: Эй, а давайте проверим, как там на улице?
*Вы подходите к окну - метель всё ещё бушует*
himitsu: Похоже, нам здесь ещё на день-два.
mitsuhа: Тогда надо проверить запасы еды...
choice Предложить помочь с инвентаризацией=>goto check_supplies|Предложить сыграть в другую игру=>goto another_game|Пойти отдохнуть=>goto take_nap
@label check_supplies
@bg day
*Вы проверяете запасы еды вместе с Мицухой*
mitsuhа: Риса хватит на пару дней, овощей меньше... Ой!
*Она случайно роняет банку, вы ловите её*
mitsuhа: *смущённо* Спасибо... ты ловкий.
@set mitsuhа_points+=10
@goto day1_evening
@label another_game
@bg day
*Вы предлагаете новую игру. Юи с энтузиазмом соглашается.*
yui: Да! Я обожаю игры! Давай что-нибудь активное!
@set yui_points+=10
@goto day1_evening
@label take_nap
@bg day
*Вы решаете вздремнуть. Химицу сидит рядом с книгой.*
himitsu: *тихо* Умный поступок. В таких ситуациях важно сохранять силы.
@set himitsu_points+=7
@goto day1_evening
# День 1 - Вечер
@label day1_evening
@bg sunset
*Солнце садится, в квартире становится темнее. Вы замечаете, как девушки начинают нервничать.*
choice Предложить зажечь свечи=>goto light_candles|Проверить телефон (вдруг появилась связь)=>goto check_phone|Начать разговор=>goto start_conversation
@label light_candles
@bg sunset
*Вы находите свечи и зажигаете их. Мицуха благодарно улыбается.*
mitsuhа: Как романтично... в каком-то смысле.
@set mitsuhа_points+=8
@set yui_points+=3
@set himitsu_points+=3
@goto day1_dinner
@label check_phone
@bg sunset
*Вы проверяете телефон - связи по-прежнему нет.*
yui: *вздыхает* Я тоже уже пробовала... Ничего.
@set sanity-=5
@goto day1_dinner
@label start_conversation
@bg sunset
*Вы пытаетесь разрядить обстановку разговором*
himitsu: *снисходительно* Ну давай, развлекай нас.
choice Расспросить о них=>goto ask_about_them|Рассказать о себе=>goto tell_about_yourself|Придумать игру=>goto create_game
@label ask_about_them
*Девушки немного оживляются, рассказывая о себе*
@set yui_points+=5
@set himitsu_points+=5
@set mitsuhа_points+=5
@goto day1_dinner
@label tell_about_yourself
*Вы рассказываете о себе. Химицу слушает с интересом.*
@set himitsu_points+=10
@goto day1_dinner
@label create_game
*Вы придумываете игру, Юи в восторге*
@set yui_points+=15
@goto day1_dinner
# Ужин первого дня
@label day1_dinner
@bg night
*Вы ужинаете при свечах. Атмосфера странным образом становится уютной.*
mitsuhа: Знаете... несмотря на всё, это довольно мило.
yui: Да уж, могло быть и хуже!
himitsu: *покатывается глазами* Вы слишком легко ко всему относитесь.
choice Согласиться с Мицухой=>goto agree_mitsuhа|Поддержать Юи=>goto agree_yui|Промолчать=>goto stay_silent
@label agree_mitsuhа
mitsuhа: *улыбается* Приятно, что ты так думаешь.
@set mitsuhа_points+=10
@goto day1_sleep
@label agree_yui
yui: Вот именно! *подмигивает*
@set yui_points+=10
@goto day1_sleep
@label stay_silent
himitsu: *кивает* Хотя бы один человек здесь адекватный.
@set himitsu_points+=7
@goto day1_sleep
# Ночь первого дня
@label day1_sleep
@bg night
*Приходит время спать. В квартире две спальни - одна для девушек, одна для вас.*
choice Предложить дежурить по очереди=>goto night_watch|Пожелать спокойной ночи=>goto good_night|Проверить двери ещё раз=>goto check_doors
@label night_watch
*Девушки удивлены вашим предложением*
yui: О, ответственный! Мне нравится!
@set yui_points+=10
@set himitsu_points+=5
@set mitsuhа_points+=5
@goto day2_morning
@label good_night
*Вы вежливо прощаетесь*
mitsuhа: Спокойной ночи... и спасибо за сегодня.
@set mitsuhа_points+=7
@goto day2_morning
@label check_doors
*Вы проверяете двери - без изменений*
himitsu: *тихо* Упрямый... но это хорошо.
@set himitsu_points+=10
@goto day2_morning
# День 2 - Утро
@label day2_morning
@bg morning
@set day = 2
*Вы просыпаетесь от запаха готовящегося завтрака. Метель за окном продолжается, но уже не так сильно.*
yui: Доброе утро! Я приготовила завтрак!
himitsu: *ворчит* И разбудила всех на три этажа.
mitsuhа: *подаёт тарелку* Кушай, пока горячее.
choice Поблагодарить Юи=>goto thank_yui|Пошутить над Химицу=>goto joke_himitsu|Помочь Мицухе=>goto help_mitsuhа
@label thank_yui
yui: *радостно* Всегда пожалуйста!
@set yui_points+=10
@goto day2_breakfast
@label joke_himitsu
himitsu: *фыркает* Смешно. Очень смешно.
@set himitsu_points+=5
@goto day2_breakfast
@label help_mitsuhа
mitsuhа: Ой, спасибо! *улыбается*
@set mitsuhа_points+=10
@goto day2_breakfast
# День 2 - Завтрак
@label day2_breakfast
@bg morning
*За завтраком девушки обсуждают, как провести день.*
himitsu: Электричество есть, но интернет не работает. Типично.
mitsuhа: Может, споём караоке? У меня есть микрофон!
yui: О да! А потом можно устроить мини-спортзал!
choice Поддержать идею караоке=>goto karaoke_time|Предложить настольные игры=>goto board_games|Пойти проверить окна=>goto check_windows
@label karaoke_time
@bg day
mitsuhа: Ура! *хлопает в ладоши* Давайте дуэтом!
@set mitsuhа_points+=10
@set sanity+=15
@goto day2_activity
@label board_games
@bg day
himitsu: Наконец-то здравая идея.
@set himitsu_points+=10
@set yui_points-=5
@goto day2_activity
@label check_windows
@bg day
*Вы проверяете окна - снег немного осел, но выйти пока невозможно.*
yui: *подходит сзади* Нашёл выход?
@set yui_points+=7
@set sanity-=5
@goto day2_activity
# День 2 - Активности
@label day2_activity
@bg day
*Внезапно гаснет свет. Раздаётся вздох разочарования.*
himitsu: Прекрасно. Просто прекрасно.
mitsuhа: *испуганно* Темно...
choice Найти фонарик=>goto find_flashlight|Успокоить Мицуху=>goto comfort_mitsuhа|Посмеяться над ситуацией=>goto laugh_situation
@label find_flashlight
@bg grey
*Вы находите фонарик в ящике. Химицу одобрительно кивает.*
himitsu: Полезно иметь такого человека рядом.
@set himitsu_points+=10
@goto day2_lunch
@label comfort_mitsuhа
@bg grey
*Вы берёте Мицуху за руку. Она постепенно успокаивается.*
mitsuhа: Спасибо... мне страшно в темноте.
@set mitsuhа_points+=15
@goto day2_lunch
@label laugh_situation
@bg grey
yui: *смеётся* Да уж, ещё один повод для воспоминаний!
@set yui_points+=10
@set mitsuhа_points-=5
@goto day2_lunch
# День 2 - Обед
@label day2_lunch
@bg day
*Свет вернулся. Вы вместе готовите обед из остатков еды.*
choice Помочь Юи с готовкой=>goto cook_with_yui|Убрать на кухне=>goto clean_kitchen|Поделиться едой с Химицу=>goto share_food
@label cook_with_yui
@bg day
*Юи учит вас готовить простое блюдо. Получается не идеально, но съедобно.*
yui: Неплохо для первого раза! *подмигивает*
@set yui_points+=12
@goto day2_evening
@label clean_kitchen
@bg day
*Вы моете посуду. Химицу неожиданно присоединяется.*
himitsu: *тихо* Ты... не такой неряха, как большинство парней.
@set himitsu_points+=10
@goto day2_evening
@label share_food
@bg day
*Вы отдаёте Химицу последний кусок пирога. Она удивлена.*
himitsu: Ты... уверен? *берет пирог, избегая зрительного контакта*
@set himitsu_points+=15
@set sanity-=5 # голод
@goto day2_evening
# День 2 - Вечер
@label day2_evening
@bg sunset
*Запасы еды заканчиваются. Напряжение растёт.*
yui: Эй, может, расскажем страшные истории? Чтобы отвлечься!
mitsuhа: *дрожит* Я... я не уверена...
himitsu: *саркастично* Отличная идея. Добавить страха в нашу и без того ужасную ситуацию.
choice Поддержать Юи=>goto scary_stories|Предложить альтернативу=>goto alternative_activity|Уйти в другую комнату=>goto leave_room
@label scary_stories
@bg night
*Вы рассказываете историю. Юи в восторге, Мицуха прячется под плед.*
@set yui_points+=15
@set mitsuhа_points-=10
@set sanity-=10
@goto day2_night
@label alternative_activity
@bg night
*Вы предлагаете рассказывать смешные истории. Атмосфера улучшается.*
@set mitsuhа_points+=10
@set yui_points+=5
@set sanity+=10
@goto day2_night
@label leave_room
@bg night
*Вы уходите, оставляя девушек разбираться самим. Химицу позже находит вас читающим.*
himitsu: Умный ход. *оставляет чашку чая рядом*
@set himitsu_points+=10
@set yui_points-=5
@goto day2_night
# День 2 - Ночь
@label day2_night
@bg night
*Вы просыпаетесь от шума. Кто-то ходит по квартире.*
choice Исследовать=>goto investigate_noise|Притвориться спящим=>goto pretend_sleep|Позвать на помощь=>goto call_for_help
@label investigate_noise
@bg black
*Это Химицу стоит у окна. Она быстро поворачивается.*
himitsu: *шепотом* Не мог спать. Метель... напоминает мне кое-что.
choice Расспросить=>goto ask_her_past|Просто постоять рядом=>goto stand_with_her|Вернуться спать=>goto return_to_sleep
@label ask_her_past
himitsu: *после паузы* Когда я была маленькой... *резко обрывает* Забудь.
@set himitsu_points+=15
@goto day3_morning
@label stand_with_her
*Вы молча стоите рядом. Через несколько минут она незаметно берёт вас за руку.*
@set himitsu_points+=20
@goto day3_morning
@label return_to_sleep
himitsu: *саркастично* Да, беги. Все бегут.
@set himitsu_points-=10
@goto day3_morning
@label pretend_sleep
@bg black
*Вы слышите, как кто-то поправляет ваше одеяло. Пахнет ванилью.*
@set mitsuhа_points+=10
@goto day3_morning
@label call_for_help
@bg black
yui: *вбегает* Что случилось?! О... *видит, что это просто Химицу*
himitsu: *ядовито* Поздравляю, всех разбудил.
@set yui_points+=5
@set himitsu_points-=10
@goto day3_morning
# День 3 - Утро
@label day3_morning
@bg morning
@set day=3
*Метель почти утихла. Девушки взволнованны.*
mitsuhа: *смотрит в окно* Кажется, сегодня сможем выбраться!
yui: Надо собрать вещи! *бегает по комнате*
himitsu: *спокойно* Наконец-то. *но выглядит немного грустной*
choice Помочь собираться=>goto help_packing|Проверить выход=>goto check_exit|Поговорить с Химицу=>goto talk_to_himitsu
@label help_packing
*Вы помогаете Мицухе собрать её многочисленные вещи.*
mitsuhа: Ты такой внимательный! *краснеет*
@set mitsuhа_points+=15
@goto day3_decision
@label check_exit
*Вы очищаете дверь от снега. Юи присоединяется.*
yui: Командная работа! *улыбается*
@set yui_points+=10
@goto day3_decision
@label talk_to_himitsu
himitsu: *неожиданно* Может... как-нибудь встретимся? Если выберемся.
@set himitsu_points+=20
@goto day3_decision
# День 3 - Решающий выбор
@label day3_decision
@bg day
*Дверь наконец открывается. Пришло время прощаться... или нет?*
choice Пригласить Юи на свидание=>goto date_yui|Предложить Химицу пойти вместе=>goto go_with_himitsu|Признаться Мицухе в чувствах=>goto confess_to_mitsuhа|Промолчать и уйти=>goto bad_ending_lonely
@label date_yui
@if yui_points>50 then goto yui_good_ending
*Юи вежливо отказывает. Похоже, вы не нашли общий язык.*
@goto credits
@label yui_good_ending
yui: *сияет* Я думала, ты никогда не предложишь!
*Вы начинаете встречаться. Её энергия заряжает вас каждый день.*
@goto credits
@label go_with_himitsu
@if himitsu_points>60 then goto himitsu_good_ending
*himitsu холодно отвечает: "Не думаю, что это хорошая идея."*
@goto credits
@label himitsu_good_ending
himitsu: *с лёгкой улыбкой* Ладно... но только если ты будешь молчать в моей мастерской.
*Вы становитесь её моделью, а затем и чем-то большим.*
@goto credits
@label confess_to_mitsuhа
@if mitsuhа_points>55 then goto mitsuhа_good_ending
*mitsuhа смущённо бормочет извинения и быстро уходит.*
@goto credits
@label mitsuhа_good_ending
mitsuhа: *тихо* Я... я тоже тебя люблю.
*Вы посещаете все её выступления и однагод делаете предложение на сцене.*
@goto credits
@label bad_ending_lonely
@bg black
*Вы уходите, не попрощавшись. Девушки больше никогда вас не видят.*
*Конец.*
@goto credits
# Титры с обновлёнными переменными
@label credits
*Спасибо за игру!*
*Итоговые показатели:*
*Дней вместе: {day}*
*Очки Юи: {yui_points}*
*Очки Химицу: {himitsu_points}*
*Очки Мицухи: {mitsuhа_points}*
*Уровень рассудка: {sanity}*
@if killed==1 then *Вас убили! Плохая концовка.*
@if sanity<30 then *Вы сошли с ума. Плохая концовка.*

397
tet/island_script_qwen.txt Normal file
View File

@@ -0,0 +1,397 @@
# Начало игры: Знакомство с игроком и событием
@label start
*Вы просыпаетесь на песчаном пляже под звуки волн и крики чаек.*
Player: Где я...? Что случилось?
*Над вами склоняется красивая девушка с длинными светлыми волосами и мягким голосом.*
Aoi: Ты очнулся... Хорошо, что ты жив.
Player: Кто вы? Почему мы здесь?
Aoi: Мы потерпели крушение. Остальные тоже выжили. Но это уже третий день, как мы здесь.
*Позади появляются ещё две девушки — одна с короткой стрижкой и весёлым взглядом, другая — задумчивая и серьёзная.*
Natsuki: Эй, он проснулся? Привет, красавчик!
Yume: Не шуми так, Natsuki. Он, наверное, всё ещё слаб.
@char Aoi:Аои|Длинные светлые волосы, голубые глаза|Спокойная, уравновешенная|Пахнет морским бризом
@char Natsuki:Нацуки|Короткие розовые волосы, карие глаза|Энергичная, любит приключения|Пахнет клубникой
@char Yume:Юме|Чёрные волосы до плеч, серые глаза|Замкнутая, но добрая внутри|Пахнет старыми книгами
@set aoi = 0
@set natsuki = 0
@set yume = 0
@set day = 1
@goto morning_start
# Утро первого дня
@label morning_start
@bg morning
*Nад вами рассвет, оранжевые облака медленно проплывают над горизонтом. Море спокойно, а воздух наполнен запахом соли.*
Aoi: Сегодня мы должны исследовать остров. Может быть, найдём еду или сигнал для спасения.
Natsuki: Ага! Я уже готова! Только давайте возьмём палки и верёвку.
Yume: Или можно поискать в пещерах. Там может быть сухо и безопасно.
choice Пойти с Аои=>goto explore_aoi | Пойти с Нацуки=>goto explore_natsuki | Пойти с Юме=>goto explore_yume
# Исследование с Аои
@label explore_aoi
@set aoi += 10
*Вы идёте по берегу вдоль скал. Аои аккуратно собирает ракушки и показывает вам, какие из них можно есть.*
Aoi: Эти ракушки — хорошее дополнение к пище. Они богаты белком.
Player: Ты знаешь много полезного...
Aoi: Я училась на биолога. Так что немного знаю природу.
*Aoi улыбается, её щёки слегка розовеют.*
@goto evening_day1
# Исследование с Нацуки
@label explore_natsuki
@set natsuki += 10
*Natsuki ведёт вас вглубь джунглей. Она легко карабкается по деревьям и срывает фрукты.*
Natsuki: Смотри, эти плоды вкусные и сочные!
Player: А они безопасны?
Natsuki: Ну, если я не умерла, то и ты не умрёшь!
*Она смеётся и протягивает тебе половину фрукта.*
Natsuki: Давай, попробуй!
Player: Вкусно...
Natsuki: Я рада!
@goto evening_day1
# Исследование с Юме
@label explore_yume
@set yume += 10
*Юме ведёт вас к древней пещере. Внутри темно, но она зажигает маленький факел.*
Yume: Здесь раньше жили люди. Видишь эти следы?
Player: Ты думаешь, они были здесь?
Yume: Возможно. Но сейчас мы одни.
*Она поворачивается к вам, её взгляд становится мягче.*
Yume: Мне приятно, что ты выбрал меня.
@goto evening_day1
# Вечер первого дня
@label evening_day1
@bg sunset
*Солнце заходит, окрашивая небо в теплые оттенки. Вы возвращаетесь на пляж.*
Player: Как прошёл ваш день?
Aoi: Мы нашли ракушки и воду.
Natsuki: А я нашла бананы! Вкуснющие!
Yume: В пещере могут быть припасы. Нужно исследовать дальше.
*Все трое садятся рядом с костром, который разожгла Нацуки.*
@set day = 2
@goto night_day1
# Ночь первого дня
@label night_day1
@bg night
*Луна светит ярко. Все трое сидят у костра, рассказывая истории.*
Aoi: Я всегда хотела побывать на необитаемом острове... Только не в таких обстоятельствах.
Natsuki: А я бы хотела стать пиратом!
Yume: Я хочу домой. К своим книгам.
Player: А что бы вы сделали, если бы нас спасли завтра?
*Девушки задумываются.*
Aoi: Пошла бы на прогулку с любимым человеком.
Natsuki: Отметила бы спасение шикарной вечеринкой!
Yume: Посидела бы с чашкой чая и книгой.
*Тихо. Только треск костра и шум волн.*
@goto morning_day2
# Утро второго дня
@label morning_day2
@bg morning
*Утро. Все выглядят немного уставшими, но бодрыми.*
Player: Что будем делать сегодня?
Aoi: Можно попробовать построить укрытие получше.
Natsuki: Или построить плот!
Yume: Лучше проверить пещеры. Может быть, там есть выход.
choice Помочь Аои=>goto help_aoi | Помочь Нацуки=>goto help_natsuki | Помочь Юме=>goto help_yume
# Помощь Аои
@label help_aoi
@set aoi += 15
*Aoi ведёт вас к месту, где можно собрать лианы и сделать кров.*
Aoi: Вот, держи эту ветку. Нужно связать их так...
Player: Как ты всё знаешь?
Aoi: Когда-то была в походе с отцом. Он был военным.
*Aoi смотрит вдаль, словно вспоминая.*
@goto evening_day2
# Помощь Нацуки
@label help_natsuki
@set natsuki += 15
*Natsuki тащит бревна и предлагает сделать плот.*
Natsuki: Если мы построим плот, сможем уйти отсюда!
Player: А ты уверена, что он удержит нас?
Natsuki: Конечно! Я мастер по плотам!
*Она хватает вас за руку.*
Natsuki: Давай, помоги мне перевернуть его!
*Вы вместе переворачиваете плот. Она смеётся.*
@goto evening_day2
# Помощь Юме
@label help_yume
@set yume += 15
*Юме снова ведёт вас в пещеру. Теперь она освещает стены факелом.*
Yume: Здесь есть какие-то символы. Может, это предупреждение?
Player: О чём?
Yume: Не знаю... Но я чувствую, что это важно.
*Она смотрит на вас своими глубокими глазами.*
Yume: Ты единственный, кому я могу доверить это.
@goto evening_day2
# Вечер второго дня
@label evening_day2
@bg sunset
*Сегодня вы вместе делали плот. Все устали, но довольны.*
Natsuki: Завтра можем попробовать на нём уплыть!
Aoi: Но лучше подождать, пока мы наберём еды.
Yume: Я всё ещё думаю, что в пещерах может быть что-то важное.
Player: Может, стоит провести ночь в пещере?
*Девушки переглядываются.*
Aoi: Я согласна, если будет тепло.
Natsuki: Только если будет музыка!
Yume: Если ты будешь рядом, я соглашусь.
*Все улыбаются.*
@set day = 3
@goto night_day2
# Ночь второго дня
@label night_day2
@bg night
*Вы в пещере. Огонь освещает лица девушек.*
Aoi: Было бы хорошо, если бы мы могли остаться так навсегда.
Natsuki: Только без дождя и пауков!
Yume: Здесь тихо... Мне нравится.
Player: Я рад, что вы все здесь.
*Тишина.*
*Aoi кладёт голову вам на плечо.*
Aoi: Ты... особенный для меня.
*Natsuki смеётся.*
Natsuki: А ты уверен, кто тебе нравится больше?
*Юме молчит, но смотрит на вас с теплотой.*
@goto morning_day3
# Утро третьего дня
@label morning_day3
@bg morning
*Вы просыпаетесь в пещере. Всё тело затекло, но рядом лежит Юме.*
Yume: Ты проснулся? Хорошо.
Player: Ты спала рядом?
Yume: Да. Мне было спокойнее.
*Вы выходите из пещеры. Вдалеке виднеется парус.*
Player: Смотрите! Это корабль!
*Все радуются.*
Natsuki: Он нас спасёт!
Aoi: Но... ты же выберешь кого-то из нас?
Player: Я...
*Выбор:*
choice Сказать "Я люблю тебя" Аои=>goto ending_aoi | Сказать "Я люблю тебя" Нацуки=>goto ending_natsuki | Сказать "Я люблю тебя" Юме=>goto ending_yume | Сказать "Я не могу выбрать"=>goto ending_all
# Концовка: Аои
@label ending_aoi
@set aoi += 20
*Aoi смотрит на вас с благодарностью.*
Aoi: Я... рада.
*Вы подходите к кораблю. Аои берёт вас за руку.*
*Финал: Вы возвращаетесь домой вместе. Через год вы женитесь на Аои.*
@bg white
*A happy ending with Aoi*
@goto end
# Концовка: Нацуки
@label ending_natsuki
@set natsuki += 20
*Natsuki смеётся и обнимает вас.*
Natsuki: Ты лучший!
*Вы подходите к кораблю. Но внезапно Нацуки достаёт нож.*
Natsuki: Я не могу позволить тебе уйти...
*Она ударяет вас в спину.*
@bg black
*Bad ending: Killed by Natsuki*
@goto end
# Концовка: Юме
@label ending_yume
@set yume += 20
*Юме берёт вас за руку.*
Yume: Я буду с тобой.
*Вы подходите к кораблю. Но Юме вдруг толкает вас вниз.*
Yume: Прости... я не могу.
*Она убегает обратно в пещеру.*
@bg black
*Sad ending: Yume leaves you behind*
@goto end
# Концовка: Не могу выбрать
@label ending_all
*Natsuki, Аои и Юме смотрят на вас с разочарованием.*
Aoi: Тогда... мы уйдём.
Natsuki: Без тебя.
Yume: Прости.
*Корабль уходит. Вы остаётесь один.*
@bg black
*Bad ending: You are left alone*
@goto end
# Конец игры
@label end
@bg black
*Игра окончена.*
*Хочешь начать заново?*
choice Перезапустить=>goto start | Выйти=>end_game
@end_game

View File

@@ -0,0 +1,410 @@
import pygame
import sys
import os
import re
import random
# Инициализация Pygame
pygame.init()
# Настройки окна
WIDTH, HEIGHT = 1280, 720
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Визуальная новелла")
# Цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
LIGHT_BLUE = (173, 216, 230)
DARK_BLUE = (0, 0, 139)
CHOICE_BG = (240, 240, 255)
# Шрифты
font = pygame.font.Font(None, 36)
character_font = pygame.font.Font(None, 32)
choice_font = pygame.font.Font(None, 30)
small_font = pygame.font.Font(None, 24)
class NovelEngine:
def __init__(self):
self.script = []
self.current_line = 0
self.running = True
self.background = None
self.characters = {}
self.variables = {}
self.choices = []
self.waiting_for_choice = False
self.call_stack = [] # Стек для хранения позиций возврата
self.text_box_rect = pygame.Rect(50, HEIGHT - 250, WIDTH - 100, 200)
self.choice_box_rect = pygame.Rect(WIDTH//2 - 300, HEIGHT//2 - 150, 600, 300)
def load_script(self, filename):
"""Загрузка скрипта из файла"""
self.script = []
script_path = os.path.join(os.path.dirname(__file__), filename)
if not os.path.exists(script_path):
print(f"Ошибка: файл {script_path} не найден!")
return False
with open(script_path, 'r', encoding='utf-8') as file:
for line in file:
line = line.strip()
if line and not line.startswith('#'):
self.script.append(line)
return True
def parse_character(self, command):
"""Обработка описания персонажа с дополнительными атрибутами"""
if command.startswith("char "):
parts = command[5:].split("|")
char_id = parts[0].strip().split(":")[0]
char_data = {
"name": parts[0].split(":")[1].strip(),
"appearance": parts[1].strip() if len(parts) > 1 else "",
"details": parts[2].strip() if len(parts) > 2 else "",
"scent": parts[3].strip() if len(parts) > 3 else ""
}
self.characters[char_id] = char_data
return True
return False
def parse_command(self, command):
"""Обработка команд скрипта"""
# Случайный переход в подпрограмму
if command.startswith("random_gosub "):
parts = command[12:].split()
if len(parts) >= 2:
probability = float(parts[0])
if random.random() < probability:
# Сохраняем текущую позицию для возврата
self.call_stack.append(self.current_line + 1)
# Переходим к случайной подпрограмме
sub_label = random.choice(parts[1:])
self.jump_to_label(sub_label)
return True
# Возврат из подпрограммы
elif command == "return":
if self.call_stack:
self.current_line = self.call_stack.pop()
else:
print("Ошибка: стек вызовов пуст!")
return True
# Установка переменной
elif command.startswith("set "):
parts = command[4:].split("|")
for part in parts:
if "=" in part:
var, val = part.split("=", 1)
self.variables[var.strip()] = val.strip()
return True
# Условие
elif command.startswith("if "):
match = re.match(r'if (\w+)([=!<>]+)(.+?) then goto (\w+)', command[3:])
if match:
var_name, op, value, label = match.groups()
current_value = self.variables.get(var_name, "")
condition_met = False
if op == "==":
condition_met = str(current_value) == value
elif op == "!=":
condition_met = str(current_value) != value
elif op == ">":
condition_met = float(current_value) > float(value)
elif op == "<":
condition_met = float(current_value) < float(value)
if condition_met:
self.jump_to_label(label)
return True
# Метка
elif command.startswith("label "):
return True
# Подпрограмма
elif command.startswith("sub_"):
return True
# Переход
elif command.startswith("goto "):
label = command[5:].strip()
self.jump_to_label(label)
return True
# Фон
elif command.startswith("bg "):
bg_color = command[3:].strip().lower()
if bg_color == "black":
self.background = BLACK
elif bg_color == "white":
self.background = WHITE
elif bg_color == "blue":
self.background = LIGHT_BLUE
elif bg_color == "sunset":
self.background = (255, 153, 51) # Оранжевый для заката
else:
self.background = GRAY
return True
# Персонаж
elif command.startswith("char "):
return self.parse_character(command)
return False
def draw_descriptions(self, text, x, y, font_obj, color):
"""Отрисовка текста с учётом звёздочек"""
if text.startswith("*") and text.endswith("*"):
# Рисуем курсивом для описаний
italic_font = pygame.font.Font(None, 32)
italic_font.set_italic(True)
self.draw_text(text[1:-1], x, y, italic_font, color)
else:
self.draw_text(text, x, y, font_obj, color)
def jump_to_label(self, label):
"""Переход к метке в скрипте"""
for i, line in enumerate(self.script):
if line.startswith(f"@label {label}") or line.startswith(f"@{label}"):
self.current_line = i
return
print(f"Метка '{label}' не найдена!")
def process_choices(self, line):
"""Обработка строки с выбором"""
if line.startswith("choice "):
choices_text = line[7:].split("|")
self.choices = []
for choice_text in choices_text:
parts = choice_text.split("=>")
if len(parts) == 2:
choice_display = parts[0].strip()
choice_action = parts[1].strip()
self.choices.append((choice_display, choice_action))
self.waiting_for_choice = True
return True
return False
def substitute_variables(self, text):
"""Подстановка переменных в текст"""
for var_name, var_value in self.variables.items():
text = text.replace(f"{{{var_name}}}", str(var_value))
return text
def get_character_info(self, char_id):
"""Возвращает полное описание персонажа"""
if char_id not in self.characters:
return f"Персонаж {char_id}", ""
char = self.characters.get(char_id)
if isinstance(char, str):
return char, ""
details = []
if char["appearance"]: details.append(char['appearance'])
if char["details"]: details.append(char['details'])
if char["scent"]: details.append(char['scent'])
return char["name"], " | ".join(details)
def process_line(self):
if self.current_line >= len(self.script):
self.running = False
return None
line = self.script[self.current_line]
line = self.substitute_variables(line)
# Обработка команд
if line.startswith("@"):
if self.parse_command(line[1:]):
self.current_line += 1
return self.process_line()
return None
# Обработка выбора
if self.process_choices(line):
self.current_line += 1
return None
# Обработка диалога с проверкой разделителя
if ":" in line and not line.startswith("*"):
parts = line.split(":", 1)
if len(parts) == 2:
char_id = parts[0].strip()
text = parts[1].strip()
return char_id, text
# Обработка описания или простого текста
return None, line
def make_choice(self, choice_index):
"""Обработка выбора игрока"""
if 0 <= choice_index < len(self.choices):
choice_action = self.choices[choice_index][1]
if choice_action.startswith("goto "):
label = choice_action[5:].strip()
self.jump_to_label(label)
elif "+=" in choice_action:
var, value = choice_action.split("+=", 1)
var = var.strip()
self.variables[var] = str(int(self.variables.get(var, 0)) + int(value.strip()))
self.current_line += 1
elif "-=" in choice_action:
var, value = choice_action.split("-=", 1)
var = var.strip()
self.variables[var] = str(int(self.variables.get(var, 0)) - int(value.strip()))
self.current_line += 1
elif "=" in choice_action:
var, value = choice_action.split("=", 1)
self.variables[var.strip()] = value.strip()
self.current_line += 1
self.choices = []
self.waiting_for_choice = False
def next_line(self):
"""Переход к следующей строке"""
self.current_line += 1
if self.current_line >= len(self.script):
self.running = False
def draw_text_box(self):
"""Отрисовка текстового поля"""
pygame.draw.rect(screen, WHITE, self.text_box_rect)
pygame.draw.rect(screen, DARK_BLUE, self.text_box_rect, 3)
def draw_choice_box(self):
"""Отрисовка поля выбора"""
pygame.draw.rect(screen, CHOICE_BG, self.choice_box_rect)
pygame.draw.rect(screen, DARK_BLUE, self.choice_box_rect, 3)
def draw_text(self, text, x, y, font_obj, color=BLACK, max_width=None):
"""Отрисовка текста с переносом строк"""
if max_width is None:
max_width = self.text_box_rect.width - 40
words = text.split(' ')
space_width = font_obj.size(' ')[0]
line_height = font_obj.get_height()
current_line = []
current_width = 0
for word in words:
word_surface = font_obj.render(word, True, color)
word_width = word_surface.get_width()
if current_width + word_width <= max_width:
current_line.append(word)
current_width += word_width + space_width
else:
line_text = ' '.join(current_line)
line_surface = font_obj.render(line_text, True, color)
screen.blit(line_surface, (x, y))
y += line_height
current_line = [word]
current_width = word_width + space_width
if current_line:
line_text = ' '.join(current_line)
line_surface = font_obj.render(line_text, True, color)
screen.blit(line_surface, (x, y))
def draw(self):
"""Отрисовка текущего состояния"""
# Фон
bg_color = self.background if self.background else LIGHT_BLUE
screen.fill(bg_color)
# Текстовое поле
self.draw_text_box()
# Текст
line_data = self.process_line()
x = self.text_box_rect.x + 20
y = self.text_box_rect.y + 20
if line_data and not self.waiting_for_choice:
if isinstance(line_data, tuple): # Диалог с персонажем
char_id, text = line_data
name, details = self.get_character_info(char_id)
# Отрисовка имени персонажа
name_surface = character_font.render(name + ":", True, DARK_BLUE)
screen.blit(name_surface, (x, y))
y += 40
# Отрисовка текста персонажа
self.draw_text(text, x, y, font, BLACK)
y += 60
# Отрисовка деталей персонажа (если есть)
if details:
details_surface = small_font.render(details, True, (100, 100, 100))
screen.blit(details_surface, (x, y))
else: # Описание или простой текст
_, text = line_data
self.draw_descriptions(text, x, y, font, BLACK)
# Варианты выбора
if self.waiting_for_choice and self.choices:
self.draw_choice_box()
choice_y = self.choice_box_rect.y + 30
for i, (choice_text, _) in enumerate(self.choices):
choice_surface = choice_font.render(f"{i+1}. {choice_text}", True, BLACK)
screen.blit(choice_surface, (self.choice_box_rect.x + 30, choice_y))
choice_y += 40
# Индикатор продолжения
if self.running and not self.waiting_for_choice and line_data:
indicator = font.render("> Нажмите ПРОБЕЛ", True, DARK_BLUE)
screen.blit(indicator, (WIDTH - 200, HEIGHT - 50))
pygame.display.flip()
def run(self):
"""Основной цикл"""
clock = pygame.time.Clock()
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and not self.waiting_for_choice:
self.next_line()
elif event.key == pygame.K_1 and self.waiting_for_choice and len(self.choices) >= 1:
self.make_choice(0)
elif event.key == pygame.K_2 and self.waiting_for_choice and len(self.choices) >= 2:
self.make_choice(1)
elif event.key == pygame.K_3 and self.waiting_for_choice and len(self.choices) >= 3:
self.make_choice(2)
elif event.key == pygame.K_4 and self.waiting_for_choice and len(self.choices) >= 4:
self.make_choice(3)
elif event.key == pygame.K_ESCAPE:
self.running = False
self.draw()
clock.tick(60)
# Создаем экземпляр движка и запускаем
if __name__ == "__main__":
engine = NovelEngine()
if engine.load_script("island_script.txt"):
engine.run()
pygame.quit()
sys.exit()

621
tet/novel.py Normal file
View File

@@ -0,0 +1,621 @@
import pygame
import sys
import os
import re
import random
# Инициализация Pygame
pygame.init()
# Настройки окна
WIDTH, HEIGHT = 1920, 1080
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Визуальная новелла")
# Цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
LIGHT_BLUE = (173, 216, 230)
DARK_BLUE = (0, 0, 139)
CHOICE_BG = (240, 240, 255)
NIGHT_BLUE = (5, 5, 30)
MORNING_YELLOW = (255, 220, 100)
MORNING_GREEN = (100, 180, 80)
MORNING_DARK_BLUE = (20, 40, 100)
DAY_GREEN = (100, 200, 80)
DAY_BLUE = (100, 200, 255)
EVENING_ORANGE = (255, 120, 50)
EVENING_DARK_GREEN = (30, 80, 40)
# Шрифты
try:
font = pygame.font.Font(None, 36)
character_font = pygame.font.Font(None, 32)
choice_font = pygame.font.Font(None, 30)
small_font = pygame.font.Font(None, 24)
italic_font = pygame.font.Font(None, 32)
italic_font.set_italic(True)
except:
font = pygame.font.Font(None, 36)
character_font = pygame.font.Font(None, 32)
choice_font = pygame.font.Font(None, 30)
small_font = pygame.font.Font(None, 24)
italic_font = pygame.font.Font(None, 32)
italic_font.set_italic(True)
class NovelEngine:
def __init__(self):
self.script = []
self.current_line = 0
self.running = True
self.background = None
self.characters = {}
self.variables = {}
self.choices = []
self.waiting_for_choice = False
self.call_stack = [] # Стек для хранения позиций возврата
self.text_box_rect = pygame.Rect(50, HEIGHT - 250, WIDTH - 100, 200)
self.choice_box_rect = pygame.Rect(WIDTH//2 - 300, HEIGHT//2 - 150, 600, 300)
self.special_background = None
self.background_textures = {} # Текстуры для сложных фонов
self.init_background_textures() # Инициализируем текстуры
def load_script(self, filename):
"""Загрузка скрипта из файла"""
self.script = []
script_path = os.path.join(os.path.dirname(__file__), filename)
if not os.path.exists(script_path):
print(f"Ошибка: файл {script_path} не найден!")
return False
with open(script_path, 'r', encoding='utf-8') as file:
for line in file:
line = line.strip()
if line and not line.startswith('#'):
self.script.append(line)
return True
def parse_character(self, command):
"""Обработка описания персонажа с дополнительными атрибутами"""
if command.startswith("char "):
parts = command[5:].split("|")
char_id = parts[0].strip().split(":")[0]
char_data = {
"name": parts[0].split(":")[1].strip(),
"appearance": parts[1].strip() if len(parts) > 1 else "",
"details": parts[2].strip() if len(parts) > 2 else "",
"scent": parts[3].strip() if len(parts) > 3 else ""
}
self.characters[char_id] = char_data
return True
return False
def init_background_textures(self):
"""Создаем текстуры для сложных фонов один раз при инициализации"""
# Ночное небо
night_surface = pygame.Surface((WIDTH, HEIGHT))
night_surface.fill(NIGHT_BLUE)
for _ in range(100):
x = random.randint(0, WIDTH)
y = random.randint(0, HEIGHT // 2)
size = random.randint(1, 3)
brightness = random.randint(200, 255)
pygame.draw.circle(night_surface, (brightness, brightness, brightness), (x, y), size)
self.background_textures["night"] = night_surface
morning_surface = pygame.Surface((WIDTH, HEIGHT))
for y in range(HEIGHT):
ratio = y / HEIGHT
# Верхняя часть (темно-синяя)
if ratio < 0.3:
r = int(MORNING_DARK_BLUE[0])
g = int(MORNING_DARK_BLUE[1])
b = int(MORNING_DARK_BLUE[2])
# Средняя часть (переход)
elif ratio < 0.7:
r = int(MORNING_DARK_BLUE[0] + (MORNING_YELLOW[0] - MORNING_DARK_BLUE[0]) * (ratio - 0.3) / 0.4)
g = int(MORNING_DARK_BLUE[1] + (MORNING_YELLOW[1] - MORNING_DARK_BLUE[1]) * (ratio - 0.3) / 0.4)
b = int(MORNING_DARK_BLUE[2] + (MORNING_YELLOW[2] - MORNING_DARK_BLUE[2]) * (ratio - 0.3) / 0.4)
# Нижняя часть (зеленая)
else:
r = int(MORNING_GREEN[0])
g = int(MORNING_GREEN[1])
b = int(MORNING_GREEN[2])
pygame.draw.line(morning_surface, (r, g, b), (0, y), (WIDTH, y))
pygame.draw.circle(morning_surface, MORNING_YELLOW, (WIDTH // 2, HEIGHT // 3), 50)
self.background_textures["morning"] = morning_surface
day_surface = pygame.Surface((WIDTH, HEIGHT))
# Градиент от голубого к зеленому
for y in range(HEIGHT):
ratio = y / HEIGHT
if ratio < 0.8:
r = int(DAY_BLUE[0])
g = int(DAY_BLUE[1])
b = int(DAY_BLUE[2])
else:
r = int(DAY_GREEN[0])
g = int(DAY_GREEN[1])
b = int(DAY_GREEN[2])
pygame.draw.line(day_surface, (r, g, b), (0, y), (WIDTH, y))
# Рисуем облака
for _ in range(5):
x = random.randint(0, WIDTH)
y = random.randint(50, HEIGHT // 3)
size = random.randint(30, 70)
pygame.draw.circle(day_surface, WHITE, (x, y), size)
pygame.draw.circle(day_surface, WHITE, (x + size//2, y - size//3), size//2)
pygame.draw.circle(day_surface, WHITE, (x - size//2, y - size//4), size//2)
self.background_textures["day"] = day_surface
evening_surface = pygame.Surface((WIDTH, HEIGHT))
for y in range(HEIGHT):
ratio = y / HEIGHT
if ratio < 0.5:
r = int(EVENING_ORANGE[0])
g = int(EVENING_ORANGE[1])
b = int(EVENING_ORANGE[2])
else:
r = int(EVENING_ORANGE[0] + (EVENING_DARK_GREEN[0] - EVENING_ORANGE[0]) * (ratio - 0.5) / 0.5)
g = int(EVENING_ORANGE[1] + (EVENING_DARK_GREEN[1] - EVENING_ORANGE[1]) * (ratio - 0.5) / 0.5)
b = int(EVENING_ORANGE[2] + (EVENING_DARK_GREEN[2] - EVENING_ORANGE[2]) * (ratio - 0.5) / 0.5)
pygame.draw.line(evening_surface, (r, g, b), (0, y), (WIDTH, y))
# Рисуем заходящее солнце
pygame.draw.circle(evening_surface, (255, 200, 100), (WIDTH // 2, HEIGHT // 2), 60)
pygame.draw.rect(evening_surface, EVENING_DARK_GREEN, (0, HEIGHT // 2, WIDTH, HEIGHT // 2))
self.background_textures["evening"] = evening_surface
def draw_night_sky(self):
"""Рисует ночное небо со звездами"""
screen.blit(self.background_textures["night"], (0, 0))
def draw_morning_sky(self):
"""Рисует утреннее небо с градиентом"""
screen.blit(self.background_textures["morning"], (0, 0))
def draw_day_sky(self):
"""Рисует дневное небо с облаками"""
screen.blit(self.background_textures["day"], (0, 0))
def draw_evening_sky(self):
"""Рисует вечернее небо с закатом"""
screen.blit(self.background_textures["evening"], (0, 0))
def parse_command(self, command):
"""Обработка команд скрипта"""
# Случайный переход в подпрограмму
if command.startswith("random_gosub "):
parts = command[12:].split()
if len(parts) >= 2:
# Создаем список вариантов с их вероятностями
options = []
probabilities = []
labels = []
# Разбираем части на вероятности и метки
i = 0
while i < len(parts):
try:
prob = float(parts[i])
label = parts[i+1]
probabilities.append(prob)
labels.append(label)
options.append((prob, label))
i += 2
except (ValueError, IndexError):
break
if options:
# Нормализуем вероятности (на случай, если они не суммируются в 1)
total = sum(prob for prob, label in options)
if total > 0:
rand = random.random() * total
cumulative = 0
for prob, label in options:
cumulative += prob
if rand <= cumulative:
# Сохраняем текущую позицию для возврата
self.call_stack.append(self.current_line + 1)
# Переходим к выбранной подпрограмме
self.jump_to_label(label)
break
return True
# Возврат из подпрограммы
elif command == "return":
if self.call_stack:
self.current_line = self.call_stack.pop()
else:
print("Ошибка: стек вызовов пуст!")
return True
# Установка переменной
elif command.startswith("set "):
parts = command[4:].split("|")
for part in parts:
part = part.strip()
if "+=" in part:
var, val = part.split("+=", 1)
var = var.strip()
current = int(self.variables.get(var, 0))
self.variables[var] = str(current + int(val.strip()))
elif "-=" in part:
var, val = part.split("-=", 1)
var = var.strip()
current = int(self.variables.get(var, 0))
self.variables[var] = str(current - int(val.strip()))
elif "=" in part:
var, val = part.split("=", 1)
var = var.strip()
val = val.strip()
# Обработка инкремента (++var)
if val.startswith("++"):
var_to_inc = val[2:]
self.variables[var] = str(int(self.variables.get(var_to_inc, 0)) + 1)
# Обработка декремента (--var)
elif val.startswith("--"):
var_to_dec = val[2:]
self.variables[var] = str(int(self.variables.get(var_to_dec, 0)) - 1)
# Обычное присваивание
else:
self.variables[var] = val
print(f"После выполнения '{command}': {self.variables}") # Отладочный вывод
return True
# Условие
elif command.startswith("if "):
# ИСПРАВЛЕННЫЙ regex с обработкой пробелов
match = re.match(r'if\s+(\w+)\s*([=!<>]+)\s*(.+?)\s+then\s+goto\s+(\w+)', command)
if match:
var_name, op, value, label = match.groups()
current_value = self.variables.get(var_name, "0")
print(f"Отладка: if {var_name}({current_value}) {op} {value} then goto {label}") # Отладка
# Пробуем численное сравнение
try:
current_num = float(current_value)
value_num = float(value)
if op == ">": condition_met = current_num > value_num
elif op == "<": condition_met = current_num < value_num
elif op == ">=": condition_met = current_num >= value_num
elif op == "<=": condition_met = current_num <= value_num
elif op == "==": condition_met = current_num == value_num
elif op == "!=": condition_met = current_num != value_num
else: condition_met = False
except ValueError:
# Строковое сравнение
if op == ">": condition_met = current_value > value
elif op == "<": condition_met = current_value < value
elif op == ">=": condition_met = current_value >= value
elif op == "<=": condition_met = current_value <= value
elif op == "==": condition_met = current_value == value
elif op == "!=": condition_met = current_value != value
else: condition_met = False
if condition_met:
print(f"Условие выполнено, переход к {label}") # Отладка
self.jump_to_label(label)
else:
print("Условие не выполнено") # Отладка
return True
# Метка
elif command.startswith("label "):
return True
# Подпрограмма
elif command.startswith("sub_"):
if not self.call_stack or self.call_stack[-1] != self.current_line:
self.call_stack.append(self.current_line)
return True
# Возврат из подпрограммы
elif command == "return":
if not self.call_stack:
print("Предупреждение: return без вызова подпрограммы, пропускаем")
self.current_line += 1
else:
self.current_line = self.call_stack.pop() + 1 # Возвращаемся на следующую строку
return True
# Переход
elif command.startswith("goto "):
label = command[5:].strip()
self.jump_to_label(label)
return True
# Фон
elif command.startswith("bg "):
bg_color = command[3:].strip().lower()
if bg_color == "black":
self.background = BLACK
self.special_background = None
elif bg_color == "white":
self.background = WHITE
self.special_background = None
elif bg_color == "blue":
self.background = LIGHT_BLUE
self.special_background = None
elif bg_color == "night":
self.special_background = "night"
elif bg_color == "morning":
self.special_background = "morning"
elif bg_color == "day":
self.special_background = "day"
elif bg_color == "evening" or bg_color == "sunset":
self.special_background = "evening"
else:
self.background = GRAY
self.special_background = None
return True
# Персонаж
elif command.startswith("char "):
return self.parse_character(command)
return False
def draw_descriptions(self, text, x, y, font_obj, color):
"""Отрисовка текста с учётом звёздочек"""
if text.startswith("*") and text.endswith("*"):
# Удаляем звёздочки и рисуем курсивом
self.draw_text(text[1:-1], x, y, italic_font, (150, 150, 150))
else:
self.draw_text(text, x, y, font_obj, color)
def jump_to_label(self, label):
"""Переход к метке в скрипте"""
for i, line in enumerate(self.script):
if line.startswith(f"@label {label}") or line.startswith(f"@{label}"):
self.current_line = i
return
print(f"Метка '{label}' не найдена!")
def process_choices(self, line):
"""Обработка строки с выбором"""
if line.startswith("choice "):
choices_text = line[7:].split("|")
self.choices = []
for choice_text in choices_text:
parts = choice_text.split("=>")
if len(parts) == 2:
choice_display = parts[0].strip()
choice_action = parts[1].strip()
self.choices.append((choice_display, choice_action))
self.waiting_for_choice = True
return True
return False
def substitute_variables(self, text):
"""Подстановка переменных в текст"""
for var_name, var_value in self.variables.items():
text = text.replace(f"{{{var_name}}}", str(var_value))
return text
def get_character_info(self, char_id):
"""Возвращает полное описание персонажа"""
# Убираем вывод "Персонаж none" для несуществующих ID
if char_id not in self.characters:
return "", "" # Возвращаем пустые строки
char = self.characters.get(char_id)
if isinstance(char, str):
return char, ""
details = []
if char.get("appearance"): details.append(char['appearance'])
if char.get("details"): details.append(char['details'])
if char.get("scent"): details.append(char['scent'])
return char.get("name", ""), " | ".join(details)
def process_line(self):
if self.current_line >= len(self.script):
self.running = False
return None
line = self.script[self.current_line]
line = self.substitute_variables(line)
# Обработка команд
if line.startswith("@"):
if self.parse_command(line[1:]):
self.current_line += 1
return self.process_line()
return None
# Обработка выбора
if self.process_choices(line):
self.current_line += 1
return None
# Обработка диалога с проверкой разделителя
if ":" in line and not line.startswith("*"):
parts = line.split(":", 1)
if len(parts) == 2:
char_id = parts[0].strip()
text = parts[1].strip()
return char_id, text
# Обработка описания или простого текста
return None, line
def make_choice(self, choice_index):
"""Обработка выбора игрока"""
if 0 <= choice_index < len(self.choices):
choice_action = self.choices[choice_index][1]
if choice_action.startswith("goto "):
label = choice_action[5:].strip()
self.jump_to_label(label)
elif "+=" in choice_action:
var, value = choice_action.split("+=", 1)
var = var.strip()
self.variables[var] = str(int(self.variables.get(var, 0)) + int(value.strip()))
self.current_line += 1
elif "-=" in choice_action:
var, value = choice_action.split("-=", 1)
var = var.strip()
self.variables[var] = str(int(self.variables.get(var, 0)) - int(value.strip()))
self.current_line += 1
elif "=" in choice_action:
var, value = choice_action.split("=", 1)
self.variables[var.strip()] = value.strip()
self.current_line += 1
self.choices = []
self.waiting_for_choice = False
def next_line(self):
"""Переход к следующей строке"""
self.current_line += 1
if self.current_line >= len(self.script):
self.running = False
def draw_text_box(self):
"""Отрисовка текстового поля"""
pygame.draw.rect(screen, WHITE, self.text_box_rect)
pygame.draw.rect(screen, DARK_BLUE, self.text_box_rect, 3)
def draw_choice_box(self):
"""Отрисовка поля выбора"""
# Создаем полупрозрачную поверхность
s = pygame.Surface((600, 300), pygame.SRCALPHA)
s.fill((240, 240, 255, 230)) # Последний параметр - прозрачность
screen.blit(s, (self.choice_box_rect.x, self.choice_box_rect.y))
pygame.draw.rect(screen, DARK_BLUE, self.choice_box_rect, 3)
def draw_text(self, text, x, y, font_obj, color=BLACK, max_width=None):
"""Отрисовка текста с переносом строк"""
if max_width is None:
max_width = self.text_box_rect.width - 40
words = text.split(' ')
space_width = font_obj.size(' ')[0]
line_height = font_obj.get_height()
current_line = []
current_width = 0
for word in words:
word_surface = font_obj.render(word, True, color)
word_width = word_surface.get_width()
if current_width + word_width <= max_width:
current_line.append(word)
current_width += word_width + space_width
else:
line_text = ' '.join(current_line)
line_surface = font_obj.render(line_text, True, color)
screen.blit(line_surface, (x, y))
y += line_height
current_line = [word]
current_width = word_width + space_width
if current_line:
line_text = ' '.join(current_line)
line_surface = font_obj.render(line_text, True, color)
screen.blit(line_surface, (x, y))
def draw(self):
"""Отрисовка текущего состояния"""
# Фон
if self.special_background and self.special_background in self.background_textures:
screen.blit(self.background_textures[self.special_background], (0, 0))
elif self.background:
screen.fill(self.background)
else:
screen.fill(LIGHT_BLUE)
# Текстовое поле (убираем очистку перед выбором)
if not self.waiting_for_choice:
self.draw_text_box()
# Текст
line_data = self.process_line()
x = self.text_box_rect.x + 20
y = self.text_box_rect.y + 20
if line_data and not self.waiting_for_choice:
if isinstance(line_data, tuple): # Диалог с персонажем
char_id, text = line_data
name, details = self.get_character_info(char_id)
# Отрисовываем имя только если оно есть
if name:
name_surface = character_font.render(name + ":", True, DARK_BLUE)
screen.blit(name_surface, (x, y))
y += 40
# Отрисовка текста персонажа
self.draw_text(text, x, y, font, BLACK)
y += 60
# Отрисовка деталей персонажа (если есть)
if details:
details_surface = small_font.render(details, True, (100, 100, 100))
screen.blit(details_surface, (x, y))
else: # Описание или простой текст
_, text = line_data
self.draw_descriptions(text, x, y, font, BLACK)
# Варианты выбора
if self.waiting_for_choice and self.choices:
self.draw_choice_box()
choice_y = self.choice_box_rect.y + 30
for i, (choice_text, _) in enumerate(self.choices):
choice_surface = choice_font.render(f"{i+1}. {choice_text}", True, BLACK)
screen.blit(choice_surface, (self.choice_box_rect.x + 30, choice_y))
choice_y += 40
# Индикатор продолжения
if self.running and not self.waiting_for_choice and line_data:
indicator = font.render("> ПРОБЕЛ", True, DARK_BLUE)
screen.blit(indicator, (WIDTH - 200, HEIGHT - 50))
pygame.display.flip()
def run(self):
"""Основной цикл"""
clock = pygame.time.Clock()
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and not self.waiting_for_choice:
self.next_line()
elif event.key == pygame.K_1 and self.waiting_for_choice and len(self.choices) >= 1:
self.make_choice(0)
elif event.key == pygame.K_2 and self.waiting_for_choice and len(self.choices) >= 2:
self.make_choice(1)
elif event.key == pygame.K_3 and self.waiting_for_choice and len(self.choices) >= 3:
self.make_choice(2)
elif event.key == pygame.K_4 and self.waiting_for_choice and len(self.choices) >= 4:
self.make_choice(3)
elif event.key == pygame.K_ESCAPE:
self.running = False
self.draw()
clock.tick(60)
# Создаем экземпляр движка и запускаем
if __name__ == "__main__":
engine = NovelEngine()
if engine.load_script("island_script.txt"):
engine.run()
pygame.quit()
sys.exit()

188
tet/pong.py Normal file
View File

@@ -0,0 +1,188 @@
import pygame
import sys
import random
import math
# Инициализация Pygame
pygame.init()
# Константы
WIDTH, HEIGHT = 1920, 1080
PADDLE_WIDTH, PADDLE_HEIGHT = 30, 200
BALL_SIZE = 30
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (50, 168, 82)
LIGHT_GREEN = (100, 200, 100)
FPS = 120 # Увеличили FPS для плавности на высоких скоростях
# Создание окна
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pong - ХЕРАЧЬ Edition v2.0")
clock = pygame.time.Clock()
# Загрузка шрифтов
try:
pixel_font = pygame.font.Font("PressStart2P-Regular.ttf", 120)
except:
pixel_font = pygame.font.SysFont('arial', 120)
# Игровые объекты
player_paddle = pygame.Rect(100, HEIGHT // 2 - PADDLE_HEIGHT // 2, PADDLE_WIDTH, PADDLE_HEIGHT)
ai_paddle = pygame.Rect(WIDTH - 100 - PADDLE_WIDTH, HEIGHT // 2 - PADDLE_HEIGHT // 2, PADDLE_WIDTH, PADDLE_HEIGHT)
ball = pygame.Rect(WIDTH // 2 - BALL_SIZE // 2, HEIGHT // 2 - BALL_SIZE // 2, BALL_SIZE, BALL_SIZE)
# Физика мяча
base_speed = 3
max_speed = 35 # Увеличили максимальную скорость
speed_increase = 0.7 # Увеличили ускорение после удара
ball_speed = base_speed
ball_dx = ball_speed * random.choice((1, -1))
ball_dy = ball_speed * random.choice((1, -1))
# Скорости
player_speed = 0
ai_speed = 0
# Счет
player_score = 0
ai_score = 0
font = pygame.font.Font(None, 72)
def draw_field():
"""Рисует поле с разметкой"""
screen.fill(GREEN)
# Полупрозрачная надпись
text_surface = pixel_font.render("ХЕРАЧЬ!", True, LIGHT_GREEN)
text_surface.set_alpha(30)
screen.blit(text_surface, (WIDTH//2 - text_surface.get_width()//2, HEIGHT//2 - text_surface.get_height()//2))
# Разметка
for y in range(0, HEIGHT, 40):
pygame.draw.rect(screen, WHITE, (WIDTH // 2 - 5, y, 10, 20))
pygame.draw.rect(screen, WHITE, (0, 0, WIDTH, HEIGHT), 10)
def reset_ball():
"""Сбрасывает мяч в центр"""
global ball_speed, ball_dx, ball_dy
ball.center = (WIDTH // 2, HEIGHT // 2)
ball_speed = base_speed
angle = math.radians(random.uniform(30, 60))
direction = random.choice((-1, 1))
ball_dx = direction * ball_speed * math.cos(angle)
ball_dy = ball_speed * math.sin(angle) * random.choice((-1, 1))
def handle_collision():
"""Обрабатывает все столкновения"""
global ball_dx, ball_dy, ball_speed
# Жесткие границы (мяч не может вылететь)
if ball.top < 0:
ball.top = 0
ball_dy = abs(ball_dy) * 0.95 # Небольшая потеря энергии
if ball.bottom > HEIGHT:
ball.bottom = HEIGHT
ball_dy = -abs(ball_dy) * 0.95
# Обработка ударов о ракетки с более сильным ускорением
if ball.colliderect(player_paddle) and ball_dx < 0:
# Сильное ускорение + случайный угол
relative_intersect = (player_paddle.centery - ball.centery) / (PADDLE_HEIGHT / 2)
ball_dx = abs(ball_dx) * 1.25 # Увеличили ускорение
ball_dy = -relative_intersect * ball_speed * 2
# Добавляем случайности
ball_dx += random.uniform(-0.5, 0.5)
ball_dy += random.uniform(-1, 1)
elif ball.colliderect(ai_paddle) and ball_dx > 0:
relative_intersect = (ai_paddle.centery - ball.centery) / (PADDLE_HEIGHT / 2)
ball_dx = -abs(ball_dx) * 1.25
ball_dy = -relative_intersect * ball_speed * 2
ball_dx += random.uniform(-0.5, 0.5)
ball_dy += random.uniform(-1, 1)
# Нормализация скорости
speed = math.sqrt(ball_dx**2 + ball_dy**2)
if speed > max_speed:
ball_dx = (ball_dx / speed) * max_speed
ball_dy = (ball_dy / speed) * max_speed
ball_speed = speed
def ai_movement():
"""Упрощенный ИИ с ошибками"""
global ai_speed
# Простое следование за мячом с задержкой и ошибками
target_y = ball.centery + random.uniform(-50, 50) # Добавляем ошибку
# Замедляем ИИ на высоких скоростях
reaction_speed = max(3, 8 - ball_speed * 0.2)
if ai_paddle.centery < target_y:
ai_speed = min(reaction_speed, target_y - ai_paddle.centery)
else:
ai_speed = max(-reaction_speed, target_y - ai_paddle.centery)
ai_paddle.y += ai_speed
# Границы
if ai_paddle.top < 0:
ai_paddle.top = 0
if ai_paddle.bottom > HEIGHT:
ai_paddle.bottom = HEIGHT
# Основной цикл
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
player_speed = 15
if event.key == pygame.K_UP:
player_speed = -15
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN or event.key == pygame.K_UP:
player_speed = 0
# Движение
player_paddle.y += player_speed
if player_paddle.top < 0:
player_paddle.top = 0
if player_paddle.bottom > HEIGHT:
player_paddle.bottom = HEIGHT
ai_movement()
# Физика мяча
ball.x += ball_dx
ball.y += ball_dy
handle_collision()
# Голы
if ball.left <= 0:
ai_score += 1
reset_ball()
if ball.right >= WIDTH:
player_score += 1
base_speed = min(15, base_speed + speed_increase)
reset_ball()
# Отрисовка
draw_field()
pygame.draw.rect(screen, WHITE, player_paddle, border_radius=10)
pygame.draw.rect(screen, WHITE, ai_paddle, border_radius=10)
pygame.draw.ellipse(screen, WHITE, ball)
# Счет
screen.blit(font.render(f"{player_score}", True, WHITE), (WIDTH//4, 50))
screen.blit(font.render(f"{ai_score}", True, WHITE), (3*WIDTH//4 - 50, 50))
pygame.display.flip()
clock.tick(FPS)

256
tet/tetris.py Normal file
View File

@@ -0,0 +1,256 @@
import pygame
import random
# Инициализация pygame
pygame.init()
# Цвета
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (70, 70, 70)
COLORS = [
(0, 255, 255), # I - голубой
(0, 0, 255), # J - синий
(255, 165, 0), # L - оранжевый
(255, 255, 0), # O - желтый
(0, 255, 0), # S - зеленый
(128, 0, 128), # T - фиолетовый
(255, 0, 0) # Z - красный
]
# Настройки игры
BLOCK_SIZE = 30
GRID_WIDTH = 10
GRID_HEIGHT = 20
SCREEN_WIDTH = BLOCK_SIZE * (GRID_WIDTH + 6)
SCREEN_HEIGHT = BLOCK_SIZE * GRID_HEIGHT
GAME_AREA_LEFT = BLOCK_SIZE
# Фигуры тетрамино
SHAPES = [
[[1, 1, 1, 1]], # I
[[1, 0, 0], [1, 1, 1]], # J
[[0, 0, 1], [1, 1, 1]], # L
[[1, 1], [1, 1]], # O
[[0, 1, 1], [1, 1, 0]], # S
[[0, 1, 0], [1, 1, 1]], # T
[[1, 1, 0], [0, 1, 1]] # Z
]
# Создание экрана
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Тетрис")
# Часы для управления FPS
clock = pygame.time.Clock()
class Tetris:
def __init__(self):
self.grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
self.current_piece = self.new_piece()
self.game_over = False
self.score = 0
self.level = 1
self.fall_speed = 0.5 # секунды между падением на 1 клетку
self.fall_time = 0
def new_piece(self):
# Выбираем случайную фигуру
shape = random.choice(SHAPES)
color = COLORS[SHAPES.index(shape)]
# Начальная позиция (по центру сверху)
x = GRID_WIDTH // 2 - len(shape[0]) // 2
y = 0
return {"shape": shape, "color": color, "x": x, "y": y}
def valid_move(self, piece, x_offset=0, y_offset=0):
for y, row in enumerate(piece["shape"]):
for x, cell in enumerate(row):
if cell:
new_x = piece["x"] + x + x_offset
new_y = piece["y"] + y + y_offset
if (new_x < 0 or new_x >= GRID_WIDTH or
new_y >= GRID_HEIGHT or
(new_y >= 0 and self.grid[new_y][new_x])):
return False
return True
def rotate_piece(self):
# Получаем текущую фигуру
piece = self.current_piece
# Транспонируем матрицу фигуры (поворот на 90 градусов)
rotated = [[piece["shape"][y][x] for y in range(len(piece["shape"])-1, -1, -1)]
for x in range(len(piece["shape"][0]))]
old_shape = piece["shape"]
piece["shape"] = rotated
# Если после поворота фигура выходит за границы или пересекается с другими блоками,
# отменяем поворот
if not self.valid_move(piece):
piece["shape"] = old_shape
def lock_piece(self):
piece = self.current_piece
for y, row in enumerate(piece["shape"]):
for x, cell in enumerate(row):
if cell:
# Проверяем, не выходит ли фигура за верхнюю границу (игра окончена)
if piece["y"] + y < 0:
self.game_over = True
else:
self.grid[piece["y"] + y][piece["x"] + x] = piece["color"]
# Проверяем заполненные линии
self.clear_lines()
# Создаем новую фигуру
self.current_piece = self.new_piece()
# Если новая фигура сразу не может разместиться, игра окончена
if not self.valid_move(self.current_piece):
self.game_over = True
def clear_lines(self):
lines_cleared = 0
for y in range(GRID_HEIGHT):
if all(self.grid[y]):
lines_cleared += 1
# Удаляем линию и сдвигаем все вышележащие линии вниз
for y2 in range(y, 0, -1):
self.grid[y2] = self.grid[y2-1][:]
self.grid[0] = [0 for _ in range(GRID_WIDTH)]
# Обновляем счет
if lines_cleared == 1:
self.score += 100 * self.level
elif lines_cleared == 2:
self.score += 300 * self.level
elif lines_cleared == 3:
self.score += 500 * self.level
elif lines_cleared == 4:
self.score += 800 * self.level
# Обновляем уровень (каждые 10 линий)
self.level = 1 + self.score // 1000
# Увеличиваем скорость (максимум 0.05 секунды между падениями)
self.fall_speed = max(0.05, 0.5 - (self.level - 1) * 0.05)
def update(self, delta_time):
if self.game_over:
return
self.fall_time += delta_time
# Автоматическое падение фигуры
if self.fall_time >= self.fall_speed:
self.fall_time = 0
if self.valid_move(self.current_piece, 0, 1):
self.current_piece["y"] += 1
else:
self.lock_piece()
def draw(self):
# Очищаем экран
screen.fill(BLACK)
# Рисуем игровую область
pygame.draw.rect(screen, WHITE, (GAME_AREA_LEFT, 0, BLOCK_SIZE * GRID_WIDTH, SCREEN_HEIGHT), 1)
# Рисуем сетку
for x in range(GRID_WIDTH):
for y in range(GRID_HEIGHT):
pygame.draw.rect(screen, GRAY,
(GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE), 1)
# Рисуем статичные блоки
for y in range(GRID_HEIGHT):
for x in range(GRID_WIDTH):
if self.grid[y][x]:
pygame.draw.rect(screen, self.grid[y][x],
(GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE))
pygame.draw.rect(screen, WHITE,
(GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE), 1)
# Рисуем текущую фигуру
if not self.game_over:
piece = self.current_piece
for y, row in enumerate(piece["shape"]):
for x, cell in enumerate(row):
if cell:
pygame.draw.rect(screen, piece["color"],
(GAME_AREA_LEFT + (piece["x"] + x) * BLOCK_SIZE,
(piece["y"] + y) * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE))
pygame.draw.rect(screen, WHITE,
(GAME_AREA_LEFT + (piece["x"] + x) * BLOCK_SIZE,
(piece["y"] + y) * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE), 1)
# Рисуем информацию (счет, уровень)
font = pygame.font.SysFont(None, 36)
score_text = font.render(f"Счет: {self.score}", True, WHITE)
level_text = font.render(f"Уровень: {self.level}", True, WHITE)
screen.blit(score_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE + 10, 30))
screen.blit(level_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE + 10, 70))
# Если игра окончена, выводим сообщение
if self.game_over:
game_over_font = pygame.font.SysFont(None, 48)
game_over_text = game_over_font.render("Игра Окончена!", True, (255, 0, 0))
screen.blit(game_over_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE // 2 - 100,
SCREEN_HEIGHT // 2 - 24))
# Создаем экземпляр игры
game = Tetris()
# Основной игровой цикл
running = True
last_time = pygame.time.get_ticks()
while running:
# Управление FPS
current_time = pygame.time.get_ticks()
delta_time = (current_time - last_time) / 1000.0 # Конвертируем в секунды
last_time = current_time
# Обработка событий
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if not game.game_over:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if game.valid_move(game.current_piece, -1, 0):
game.current_piece["x"] -= 1
elif event.key == pygame.K_RIGHT:
if game.valid_move(game.current_piece, 1, 0):
game.current_piece["x"] += 1
elif event.key == pygame.K_DOWN:
if game.valid_move(game.current_piece, 0, 1):
game.current_piece["y"] += 1
elif event.key == pygame.K_UP:
game.rotate_piece()
elif event.key == pygame.K_SPACE:
# Мгновенное падение
while game.valid_move(game.current_piece, 0, 1):
game.current_piece["y"] += 1
game.lock_piece()
# Обновление игры
game.update(delta_time)
# Отрисовка
game.draw()
pygame.display.flip()
# Ограничиваем FPS
clock.tick(60)
pygame.quit()

88
twitch.py Normal file
View File

@@ -0,0 +1,88 @@
############################################### twitchSockets
import re
from zoneinfo import *
from datetime import datetime
import socket
# from huy import tw_comments
class TwitchChatIRC():
__HOST = 'irc.chat.twitch.tv'
__NICK = 'justinfan67420'
__PASS = 'SCHMOOPIIE'
__PORT = 6667
all_messages = []
__PATTERN = re.compile(r'@(.+?(?=\s+:)).*PRIVMSG[^:]*:([^\r\n]*)')
def __init__(self, channel):
self.__SOCKET = socket.socket()
self.__SOCKET.connect((self.__HOST, self.__PORT))
print('Connected to twitch socket:',self.__HOST,'on port',self.__PORT)
self.__send_raw('CAP REQ :twitch.tv/tags')
self.__send_raw('PASS ' + self.__PASS)
self.__send_raw('NICK ' + self.__NICK)
self.__send_raw('JOIN #{}'.format(channel))
self.__SOCKET.settimeout(2.0)
def __send_raw(self, string):
self.__SOCKET.send((string+'\r\n').encode('utf-8'))
def __recvall(self,buffer_size):
data = b''
while True:
part =self.__SOCKET.recv(buffer_size)
data += part
if len(part) < buffer_size:
break
return data.decode('utf-8')
def close_connection(__SOCKET):
__SOCKET.close()
print('Connection closed')
def listen(self, timeout=None, message_timeout=1.0, on_message = None, buffer_size = 4096, message_limit = None, output=None):
readbuffer = ''
print('Starting twitch thread...')
try:
while True:
try:
new_info = self.__recvall(buffer_size)
readbuffer += new_info
if('PING :tmi.twitch.tv' in readbuffer):
self.__send_raw('PONG :tmi.twitch.tv')
matches = list(self.__PATTERN.finditer(readbuffer))
if(matches):
if(len(matches) > 1):
matches = matches[:-1] # assume last one is incomplete
last_index = matches[-1].span()[1]
readbuffer = readbuffer[last_index:]
for match in matches:
data = {}
for item in match.group(1).split(';'):
keys = item.split('=',1)
data[keys[0]]=keys[1]
data['message'] = match.group(2)
dt = datetime.fromtimestamp(int(data['tmi-sent-ts'])/1000).replace(tzinfo=ZoneInfo('Asia/Yekaterinburg'))
my_data = dict({'id': data['id'], 'type': 'tw', 'date': dt, 'sendr': data['display-name'], 'msg': data['message'].encode('utf-8').decode('utf-8','ignore')})
# print(data)
self.all_messages.append(my_data)
except socket.timeout:
if(timeout != None):
print('timeout!')
except KeyboardInterrupt:
print('Interrupted by user.')
# except Exception as e:
# print('Unknown Error:',e)
# raise e
# return messages
########################################################################################

2
twitchchatirc/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.env
__pycache__

21
twitchchatirc/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Joshua Lochner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

189
twitchchatirc/README.md Normal file
View File

@@ -0,0 +1,189 @@
# Twitch Chat IRC
A simple tool used to send and receive Twitch chat messages over IRC with python web sockets. Receiving does not require authentication, while sending does.
## Setup
### Requirements:
* This tool was created in a Python 3 environment.
* Run `pip install -r requirements.txt` to ensure you have the necessary dependencies.
### Authentication
If you intend to send messages, you will require authentication.
1. Go to https://twitchapps.com/tmi/
2. Click "Connect".
3. Log in with Twitch.
4. Copy the generated oath token. Now, there are 2 ways to proceed:
- (Recommended) Create a file called `.env` and save your credentials here as:
> NICK=x <br> PASS=y
replacing `x` and `y` with your username and oauth token respectively.<br> See `example.env` for an example.
- Pass your credentials as function/command line arguments. See below for examples.
## Command line:
### Usage
```
usage: twitch_chat_irc.py [-h] [-timeout TIMEOUT]
[-message_timeout MESSAGE_TIMEOUT]
[-buffer_size BUFFER_SIZE]
[-message_limit MESSAGE_LIMIT] [-username USERNAME]
[-oauth OAUTH] [--send] [-output OUTPUT]
channel_name
Send and receive Twitch chat messages over IRC with python web sockets. For
more info, go to https://dev.twitch.tv/docs/irc/guide
positional arguments:
channel_name Twitch channel name (username)
optional arguments:
-h, --help show this help message and exit
-timeout TIMEOUT, -t TIMEOUT
time in seconds needed to close connection after not
receiving any new data (default: None = no timeout)
-message_timeout MESSAGE_TIMEOUT, -mt MESSAGE_TIMEOUT
time in seconds between checks for new data (default:
1 second)
-buffer_size BUFFER_SIZE, -b BUFFER_SIZE
buffer size (default: 4096 bytes = 4 KB)
-message_limit MESSAGE_LIMIT, -l MESSAGE_LIMIT
maximum amount of messages to get (default: None =
unlimited)
-username USERNAME, -u USERNAME
username (default: None)
-oauth OAUTH, -password OAUTH, -p OAUTH
oath token (default: None). Get custom one from
https://twitchapps.com/tmi/
--send send mode (default: False)
-output OUTPUT, -o OUTPUT
output file (default: None = print to standard output)
```
### Examples
#### Receiving messages
##### 1. Output messages from a livestream to standard output
```
python twitch_chat_irc.py <channel_name>
```
##### 2. Output messages from a livestream to a file
```
python twitch_chat_irc.py <channel_name> -output <file_name>
```
If the file name ends in `.json`, the array will be written to the file in JSON format. Similarly, if the file name ends in `.csv`, the data will be written in CSV format. <br> Otherwise, the chat messages will be outputted to the file in the following format:<br>
`[<time>] <author>: <message>`
##### 3. Set a timeout (close connection if no message has been sent in a certain time)
```
python twitch_chat_irc.py <channel_name> -timeout <time_in_seconds> -output <file_name>
```
There are other options, such as `message_timeout` and `buffer_size`, but these normally do not need to be changed. See above for a description of all options.
##### 4. Set a maximum number of messages to read (close connection once limit has been reached)
```
python twitch_chat_irc.py <channel_name> -message_limit <number_of_messages> -output <file_name>
```
#### Example outputs
[JSON Example](examples/example.json):
```
python twitch_chat_irc.py <channel_name> -output example.json
```
[CSV Example](examples/example.csv):
```
python twitch_chat_irc.py <channel_name> -output example.csv
```
[Text Example](examples/example.txt):
```
python twitch_chat_irc.py <channel_name> -output example.txt
```
#### Sending messages
This will open an interactive session which allows you to send messages to the specified channel.
##### 1. Send messages to a channel (authentication via .env)
```
python twitch_chat_irc.py --send <channel_name>
```
##### 2. Send messages to a channel (authentication via arguments)
```
python twitch_chat_irc.py --send <channel_name> -username <username> -oauth <oauth_token>
```
## Python module
### Importing the module
```python
import twitch_chat_irc
```
### Examples
#### Starting a connection
This allows for both receiving and sending of messages
##### 1. Start a connection with Twitch chat using credentials in `.env` (if any)
```python
connection = twitch_chat_irc.TwitchChatIRC()
```
##### 2. Start a connection with Twitch chat using credentials
```python
connection = twitch_chat_irc.TwitchChatIRC('username','oauth:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
```
#### Receiving messages
The `listen` method returns a list when a `KeyboardInterrupt` is fired, or when a timeout/limit has been reached. The arguments shown below can be used together to form more complex method calls.
##### 1. Get a list of messages from a channel
```python
messages = connection.listen('channel_name')
```
##### 2. Get a list of messages from a channel, stopping after not getting a message for 30 seconds
```python
messages = connection.listen('channel_name', timeout=30)
```
##### 3. Get a list of messages from a channel, stopping after getting 100 messages
```python
messages = connection.listen('channel_name', message_limit=100)
```
##### 4. Write messages from a channel to a file
```python
connection.listen('channel_name', output='file.txt')
```
##### 5. Set a callback function to be fired each time a message is received
```python
def do_something(message):
print(message)
connection.listen('channel_name', on_message=do_something)
```
#### Sending messages
The `send` method allows for messages to be sent to different channels. This method requires valid authentication to be provided, otherwise an exception will be called.
##### 1. Send a message
```python
message = 'Hello world!'
connection.send('channel_name', message)
```
#### Close connection
The `close_connection` method closes the connection with Twitch chat. No futher messages can be received or sent now.
##### 1. Close a connection
```python
connection.close()
```

View File

@@ -0,0 +1,4 @@
# Once credentials are set up, rename this file to .env
# Go to https://twitchapps.com/tmi/ to get your oauth token
NICK=username
PASS=oauth:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

View File

@@ -0,0 +1,128 @@
badge-info,emote-only,badges,emotes,room-id,client-nonce,user-type,tmi-sent-ts,mod,user-id,flags,turbo,display-name,subscriber,id,message,color
subscriber/1,1,subscriber/0,25:0-4,127550308,09b8128f063b62f7942334efb9a66909,,1595816099308,0,430645544,,0,sophiexbc,1,79f7b57f-e341-4f7a-baed-2f4af2842d87,Kappa,#1E90FF
,,premium/1,25:4-8,127550308,4f32226107d3c55d19776502289d4dc2,,1595816099422,0,72104509,,0,dougie___jones,0,cf73e3c1-ce4e-4b46-9f2f-c61a0992ef2a,lag Kappa,#00FF7F
,,bits-charity/1,,127550308,185dee001c30ccb0fadc56f02d13e8b0,,1595816099572,0,148564215,,0,coffeeindex,0,63c97135-ac87-466e-8683-00168f2a629e,L OMEGALUL G,#4C3D30
,1,,25:0-4,127550308,a270a675bf2b23165cd938e47c0caf5b,,1595816099785,0,68412986,,0,AmazonESP,0,3dd26b43-94ef-4f52-b02b-0c37d912db57,Kappa,#1E90FF
subscriber/1,,subscriber/0,25:0-4,127550308,a7c8803dc1952befc7af87e3fbf998e4,,1595816100038,0,36029783,,0,Deflecti0n,1,29a116c0-c9a2-4db5-985b-c1f6420575ed,Kappa lag,#FF0000
subscriber/1,,subscriber/0,,127550308,7fd5330dbaebcb8c5ea041cfe28f5ebf,,1595816100393,0,187748286,,0,Dortok,1,35ee1917-0e1f-4b9f-b93a-c030d740bd66,YEP lag,#8A2BE2
subscriber/2,,"subscriber/0,premium/1",,127550308,d016325ea59d18b1b3c47ebd9a45e82d,,1595816100907,0,58745385,,0,danification9,1,98ea9d04-e3c0-4fb9-8de6-f053ea13f8a7,Sadge,
subscriber/2,,subscriber/0,,127550308,fb41538db686b39f413eda0af42cec1c,,1595816101643,0,43658581,,0,pab1994,1,35ed9d06-f3cd-41c4-9fcd-3d25dc94fd5a,yup,
,,,,127550308,8163a20dc852d1e8cc783411b38b22b4,,1595816101637,0,164828199,,0,aa175,0,83da06ce-193a-4b9c-b7da-35b65a1b5ff2,g3 rooooooooooook @BotezLive,
subscriber/1,,subscriber/0,,127550308,c83235028c79087d0146bb8735412f87,,1595816102163,0,25101760,,0,vespereq_,1,b1673d7c-a049-46c9-bae0-f56bfaa7ac2e,It's t h e wine,
subscriber/2,,subscriber/0,,127550308,28eb83194e637818b539d2a411bce483,,1595816102288,0,541613570,0-4:A.3,0,botezslavic,1,6f371af1-9680-4743-8402-fa4154fa4327,DRUNK,#8A2BE2
subscriber/1,,subscriber/0,,127550308,a6754c4e9795f9d1e344f689b72e4ab1,,1595816102306,0,52430007,,0,rowrow_,1,daa114be-9c2b-409c-be84-0fe03e10790c,no johns,#DAA520
subscriber/2,1,"subscriber/0,premium/1",115847:0-6,127550308,c4cc2b7fbab56d770b1b892b7bcfe452,,1595816102360,0,168644445,,0,slightlyHyPhi,1,1ba8cdea-403f-4265-b0ca-29edfd0b9725,KappaHD,
,,hype-train/2,,127550308,c779bfdd9b99c56aaafe4c9c122f448a,,1595816102389,0,56448721,,0,ReadingRailroad,0,3c9f340c-b408-48ef-86df-9e6fc64ac13c,Yep,#D2691E
,,premium/1,,127550308,59d0902b7dd8e7823c044688a26b246c,,1595816102598,0,466535256,,0,CrenshawViews,0,828c2fbd-b921-4430-b95d-dc8549a14591,yeah it glitched,#1546D1
,,premium/1,,127550308,a2c5a2d65b01bdb151944299d42be320,,1595816102879,0,92289099,,0,Heat_Signature,0,be24b7b2-11db-4e0c-8fdf-296561fb56bd,LAG ON CHESS OMEGALUL,#FF0000
subscriber/1,,subscriber/0,25:0-4,127550308,45bdd07b402d1bc7b630f3399248954e,,1595816103185,0,25334507,,0,LeetChocolate,1,577286ea-4a0b-47b9-a78e-98bad4bbf9c5,Kappa lag,#FF4500
,,,,127550308,f659cba7c6f4ffb5e30753d5840002f7,,1595816103329,0,499095797,,0,swornheart,0,b5d0b644-982a-4171-bf0f-a2dcd0b7ee22,that was brain lag,#0000FF
,,,,127550308,cb3d75a24f56025acb5dd10ea71334ef,,1595816103349,0,93958150,,0,JpForrReal,0,59ec74e2-c256-4d5e-810b-91d6d074660d,OMEGALUL,#F4BBFF
,1,premium/1,1140308:0-5,127550308,,,1595816103439,0,220980492,,0,AleFalnx,0,4ebf0739-9a1e-4cbf-86af-c395c1f1eec0,atpCap,#89DF9A
,1,,25:0-4,127550308,b1a00f55915c59e8e87b3c78c97809f0,,1595816103488,0,178346898,,0,hericium7,0,badf7c28-9ce0-4f22-ad6c-14a4b232298a,Kappa,
subscriber/1,,"subscriber/0,glhf-pledge/1",,127550308,679619cd7f623b08fb7cef135b335d6d,,1595816103492,0,246206955,,0,ezeroh13,1,c8951d08-159d-45ef-9d55-94244df817d6,YEP LAG,#B22222
,,premium/1,25:4-8,127550308,8db72e3f8b40969d001812f9fd88d04c,,1595816103535,0,195983667,,0,Nativezk,0,f3d2809c-a2e1-414c-99cf-f861afa1e667,lag Kappa,#FF69B4
,,premium/1,25:13-17,127550308,516d0459f3764bec68c66474f502c768,,1595816103731,0,72104509,,0,dougie___jones,0,2b6b4971-d03c-48ef-b30e-2625a9594ec8,yeah totally Kappa,#00FF7F
,1,,25:0-4,127550308,3566311f7dad1ccec17385d4fd0ecd25,,1595816103979,0,47117924,,0,CoDyPhin,0,8531ead3-783a-4394-8e0d-39555e6cae11,Kappa,#1E90FF
subscriber/1,,"subscriber/0,premium/1",,127550308,a1f63fd5d71add06d18519e24ae4d649,,1595816104011,0,57651751,,0,Nico3094,1,99b7e9dc-0b98-4a4f-839b-b049ed293022,lag YEP,#0000FF
subscriber/1,,"subscriber/0,premium/1",,127550308,ed024a395f2653252d0f1f0719e082f4,,1595816104086,0,76578093,,0,RoLoSC,1,829e8f65-e498-40cd-b575-b99e6141cd0e,yeah little lage,#FF0000
subscriber/1,,"subscriber/0,premium/1",25:0-4,127550308,e4f66802252d122a6a1aec5d6be1911a,,1595816104351,0,46899419,,0,ArcticPolarbear,1,eb399ea9-7198-4abc-a0b9-34c6f7b9f743,Kappa lag,#B22222
subscriber/1,,"subscriber/0,bits/1000",,127550308,030d87013b0cf82db86359a62986b341,,1595816104364,0,426507835,,0,kzp99,1,a619a855-265c-44cf-9415-b920b1d88bea,LAG,
,,premium/1,,127550308,d7997a5b244bdd712f140c3641ca2bd7,,1595816104463,0,59865720,,0,FrankDaTankGaming,0,5cd8fd7b-0609-4b65-ba19-a53bda8ac7a1,does that for me sometimes too,#CC0000
,,premium/1,,127550308,68b246b5bd6667927320467e39f3d6a7,,1595816104600,0,22265843,,0,modestmage,0,d1deb4da-9673-48e1-898c-741b6e0565b9,wasnt that a trade?,#008000
,,,,127550308,3afd5d8d06cc3d97b13d56522fa14e80,,1595816104624,0,45557046,,0,yop01,0,faae5af5-d551-42b7-993a-3d99d1f1c840,Yes,#00FF7F
subscriber/1,,subscriber/0,25:0-4,127550308,160b2211a3db32b13014711567d491fe,,1595816104597,0,430645544,,0,sophiexbc,1,7a357cf3-5314-4885-b30a-9f7b43b9a9a7,Kappa lag,#1E90FF
subscriber/1,,"subscriber/0,premium/1",,127550308,663889801a61a035f00b2d397988822f,,1595816104756,0,169719325,,0,swift_ocelot,1,0e1c06c1-1697-422d-b58d-6ff0b8e713fb,YEP lag,#FF7F50
,,,,127550308,,,1595816105421,0,39067863,,0,cinasxd,0,613a93e5-82ce-410c-b040-5f781f2cf2e6,kappa,
,,premium/1,,127550308,,,1595816105609,0,208236597,,0,jrude72,0,71baa10e-4edb-43fa-a289-469e1c4d1161,So what r u up to for the next 24 hours?,
,,,,127550308,c78950b7be2e6822bda92a6db5f57509,,1595816105662,0,44112166,,0,brettydoes,0,aeecd502-e436-4628-af05-933d28f1dba2,YEP lag,#FF69B4
,,,,127550308,86ad8f283188e0a1495b7c842137b75f,,1595816105720,0,553991126,,0,kavifa6176,0,59b15ae1-4061-470a-952b-ee6283c530ef,Brain lag,
subscriber/3,,subscriber/3,25:6-10,127550308,88c2064750caacd13b04453b343ab1bc,,1595816106052,0,233736723,,0,drawingdead,1,77fcfbed-dae2-45cd-99a6-b681adeb3211,mhmmm Kappa,
,,,,127550308,dca8af8308374e8cda730d766192a417,,1595816106179,0,27479429,,0,Cajun292,0,88fdf5b9-4a98-4bea-ae02-eccade8f2a62,bullet lag,#FE02CC
,,premium/1,,127550308,8487307d22ca70080bf127bd1cbc259a,,1595816106261,0,107123504,,0,bittersandwich,0,32122034-f1e1-486c-b980-5241ce9f305f,blaming on lag LULW,#14DBD1
,,,,127550308,5000e2f06c600b36b1e99bba6720cbe0,,1595816106687,0,189862796,0-3:A.3,0,loayakram,0,ef39469c-4532-4d63-a0f2-c892b9d98763,fake,
subscriber/1,,subscriber/0,,127550308,7bab671f446e42a643744a4cfe29c4e9,,1595816106783,0,233579908,7-11:A.3,0,xivi76,1,40b88458-e54f-4862-9e96-df1ef2429530,you're drunk,
subscriber/1,,subscriber/0,,127550308,9964a62a8c7e8fa5253018dddbccff18,,1595816106749,0,25101760,,0,vespereq_,1,1834b9a3-be36-475c-a20f-2519d07ad5a4,WINE LAG,
,,,,127550308,901dc1be63bbc1b233d7fc8cd79b5d2c,,1595816106826,0,484766599,0-4:A.3,0,deepbishop,0,c90fad1e-d6c1-47d4-85bf-ec57b1bfc866,drunk,
subscriber/1,1,"subscriber/0,premium/1",25:0-4,127550308,6d002d55bd5c748445848baef962a43f,,1595816106963,0,77110683,,0,HaloMonkey3009,1,1568de89-043b-4052-bb5d-4877c4a836f3,Kappa,#00FCFF
subscriber/1,1,subscriber/0,25:0-4,127550308,a2a1400a09c0c8d1e0056b5473e0d15e,,1595816107192,0,74878349,,0,kilner111,1,744dde86-9485-446a-9a86-e0ff2f83260b,Kappa,#8A2BE2
,,,,127550308,7e861ef2cecfb902c95351920555e2f6,,1595816107269,0,452580538,,0,NotReformeduwu,0,4f4140f6-5dd7-4baa-9c5c-06237f24011f,YEP,
,,,,127550308,,,1595816107375,0,254499567,,0,juanhc24v2,0,0778230b-6174-450f-b852-a4f7b2823ebe,YEP LAG,#00FF7F
subscriber/2,,"subscriber/0,premium/1",,127550308,74b2411af72bc224a6b125769950b9d5,,1595816107440,0,58745385,,0,danification9,1,91c2e96c-5450-4cf9-bae4-a1ae89f43965,CHESS LAG,
subscriber/1,1,subscriber/0,25:0-4,127550308,084dd2f2f4f9d8003edc2e7abe2d9320,,1595816107521,0,120169544,,0,ItsRua,1,15090353-1236-4cae-ac3a-8ed6597cf17a,Kappa,
,1,premium/1,25:0-4,127550308,008abf709a01b2cec0e77ae608748fb0,,1595816107628,0,500900526,,0,Pong8770,0,599ebd5a-f07a-4d62-b86a-d1889a1db71f,Kappa,#B22222
,1,premium/1,25:0-4,127550308,,,1595816107793,0,39491422,,0,magnumd0nger,0,7ea756ff-736c-4199-890b-913585edb080,Kappa,#850303
subscriber/1,,subscriber/0,,127550308,9cd9d5322cb32748c80f9ac636785fa9,,1595816107829,0,52430007,,0,rowrow_,1,cf7fd9ef-c2e8-450e-9968-5aa25b3007e3,no johns boatz,#DAA520
subscriber/1,,"subscriber/0,premium/1",,127550308,884ab0300555032462e1f65005166f11,,1595816108173,0,46899419,,0,ArcticPolarbear,1,17d7c1ad-4e6f-49f0-a523-a65e3ec2da7a,brain lag,#B22222
,,bits/1000,,127550308,c65720b8372d7b27a8fab30829848eb4,,1595816108223,0,169027853,,0,febog,0,61d074ac-d6e5-4446-a37e-5eae0f224165,YEP lag,#1E90FF
subscriber/3,,subscriber/3,,127550308,23c8813ef0fc52c15f90a741371b1770,,1595816108353,0,28276685,,0,1y1e,1,855d978e-dfb9-4c9e-8739-4c37b36eb77e,lag exists between eyes and brain,#2E8B57
,,premium/1,25:4-8,127550308,,,1595816108409,0,25286001,,0,Nicktown,0,d763a6fc-634d-42af-9c52-f66a70bce5ce,lag Kappa,#0000FF
,,,,127550308,69f54844b1ecdc5a5306bf75b67cbffe,,1595816108414,0,24651046,,0,Gabber__,0,d1e612ea-338e-42e8-84a0-4584ee18008b,monkaHmm,#FFFFFF
subscriber/7,,"subscriber/6,bits/100",,127550308,58fc6c30a6445398e467483f4629ab79,,1595816108844,0,217399619,,0,Adenosine_Tri_Phosphate,1,afd25cc8-9510-4550-b5eb-9324b6ca610f,#blamechesscom,#999999
,,,,127550308,94f92dad885d49cdf0d4d74d694b94d4,,1595816108963,0,265540494,,0,maek_28,0,973dfe4b-9be9-4d05-85ca-755551f52190,nope,
,,,,127550308,ce7721c36b549cd969d1732b0c66f5a7,,1595816109129,0,274725794,,0,einn9,0,75b1f985-8db0-4a91-995e-d3261a51b90e,sadchamp,
subscriber/1,,subscriber/0,,127550308,cedca7b9fa8f9889d212559ef4a65bc4,,1595816109165,0,97151792,,0,thekid_54,1,be0445d4-96fd-4a2d-9a98-85b298e2d5c4,24 hours?,#FD00BB
,1,,25:0-4,127550308,d21664375fd9a9a340c0d18f8476cf87,,1595816109286,0,132665916,,0,oceanman_takemebytheh4nd,0,218ab304-f255-4e24-82fc-4412db8769fc,Kappa,#551A8B
,,,25:4-8,127550308,99d8e8432f44cf0fd5fc0c37c515c046,,1595816109366,0,31050861,,0,skitlzx,0,fc682baf-6159-4e62-8902-fc941ae6b3e4,lag Kappa,#0000FF
,,,,127550308,65cc7bea1952413af77c3beb754eee9b,,1595816109437,0,204434546,,0,ImDisManyTwitch,0,9362896b-3856-4ede-bb62-b37dc12345a1,'Wine Lag',
,,,,127550308,0da04429d4f57809a0d152ce649b93f1,,1595816109656,0,484766599,,0,deepbishop,0,27c630ae-443e-4527-9dff-2a40698607a2,lag in your brain,
,,,,127550308,cc09588431d2060e47a58712164dbdaa,,1595816109830,0,534243080,,0,gretasdisciples,0,b2c20b7b-e3fa-4e8f-a9e7-9a2e1e98f958,"SURE, A lag",
,1,,25:0-4,127550308,be44d05ef78860a93763195c268e8d05,,1595816110137,0,254157596,,0,cupofcocoa__,0,edfe34a2-9c4d-4399-a7d3-c05d41fdaa18,Kappa,#0000FF
,,,,127550308,f7f49c9e34784250d858b7a763b0d3d2,,1595816110138,0,77980562,,0,BBeatless,0,c7cd9b9f-651a-4b35-a66c-1d16f47c724e,brain LAG,#1E90FF
subscriber/1,,subscriber/0,25:0-4,127550308,4276af5f703b600d8f49fee2f41b10cf,,1595816110119,0,430645544,,0,sophiexbc,1,d40b23ce-ada7-486a-8770-ea37e7f60cae,Kappa sure,#1E90FF
,,,,127550308,5c4a80567ab0f943af66d0998cbdcee8,,1595816110594,0,189862796,,0,loayakram,0,9e8eed62-e2c3-4011-b31e-547d304b7285,NO,
subscriber/5,,subscriber/3,,127550308,65e436840083d37e6cc9daf6a9b38fb5,,1595816110766,0,207843882,,0,Shroffy7,1,1fb7c924-ea3c-4cfc-9cd6-6808a1aacfad,chess.com PepeLaugh,#FF4500
,,,,127550308,f26a03c645cc67bf375b6847ef3d6c93,,1595816110976,0,263124733,,0,LudwigVanBeethoven23,0,d35c610a-c7d9-4a5b-affd-9ae7e935d7cb,lag in chess,
,,,,127550308,b9eadfa3e9dfe27f6db4083634fa7b56,,1595816111332,0,164828199,,0,aa175,0,7b3c6764-5ed9-4b6a-bdc9-188915db017f,THE FINAL POSITION IS A DRAw,
subscriber/2,,"subscriber/0,premium/1",,127550308,04f914d5b9b8405c21597e9b9161a502,,1595816111530,0,58745385,,0,danification9,1,6429e1e0-c6cf-4666-b884-bef0a8e5d8a2,Brain lag,
,1,,25:0-4,127550308,,,1595816111656,0,51032758,,0,Whole_Lotta_Lies,0,94d64716-8213-45ce-a6f1-ef60ab9f8440,Kappa,#2E8B57
subscriber/1,,subscriber/0,,127550308,1b843e3869ab21c8923dd1d7f4795673,,1595816111645,0,557195178,,0,byebrows2020,1,9ff86b87-f69b-4343-8faa-91c1be1284ff,LAG BLAME,
,,,,127550308,9d293af5749552b8629f0897523baf7d,,1595816112076,0,262128196,,0,slinkyshoots,0,d5ca1063-6f94-44aa-a239-00fe530785b1,Kapp,#00FF7F
subscriber/2,,subscriber/0,25:0-4,127550308,db149a2243bb3914841fe23d9cb1bbeb,,1595816112201,0,541613570,6-10:A.3,0,botezslavic,1,eb0c8775-b1b5-49ca-9ec4-1832b62947bb,Kappa Drunk already,#8A2BE2
,1,premium/1,25:0-4,127550308,74fe1bc5dae66988b60a8c54e68798e0,,1595816112487,0,195983667,,0,Nativezk,0,36b645e1-e01f-404a-af35-1d478c171c72,Kappa,#FF69B4
,,,,127550308,bfbb279442719e5920d553a2761538dc,,1595816112658,0,119618817,,0,ElJavieer,0,f05fb74b-dff1-4654-98e4-28d03d6e78f2,Brain lag,#2E8B57
,1,,25:0-4,127550308,,,1595816112802,0,413018612,,0,k4rzheka,0,c4561234-f570-4f41-8904-09aa52c33fd8,Kappa,
,,,,127550308,9ad449b192d1de4d7aa596bd156a2062,,1595816113542,0,71627954,,0,Toorshul891,0,0a2f91e4-04c0-43c2-a9c4-7be881a83cfe,yes,#FF0000
subscriber/1,,subscriber/0,,127550308,,,1595816113595,0,41972554,,0,elsenatto,1,d0a07de4-fd30-4216-8e58-62c9dbf65797,YEP LAG,#FF0000
,,premium/1,,127550308,5f16e408c7c90ffbe042ab4375fff7c7,,1595816113605,0,409091205,,0,iamzul95,0,57c2de5e-fa67-4462-ae17-3aed3f9d91ce,there was a lag,
subscriber/1,,"subscriber/0,premium/1",,127550308,,,1595816113693,0,87187380,,0,SemiPro19,1,1ab4c9b5-8383-473a-a860-95121028f0f9,wine lag,
,,premium/1,,127550308,e64fcb6a9b5a08b259cc04c152d1dfec,,1595816114198,0,101983685,,0,Clench1k,0,2ca56351-ee78-4efd-8c32-72694cfec3d8,YEP lag,#FF0000
subscriber/1,,subscriber/0,,127550308,9021f68fc93100962d0e988f6143018f,,1595816114801,0,23289875,,0,Jaaledon,1,6da1d281-2924-40b3-8fa7-bc425c03beba,"Sure, blame it on your ISP",#0000FF
,,,25:8-12,127550308,64c03873fd1d7f7ef5fd375842d73de2,,1595816114958,0,504713042,,0,ocelot022,0,3797dcd3-52ff-45f7-b573-5cc52412e549,ok sure Kappa,
subscriber/10,,subscriber/6,"302934780:10-18,26-34,42-50,58-66,74-82",127550308,516affced6902164299a700a388cf543,,1595816115272,0,117880554,,0,sepehr91,1,87d8db4c-04e8-4ec9-9bc2-8fb8c61a286b,lag pepeD botez2300 pepeD botez2300 pepeD botez2300 pepeD botez2300 pepeD botez2300 lag,#00FF7F
,,,,127550308,d8e9fbbe67345be0e78d4fab5bdfbc23,,1595816115454,0,484766599,,0,deepbishop,0,467592bf-bdf1-46eb-a8b2-a9b5bd2a6bb6,brain lag,
,,premium/1,,127550308,,,1595816115903,0,512437416,,0,augusto_vam,0,384f4487-62fd-464b-aa43-132f5d29c97d,BRAIN LAG,
,,,,127550308,,,1595816115910,0,550092913,,0,010293101,0,acb3ba00-6e77-4039-b298-9d8c226bceee,Dronk,
subscriber/1,,subscriber/0,,127550308,89a17afbfa128e565f95c860f2a3a6ca,,1595816115909,0,58317233,,0,mrchair1982,1,91dd1bf2-2737-4951-862b-f8021e9f6d02,how have you already dropped so far down from 2300?,#FF0000
subscriber/1,,subscriber/0,,127550308,,,1595816116392,0,113854995,,0,xavierrocket,1,6200b631-4f59-4374-a551-1185e3eff4d9,"I've had a ton of messed up moves because of lag, I know the pain Sadge",#CC0000
,,,25:4-8,127550308,d3edaa32d363cf4b4220b4bfbf730c3c,,1595816116471,0,6888738,,0,AznBoy222,0,73251b3e-c38e-4041-bb10-67adb9ca183b,yep Kappa,#FF0000
subscriber/1,,subscriber/0,,127550308,,,1595816116526,0,48780004,,0,Cnoized,1,fffd4298-a450-42be-a2db-cb0e0e53a148,I saw it.,#00FF7F
,,,,127550308,,,1595816116580,0,144960091,,0,jisos12369,0,f9c2ff7f-d306-4ca7-bbbd-2dbdd25c0614,YEP lag,#1E90FF
,,premium/1,,127550308,3c37ca135a77f7597a4cdf86321b5bca,,1595816116668,0,442498004,,0,juanber,0,f8c1c408-4c4a-4a8e-b1a4-422345ce902f,brain lag,
subscriber/7,1,subscriber/2006,302895853:0-7,127550308,10ba03ddf7192e3c492547c018c47c83,,1595816116704,0,255884924,,0,RO0PE,1,1a125c0f-3ffd-45c2-ae32-5c4758634c43,botezCIA,
,,,25:58-62,127550308,7cab32d02b49d46c0f8f094192eb4e3a,,1595816117665,0,90516629,,0,Mossico,0,2104a46a-a31e-4811-8de9-42777b9ce925,perhaps your perception of time is impaired at the moment Kappa,
subscriber/3,,subscriber/3,88:15-22,127550308,649c5c64e0b9a9946509692b9fe935fa,,1595816118589,0,152865823,,0,lurker_above,1,b4ae57d5-ff9b-4751-8b90-63aefd1015d4,24 hour stream PogChamp,
,,premium/1,,127550308,805dc602bc1d75963a5e5bf9ffb86ab6,,1595816118924,0,177511477,,0,dildo_fire,0,f504ed44-9c19-4c4d-b69c-7456e76c74ba,that's why i play on lichess,#504B44
,,,,127550308,,,1595816119093,0,527834016,,0,zloriginals,0,48474373-5e57-42e5-ba93-d346eaf8f184,Just u,
,,,,127550308,319a67044c5003601f705abaf16542cd,,1595816119284,0,47117924,,0,CoDyPhin,0,f1a5b6d5-3614-4d6f-8a8f-c9511c7e3a61,1345 AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance,#1E90FF
subscriber/1,,"subscriber/0,premium/1",,127550308,,,1595816119373,0,98416009,0-4:A.3,0,Schultzky,1,507e9eb5-593d-48f5-b014-10b6784b5e8a,drunk,#FF0000
,,,,127550308,ee1bbc8080c48ce26accd61ea405d39c,,1595816119464,0,189862796,,0,loayakram,0,a9fa6238-e237-4ac7-b9bd-57374a109d07,KAPPA,
,1,,"145315:0-12,14-26,28-40,42-54,56-68,70-82,84-96,98-110,112-124,126-138,140-152,154-166,168-180,182-194,196-208,210-222,224-236,238-250,252-264,266-278,280-292,294-306,308-320",127550308,,,1595816119454,0,436262291,,0,itzghost6890,0,64ac2f7d-e975-457c-aa3e-ced46c94f678,TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati,
subscriber/1,,"subscriber/2000,bits/100",,127550308,8aab484c2f0ef821c0536dde4f90f8fb,,1595816119878,0,55373647,,0,EpicTripleAssTap,1,11770323-aec0-4767-81b6-588208c53310,PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls,#00FF7F
,,premium/1,,127550308,d8386d364e9de4113d16f99f088ad8ca,,1595816119897,0,478625547,,0,skitzt,0,074ab457-dcb8-49c3-be2f-163d20afe789,so 24hr stream?,
subscriber/1,,"subscriber/0,premium/1",,127550308,,,1595816120966,0,9095096,,0,NoPantzzz,1,19d535d1-fe64-4750-8a9e-ffe7e43882d2,Laggggggg,#FEA400
subscriber/11,,subscriber/6,,127550308,e2b66a7a4278499c62ef48eef673a41e,,1595816121587,0,250839454,,0,zPOUTINEZ,1,5241f949-62dc-45c5-bf81-176cd812b54b,its the wine dude,#FF0000
,,,,127550308,5d93ca39fa974f87ae34faa6da934d3c,,1595816122054,0,500766391,,0,merlinnimue,0,5bc1e672-a956-4c64-8bf8-25884361a120,spirit of rasputin,
subscriber/2,,subscriber/0,25:9-13,127550308,e84f1dc8db2401daa4e706f8e25802a4,,1595816122170,0,541613570,,0,botezslavic,1,71281c31-2ccc-4ca6-8115-dfcebe388ce4,wine lag Kappa,#8A2BE2
,,premium/1,,127550308,3ba4d9d4e0e8bf2f750121df96d36bba,,1595816122308,0,152601449,,0,midgetpanda96,0,eedf2720-66c6-4459-84e0-9bdd6f82152c,ya,
,,,25:0-4,127550308,8c590466109e0380d4329bdc33dded67,,1595816123077,0,152709545,,0,stepkc,0,88683f85-805a-4e87-9b78-4a72cadaab7a,Kappa hmm,#00FF7F
,,,,127550308,4ba0e28fa15dda235da65be4fe4b7e5e,,1595816123425,0,265540494,,0,maek_28,0,1088b96e-4a40-433a-a620-36a569dec5ec,no lag nope,
subscriber/1,1,"subscriber/0,sub-gifter/1",70433:0-8,127550308,,,1595816123499,0,553594803,,0,dogplatformr2,1,46ddc40c-e032-4056-a8a2-e751087f3162,KappaRoss,
,,,,127550308,,,1595816123729,0,51032758,,0,Whole_Lotta_Lies,0,72c0bdeb-ce70-4a9d-95c8-777923a4685c,5Head lag,#2E8B57
,1,,301443647:0-4/301443646:6-10,127550308,,,1595816124273,0,76087796,,0,Krappa_1_2_3,0,6606358f-2bbb-47e7-9341-3961719ebeea,nymn1 nymn2,#FF0000
subscriber/1,,subscriber/0,,127550308,b43c8b5a271298708a7808d74ef71363,,1595816124725,0,522200051,,0,creatovert,1,edfd099d-37b8-4a69-b564-7467d8969fcf,MIND LAG DUE TO WINE,#8A2BE2
,,,,127550308,,,1595816124894,0,484284968,,0,kaibennett06,0,a703c39a-7206-42c3-a559-99459054931f,YEP LAG,
subscriber/1,,subscriber/0,,127550308,,,1595816124950,0,130382221,,0,k33ling33,1,8fe6738f-d9e7-4490-a703-cd240726ce39,Omg lag,
,,,,127550308,f15ab8ab2a81f42f6919b7753be2285d,,1595816125071,0,32171084,,0,dslx,0,d5509a70-fe08-427c-b63a-fd4087dc06e7,Yep lag,#9ACD32
,,glhf-pledge/1,123171:10-21,127550308,b182592194b2e3a041c4d0a3ceec34e5,,1595816126541,0,179916073,0-4:A.3,0,nefderek,0,a815d176-d0b5-486c-8c2f-dd606ec77bb5,drunk lag CoolStoryBob,#FF69B4
,,,,127550308,f1742a95c860173cbed53c898e6ce917,,1595816126586,0,484766599,,0,deepbishop,0,1c14dd76-5384-47b4-bd4e-2f9e5bd010f7,keep chugging,
1 badge-info emote-only badges emotes room-id client-nonce user-type tmi-sent-ts mod user-id flags turbo display-name subscriber id message color
2 subscriber/1 1 subscriber/0 25:0-4 127550308 09b8128f063b62f7942334efb9a66909 1595816099308 0 430645544 0 sophiexbc 1 79f7b57f-e341-4f7a-baed-2f4af2842d87 Kappa #1E90FF
3 premium/1 25:4-8 127550308 4f32226107d3c55d19776502289d4dc2 1595816099422 0 72104509 0 dougie___jones 0 cf73e3c1-ce4e-4b46-9f2f-c61a0992ef2a lag Kappa #00FF7F
4 bits-charity/1 127550308 185dee001c30ccb0fadc56f02d13e8b0 1595816099572 0 148564215 0 coffeeindex 0 63c97135-ac87-466e-8683-00168f2a629e L OMEGALUL G #4C3D30
5 1 25:0-4 127550308 a270a675bf2b23165cd938e47c0caf5b 1595816099785 0 68412986 0 AmazonESP 0 3dd26b43-94ef-4f52-b02b-0c37d912db57 Kappa #1E90FF
6 subscriber/1 subscriber/0 25:0-4 127550308 a7c8803dc1952befc7af87e3fbf998e4 1595816100038 0 36029783 0 Deflecti0n 1 29a116c0-c9a2-4db5-985b-c1f6420575ed Kappa lag #FF0000
7 subscriber/1 subscriber/0 127550308 7fd5330dbaebcb8c5ea041cfe28f5ebf 1595816100393 0 187748286 0 Dortok 1 35ee1917-0e1f-4b9f-b93a-c030d740bd66 YEP lag #8A2BE2
8 subscriber/2 subscriber/0,premium/1 127550308 d016325ea59d18b1b3c47ebd9a45e82d 1595816100907 0 58745385 0 danification9 1 98ea9d04-e3c0-4fb9-8de6-f053ea13f8a7 Sadge
9 subscriber/2 subscriber/0 127550308 fb41538db686b39f413eda0af42cec1c 1595816101643 0 43658581 0 pab1994 1 35ed9d06-f3cd-41c4-9fcd-3d25dc94fd5a yup
10 127550308 8163a20dc852d1e8cc783411b38b22b4 1595816101637 0 164828199 0 aa175 0 83da06ce-193a-4b9c-b7da-35b65a1b5ff2 g3 rooooooooooook @BotezLive
11 subscriber/1 subscriber/0 127550308 c83235028c79087d0146bb8735412f87 1595816102163 0 25101760 0 vespereq_ 1 b1673d7c-a049-46c9-bae0-f56bfaa7ac2e It's t h e wine
12 subscriber/2 subscriber/0 127550308 28eb83194e637818b539d2a411bce483 1595816102288 0 541613570 0-4:A.3 0 botezslavic 1 6f371af1-9680-4743-8402-fa4154fa4327 DRUNK #8A2BE2
13 subscriber/1 subscriber/0 127550308 a6754c4e9795f9d1e344f689b72e4ab1 1595816102306 0 52430007 0 rowrow_ 1 daa114be-9c2b-409c-be84-0fe03e10790c no johns #DAA520
14 subscriber/2 1 subscriber/0,premium/1 115847:0-6 127550308 c4cc2b7fbab56d770b1b892b7bcfe452 1595816102360 0 168644445 0 slightlyHyPhi 1 1ba8cdea-403f-4265-b0ca-29edfd0b9725 KappaHD
15 hype-train/2 127550308 c779bfdd9b99c56aaafe4c9c122f448a 1595816102389 0 56448721 0 ReadingRailroad 0 3c9f340c-b408-48ef-86df-9e6fc64ac13c Yep #D2691E
16 premium/1 127550308 59d0902b7dd8e7823c044688a26b246c 1595816102598 0 466535256 0 CrenshawViews 0 828c2fbd-b921-4430-b95d-dc8549a14591 yeah it glitched #1546D1
17 premium/1 127550308 a2c5a2d65b01bdb151944299d42be320 1595816102879 0 92289099 0 Heat_Signature 0 be24b7b2-11db-4e0c-8fdf-296561fb56bd LAG ON CHESS OMEGALUL #FF0000
18 subscriber/1 subscriber/0 25:0-4 127550308 45bdd07b402d1bc7b630f3399248954e 1595816103185 0 25334507 0 LeetChocolate 1 577286ea-4a0b-47b9-a78e-98bad4bbf9c5 Kappa lag #FF4500
19 127550308 f659cba7c6f4ffb5e30753d5840002f7 1595816103329 0 499095797 0 swornheart 0 b5d0b644-982a-4171-bf0f-a2dcd0b7ee22 that was brain lag #0000FF
20 127550308 cb3d75a24f56025acb5dd10ea71334ef 1595816103349 0 93958150 0 JpForrReal 0 59ec74e2-c256-4d5e-810b-91d6d074660d OMEGALUL #F4BBFF
21 1 premium/1 1140308:0-5 127550308 1595816103439 0 220980492 0 AleFalnx 0 4ebf0739-9a1e-4cbf-86af-c395c1f1eec0 atpCap #89DF9A
22 1 25:0-4 127550308 b1a00f55915c59e8e87b3c78c97809f0 1595816103488 0 178346898 0 hericium7 0 badf7c28-9ce0-4f22-ad6c-14a4b232298a Kappa
23 subscriber/1 subscriber/0,glhf-pledge/1 127550308 679619cd7f623b08fb7cef135b335d6d 1595816103492 0 246206955 0 ezeroh13 1 c8951d08-159d-45ef-9d55-94244df817d6 YEP LAG #B22222
24 premium/1 25:4-8 127550308 8db72e3f8b40969d001812f9fd88d04c 1595816103535 0 195983667 0 Nativezk 0 f3d2809c-a2e1-414c-99cf-f861afa1e667 lag Kappa #FF69B4
25 premium/1 25:13-17 127550308 516d0459f3764bec68c66474f502c768 1595816103731 0 72104509 0 dougie___jones 0 2b6b4971-d03c-48ef-b30e-2625a9594ec8 yeah totally Kappa #00FF7F
26 1 25:0-4 127550308 3566311f7dad1ccec17385d4fd0ecd25 1595816103979 0 47117924 0 CoDyPhin 0 8531ead3-783a-4394-8e0d-39555e6cae11 Kappa #1E90FF
27 subscriber/1 subscriber/0,premium/1 127550308 a1f63fd5d71add06d18519e24ae4d649 1595816104011 0 57651751 0 Nico3094 1 99b7e9dc-0b98-4a4f-839b-b049ed293022 lag YEP #0000FF
28 subscriber/1 subscriber/0,premium/1 127550308 ed024a395f2653252d0f1f0719e082f4 1595816104086 0 76578093 0 RoLoSC 1 829e8f65-e498-40cd-b575-b99e6141cd0e yeah little lage #FF0000
29 subscriber/1 subscriber/0,premium/1 25:0-4 127550308 e4f66802252d122a6a1aec5d6be1911a 1595816104351 0 46899419 0 ArcticPolarbear 1 eb399ea9-7198-4abc-a0b9-34c6f7b9f743 Kappa lag #B22222
30 subscriber/1 subscriber/0,bits/1000 127550308 030d87013b0cf82db86359a62986b341 1595816104364 0 426507835 0 kzp99 1 a619a855-265c-44cf-9415-b920b1d88bea LAG
31 premium/1 127550308 d7997a5b244bdd712f140c3641ca2bd7 1595816104463 0 59865720 0 FrankDaTankGaming 0 5cd8fd7b-0609-4b65-ba19-a53bda8ac7a1 does that for me sometimes too #CC0000
32 premium/1 127550308 68b246b5bd6667927320467e39f3d6a7 1595816104600 0 22265843 0 modestmage 0 d1deb4da-9673-48e1-898c-741b6e0565b9 wasnt that a trade? #008000
33 127550308 3afd5d8d06cc3d97b13d56522fa14e80 1595816104624 0 45557046 0 yop01 0 faae5af5-d551-42b7-993a-3d99d1f1c840 Yes #00FF7F
34 subscriber/1 subscriber/0 25:0-4 127550308 160b2211a3db32b13014711567d491fe 1595816104597 0 430645544 0 sophiexbc 1 7a357cf3-5314-4885-b30a-9f7b43b9a9a7 Kappa lag #1E90FF
35 subscriber/1 subscriber/0,premium/1 127550308 663889801a61a035f00b2d397988822f 1595816104756 0 169719325 0 swift_ocelot 1 0e1c06c1-1697-422d-b58d-6ff0b8e713fb YEP lag #FF7F50
36 127550308 1595816105421 0 39067863 0 cinasxd 0 613a93e5-82ce-410c-b040-5f781f2cf2e6 kappa
37 premium/1 127550308 1595816105609 0 208236597 0 jrude72 0 71baa10e-4edb-43fa-a289-469e1c4d1161 So what r u up to for the next 24 hours?
38 127550308 c78950b7be2e6822bda92a6db5f57509 1595816105662 0 44112166 0 brettydoes 0 aeecd502-e436-4628-af05-933d28f1dba2 YEP lag #FF69B4
39 127550308 86ad8f283188e0a1495b7c842137b75f 1595816105720 0 553991126 0 kavifa6176 0 59b15ae1-4061-470a-952b-ee6283c530ef Brain lag
40 subscriber/3 subscriber/3 25:6-10 127550308 88c2064750caacd13b04453b343ab1bc 1595816106052 0 233736723 0 drawingdead 1 77fcfbed-dae2-45cd-99a6-b681adeb3211 mhmmm Kappa
41 127550308 dca8af8308374e8cda730d766192a417 1595816106179 0 27479429 0 Cajun292 0 88fdf5b9-4a98-4bea-ae02-eccade8f2a62 bullet lag #FE02CC
42 premium/1 127550308 8487307d22ca70080bf127bd1cbc259a 1595816106261 0 107123504 0 bittersandwich 0 32122034-f1e1-486c-b980-5241ce9f305f blaming on lag LULW #14DBD1
43 127550308 5000e2f06c600b36b1e99bba6720cbe0 1595816106687 0 189862796 0-3:A.3 0 loayakram 0 ef39469c-4532-4d63-a0f2-c892b9d98763 fake
44 subscriber/1 subscriber/0 127550308 7bab671f446e42a643744a4cfe29c4e9 1595816106783 0 233579908 7-11:A.3 0 xivi76 1 40b88458-e54f-4862-9e96-df1ef2429530 you're drunk
45 subscriber/1 subscriber/0 127550308 9964a62a8c7e8fa5253018dddbccff18 1595816106749 0 25101760 0 vespereq_ 1 1834b9a3-be36-475c-a20f-2519d07ad5a4 WINE LAG
46 127550308 901dc1be63bbc1b233d7fc8cd79b5d2c 1595816106826 0 484766599 0-4:A.3 0 deepbishop 0 c90fad1e-d6c1-47d4-85bf-ec57b1bfc866 drunk
47 subscriber/1 1 subscriber/0,premium/1 25:0-4 127550308 6d002d55bd5c748445848baef962a43f 1595816106963 0 77110683 0 HaloMonkey3009 1 1568de89-043b-4052-bb5d-4877c4a836f3 Kappa #00FCFF
48 subscriber/1 1 subscriber/0 25:0-4 127550308 a2a1400a09c0c8d1e0056b5473e0d15e 1595816107192 0 74878349 0 kilner111 1 744dde86-9485-446a-9a86-e0ff2f83260b Kappa #8A2BE2
49 127550308 7e861ef2cecfb902c95351920555e2f6 1595816107269 0 452580538 0 NotReformeduwu 0 4f4140f6-5dd7-4baa-9c5c-06237f24011f YEP
50 127550308 1595816107375 0 254499567 0 juanhc24v2 0 0778230b-6174-450f-b852-a4f7b2823ebe YEP LAG #00FF7F
51 subscriber/2 subscriber/0,premium/1 127550308 74b2411af72bc224a6b125769950b9d5 1595816107440 0 58745385 0 danification9 1 91c2e96c-5450-4cf9-bae4-a1ae89f43965 CHESS LAG
52 subscriber/1 1 subscriber/0 25:0-4 127550308 084dd2f2f4f9d8003edc2e7abe2d9320 1595816107521 0 120169544 0 ItsRua 1 15090353-1236-4cae-ac3a-8ed6597cf17a Kappa
53 1 premium/1 25:0-4 127550308 008abf709a01b2cec0e77ae608748fb0 1595816107628 0 500900526 0 Pong8770 0 599ebd5a-f07a-4d62-b86a-d1889a1db71f Kappa #B22222
54 1 premium/1 25:0-4 127550308 1595816107793 0 39491422 0 magnumd0nger 0 7ea756ff-736c-4199-890b-913585edb080 Kappa #850303
55 subscriber/1 subscriber/0 127550308 9cd9d5322cb32748c80f9ac636785fa9 1595816107829 0 52430007 0 rowrow_ 1 cf7fd9ef-c2e8-450e-9968-5aa25b3007e3 no johns boatz #DAA520
56 subscriber/1 subscriber/0,premium/1 127550308 884ab0300555032462e1f65005166f11 1595816108173 0 46899419 0 ArcticPolarbear 1 17d7c1ad-4e6f-49f0-a523-a65e3ec2da7a brain lag #B22222
57 bits/1000 127550308 c65720b8372d7b27a8fab30829848eb4 1595816108223 0 169027853 0 febog 0 61d074ac-d6e5-4446-a37e-5eae0f224165 YEP lag #1E90FF
58 subscriber/3 subscriber/3 127550308 23c8813ef0fc52c15f90a741371b1770 1595816108353 0 28276685 0 1y1e 1 855d978e-dfb9-4c9e-8739-4c37b36eb77e lag exists between eyes and brain #2E8B57
59 premium/1 25:4-8 127550308 1595816108409 0 25286001 0 Nicktown 0 d763a6fc-634d-42af-9c52-f66a70bce5ce lag Kappa #0000FF
60 127550308 69f54844b1ecdc5a5306bf75b67cbffe 1595816108414 0 24651046 0 Gabber__ 0 d1e612ea-338e-42e8-84a0-4584ee18008b monkaHmm #FFFFFF
61 subscriber/7 subscriber/6,bits/100 127550308 58fc6c30a6445398e467483f4629ab79 1595816108844 0 217399619 0 Adenosine_Tri_Phosphate 1 afd25cc8-9510-4550-b5eb-9324b6ca610f #blamechesscom #999999
62 127550308 94f92dad885d49cdf0d4d74d694b94d4 1595816108963 0 265540494 0 maek_28 0 973dfe4b-9be9-4d05-85ca-755551f52190 nope
63 127550308 ce7721c36b549cd969d1732b0c66f5a7 1595816109129 0 274725794 0 einn9 0 75b1f985-8db0-4a91-995e-d3261a51b90e sadchamp
64 subscriber/1 subscriber/0 127550308 cedca7b9fa8f9889d212559ef4a65bc4 1595816109165 0 97151792 0 thekid_54 1 be0445d4-96fd-4a2d-9a98-85b298e2d5c4 24 hours? #FD00BB
65 1 25:0-4 127550308 d21664375fd9a9a340c0d18f8476cf87 1595816109286 0 132665916 0 oceanman_takemebytheh4nd 0 218ab304-f255-4e24-82fc-4412db8769fc Kappa #551A8B
66 25:4-8 127550308 99d8e8432f44cf0fd5fc0c37c515c046 1595816109366 0 31050861 0 skitlzx 0 fc682baf-6159-4e62-8902-fc941ae6b3e4 lag Kappa #0000FF
67 127550308 65cc7bea1952413af77c3beb754eee9b 1595816109437 0 204434546 0 ImDisManyTwitch 0 9362896b-3856-4ede-bb62-b37dc12345a1 'Wine Lag'
68 127550308 0da04429d4f57809a0d152ce649b93f1 1595816109656 0 484766599 0 deepbishop 0 27c630ae-443e-4527-9dff-2a40698607a2 lag in your brain
69 127550308 cc09588431d2060e47a58712164dbdaa 1595816109830 0 534243080 0 gretasdisciples 0 b2c20b7b-e3fa-4e8f-a9e7-9a2e1e98f958 SURE, A lag
70 1 25:0-4 127550308 be44d05ef78860a93763195c268e8d05 1595816110137 0 254157596 0 cupofcocoa__ 0 edfe34a2-9c4d-4399-a7d3-c05d41fdaa18 Kappa #0000FF
71 127550308 f7f49c9e34784250d858b7a763b0d3d2 1595816110138 0 77980562 0 BBeatless 0 c7cd9b9f-651a-4b35-a66c-1d16f47c724e brain LAG #1E90FF
72 subscriber/1 subscriber/0 25:0-4 127550308 4276af5f703b600d8f49fee2f41b10cf 1595816110119 0 430645544 0 sophiexbc 1 d40b23ce-ada7-486a-8770-ea37e7f60cae Kappa sure #1E90FF
73 127550308 5c4a80567ab0f943af66d0998cbdcee8 1595816110594 0 189862796 0 loayakram 0 9e8eed62-e2c3-4011-b31e-547d304b7285 NO
74 subscriber/5 subscriber/3 127550308 65e436840083d37e6cc9daf6a9b38fb5 1595816110766 0 207843882 0 Shroffy7 1 1fb7c924-ea3c-4cfc-9cd6-6808a1aacfad chess.com PepeLaugh #FF4500
75 127550308 f26a03c645cc67bf375b6847ef3d6c93 1595816110976 0 263124733 0 LudwigVanBeethoven23 0 d35c610a-c7d9-4a5b-affd-9ae7e935d7cb lag in chess
76 127550308 b9eadfa3e9dfe27f6db4083634fa7b56 1595816111332 0 164828199 0 aa175 0 7b3c6764-5ed9-4b6a-bdc9-188915db017f THE FINAL POSITION IS A DRAw
77 subscriber/2 subscriber/0,premium/1 127550308 04f914d5b9b8405c21597e9b9161a502 1595816111530 0 58745385 0 danification9 1 6429e1e0-c6cf-4666-b884-bef0a8e5d8a2 Brain lag
78 1 25:0-4 127550308 1595816111656 0 51032758 0 Whole_Lotta_Lies 0 94d64716-8213-45ce-a6f1-ef60ab9f8440 Kappa #2E8B57
79 subscriber/1 subscriber/0 127550308 1b843e3869ab21c8923dd1d7f4795673 1595816111645 0 557195178 0 byebrows2020 1 9ff86b87-f69b-4343-8faa-91c1be1284ff LAG BLAME
80 127550308 9d293af5749552b8629f0897523baf7d 1595816112076 0 262128196 0 slinkyshoots 0 d5ca1063-6f94-44aa-a239-00fe530785b1 Kapp #00FF7F
81 subscriber/2 subscriber/0 25:0-4 127550308 db149a2243bb3914841fe23d9cb1bbeb 1595816112201 0 541613570 6-10:A.3 0 botezslavic 1 eb0c8775-b1b5-49ca-9ec4-1832b62947bb Kappa Drunk already #8A2BE2
82 1 premium/1 25:0-4 127550308 74fe1bc5dae66988b60a8c54e68798e0 1595816112487 0 195983667 0 Nativezk 0 36b645e1-e01f-404a-af35-1d478c171c72 Kappa #FF69B4
83 127550308 bfbb279442719e5920d553a2761538dc 1595816112658 0 119618817 0 ElJavieer 0 f05fb74b-dff1-4654-98e4-28d03d6e78f2 Brain lag #2E8B57
84 1 25:0-4 127550308 1595816112802 0 413018612 0 k4rzheka 0 c4561234-f570-4f41-8904-09aa52c33fd8 Kappa
85 127550308 9ad449b192d1de4d7aa596bd156a2062 1595816113542 0 71627954 0 Toorshul891 0 0a2f91e4-04c0-43c2-a9c4-7be881a83cfe yes #FF0000
86 subscriber/1 subscriber/0 127550308 1595816113595 0 41972554 0 elsenatto 1 d0a07de4-fd30-4216-8e58-62c9dbf65797 YEP LAG #FF0000
87 premium/1 127550308 5f16e408c7c90ffbe042ab4375fff7c7 1595816113605 0 409091205 0 iamzul95 0 57c2de5e-fa67-4462-ae17-3aed3f9d91ce there was a lag
88 subscriber/1 subscriber/0,premium/1 127550308 1595816113693 0 87187380 0 SemiPro19 1 1ab4c9b5-8383-473a-a860-95121028f0f9 wine lag
89 premium/1 127550308 e64fcb6a9b5a08b259cc04c152d1dfec 1595816114198 0 101983685 0 Clench1k 0 2ca56351-ee78-4efd-8c32-72694cfec3d8 YEP lag #FF0000
90 subscriber/1 subscriber/0 127550308 9021f68fc93100962d0e988f6143018f 1595816114801 0 23289875 0 Jaaledon 1 6da1d281-2924-40b3-8fa7-bc425c03beba Sure, blame it on your ISP #0000FF
91 25:8-12 127550308 64c03873fd1d7f7ef5fd375842d73de2 1595816114958 0 504713042 0 ocelot022 0 3797dcd3-52ff-45f7-b573-5cc52412e549 ok sure Kappa
92 subscriber/10 subscriber/6 302934780:10-18,26-34,42-50,58-66,74-82 127550308 516affced6902164299a700a388cf543 1595816115272 0 117880554 0 sepehr91 1 87d8db4c-04e8-4ec9-9bc2-8fb8c61a286b lag pepeD botez2300 pepeD botez2300 pepeD botez2300 pepeD botez2300 pepeD botez2300 lag #00FF7F
93 127550308 d8e9fbbe67345be0e78d4fab5bdfbc23 1595816115454 0 484766599 0 deepbishop 0 467592bf-bdf1-46eb-a8b2-a9b5bd2a6bb6 brain lag
94 premium/1 127550308 1595816115903 0 512437416 0 augusto_vam 0 384f4487-62fd-464b-aa43-132f5d29c97d BRAIN LAG
95 127550308 1595816115910 0 550092913 0 010293101 0 acb3ba00-6e77-4039-b298-9d8c226bceee Dronk
96 subscriber/1 subscriber/0 127550308 89a17afbfa128e565f95c860f2a3a6ca 1595816115909 0 58317233 0 mrchair1982 1 91dd1bf2-2737-4951-862b-f8021e9f6d02 how have you already dropped so far down from 2300? #FF0000
97 subscriber/1 subscriber/0 127550308 1595816116392 0 113854995 0 xavierrocket 1 6200b631-4f59-4374-a551-1185e3eff4d9 I've had a ton of messed up moves because of lag, I know the pain Sadge #CC0000
98 25:4-8 127550308 d3edaa32d363cf4b4220b4bfbf730c3c 1595816116471 0 6888738 0 AznBoy222 0 73251b3e-c38e-4041-bb10-67adb9ca183b yep Kappa #FF0000
99 subscriber/1 subscriber/0 127550308 1595816116526 0 48780004 0 Cnoized 1 fffd4298-a450-42be-a2db-cb0e0e53a148 I saw it. #00FF7F
100 127550308 1595816116580 0 144960091 0 jisos12369 0 f9c2ff7f-d306-4ca7-bbbd-2dbdd25c0614 YEP lag #1E90FF
101 premium/1 127550308 3c37ca135a77f7597a4cdf86321b5bca 1595816116668 0 442498004 0 juanber 0 f8c1c408-4c4a-4a8e-b1a4-422345ce902f brain lag
102 subscriber/7 1 subscriber/2006 302895853:0-7 127550308 10ba03ddf7192e3c492547c018c47c83 1595816116704 0 255884924 0 RO0PE 1 1a125c0f-3ffd-45c2-ae32-5c4758634c43 botezCIA
103 25:58-62 127550308 7cab32d02b49d46c0f8f094192eb4e3a 1595816117665 0 90516629 0 Mossico 0 2104a46a-a31e-4811-8de9-42777b9ce925 perhaps your perception of time is impaired at the moment Kappa
104 subscriber/3 subscriber/3 88:15-22 127550308 649c5c64e0b9a9946509692b9fe935fa 1595816118589 0 152865823 0 lurker_above 1 b4ae57d5-ff9b-4751-8b90-63aefd1015d4 24 hour stream PogChamp
105 premium/1 127550308 805dc602bc1d75963a5e5bf9ffb86ab6 1595816118924 0 177511477 0 dildo_fire 0 f504ed44-9c19-4c4d-b69c-7456e76c74ba that's why i play on lichess #504B44
106 127550308 1595816119093 0 527834016 0 zloriginals 0 48474373-5e57-42e5-ba93-d346eaf8f184 Just u
107 127550308 319a67044c5003601f705abaf16542cd 1595816119284 0 47117924 0 CoDyPhin 0 f1a5b6d5-3614-4d6f-8a8f-c9511c7e3a61 1345 AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance #1E90FF
108 subscriber/1 subscriber/0,premium/1 127550308 1595816119373 0 98416009 0-4:A.3 0 Schultzky 1 507e9eb5-593d-48f5-b014-10b6784b5e8a drunk #FF0000
109 127550308 ee1bbc8080c48ce26accd61ea405d39c 1595816119464 0 189862796 0 loayakram 0 a9fa6238-e237-4ac7-b9bd-57374a109d07 KAPPA
110 1 145315:0-12,14-26,28-40,42-54,56-68,70-82,84-96,98-110,112-124,126-138,140-152,154-166,168-180,182-194,196-208,210-222,224-236,238-250,252-264,266-278,280-292,294-306,308-320 127550308 1595816119454 0 436262291 0 itzghost6890 0 64ac2f7d-e975-457c-aa3e-ced46c94f678 TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati
111 subscriber/1 subscriber/2000,bits/100 127550308 8aab484c2f0ef821c0536dde4f90f8fb 1595816119878 0 55373647 0 EpicTripleAssTap 1 11770323-aec0-4767-81b6-588208c53310 PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls #00FF7F
112 premium/1 127550308 d8386d364e9de4113d16f99f088ad8ca 1595816119897 0 478625547 0 skitzt 0 074ab457-dcb8-49c3-be2f-163d20afe789 so 24hr stream?
113 subscriber/1 subscriber/0,premium/1 127550308 1595816120966 0 9095096 0 NoPantzzz 1 19d535d1-fe64-4750-8a9e-ffe7e43882d2 Laggggggg #FEA400
114 subscriber/11 subscriber/6 127550308 e2b66a7a4278499c62ef48eef673a41e 1595816121587 0 250839454 0 zPOUTINEZ 1 5241f949-62dc-45c5-bf81-176cd812b54b its the wine dude #FF0000
115 127550308 5d93ca39fa974f87ae34faa6da934d3c 1595816122054 0 500766391 0 merlinnimue 0 5bc1e672-a956-4c64-8bf8-25884361a120 spirit of rasputin
116 subscriber/2 subscriber/0 25:9-13 127550308 e84f1dc8db2401daa4e706f8e25802a4 1595816122170 0 541613570 0 botezslavic 1 71281c31-2ccc-4ca6-8115-dfcebe388ce4 wine lag Kappa #8A2BE2
117 premium/1 127550308 3ba4d9d4e0e8bf2f750121df96d36bba 1595816122308 0 152601449 0 midgetpanda96 0 eedf2720-66c6-4459-84e0-9bdd6f82152c ya
118 25:0-4 127550308 8c590466109e0380d4329bdc33dded67 1595816123077 0 152709545 0 stepkc 0 88683f85-805a-4e87-9b78-4a72cadaab7a Kappa hmm #00FF7F
119 127550308 4ba0e28fa15dda235da65be4fe4b7e5e 1595816123425 0 265540494 0 maek_28 0 1088b96e-4a40-433a-a620-36a569dec5ec no lag nope
120 subscriber/1 1 subscriber/0,sub-gifter/1 70433:0-8 127550308 1595816123499 0 553594803 0 dogplatformr2 1 46ddc40c-e032-4056-a8a2-e751087f3162 KappaRoss
121 127550308 1595816123729 0 51032758 0 Whole_Lotta_Lies 0 72c0bdeb-ce70-4a9d-95c8-777923a4685c 5Head lag #2E8B57
122 1 301443647:0-4/301443646:6-10 127550308 1595816124273 0 76087796 0 Krappa_1_2_3 0 6606358f-2bbb-47e7-9341-3961719ebeea nymn1 nymn2 #FF0000
123 subscriber/1 subscriber/0 127550308 b43c8b5a271298708a7808d74ef71363 1595816124725 0 522200051 0 creatovert 1 edfd099d-37b8-4a69-b564-7467d8969fcf MIND LAG DUE TO WINE #8A2BE2
124 127550308 1595816124894 0 484284968 0 kaibennett06 0 a703c39a-7206-42c3-a559-99459054931f YEP LAG
125 subscriber/1 subscriber/0 127550308 1595816124950 0 130382221 0 k33ling33 1 8fe6738f-d9e7-4490-a703-cd240726ce39 Omg lag
126 127550308 f15ab8ab2a81f42f6919b7753be2285d 1595816125071 0 32171084 0 dslx 0 d5509a70-fe08-427c-b63a-fd4087dc06e7 Yep lag #9ACD32
127 glhf-pledge/1 123171:10-21 127550308 b182592194b2e3a041c4d0a3ceec34e5 1595816126541 0 179916073 0-4:A.3 0 nefderek 0 a815d176-d0b5-486c-8c2f-dd606ec77bb5 drunk lag CoolStoryBob #FF69B4
128 127550308 f1742a95c860173cbed53c898e6ce917 1595816126586 0 484766599 0 deepbishop 0 1c14dd76-5384-47b4-bd4e-2f9e5bd010f7 keep chugging

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,127 @@
[1595816099308] sophiexbc: Kappa
[1595816099422] dougie___jones: lag Kappa
[1595816099572] coffeeindex: L OMEGALUL G
[1595816099785] AmazonESP: Kappa
[1595816100038] Deflecti0n: Kappa lag
[1595816100393] Dortok: YEP lag
[1595816100907] danification9: Sadge
[1595816101643] pab1994: yup
[1595816101637] aa175: g3 rooooooooooook @BotezLive
[1595816102163] vespereq_: It's t h e wine
[1595816102288] botezslavic: DRUNK
[1595816102306] rowrow_: no johns
[1595816102360] slightlyHyPhi: KappaHD
[1595816102389] ReadingRailroad: Yep
[1595816102598] CrenshawViews: yeah it glitched
[1595816102879] Heat_Signature: LAG ON CHESS OMEGALUL
[1595816103185] LeetChocolate: Kappa lag
[1595816103329] swornheart: that was brain lag
[1595816103349] JpForrReal: OMEGALUL
[1595816103439] AleFalnx: atpCap
[1595816103488] hericium7: Kappa
[1595816103492] ezeroh13: YEP LAG
[1595816103535] Nativezk: lag Kappa
[1595816103731] dougie___jones: yeah totally Kappa
[1595816103979] CoDyPhin: Kappa
[1595816104011] Nico3094: lag YEP
[1595816104086] RoLoSC: yeah little lage
[1595816104351] ArcticPolarbear: Kappa lag
[1595816104364] kzp99: LAG
[1595816104463] FrankDaTankGaming: does that for me sometimes too
[1595816104600] modestmage: wasnt that a trade?
[1595816104624] yop01: Yes
[1595816104597] sophiexbc: Kappa lag
[1595816104756] swift_ocelot: YEP lag
[1595816105421] cinasxd: kappa
[1595816105609] jrude72: So what r u up to for the next 24 hours?
[1595816105662] brettydoes: YEP lag
[1595816105720] kavifa6176: Brain lag
[1595816106052] drawingdead: mhmmm Kappa
[1595816106179] Cajun292: bullet lag
[1595816106261] bittersandwich: blaming on lag LULW
[1595816106687] loayakram: fake
[1595816106783] xivi76: you're drunk
[1595816106749] vespereq_: WINE LAG
[1595816106826] deepbishop: drunk
[1595816106963] HaloMonkey3009: Kappa
[1595816107192] kilner111: Kappa
[1595816107269] NotReformeduwu: YEP
[1595816107375] juanhc24v2: YEP LAG
[1595816107440] danification9: CHESS LAG
[1595816107521] ItsRua: Kappa
[1595816107628] Pong8770: Kappa
[1595816107793] magnumd0nger: Kappa
[1595816107829] rowrow_: no johns boatz
[1595816108173] ArcticPolarbear: brain lag
[1595816108223] febog: YEP lag
[1595816108353] 1y1e: lag exists between eyes and brain
[1595816108409] Nicktown: lag Kappa
[1595816108414] Gabber__: monkaHmm
[1595816108844] Adenosine_Tri_Phosphate: #blamechesscom
[1595816108963] maek_28: nope
[1595816109129] einn9: sadchamp
[1595816109165] thekid_54: 24 hours?
[1595816109286] oceanman_takemebytheh4nd: Kappa
[1595816109366] skitlzx: lag Kappa
[1595816109437] ImDisManyTwitch: 'Wine Lag'
[1595816109656] deepbishop: lag in your brain
[1595816109830] gretasdisciples: SURE, A lag
[1595816110137] cupofcocoa__: Kappa
[1595816110138] BBeatless: brain LAG
[1595816110119] sophiexbc: Kappa sure
[1595816110594] loayakram: NO
[1595816110766] Shroffy7: chess.com PepeLaugh
[1595816110976] LudwigVanBeethoven23: lag in chess
[1595816111332] aa175: THE FINAL POSITION IS A DRAw
[1595816111530] danification9: Brain lag
[1595816111656] Whole_Lotta_Lies: Kappa
[1595816111645] byebrows2020: LAG BLAME
[1595816112076] slinkyshoots: Kapp
[1595816112201] botezslavic: Kappa Drunk already
[1595816112487] Nativezk: Kappa
[1595816112658] ElJavieer: Brain lag
[1595816112802] k4rzheka: Kappa
[1595816113542] Toorshul891: yes
[1595816113595] elsenatto: YEP LAG
[1595816113605] iamzul95: there was a lag
[1595816113693] SemiPro19: wine lag
[1595816114198] Clench1k: YEP lag
[1595816114801] Jaaledon: Sure, blame it on your ISP
[1595816114958] ocelot022: ok sure Kappa
[1595816115272] sepehr91: lag pepeD botez2300 pepeD botez2300 pepeD botez2300 pepeD botez2300 pepeD botez2300 lag
[1595816115454] deepbishop: brain lag
[1595816115903] augusto_vam: BRAIN LAG
[1595816115910] 010293101: Dronk
[1595816115909] mrchair1982: how have you already dropped so far down from 2300?
[1595816116392] xavierrocket: I've had a ton of messed up moves because of lag, I know the pain Sadge
[1595816116471] AznBoy222: yep Kappa
[1595816116526] Cnoized: I saw it.
[1595816116580] jisos12369: YEP lag
[1595816116668] juanber: brain lag
[1595816116704] RO0PE: botezCIA
[1595816117665] Mossico: perhaps your perception of time is impaired at the moment Kappa
[1595816118589] lurker_above: 24 hour stream PogChamp
[1595816118924] dildo_fire: that's why i play on lichess
[1595816119093] zloriginals: Just u
[1595816119284] CoDyPhin: 1345 AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance AndreaPls pepeD blobDance
[1595816119373] Schultzky: drunk
[1595816119464] loayakram: KAPPA
[1595816119454] itzghost6890: TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati TheIlluminati
[1595816119878] EpicTripleAssTap: PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls PUTINWALK AndreaPls
[1595816119897] skitzt: so 24hr stream?
[1595816120966] NoPantzzz: Laggggggg
[1595816121587] zPOUTINEZ: its the wine dude
[1595816122054] merlinnimue: spirit of rasputin
[1595816122170] botezslavic: wine lag Kappa
[1595816122308] midgetpanda96: ya
[1595816123077] stepkc: Kappa hmm
[1595816123425] maek_28: no lag nope
[1595816123499] dogplatformr2: KappaRoss
[1595816123729] Whole_Lotta_Lies: 5Head lag
[1595816124273] Krappa_1_2_3: nymn1 nymn2
[1595816124725] creatovert: MIND LAG DUE TO WINE
[1595816124894] kaibennett06: YEP LAG
[1595816124950] k33ling33: Omg lag
[1595816125071] dslx: Yep lag
[1595816126541] nefderek: drunk lag CoolStoryBob
[1595816126586] deepbishop: keep chugging

1
twitchchatirc/gonvo.txt Normal file
View File

@@ -0,0 +1 @@
<socket.socket fd=1180, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.88.240', 62994), raddr=('34.212.92.60', 6667)>

View File

@@ -0,0 +1,4 @@
argparse
python-decouple
emoji
csv

View File

@@ -0,0 +1,216 @@
import socket, re, json, argparse, emoji, csv
# from decouple import config
class DefaultUser(Exception):
"""Raised when you try send a message with the default user"""
pass
class CallbackFunction(Exception):
"""Raised when the callback function does not have (only) one required positional argument"""
pass
class TwitchChatIRC():
__HOST = 'irc.chat.twitch.tv'
__DEFAULT_NICK = 'justinfan67420'
__DEFAULT_PASS = 'SCHMOOPIIE'
__PORT = 6667
__PATTERN = re.compile(r'@(.+?(?=\s+:)).*PRIVMSG[^:]*:([^\r\n]*)')
__CURRENT_CHANNEL = None
def __init__(self, username = None, password = None):
self.__NICK = self.__DEFAULT_NICK
self.__PASS = self.__DEFAULT_PASS
# overwrite if specified
if(username is not None):
self.__NICK = username
if(password is not None):
self.__PASS = 'oauth:'+str(password).lstrip('oauth:')
# create new socket
self.__SOCKET = socket.socket()
# start connection
self.__SOCKET.connect((self.__HOST, self.__PORT))
print('Connected to',self.__HOST,'on port',self.__PORT)
# log in
self.__send_raw('CAP REQ :twitch.tv/tags')
self.__send_raw('PASS ' + self.__PASS)
self.__send_raw('NICK ' + self.__NICK)
def __send_raw(self, string):
self.__SOCKET.send((string+'\r\n').encode('utf-8'))
def __print_message(self, message):
print('['+message['tmi-sent-ts']+']',message['display-name']+':',emoji.demojize(message['message']).encode('utf-8').decode('utf-8','ignore'))
def __recvall(self, buffer_size):
data = b''
while True:
part = self.__SOCKET.recv(buffer_size)
data += part
if len(part) < buffer_size:
break
return data.decode('utf-8')#,'ignore'
def __join_channel(self,channel_name):
channel_lower = channel_name.lower()
if(self.__CURRENT_CHANNEL != channel_lower):
self.__send_raw('JOIN #{}'.format(channel_lower))
self.__CURRENT_CHANNEL = channel_lower
def is_default_user(self):
return self.__NICK == self.__DEFAULT_NICK
def close_connection(self):
self.__SOCKET.close()
print('Connection closed')
def listen(self, channel_name, messages = [], timeout=None, message_timeout=1.0, on_message = None, buffer_size = 4096, message_limit = None, output=None):
self.__join_channel(channel_name)
self.__SOCKET.settimeout(message_timeout)
if(on_message is None):
on_message = self.__print_message
print('Begin retrieving messages:')
time_since_last_message = 0
readbuffer = ''
try:
while True:
try:
new_info = self.__recvall(buffer_size)
readbuffer += new_info
if('PING :tmi.twitch.tv' in readbuffer):
self.__send_raw('PONG :tmi.twitch.tv')
matches = list(self.__PATTERN.finditer(readbuffer))
if(matches):
time_since_last_message = 0
if(len(matches) > 1):
matches = matches[:-1] # assume last one is incomplete
last_index = matches[-1].span()[1]
readbuffer = readbuffer[last_index:]
for match in matches:
data = {}
for item in match.group(1).split(';'):
keys = item.split('=',1)
data[keys[0]]=keys[1]
data['message'] = match.group(2)
print(data)
messages.append(data)
if(callable(on_message)):
try:
on_message(data)
except TypeError:
raise Exception('Incorrect number of parameters for function '+on_message.__name__)
if(message_limit is not None and len(messages) >= message_limit):
return messages
except socket.timeout:
if(timeout != None):
time_since_last_message += message_timeout
if(time_since_last_message >= timeout):
print('No data received in',timeout,'seconds. Timing out.')
break
except KeyboardInterrupt:
print('Interrupted by user.')
except Exception as e:
print('Unknown Error:',e)
raise e
return messages
def send(self, channel_name, message):
self.__join_channel(channel_name)
# check that is using custom login, not default
if(self.is_default_user()):
raise DefaultUser
else:
self.__send_raw('PRIVMSG #{} :{}'.format(channel_name.lower(),message))
print('Sent "{}" to {}'.format(message,channel_name))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Send and receive Twitch chat messages over IRC with python web sockets. For more info, go to https://dev.twitch.tv/docs/irc/guide')
parser.add_argument('channel_name', help='Twitch channel name (username)')
parser.add_argument('-timeout','-t', default=None, type=float, help='time in seconds needed to close connection after not receiving any new data (default: None = no timeout)')
parser.add_argument('-message_timeout','-mt', default=1.0, type=float, help='time in seconds between checks for new data (default: 1 second)')
parser.add_argument('-buffer_size','-b', default=4096, type=int, help='buffer size (default: 4096 bytes = 4 KB)')
parser.add_argument('-message_limit','-l', default=None, type=int, help='maximum amount of messages to get (default: None = unlimited)')
parser.add_argument('-username','-u', default=None, help='username (default: None)')
parser.add_argument('-oauth', '-password','-p', default=None, help='oath token (default: None). Get custom one from https://twitchapps.com/tmi/')
parser.add_argument('--send', action='store_true', help='send mode (default: False)')
parser.add_argument('-output','-o', default=None, help='output file (default: None = print to standard output)')
args = parser.parse_args()
twitch_chat_irc = TwitchChatIRC(username=args.username,password=args.oauth)
if(args.send):
if(twitch_chat_irc.is_default_user()):
print('Unable to send messages with default user. Please provide valid authentication.')
else:
try:
while True:
message = input('>>> Enter message (blank to exit): \n')
if(not message):
break
twitch_chat_irc.send(args.channel_name, message)
except KeyboardInterrupt:
print('\nInterrupted by user.')
else:
messages = twitch_chat_irc.listen(
args.channel_name,
timeout=args.timeout,
message_timeout=args.message_timeout,
buffer_size=args.buffer_size,
message_limit=args.message_limit)
if(args.output != None):
if(args.output.endswith('.json')):
with open(args.output, 'w') as fp:
json.dump(messages, fp)
elif(args.output.endswith('.csv')):
with open(args.output, 'w', newline='',encoding='utf-8') as fp:
fieldnames = []
for message in messages:
fieldnames+=message.keys()
if(len(messages)>0):
fc = csv.DictWriter(fp,fieldnames=list(set(fieldnames)))
fc.writeheader()
fc.writerows(messages)
else:
f = open(args.output,'w', encoding='utf-8')
for message in messages:
print('['+message['tmi-sent-ts']+']',message['display-name']+':',message['message'],file=f)
f.close()
print('Finished writing',len(messages),'messages to',args.output)
twitch_chat_irc.close_connection()