By registering with us, you'll be able to discuss, share and private message with other members of our community.
SignUp Now!import json
import random
import threading
import time
from typing import Dict, Any, List, Optional
from vk_api.keyboard import VkKeyboard, VkKeyboardColor
ROLE_MAFIA = "мафия"
ROLE_DETECTIVE = "комиссар"
ROLE_DOCTOR = "доктор"
ROLE_CIVIL = "мирный"
PHASE_LOBBY = "lobby"
PHASE_NIGHT = "night"
PHASE_DAY = "day"
PHASE_VOTE = "vote"
PHASE_ENDED = "ended"
class MafiaModule:
def __init__(
self,
vk,
*,
admin_id: int = 0,
night_sec: int = 60,
day_sec: int = 90,
vote_sec: int = 45,
min_players: int = 3,
max_players: int = 999,
):
self.vk = vk
self.admin_id = admin_id
self.night_sec = night_sec
self.day_sec...
CRMP Mobile форум готовыйВсем привет, чет скучно. Скажите, что лучше сделать и слить
Да вы зае*** со своим CRMP online!!! Их доху*** чё он вам так нравится?!! Скачайте во н лучше бр там и то стиль красивееCRMP Mobile форум готовый
CRMP Mobile*CRMP online!!!
Одно и тоже мобаил это игра а онлайн это форумCRMP Mobile*
крмп мобайл это копия крмп онлайна?Одно и тоже мобаил это игра а онлайн это форум
Это сама игракрмп мобайл это копия крмп онлайна?
слей код мафиюВсем привет, чет скучно. Скажите, что лучше сделать и слить
слей код мафию
код игры мафии для вк бота?слей код мафию
Дакод игры мафии для вк бота?
import json
import random
import threading
import time
from typing import Dict, Any, List, Optional
from vk_api.keyboard import VkKeyboard, VkKeyboardColor
ROLE_MAFIA = "мафия"
ROLE_DETECTIVE = "комиссар"
ROLE_DOCTOR = "доктор"
ROLE_CIVIL = "мирный"
PHASE_LOBBY = "lobby"
PHASE_NIGHT = "night"
PHASE_DAY = "day"
PHASE_VOTE = "vote"
PHASE_ENDED = "ended"
class MafiaModule:
def __init__(
self,
vk,
*,
admin_id: int = 0,
night_sec: int = 60,
day_sec: int = 90,
vote_sec: int = 45,
min_players: int = 3,
max_players: int = 999,
):
self.vk = vk
self.admin_id = admin_id
self.night_sec = night_sec
self.day_sec = day_sec
self.vote_sec = vote_sec
self.min_players = min_players
self.max_players = max_players
self.games: Dict[int, Dict[str, Any]] = {}
self.lock = threading.Lock()
self.name_cache: Dict[int, str] = {}
t = threading.Thread(target=self._ticker_loop, daemon=True)
t.start()
def _ticker_loop(self):
while True:
try:
self._tick()
except Exception:
pass
time.sleep(1)
def _tick(self):
with self.lock:
games = list(self.games.values())
now = time.time()
for game in games:
if not game.get("phase_end"):
continue
if now < game["phase_end"]:
continue
phase = game.get("phase")
if phase == PHASE_NIGHT:
self._resolve_night(game)
elif phase == PHASE_DAY:
self._begin_vote(game)
elif phase == PHASE_VOTE:
self._resolve_vote(game)
def _get_name(self, user_id: int) -> str:
if user_id in self.name_cache:
return self.name_cache[user_id]
try:
info = self.vk.users.get(user_ids=user_id)[0]
name = info["first_name"]
except Exception:
name = str(user_id)
self.name_cache[user_id] = name
return name
def _mention(self, user_id: int) -> str:
return f"[id{user_id}|{self._get_name(user_id)}]"
def _is_chat(self, peer_id: int) -> bool:
return peer_id >= 2000000000
def _peer_to_chat_id(self, peer_id: int) -> int:
return peer_id - 2000000000
def _send(self, peer_id: int, text: str, keyboard: Optional[VkKeyboard] = None):
params = {"peer_id": peer_id, "random_id": random.randint(1, 10**9), "message": text}
if keyboard is not None:
params["keyboard"] = keyboard.get_keyboard()
self.vk.messages.send(**params)
def _new_game(self, chat_id: int) -> Dict[str, Any]:
return {
"chat_id": chat_id,
"phase": PHASE_LOBBY,
"players": {},
"phase_end": 0,
"night": {},
"day_votes": {},
"round": 0,
}
def _get_game(self, chat_id: int) -> Dict[str, Any]:
with self.lock:
game = self.games.get(chat_id)
if not game:
game = self._new_game(chat_id)
self.games[chat_id] = game
return game
def _player(self, game: Dict[str, Any], user_id: int):
return game["players"].get(str(user_id))
def _list_players(self, game: Dict[str, Any], alive_only=False) -> List[int]:
ids = []
for uid_str, p in game["players"].items():
if alive_only and not p.get("alive"):
continue
ids.append(int(uid_str))
return ids
def _add_player(self, game: Dict[str, Any], user_id: int):
if str(user_id) in game["players"]:
return
if len(game["players"]) >= self.max_players:
return
game["players"][str(user_id)] = {
"name": self._get_name(user_id),
"alive": True,
"role": None,
}
def _remove_player(self, game: Dict[str, Any], user_id: int):
if str(user_id) in game["players"]:
del game["players"][str(user_id)]
def _assign_roles(self, game: Dict[str, Any]):
ids = self._list_players(game)
random.shuffle(ids)
mafia_count = max(1, len(ids) // 3)
mafia_ids = ids[:mafia_count]
rest = ids[mafia_count:]
detective = rest[0] if len(rest) > 0 else None
doctor = rest[1] if len(rest) > 1 else None
for uid in ids:
role = ROLE_CIVIL
if uid in mafia_ids:
role = ROLE_MAFIA
elif detective == uid:
role = ROLE_DETECTIVE
elif doctor == uid:
role = ROLE_DOCTOR
game["players"][str(uid)]["role"] = role
def _send_roles(self, game: Dict[str, Any]):
mafia_ids = [uid for uid in self._list_players(game) if self._player(game, uid)["role"] == ROLE_MAFIA]
mafia_names = ", ".join(self._mention(uid) for uid in mafia_ids)
for uid in self._list_players(game):
role = self._player(game, uid)["role"]
if role == ROLE_MAFIA:
text = f"🕶 Роль: МАФИЯ\nСоюзники: {mafia_names}\nНочью выбирай жертву."
elif role == ROLE_DETECTIVE:
text = "🕵️ Роль: КОМИССАР. Ночью проверяй игроков."
elif role == ROLE_DOCTOR:
text = "🩺 Роль: ДОКТОР. Ночью выбирай, кого спасти."
else:
text = "🙂 Роль: МИРНЫЙ. Днём ищи мафию."
self._send(uid, text)
def _build_lobby_keyboard(self):
kb = VkKeyboard(one_time=False)
kb.add_button("✅ Войти", VkKeyboardColor.POSITIVE, payload={"action": "join"})
kb.add_button("🚪 Выйти", VkKeyboardColor.NEGATIVE, payload={"action": "leave"})
kb.add_line()
kb.add_button("🚀 Старт", VkKeyboardColor.PRIMARY, payload={"action": "start"})
kb.add_button("📊 Статус", VkKeyboardColor.SECONDARY, payload={"action": "status"})
kb.add_line()
kb.add_button("🛑 Стоп", VkKeyboardColor.NEGATIVE, payload={"action": "stop"})
return kb
def _build_targets_keyboard(self, targets: List[int], action: str, chat_id: int):
if len(targets) == 0 or len(targets) > 10:
return None
kb = VkKeyboard(one_time=True, inline=True)
for uid in targets:
kb.add_button(
self._get_name(uid),
VkKeyboardColor.PRIMARY,
payload={"action": action, "chat_id": chat_id, "target": uid},
)
return kb
def _start_game(self, game: Dict[str, Any], peer_id: int):
if game["phase"] != PHASE_LOBBY:
self._send(peer_id, "Игра уже идёт.")
return
if len(game["players"]) < self.min_players:
self._send(peer_id, f"Нужно минимум {self.min_players} игроков.")
return
self._assign_roles(game)
self._send_roles(game)
game["round"] = 1
self._begin_night(game)
self._send(peer_id, "🎬 Игра началась! Ночь наступает...")
def _begin_night(self, game: Dict[str, Any]):
game["phase"] = PHASE_NIGHT
game["phase_end"] = time.time() + self.night_sec
game["night"] = {"mafia_votes": {}, "doctor": None, "detective": None}
chat_peer = game["chat_id"] + 2000000000
self._send(chat_peer, "🌙 Ночь. Все засыпают...")
alive = self._list_players(game, alive_only=True)
mafia_ids = [uid for uid in alive if self._player(game, uid)["role"] == ROLE_MAFIA]
targetable = [uid for uid in alive if self._player(game, uid)["role"] != ROLE_MAFIA]
for uid in mafia_ids:
kb = self._build_targets_keyboard(targetable, "kill", game["chat_id"])
if kb:
self._send(uid, "Выберите жертву:", keyboard=kb)
else:
self._send(uid, "Выберите жертву: kill ID")
for uid in alive:
role = self._player(game, uid)["role"]
if role == ROLE_DOCTOR:
kb = self._build_targets_keyboard(alive, "heal", game["chat_id"])
self._send(uid, "Кого лечить?" if kb else "Кого лечить? heal ID", keyboard=kb)
if role == ROLE_DETECTIVE:
kb = self._build_targets_keyboard(alive, "check", game["chat_id"])
self._send(uid, "Кого проверить?" if kb else "Кого проверить? check ID", keyboard=kb)
def _resolve_night(self, game: Dict[str, Any]):
alive = self._list_players(game, alive_only=True)
mafia_votes = game["night"].get("mafia_votes", {})
doctor_target = game["night"].get("doctor")
detective_target = game["night"].get("detective")
kill_target = None
if mafia_votes:
max_votes = max(mafia_votes.values())
top = [int(uid) for uid, v in mafia_votes.items() if v == max_votes]
kill_target = random.choice(top)
killed = None
if kill_target and kill_target in alive and kill_target != doctor_target:
self._player(game, kill_target)["alive"] = False
killed = kill_target
if detective_target and detective_target in alive:
role = self._player(game, detective_target)["role"]
msg = "🔎 Проверка: МАФИЯ" if role == ROLE_MAFIA else "🔎 Проверка: НЕ мафия"
det_id = next((u for u in alive if self._player(game, u)["role"] == ROLE_DETECTIVE), None)
if det_id:
self._send(det_id, msg)
chat_peer = game["chat_id"] + 2000000000
if killed:
self._send(chat_peer, f"☀️ Утро. Ночью был убит: {self._mention(killed)}")
else:
self._send(chat_peer, "☀️ Утро. Ночь прошла без жертв.")
if self._check_win(game):
return
game["phase"] = PHASE_DAY
game["phase_end"] = time.time() + self.day_sec
game["day_votes"] = {}
self._send(chat_peer, "🗣 День. Обсуждаем. Скоро голосование.")
def _begin_vote(self, game: Dict[str, Any]):
game["phase"] = PHASE_VOTE
game["phase_end"] = time.time() + self.vote_sec
game["day_votes"] = {}
chat_peer = game["chat_id"] + 2000000000
alive = self._list_players(game, alive_only=True)
names = [self._mention(uid) for uid in alive]
self._send(chat_peer, "🗳 Голосование! Кого линчуем?\n" + "\n".join(names))
kb = self._build_targets_keyboard(alive, "vote", game["chat_id"])
if kb:
self._send(chat_peer, "Выберите голос кнопкой:", keyboard=kb)
else:
self._send(chat_peer, "Напишите: vote ID")
def _resolve_vote(self, game: Dict[str, Any]):
votes = game.get("day_votes", {})
alive = self._list_players(game, alive_only=True)
counted = {}
for voter, target in votes.items():
if int(voter) not in alive:
continue
if target not in alive:
continue
counted[target] = counted.get(target, 0) + 1
chat_peer = game["chat_id"] + 2000000000
if not counted:
self._send(chat_peer, "Никого не линчуем.")
else:
max_votes = max(counted.values())
top = [uid for uid, v in counted.items() if v == max_votes]
lynched = random.choice(top)
self._player(game, lynched)["alive"] = False
self._send(chat_peer, f"⚖️ Линчевали: {self._mention(lynched)}")
if self._check_win(game):
return
game["round"] += 1
self._begin_night(game)
def _check_win(self, game: Dict[str, Any]) -> bool:
alive = self._list_players(game, alive_only=True)
mafia = [uid for uid in alive if self._player(game, uid)["role"] == ROLE_MAFIA]
civ = [uid for uid in alive if self._player(game, uid)["role"] != ROLE_MAFIA]
chat_peer = game["chat_id"] + 2000000000
if len(mafia) == 0:
self._send(chat_peer, "🏆 Победа мирных!")
game["phase"] = PHASE_ENDED
game["phase_end"] = 0
return True
if len(mafia) >= len(civ):
self._send(chat_peer, "😈 Победа мафии!")
game["phase"] = PHASE_ENDED
game["phase_end"] = 0
return True
return False
def _status_text(self, game: Dict[str, Any]) -> str:
players = []
for uid in self._list_players(game):
p = self._player(game, uid)
status = "✅" if p.get("alive") else "💀"
players.append(f"{status} {self._mention(uid)}")
phase_map = {
PHASE_LOBBY: "лобби",
PHASE_NIGHT: "ночь",
PHASE_DAY: "день",
PHASE_VOTE: "голосование",
PHASE_ENDED: "завершена",
}
return (
f"🎮 Мафия\nФаза: {phase_map.get(game['phase'], game['phase'])}\n"
f"Раунд: {game.get('round', 0)}\n\n"
f"Игроки ({len(game['players'])}):\n" + "\n".join(players)
)
def _handle_payload(self, peer_id: int, user_id: int, payload: Dict[str, Any]):
action = payload.get("action")
chat_id = payload.get("chat_id")
if action in {"join", "leave", "start", "status", "stop"}:
if not self._is_chat(peer_id):
return
chat_id = self._peer_to_chat_id(peer_id)
game = self._get_game(chat_id)
if action == "join":
self._add_player(game, user_id)
self._send(peer_id, f"{self._mention(user_id)} в игре!")
elif action == "leave":
if game["phase"] == PHASE_LOBBY:
self._remove_player(game, user_id)
self._send(peer_id, f"{self._mention(user_id)} вышел.")
else:
self._player(game, user_id)["alive"] = False
self._send(peer_id, f"{self._mention(user_id)} покинул игру и считается мёртвым.")
self._check_win(game)
elif action == "start":
self._start_game(game, peer_id)
elif action == "status":
self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard())
elif action == "stop":
if self.admin_id and user_id != self.admin_id:
self._send(peer_id, "Только админ может стопнуть игру.")
else:
game["phase"] = PHASE_ENDED
game["phase_end"] = 0
self._send(peer_id, "🛑 Игра остановлена.")
return
if action in {"kill", "heal", "check", "vote"}:
if not chat_id:
return
game = self._get_game(int(chat_id))
target = payload.get("target")
if target is None:
return
self._handle_action(game, user_id, action, int(target))
def _handle_action(self, game: Dict[str, Any], user_id: int, action: str, target: int):
player = self._player(game, user_id)
if not player or not player.get("alive"):
return
if game["phase"] == PHASE_NIGHT:
if action == "kill" and player.get("role") == ROLE_MAFIA:
game["night"]["mafia_votes"][str(target)] = game["night"]["mafia_votes"].get(str(target), 0) + 1
self._send(user_id, "✅ Голос за убийство принят.")
elif action == "heal" and player.get("role") == ROLE_DOCTOR:
game["night"]["doctor"] = target
self._send(user_id, "✅ Лечение принято.")
elif action == "check" and player.get("role") == ROLE_DETECTIVE:
game["night"]["detective"] = target
self._send(user_id, "✅ Проверка принята.")
elif game["phase"] == PHASE_VOTE and action == "vote":
if not self._player(game, target) or not self._player(game, target).get("alive"):
return
game["day_votes"][str(user_id)] = target
chat_peer = game["chat_id"] + 2000000000
self._send(chat_peer, f"🗳 {self._mention(user_id)} голосует.")
def _handle_text_action(self, peer_id: int, user_id: int, text: str):
parts = text.strip().split()
if len(parts) != 2:
return
cmd, target_str = parts[0].lower(), parts[1]
if not target_str.isdigit():
return
target = int(target_str)
if cmd not in {"kill", "heal", "check", "vote"}:
return
if self._is_chat(peer_id):
chat_id = self._peer_to_chat_id(peer_id)
else:
chat_id = None
for g in self.games.values():
if str(user_id) in g.get("players", {}):
chat_id = g["chat_id"]
break
if not chat_id:
return
game = self._get_game(chat_id)
self._handle_action(game, user_id, cmd, target)
def handle_message(self, event):
msg = event.message
peer_id = msg["peer_id"]
user_id = msg["from_id"]
text = (msg.get("text") or "").strip()
payload_raw = msg.get("payload")
if payload_raw:
try:
payload = json.loads(payload_raw)
self._handle_payload(peer_id, user_id, payload)
return
except Exception:
pass
text_lower = text.lower()
if self._is_chat(peer_id):
chat_id = self._peer_to_chat_id(peer_id)
game = self._get_game(chat_id)
if text_lower in {"/mafia", "мафия", "игра"}:
self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard())
return
if text_lower in {"/help", "помощь"}:
self._send(peer_id, "Команды: мафия, войти, выйти, старт, статус, стоп")
return
if text_lower in {"войти", "join"}:
self._add_player(game, user_id)
self._send(peer_id, f"{self._mention(user_id)} в игре!")
return
if text_lower in {"выйти", "leave"}:
if game["phase"] == PHASE_LOBBY:
self._remove_player(game, user_id)
self._send(peer_id, f"{self._mention(user_id)} вышел.")
else:
self._player(game, user_id)["alive"] = False
self._send(peer_id, f"{self._mention(user_id)} покинул игру и считается мёртвым.")
self._check_win(game)
return
if text_lower in {"старт", "start"}:
self._start_game(game, peer_id)
return
if text_lower in {"статус", "status"}:
self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard())
return
if text_lower in {"стоп", "stop"}:
if self.admin_id and user_id != self.admin_id:
self._send(peer_id, "Только админ может стопнуть игру.")
else:
game["phase"] = PHASE_ENDED
game["phase_end"] = 0
self._send(peer_id, "🛑 Игра остановлена.")
return
self._handle_text_action(peer_id, user_id, text_lower)
js bot work будет?фреймворк вк апи
код:import json import random import threading import time from typing import Dict, Any, List, Optional from vk_api.keyboard import VkKeyboard, VkKeyboardColor ROLE_MAFIA = "мафия" ROLE_DETECTIVE = "комиссар" ROLE_DOCTOR = "доктор" ROLE_CIVIL = "мирный" PHASE_LOBBY = "lobby" PHASE_NIGHT = "night" PHASE_DAY = "day" PHASE_VOTE = "vote" PHASE_ENDED = "ended" class MafiaModule: def __init__( self, vk, *, admin_id: int = 0, night_sec: int = 60, day_sec: int = 90, vote_sec: int = 45, min_players: int = 3, max_players: int = 999, ): self.vk = vk self.admin_id = admin_id self.night_sec = night_sec self.day_sec = day_sec self.vote_sec = vote_sec self.min_players = min_players self.max_players = max_players self.games: Dict[int, Dict[str, Any]] = {} self.lock = threading.Lock() self.name_cache: Dict[int, str] = {} t = threading.Thread(target=self._ticker_loop, daemon=True) t.start() def _ticker_loop(self): while True: try: self._tick() except Exception: pass time.sleep(1) def _tick(self): with self.lock: games = list(self.games.values()) now = time.time() for game in games: if not game.get("phase_end"): continue if now < game["phase_end"]: continue phase = game.get("phase") if phase == PHASE_NIGHT: self._resolve_night(game) elif phase == PHASE_DAY: self._begin_vote(game) elif phase == PHASE_VOTE: self._resolve_vote(game) def _get_name(self, user_id: int) -> str: if user_id in self.name_cache: return self.name_cache[user_id] try: info = self.vk.users.get(user_ids=user_id)[0] name = info["first_name"] except Exception: name = str(user_id) self.name_cache[user_id] = name return name def _mention(self, user_id: int) -> str: return f"[id{user_id}|{self._get_name(user_id)}]" def _is_chat(self, peer_id: int) -> bool: return peer_id >= 2000000000 def _peer_to_chat_id(self, peer_id: int) -> int: return peer_id - 2000000000 def _send(self, peer_id: int, text: str, keyboard: Optional[VkKeyboard] = None): params = {"peer_id": peer_id, "random_id": random.randint(1, 10**9), "message": text} if keyboard is not None: params["keyboard"] = keyboard.get_keyboard() self.vk.messages.send(**params) def _new_game(self, chat_id: int) -> Dict[str, Any]: return { "chat_id": chat_id, "phase": PHASE_LOBBY, "players": {}, "phase_end": 0, "night": {}, "day_votes": {}, "round": 0, } def _get_game(self, chat_id: int) -> Dict[str, Any]: with self.lock: game = self.games.get(chat_id) if not game: game = self._new_game(chat_id) self.games[chat_id] = game return game def _player(self, game: Dict[str, Any], user_id: int): return game["players"].get(str(user_id)) def _list_players(self, game: Dict[str, Any], alive_only=False) -> List[int]: ids = [] for uid_str, p in game["players"].items(): if alive_only and not p.get("alive"): continue ids.append(int(uid_str)) return ids def _add_player(self, game: Dict[str, Any], user_id: int): if str(user_id) in game["players"]: return if len(game["players"]) >= self.max_players: return game["players"][str(user_id)] = { "name": self._get_name(user_id), "alive": True, "role": None, } def _remove_player(self, game: Dict[str, Any], user_id: int): if str(user_id) in game["players"]: del game["players"][str(user_id)] def _assign_roles(self, game: Dict[str, Any]): ids = self._list_players(game) random.shuffle(ids) mafia_count = max(1, len(ids) // 3) mafia_ids = ids[:mafia_count] rest = ids[mafia_count:] detective = rest[0] if len(rest) > 0 else None doctor = rest[1] if len(rest) > 1 else None for uid in ids: role = ROLE_CIVIL if uid in mafia_ids: role = ROLE_MAFIA elif detective == uid: role = ROLE_DETECTIVE elif doctor == uid: role = ROLE_DOCTOR game["players"][str(uid)]["role"] = role def _send_roles(self, game: Dict[str, Any]): mafia_ids = [uid for uid in self._list_players(game) if self._player(game, uid)["role"] == ROLE_MAFIA] mafia_names = ", ".join(self._mention(uid) for uid in mafia_ids) for uid in self._list_players(game): role = self._player(game, uid)["role"] if role == ROLE_MAFIA: text = f"🕶 Роль: МАФИЯ\nСоюзники: {mafia_names}\nНочью выбирай жертву." elif role == ROLE_DETECTIVE: text = "🕵️ Роль: КОМИССАР. Ночью проверяй игроков." elif role == ROLE_DOCTOR: text = "🩺 Роль: ДОКТОР. Ночью выбирай, кого спасти." else: text = "🙂 Роль: МИРНЫЙ. Днём ищи мафию." self._send(uid, text) def _build_lobby_keyboard(self): kb = VkKeyboard(one_time=False) kb.add_button("✅ Войти", VkKeyboardColor.POSITIVE, payload={"action": "join"}) kb.add_button("🚪 Выйти", VkKeyboardColor.NEGATIVE, payload={"action": "leave"}) kb.add_line() kb.add_button("🚀 Старт", VkKeyboardColor.PRIMARY, payload={"action": "start"}) kb.add_button("📊 Статус", VkKeyboardColor.SECONDARY, payload={"action": "status"}) kb.add_line() kb.add_button("🛑 Стоп", VkKeyboardColor.NEGATIVE, payload={"action": "stop"}) return kb def _build_targets_keyboard(self, targets: List[int], action: str, chat_id: int): if len(targets) == 0 or len(targets) > 10: return None kb = VkKeyboard(one_time=True, inline=True) for uid in targets: kb.add_button( self._get_name(uid), VkKeyboardColor.PRIMARY, payload={"action": action, "chat_id": chat_id, "target": uid}, ) return kb def _start_game(self, game: Dict[str, Any], peer_id: int): if game["phase"] != PHASE_LOBBY: self._send(peer_id, "Игра уже идёт.") return if len(game["players"]) < self.min_players: self._send(peer_id, f"Нужно минимум {self.min_players} игроков.") return self._assign_roles(game) self._send_roles(game) game["round"] = 1 self._begin_night(game) self._send(peer_id, "🎬 Игра началась! Ночь наступает...") def _begin_night(self, game: Dict[str, Any]): game["phase"] = PHASE_NIGHT game["phase_end"] = time.time() + self.night_sec game["night"] = {"mafia_votes": {}, "doctor": None, "detective": None} chat_peer = game["chat_id"] + 2000000000 self._send(chat_peer, "🌙 Ночь. Все засыпают...") alive = self._list_players(game, alive_only=True) mafia_ids = [uid for uid in alive if self._player(game, uid)["role"] == ROLE_MAFIA] targetable = [uid for uid in alive if self._player(game, uid)["role"] != ROLE_MAFIA] for uid in mafia_ids: kb = self._build_targets_keyboard(targetable, "kill", game["chat_id"]) if kb: self._send(uid, "Выберите жертву:", keyboard=kb) else: self._send(uid, "Выберите жертву: kill ID") for uid in alive: role = self._player(game, uid)["role"] if role == ROLE_DOCTOR: kb = self._build_targets_keyboard(alive, "heal", game["chat_id"]) self._send(uid, "Кого лечить?" if kb else "Кого лечить? heal ID", keyboard=kb) if role == ROLE_DETECTIVE: kb = self._build_targets_keyboard(alive, "check", game["chat_id"]) self._send(uid, "Кого проверить?" if kb else "Кого проверить? check ID", keyboard=kb) def _resolve_night(self, game: Dict[str, Any]): alive = self._list_players(game, alive_only=True) mafia_votes = game["night"].get("mafia_votes", {}) doctor_target = game["night"].get("doctor") detective_target = game["night"].get("detective") kill_target = None if mafia_votes: max_votes = max(mafia_votes.values()) top = [int(uid) for uid, v in mafia_votes.items() if v == max_votes] kill_target = random.choice(top) killed = None if kill_target and kill_target in alive and kill_target != doctor_target: self._player(game, kill_target)["alive"] = False killed = kill_target if detective_target and detective_target in alive: role = self._player(game, detective_target)["role"] msg = "🔎 Проверка: МАФИЯ" if role == ROLE_MAFIA else "🔎 Проверка: НЕ мафия" det_id = next((u for u in alive if self._player(game, u)["role"] == ROLE_DETECTIVE), None) if det_id: self._send(det_id, msg) chat_peer = game["chat_id"] + 2000000000 if killed: self._send(chat_peer, f"☀️ Утро. Ночью был убит: {self._mention(killed)}") else: self._send(chat_peer, "☀️ Утро. Ночь прошла без жертв.") if self._check_win(game): return game["phase"] = PHASE_DAY game["phase_end"] = time.time() + self.day_sec game["day_votes"] = {} self._send(chat_peer, "🗣 День. Обсуждаем. Скоро голосование.") def _begin_vote(self, game: Dict[str, Any]): game["phase"] = PHASE_VOTE game["phase_end"] = time.time() + self.vote_sec game["day_votes"] = {} chat_peer = game["chat_id"] + 2000000000 alive = self._list_players(game, alive_only=True) names = [self._mention(uid) for uid in alive] self._send(chat_peer, "🗳 Голосование! Кого линчуем?\n" + "\n".join(names)) kb = self._build_targets_keyboard(alive, "vote", game["chat_id"]) if kb: self._send(chat_peer, "Выберите голос кнопкой:", keyboard=kb) else: self._send(chat_peer, "Напишите: vote ID") def _resolve_vote(self, game: Dict[str, Any]): votes = game.get("day_votes", {}) alive = self._list_players(game, alive_only=True) counted = {} for voter, target in votes.items(): if int(voter) not in alive: continue if target not in alive: continue counted[target] = counted.get(target, 0) + 1 chat_peer = game["chat_id"] + 2000000000 if not counted: self._send(chat_peer, "Никого не линчуем.") else: max_votes = max(counted.values()) top = [uid for uid, v in counted.items() if v == max_votes] lynched = random.choice(top) self._player(game, lynched)["alive"] = False self._send(chat_peer, f"⚖️ Линчевали: {self._mention(lynched)}") if self._check_win(game): return game["round"] += 1 self._begin_night(game) def _check_win(self, game: Dict[str, Any]) -> bool: alive = self._list_players(game, alive_only=True) mafia = [uid for uid in alive if self._player(game, uid)["role"] == ROLE_MAFIA] civ = [uid for uid in alive if self._player(game, uid)["role"] != ROLE_MAFIA] chat_peer = game["chat_id"] + 2000000000 if len(mafia) == 0: self._send(chat_peer, "🏆 Победа мирных!") game["phase"] = PHASE_ENDED game["phase_end"] = 0 return True if len(mafia) >= len(civ): self._send(chat_peer, "😈 Победа мафии!") game["phase"] = PHASE_ENDED game["phase_end"] = 0 return True return False def _status_text(self, game: Dict[str, Any]) -> str: players = [] for uid in self._list_players(game): p = self._player(game, uid) status = "✅" if p.get("alive") else "💀" players.append(f"{status} {self._mention(uid)}") phase_map = { PHASE_LOBBY: "лобби", PHASE_NIGHT: "ночь", PHASE_DAY: "день", PHASE_VOTE: "голосование", PHASE_ENDED: "завершена", } return ( f"🎮 Мафия\nФаза: {phase_map.get(game['phase'], game['phase'])}\n" f"Раунд: {game.get('round', 0)}\n\n" f"Игроки ({len(game['players'])}):\n" + "\n".join(players) ) def _handle_payload(self, peer_id: int, user_id: int, payload: Dict[str, Any]): action = payload.get("action") chat_id = payload.get("chat_id") if action in {"join", "leave", "start", "status", "stop"}: if not self._is_chat(peer_id): return chat_id = self._peer_to_chat_id(peer_id) game = self._get_game(chat_id) if action == "join": self._add_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} в игре!") elif action == "leave": if game["phase"] == PHASE_LOBBY: self._remove_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} вышел.") else: self._player(game, user_id)["alive"] = False self._send(peer_id, f"{self._mention(user_id)} покинул игру и считается мёртвым.") self._check_win(game) elif action == "start": self._start_game(game, peer_id) elif action == "status": self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard()) elif action == "stop": if self.admin_id and user_id != self.admin_id: self._send(peer_id, "Только админ может стопнуть игру.") else: game["phase"] = PHASE_ENDED game["phase_end"] = 0 self._send(peer_id, "🛑 Игра остановлена.") return if action in {"kill", "heal", "check", "vote"}: if not chat_id: return game = self._get_game(int(chat_id)) target = payload.get("target") if target is None: return self._handle_action(game, user_id, action, int(target)) def _handle_action(self, game: Dict[str, Any], user_id: int, action: str, target: int): player = self._player(game, user_id) if not player or not player.get("alive"): return if game["phase"] == PHASE_NIGHT: if action == "kill" and player.get("role") == ROLE_MAFIA: game["night"]["mafia_votes"][str(target)] = game["night"]["mafia_votes"].get(str(target), 0) + 1 self._send(user_id, "✅ Голос за убийство принят.") elif action == "heal" and player.get("role") == ROLE_DOCTOR: game["night"]["doctor"] = target self._send(user_id, "✅ Лечение принято.") elif action == "check" and player.get("role") == ROLE_DETECTIVE: game["night"]["detective"] = target self._send(user_id, "✅ Проверка принята.") elif game["phase"] == PHASE_VOTE and action == "vote": if not self._player(game, target) or not self._player(game, target).get("alive"): return game["day_votes"][str(user_id)] = target chat_peer = game["chat_id"] + 2000000000 self._send(chat_peer, f"🗳 {self._mention(user_id)} голосует.") def _handle_text_action(self, peer_id: int, user_id: int, text: str): parts = text.strip().split() if len(parts) != 2: return cmd, target_str = parts[0].lower(), parts[1] if not target_str.isdigit(): return target = int(target_str) if cmd not in {"kill", "heal", "check", "vote"}: return if self._is_chat(peer_id): chat_id = self._peer_to_chat_id(peer_id) else: chat_id = None for g in self.games.values(): if str(user_id) in g.get("players", {}): chat_id = g["chat_id"] break if not chat_id: return game = self._get_game(chat_id) self._handle_action(game, user_id, cmd, target) def handle_message(self, event): msg = event.message peer_id = msg["peer_id"] user_id = msg["from_id"] text = (msg.get("text") or "").strip() payload_raw = msg.get("payload") if payload_raw: try: payload = json.loads(payload_raw) self._handle_payload(peer_id, user_id, payload) return except Exception: pass text_lower = text.lower() if self._is_chat(peer_id): chat_id = self._peer_to_chat_id(peer_id) game = self._get_game(chat_id) if text_lower in {"/mafia", "мафия", "игра"}: self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard()) return if text_lower in {"/help", "помощь"}: self._send(peer_id, "Команды: мафия, войти, выйти, старт, статус, стоп") return if text_lower in {"войти", "join"}: self._add_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} в игре!") return if text_lower in {"выйти", "leave"}: if game["phase"] == PHASE_LOBBY: self._remove_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} вышел.") else: self._player(game, user_id)["alive"] = False self._send(peer_id, f"{self._mention(user_id)} покинул игру и считается мёртвым.") self._check_win(game) return if text_lower in {"старт", "start"}: self._start_game(game, peer_id) return if text_lower in {"статус", "status"}: self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard()) return if text_lower in {"стоп", "stop"}: if self.admin_id and user_id != self.admin_id: self._send(peer_id, "Только админ может стопнуть игру.") else: game["phase"] = PHASE_ENDED game["phase_end"] = 0 self._send(peer_id, "🛑 Игра остановлена.") return self._handle_text_action(peer_id, user_id, text_lower)
это же python, a можешь для js скинут пожалуйста ну или это js работат будет?фреймворк вк апи
код:import json import random import threading import time from typing import Dict, Any, List, Optional from vk_api.keyboard import VkKeyboard, VkKeyboardColor ROLE_MAFIA = "мафия" ROLE_DETECTIVE = "комиссар" ROLE_DOCTOR = "доктор" ROLE_CIVIL = "мирный" PHASE_LOBBY = "lobby" PHASE_NIGHT = "night" PHASE_DAY = "day" PHASE_VOTE = "vote" PHASE_ENDED = "ended" class MafiaModule: def __init__( self, vk, *, admin_id: int = 0, night_sec: int = 60, day_sec: int = 90, vote_sec: int = 45, min_players: int = 3, max_players: int = 999, ): self.vk = vk self.admin_id = admin_id self.night_sec = night_sec self.day_sec = day_sec self.vote_sec = vote_sec self.min_players = min_players self.max_players = max_players self.games: Dict[int, Dict[str, Any]] = {} self.lock = threading.Lock() self.name_cache: Dict[int, str] = {} t = threading.Thread(target=self._ticker_loop, daemon=True) t.start() def _ticker_loop(self): while True: try: self._tick() except Exception: pass time.sleep(1) def _tick(self): with self.lock: games = list(self.games.values()) now = time.time() for game in games: if not game.get("phase_end"): continue if now < game["phase_end"]: continue phase = game.get("phase") if phase == PHASE_NIGHT: self._resolve_night(game) elif phase == PHASE_DAY: self._begin_vote(game) elif phase == PHASE_VOTE: self._resolve_vote(game) def _get_name(self, user_id: int) -> str: if user_id in self.name_cache: return self.name_cache[user_id] try: info = self.vk.users.get(user_ids=user_id)[0] name = info["first_name"] except Exception: name = str(user_id) self.name_cache[user_id] = name return name def _mention(self, user_id: int) -> str: return f"[id{user_id}|{self._get_name(user_id)}]" def _is_chat(self, peer_id: int) -> bool: return peer_id >= 2000000000 def _peer_to_chat_id(self, peer_id: int) -> int: return peer_id - 2000000000 def _send(self, peer_id: int, text: str, keyboard: Optional[VkKeyboard] = None): params = {"peer_id": peer_id, "random_id": random.randint(1, 10**9), "message": text} if keyboard is not None: params["keyboard"] = keyboard.get_keyboard() self.vk.messages.send(**params) def _new_game(self, chat_id: int) -> Dict[str, Any]: return { "chat_id": chat_id, "phase": PHASE_LOBBY, "players": {}, "phase_end": 0, "night": {}, "day_votes": {}, "round": 0, } def _get_game(self, chat_id: int) -> Dict[str, Any]: with self.lock: game = self.games.get(chat_id) if not game: game = self._new_game(chat_id) self.games[chat_id] = game return game def _player(self, game: Dict[str, Any], user_id: int): return game["players"].get(str(user_id)) def _list_players(self, game: Dict[str, Any], alive_only=False) -> List[int]: ids = [] for uid_str, p in game["players"].items(): if alive_only and not p.get("alive"): continue ids.append(int(uid_str)) return ids def _add_player(self, game: Dict[str, Any], user_id: int): if str(user_id) in game["players"]: return if len(game["players"]) >= self.max_players: return game["players"][str(user_id)] = { "name": self._get_name(user_id), "alive": True, "role": None, } def _remove_player(self, game: Dict[str, Any], user_id: int): if str(user_id) in game["players"]: del game["players"][str(user_id)] def _assign_roles(self, game: Dict[str, Any]): ids = self._list_players(game) random.shuffle(ids) mafia_count = max(1, len(ids) // 3) mafia_ids = ids[:mafia_count] rest = ids[mafia_count:] detective = rest[0] if len(rest) > 0 else None doctor = rest[1] if len(rest) > 1 else None for uid in ids: role = ROLE_CIVIL if uid in mafia_ids: role = ROLE_MAFIA elif detective == uid: role = ROLE_DETECTIVE elif doctor == uid: role = ROLE_DOCTOR game["players"][str(uid)]["role"] = role def _send_roles(self, game: Dict[str, Any]): mafia_ids = [uid for uid in self._list_players(game) if self._player(game, uid)["role"] == ROLE_MAFIA] mafia_names = ", ".join(self._mention(uid) for uid in mafia_ids) for uid in self._list_players(game): role = self._player(game, uid)["role"] if role == ROLE_MAFIA: text = f"🕶 Роль: МАФИЯ\nСоюзники: {mafia_names}\nНочью выбирай жертву." elif role == ROLE_DETECTIVE: text = "🕵️ Роль: КОМИССАР. Ночью проверяй игроков." elif role == ROLE_DOCTOR: text = "🩺 Роль: ДОКТОР. Ночью выбирай, кого спасти." else: text = "🙂 Роль: МИРНЫЙ. Днём ищи мафию." self._send(uid, text) def _build_lobby_keyboard(self): kb = VkKeyboard(one_time=False) kb.add_button("✅ Войти", VkKeyboardColor.POSITIVE, payload={"action": "join"}) kb.add_button("🚪 Выйти", VkKeyboardColor.NEGATIVE, payload={"action": "leave"}) kb.add_line() kb.add_button("🚀 Старт", VkKeyboardColor.PRIMARY, payload={"action": "start"}) kb.add_button("📊 Статус", VkKeyboardColor.SECONDARY, payload={"action": "status"}) kb.add_line() kb.add_button("🛑 Стоп", VkKeyboardColor.NEGATIVE, payload={"action": "stop"}) return kb def _build_targets_keyboard(self, targets: List[int], action: str, chat_id: int): if len(targets) == 0 or len(targets) > 10: return None kb = VkKeyboard(one_time=True, inline=True) for uid in targets: kb.add_button( self._get_name(uid), VkKeyboardColor.PRIMARY, payload={"action": action, "chat_id": chat_id, "target": uid}, ) return kb def _start_game(self, game: Dict[str, Any], peer_id: int): if game["phase"] != PHASE_LOBBY: self._send(peer_id, "Игра уже идёт.") return if len(game["players"]) < self.min_players: self._send(peer_id, f"Нужно минимум {self.min_players} игроков.") return self._assign_roles(game) self._send_roles(game) game["round"] = 1 self._begin_night(game) self._send(peer_id, "🎬 Игра началась! Ночь наступает...") def _begin_night(self, game: Dict[str, Any]): game["phase"] = PHASE_NIGHT game["phase_end"] = time.time() + self.night_sec game["night"] = {"mafia_votes": {}, "doctor": None, "detective": None} chat_peer = game["chat_id"] + 2000000000 self._send(chat_peer, "🌙 Ночь. Все засыпают...") alive = self._list_players(game, alive_only=True) mafia_ids = [uid for uid in alive if self._player(game, uid)["role"] == ROLE_MAFIA] targetable = [uid for uid in alive if self._player(game, uid)["role"] != ROLE_MAFIA] for uid in mafia_ids: kb = self._build_targets_keyboard(targetable, "kill", game["chat_id"]) if kb: self._send(uid, "Выберите жертву:", keyboard=kb) else: self._send(uid, "Выберите жертву: kill ID") for uid in alive: role = self._player(game, uid)["role"] if role == ROLE_DOCTOR: kb = self._build_targets_keyboard(alive, "heal", game["chat_id"]) self._send(uid, "Кого лечить?" if kb else "Кого лечить? heal ID", keyboard=kb) if role == ROLE_DETECTIVE: kb = self._build_targets_keyboard(alive, "check", game["chat_id"]) self._send(uid, "Кого проверить?" if kb else "Кого проверить? check ID", keyboard=kb) def _resolve_night(self, game: Dict[str, Any]): alive = self._list_players(game, alive_only=True) mafia_votes = game["night"].get("mafia_votes", {}) doctor_target = game["night"].get("doctor") detective_target = game["night"].get("detective") kill_target = None if mafia_votes: max_votes = max(mafia_votes.values()) top = [int(uid) for uid, v in mafia_votes.items() if v == max_votes] kill_target = random.choice(top) killed = None if kill_target and kill_target in alive and kill_target != doctor_target: self._player(game, kill_target)["alive"] = False killed = kill_target if detective_target and detective_target in alive: role = self._player(game, detective_target)["role"] msg = "🔎 Проверка: МАФИЯ" if role == ROLE_MAFIA else "🔎 Проверка: НЕ мафия" det_id = next((u for u in alive if self._player(game, u)["role"] == ROLE_DETECTIVE), None) if det_id: self._send(det_id, msg) chat_peer = game["chat_id"] + 2000000000 if killed: self._send(chat_peer, f"☀️ Утро. Ночью был убит: {self._mention(killed)}") else: self._send(chat_peer, "☀️ Утро. Ночь прошла без жертв.") if self._check_win(game): return game["phase"] = PHASE_DAY game["phase_end"] = time.time() + self.day_sec game["day_votes"] = {} self._send(chat_peer, "🗣 День. Обсуждаем. Скоро голосование.") def _begin_vote(self, game: Dict[str, Any]): game["phase"] = PHASE_VOTE game["phase_end"] = time.time() + self.vote_sec game["day_votes"] = {} chat_peer = game["chat_id"] + 2000000000 alive = self._list_players(game, alive_only=True) names = [self._mention(uid) for uid in alive] self._send(chat_peer, "🗳 Голосование! Кого линчуем?\n" + "\n".join(names)) kb = self._build_targets_keyboard(alive, "vote", game["chat_id"]) if kb: self._send(chat_peer, "Выберите голос кнопкой:", keyboard=kb) else: self._send(chat_peer, "Напишите: vote ID") def _resolve_vote(self, game: Dict[str, Any]): votes = game.get("day_votes", {}) alive = self._list_players(game, alive_only=True) counted = {} for voter, target in votes.items(): if int(voter) not in alive: continue if target not in alive: continue counted[target] = counted.get(target, 0) + 1 chat_peer = game["chat_id"] + 2000000000 if not counted: self._send(chat_peer, "Никого не линчуем.") else: max_votes = max(counted.values()) top = [uid for uid, v in counted.items() if v == max_votes] lynched = random.choice(top) self._player(game, lynched)["alive"] = False self._send(chat_peer, f"⚖️ Линчевали: {self._mention(lynched)}") if self._check_win(game): return game["round"] += 1 self._begin_night(game) def _check_win(self, game: Dict[str, Any]) -> bool: alive = self._list_players(game, alive_only=True) mafia = [uid for uid in alive if self._player(game, uid)["role"] == ROLE_MAFIA] civ = [uid for uid in alive if self._player(game, uid)["role"] != ROLE_MAFIA] chat_peer = game["chat_id"] + 2000000000 if len(mafia) == 0: self._send(chat_peer, "🏆 Победа мирных!") game["phase"] = PHASE_ENDED game["phase_end"] = 0 return True if len(mafia) >= len(civ): self._send(chat_peer, "😈 Победа мафии!") game["phase"] = PHASE_ENDED game["phase_end"] = 0 return True return False def _status_text(self, game: Dict[str, Any]) -> str: players = [] for uid in self._list_players(game): p = self._player(game, uid) status = "✅" if p.get("alive") else "💀" players.append(f"{status} {self._mention(uid)}") phase_map = { PHASE_LOBBY: "лобби", PHASE_NIGHT: "ночь", PHASE_DAY: "день", PHASE_VOTE: "голосование", PHASE_ENDED: "завершена", } return ( f"🎮 Мафия\nФаза: {phase_map.get(game['phase'], game['phase'])}\n" f"Раунд: {game.get('round', 0)}\n\n" f"Игроки ({len(game['players'])}):\n" + "\n".join(players) ) def _handle_payload(self, peer_id: int, user_id: int, payload: Dict[str, Any]): action = payload.get("action") chat_id = payload.get("chat_id") if action in {"join", "leave", "start", "status", "stop"}: if not self._is_chat(peer_id): return chat_id = self._peer_to_chat_id(peer_id) game = self._get_game(chat_id) if action == "join": self._add_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} в игре!") elif action == "leave": if game["phase"] == PHASE_LOBBY: self._remove_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} вышел.") else: self._player(game, user_id)["alive"] = False self._send(peer_id, f"{self._mention(user_id)} покинул игру и считается мёртвым.") self._check_win(game) elif action == "start": self._start_game(game, peer_id) elif action == "status": self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard()) elif action == "stop": if self.admin_id and user_id != self.admin_id: self._send(peer_id, "Только админ может стопнуть игру.") else: game["phase"] = PHASE_ENDED game["phase_end"] = 0 self._send(peer_id, "🛑 Игра остановлена.") return if action in {"kill", "heal", "check", "vote"}: if not chat_id: return game = self._get_game(int(chat_id)) target = payload.get("target") if target is None: return self._handle_action(game, user_id, action, int(target)) def _handle_action(self, game: Dict[str, Any], user_id: int, action: str, target: int): player = self._player(game, user_id) if not player or not player.get("alive"): return if game["phase"] == PHASE_NIGHT: if action == "kill" and player.get("role") == ROLE_MAFIA: game["night"]["mafia_votes"][str(target)] = game["night"]["mafia_votes"].get(str(target), 0) + 1 self._send(user_id, "✅ Голос за убийство принят.") elif action == "heal" and player.get("role") == ROLE_DOCTOR: game["night"]["doctor"] = target self._send(user_id, "✅ Лечение принято.") elif action == "check" and player.get("role") == ROLE_DETECTIVE: game["night"]["detective"] = target self._send(user_id, "✅ Проверка принята.") elif game["phase"] == PHASE_VOTE and action == "vote": if not self._player(game, target) or not self._player(game, target).get("alive"): return game["day_votes"][str(user_id)] = target chat_peer = game["chat_id"] + 2000000000 self._send(chat_peer, f"🗳 {self._mention(user_id)} голосует.") def _handle_text_action(self, peer_id: int, user_id: int, text: str): parts = text.strip().split() if len(parts) != 2: return cmd, target_str = parts[0].lower(), parts[1] if not target_str.isdigit(): return target = int(target_str) if cmd not in {"kill", "heal", "check", "vote"}: return if self._is_chat(peer_id): chat_id = self._peer_to_chat_id(peer_id) else: chat_id = None for g in self.games.values(): if str(user_id) in g.get("players", {}): chat_id = g["chat_id"] break if not chat_id: return game = self._get_game(chat_id) self._handle_action(game, user_id, cmd, target) def handle_message(self, event): msg = event.message peer_id = msg["peer_id"] user_id = msg["from_id"] text = (msg.get("text") or "").strip() payload_raw = msg.get("payload") if payload_raw: try: payload = json.loads(payload_raw) self._handle_payload(peer_id, user_id, payload) return except Exception: pass text_lower = text.lower() if self._is_chat(peer_id): chat_id = self._peer_to_chat_id(peer_id) game = self._get_game(chat_id) if text_lower in {"/mafia", "мафия", "игра"}: self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard()) return if text_lower in {"/help", "помощь"}: self._send(peer_id, "Команды: мафия, войти, выйти, старт, статус, стоп") return if text_lower in {"войти", "join"}: self._add_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} в игре!") return if text_lower in {"выйти", "leave"}: if game["phase"] == PHASE_LOBBY: self._remove_player(game, user_id) self._send(peer_id, f"{self._mention(user_id)} вышел.") else: self._player(game, user_id)["alive"] = False self._send(peer_id, f"{self._mention(user_id)} покинул игру и считается мёртвым.") self._check_win(game) return if text_lower in {"старт", "start"}: self._start_game(game, peer_id) return if text_lower in {"статус", "status"}: self._send(peer_id, self._status_text(game), keyboard=self._build_lobby_keyboard()) return if text_lower in {"стоп", "stop"}: if self.admin_id and user_id != self.admin_id: self._send(peer_id, "Только админ может стопнуть игру.") else: game["phase"] = PHASE_ENDED game["phase_end"] = 0 self._send(peer_id, "🛑 Игра остановлена.") return self._handle_text_action(peer_id, user_id, text_lower)
// mafia_module.js
const { Keyboard } = require("vk-io");
const ROLE_MAFIA = "мафия";
const ROLE_DETECTIVE = "комиссар";
const ROLE_DOCTOR = "доктор";
const ROLE_CIVIL = "мирный";
const PHASE_LOBBY = "lobby";
const PHASE_NIGHT = "night";
const PHASE_DAY = "day";
const PHASE_VOTE = "vote";
const PHASE_ENDED = "ended";
class MafiaModule {
constructor(vk, {
adminId = 0,
nightSec = 60,
daySec = 90,
voteSec = 45,
minPlayers = 3,
maxPlayers = 999,
} = {}) {
this.vk = vk;
this.adminId = adminId;
this.nightSec = nightSec;
this.daySec = daySec;
this.voteSec = voteSec;
this.minPlayers = minPlayers;
this.maxPlayers = maxPlayers;
this.games = new Map();
this.nameCache = new Map();
setInterval(() => this._tick(), 1000);
}
_isChat(peerId) {
return peerId >= 2000000000;
}
_peerToChatId(peerId) {
return peerId - 2000000000;
}
async _getName(userId) {
if (this.nameCache.has(userId)) return this.nameCache.get(userId);
try {
const [info] = await this.vk.api.users.get({ user_ids: userId });
const name = info.first_name || String(userId);
this.nameCache.set(userId, name);
return name;
} catch {
return String(userId);
}
}
async _mention(userId) {
const name = await this._getName(userId);
return `[id${userId}|${name}]`;
}
async _send(peerId, text, keyboard = null) {
const params = { peer_id: peerId, random_id: Date.now(), message: text };
if (keyboard) params.keyboard = keyboard;
await this.vk.api.messages.send(params);
}
_newGame(chatId) {
return {
chatId,
phase: PHASE_LOBBY,
players: {},
phaseEnd: 0,
night: {},
dayVotes: {},
round: 0,
};
}
_getGame(chatId) {
if (!this.games.has(chatId)) this.games.set(chatId, this._newGame(chatId));
return this.games.get(chatId);
}
_player(game, userId) {
return game.players[String(userId)];
}
_listPlayers(game, aliveOnly = false) {
const ids = [];
for (const [uid, p] of Object.entries(game.players)) {
if (aliveOnly && !p.alive) continue;
ids.push(Number(uid));
}
return ids;
}
async _addPlayer(game, userId) {
if (game.players[String(userId)]) return;
if (Object.keys(game.players).length >= this.maxPlayers) return;
const name = await this._getName(userId);
game.players[String(userId)] = { name, alive: true, role: null };
}
_removePlayer(game, userId) {
delete game.players[String(userId)];
}
_assignRoles(game) {
const ids = this._listPlayers(game);
for (let i = ids.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[ids[i], ids[j]] = [ids[j], ids[i]];
}
const mafiaCount = Math.max(1, Math.floor(ids.length / 3));
const mafiaIds = ids.slice(0, mafiaCount);
const rest = ids.slice(mafiaCount);
const detective = rest[0] || null;
const doctor = rest[1] || null;
for (const uid of ids) {
let role = ROLE_CIVIL;
if (mafiaIds.includes(uid)) role = ROLE_MAFIA;
else if (uid === detective) role = ROLE_DETECTIVE;
else if (uid === doctor) role = ROLE_DOCTOR;
game.players[String(uid)].role = role;
}
}
async _sendRoles(game) {
const mafiaIds = this._listPlayers(game).filter(
(uid) => this._player(game, uid).role === ROLE_MAFIA
);
const mafiaNames = (await Promise.all(mafiaIds.map((u) => this._mention(u)))).join(", ");
for (const uid of this._listPlayers(game)) {
const role = this._player(game, uid).role;
let text = "🙂 Роль: МИРНЫЙ. Днём ищи мафию.";
if (role === ROLE_MAFIA) text = `🕶 Роль: МАФИЯ\nСоюзники: ${mafiaNames}\nНочью выбирай жертву.`;
if (role === ROLE_DETECTIVE) text = "🕵️ Роль: КОМИССАР. Ночью проверяй игроков.";
if (role === ROLE_DOCTOR) text = "🩺 Роль: ДОКТОР. Ночью выбирай, кого спасти.";
await this._send(uid, text);
}
}
_buildLobbyKeyboard() {
return Keyboard.builder()
.textButton({ label: "✅ Войти", color: Keyboard.POSITIVE_COLOR, payload: { action: "join" } })
.textButton({ label: "🚪 Выйти", color: Keyboard.NEGATIVE_COLOR, payload: { action: "leave" } })
.row()
.textButton({ label: "🚀 Старт", color: Keyboard.PRIMARY_COLOR, payload: { action: "start" } })
.textButton({ label: "📊 Статус", color: Keyboard.SECONDARY_COLOR, payload: { action: "status" } })
.row()
.textButton({ label: "🛑 Стоп", color: Keyboard.NEGATIVE_COLOR, payload: { action: "stop" } })
.inline(false)
.oneTime(false)
.build();
}
_buildTargetsKeyboard(targets, action, chatId) {
if (targets.length === 0 || targets.length > 10) return null;
const kb = Keyboard.builder().inline().oneTime();
for (const uid of targets) {
kb.textButton({
label: String(uid),
color: Keyboard.PRIMARY_COLOR,
payload: { action, chatId, target: uid },
});
}
return kb.build();
}
async _startGame(game, peerId) {
if (game.phase !== PHASE_LOBBY) {
await this._send(peerId, "Игра уже идёт.");
return;
}
if (Object.keys(game.players).length < this.minPlayers) {
await this._send(peerId, `Нужно минимум ${this.minPlayers} игроков.`);
return;
}
this._assignRoles(game);
await this._sendRoles(game);
game.round = 1;
await this._beginNight(game);
await this._send(peerId, "🎬 Игра началась! Ночь наступает...");
}
async _beginNight(game) {
game.phase = PHASE_NIGHT;
game.phaseEnd = Date.now() + this.nightSec * 1000;
game.night = { mafiaVotes: {}, doctor: null, detective: null };
const chatPeer = game.chatId + 2000000000;
await this._send(chatPeer, "🌙 Ночь. Все засыпают...");
const alive = this._listPlayers(game, true);
const mafiaIds = alive.filter((u) => this._player(game, u).role === ROLE_MAFIA);
const targetable = alive.filter((u) => this._player(game, u).role !== ROLE_MAFIA);
for (const uid of mafiaIds) {
const kb = this._buildTargetsKeyboard(targetable, "kill", game.chatId);
if (kb) await this._send(uid, "Выберите жертву:", kb);
else await this._send(uid, "Выберите жертву: kill ID");
}
for (const uid of alive) {
const role = this._player(game, uid).role;
if (role === ROLE_DOCTOR) {
const kb = this._buildTargetsKeyboard(alive, "heal", game.chatId);
await this._send(uid, kb ? "Кого лечить?" : "Кого лечить? heal ID", kb);
}
if (role === ROLE_DETECTIVE) {
const kb = this._buildTargetsKeyboard(alive, "check", game.chatId);
await this._send(uid, kb ? "Кого проверить?" : "Кого проверить? check ID", kb);
}
}
}
async _resolveNight(game) {
const alive = this._listPlayers(game, true);
const mafiaVotes = game.night.mafiaVotes || {};
const doctorTarget = game.night.doctor;
const detectiveTarget = game.night.detective;
let killTarget = null;
const entries = Object.entries(mafiaVotes);
if (entries.length > 0) {
const maxVotes = Math.max(...entries.map(([, v]) => v));
const top = entries.filter(([, v]) => v === maxVotes).map(([u]) => Number(u));
killTarget = top[Math.floor(Math.random() * top.length)];
}
let killed = null;
if (killTarget && alive.includes(killTarget) && killTarget !== doctorTarget) {
this._player(game, killTarget).alive = false;
killed = killTarget;
}
if (detectiveTarget && alive.includes(detectiveTarget)) {
const role = this._player(game, detectiveTarget).role;
const msg = role === ROLE_MAFIA ? "🔎 Проверка: МАФИЯ" : "🔎 Проверка: НЕ мафия";
const detId = alive.find((u) => this._player(game, u).role === ROLE_DETECTIVE);
if (detId) await this._send(detId, msg);
}
const chatPeer = game.chatId + 2000000000;
if (killed) await this._send(chatPeer, `☀️ Утро. Ночью был убит: ${await this._mention(killed)}`);
else await this._send(chatPeer, "☀️ Утро. Ночь прошла без жертв.");
if (await this._checkWin(game)) return;
game.phase = PHASE_DAY;
game.phaseEnd = Date.now() + this.daySec * 1000;
game.dayVotes = {};
await this._send(chatPeer, "🗣 День. Обсуждаем. Скоро голосование.");
}
async _beginVote(game) {
game.phase = PHASE_VOTE;
game.phaseEnd = Date.now() + this.voteSec * 1000;
game.dayVotes = {};
const chatPeer = game.chatId + 2000000000;
const alive = this._listPlayers(game, true);
const names = await Promise.all(alive.map((u) => this._mention(u)));
await this._send(chatPeer, "🗳 Голосование! Кого линчуем?\n" + names.join("\n"));
const kb = this._buildTargetsKeyboard(alive, "vote", game.chatId);
if (kb) await this._send(chatPeer, "Выберите голос кнопкой:", kb);
else await this._send(chatPeer, "Напишите: vote ID");
}
async _resolveVote(game) {
const votes = game.dayVotes || {};
const alive = this._listPlayers(game, true);
const counted = {};
for (const [voter, target] of Object.entries(votes)) {
if (!alive.includes(Number(voter))) continue;
if (!alive.includes(target)) continue;
counted[target] = (counted[target] || 0) + 1;
}
const chatPeer = game.chatId + 2000000000;
const entries = Object.entries(counted);
if (entries.length === 0) {
await this._send(chatPeer, "Никого не линчуем.");
} else {
const maxVotes = Math.max(...entries.map(([, v]) => v));
const top = entries.filter(([, v]) => v === maxVotes).map(([u]) => Number(u));
const lynched = top[Math.floor(Math.random() * top.length)];
this._player(game, lynched).alive = false;
await this._send(chatPeer, `⚖️ Линчевали: ${await this._mention(lynched)}`);
}
if (await this._checkWin(game)) return;
game.round += 1;
await this._beginNight(game);
}
async _checkWin(game) {
const alive = this._listPlayers(game, true);
const mafia = alive.filter((u) => this._player(game, u).role === ROLE_MAFIA);
const civ = alive.filter((u) => this._player(game, u).role !== ROLE_MAFIA);
const chatPeer = game.chatId + 2000000000;
if (mafia.length === 0) {
await this._send(chatPeer, "🏆 Победа мирных!");
game.phase = PHASE_ENDED;
game.phaseEnd = 0;
return true;
}
if (mafia.length >= civ.length) {
await this._send(chatPeer, "😈 Победа мафии!");
game.phase = PHASE_ENDED;
game.phaseEnd = 0;
return true;
}
return false;
}
async _handlePayload(peerId, userId, payload) {
const action = payload?.action;
const chatId = payload?.chatId;
if (["join", "leave", "start", "status", "stop"].includes(action)) {
if (!this._isChat(peerId)) return;
const game = this._getGame(this._peerToChatId(peerId));
if (action === "join") {
await this._addPlayer(game, userId);
await this._send(peerId, `${await this._mention(userId)} в игре!`);
} else if (action === "leave") {
if (game.phase === PHASE_LOBBY) {
this._removePlayer(game, userId);
await this._send(peerId, `${await this._mention(userId)} вышел.`);
} else {
this._player(game, userId).alive = false;
await this._send(peerId, `${await this._mention(userId)} покинул игру и считается мёртвым.`);
await this._checkWin(game);
}
} else if (action === "start") {
await this._startGame(game, peerId);
} else if (action === "status") {
await this._send(peerId, await this._statusText(game), this._buildLobbyKeyboard());
} else if (action === "stop") {
if (this.adminId && userId !== this.adminId) {
await this._send(peerId, "Только админ может стопнуть игру.");
} else {
game.phase = PHASE_ENDED;
game.phaseEnd = 0;
await this._send(peerId, "🛑 Игра остановлена.");
}
}
return;
}
if (["kill", "heal", "check", "vote"].includes(action)) {
if (!chatId) return;
const game = this._getGame(Number(chatId));
const target = payload?.target;
if (target == null) return;
await this._handleAction(game, userId, action, Number(target));
}
}
async _handleAction(game, userId, action, target) {
const player = this._player(game, userId);
if (!player || !player.alive) return;
if (game.phase === PHASE_NIGHT) {
if (action === "kill" && player.role === ROLE_MAFIA) {
game.night.mafiaVotes[String(target)] = (game.night.mafiaVotes[String(target)] || 0) + 1;
await this._send(userId, "✅ Голос за убийство принят.");
} else if (action === "heal" && player.role === ROLE_DOCTOR) {
game.night.doctor = target;
await this._send(userId, "✅ Лечение принято.");
} else if (action === "check" && player.role === ROLE_DETECTIVE) {
game.night.detective = target;
await this._send(userId, "✅ Проверка принята.");
}
} else if (game.phase === PHASE_VOTE && action === "vote") {
if (!this._player(game, target) || !this._player(game, target).alive) return;
game.dayVotes[String(userId)] = target;
const chatPeer = game.chatId + 2000000000;
await this._send(chatPeer, `🗳 ${await this._mention(userId)} голосует.`);
}
}
async _handleTextAction(peerId, userId, text) {
const parts = text.trim().split(/\s+/);
if (parts.length !== 2) return;
const cmd = parts[0].toLowerCase();
const targetStr = parts[1];
if (!/^\d+$/.test(targetStr)) return;
const target = Number(targetStr);
if (!["kill", "heal", "check", "vote"].includes(cmd)) return;
let chatId = null;
if (this._isChat(peerId)) chatId = this._peerToChatId(peerId);
else {
for (const g of this.games.values()) {
if (g.players[String(userId)]) {
chatId = g.chatId;
break;
}
}
}
if (!chatId) return;
const game = this._getGame(chatId);
await this._handleAction(game, userId, cmd, target);
}
async _statusText(game) {
const players = [];
for (const uid of this._listPlayers(game)) {
const p = this._player(game, uid);
const status = p.alive ? "✅" : "💀";
players.push(`${status} ${await this._mention(uid)}`);
}
const phaseMap = {
[PHASE_LOBBY]: "лобби",
[PHASE_NIGHT]: "ночь",
[PHASE_DAY]: "день",
[PHASE_VOTE]: "голосование",
[PHASE_ENDED]: "завершена",
};
return `🎮 Мафия\nФаза: ${phaseMap[game.phase] || game.phase}\nРаунд: ${game.round}\n\nИгроки (${Object.keys(game.players).length}):\n${players.join("\n")}`;
}
async _tick() {
const now = Date.now();
for (const game of this.games.values()) {
if (!game.phaseEnd || now < game.phaseEnd) continue;
if (game.phase === PHASE_NIGHT) await this._resolveNight(game);
else if (game.phase === PHASE_DAY) await this._beginVote(game);
else if (game.phase === PHASE_VOTE) await this._resolveVote(game);
}
}
async handleMessage(ctx) {
const peerId = ctx.peerId;
const userId = ctx.senderId;
const text = (ctx.text || "").trim();
if (ctx.messagePayload) {
await this._handlePayload(peerId, userId, ctx.messagePayload);
return;
}
const t = text.toLowerCase();
if (this._isChat(peerId)) {
const game = this._getGame(this._peerToChatId(peerId));
if (["/mafia", "мафия", "игра"].includes(t)) {
await this._send(peerId, await this._statusText(game), this._buildLobbyKeyboard());
return;
}
if (["/help", "помощь"].includes(t)) {
await this._send(peerId, "Команды: мафия, войти, выйти, старт, статус, стоп");
return;
}
if (["войти", "join"].includes(t)) {
await this._addPlayer(game, userId);
await this._send(peerId, `${await this._mention(userId)} в игре!`);
return;
}
if (["выйти", "leave"].includes(t)) {
if (game.phase === PHASE_LOBBY) {
this._removePlayer(game, userId);
await this._send(peerId, `${await this._mention(userId)} вышел.`);
} else {
this._player(game, userId).alive = false;
await this._send(peerId, `${await this._mention(userId)} покинул игру и считается мёртвым.`);
await this._checkWin(game);
}
return;
}
if (["старт", "start"].includes(t)) {
await this._startGame(game, peerId);
return;
}
if (["статус", "status"].includes(t)) {
await this._send(peerId, await this._statusText(game), this._buildLobbyKeyboard());
return;
}
if (["стоп", "stop"].includes(t)) {
if (this.adminId && userId !== this.adminId) {
await this._send(peerId, "Только админ может стопнуть игру.");
} else {
game.phase = PHASE_ENDED;
game.phaseEnd = 0;
await this._send(peerId, "🛑 Игра остановлена.");
}
return;
}
}
await this._handleTextAction(peerId, userId, t);
}
}
module.exports = { MafiaModule };