SPP bot world as of 2026-08-26: merged state of all Cowork sessions (brain, combat data, chat seams 2.0, idiolect, heard/context, headless players, name generator, crests, seeds)
This commit is contained in:
+245
@@ -0,0 +1,245 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>NickGen — генератор ников</title>
|
||||
<style>
|
||||
body { background:#16181d; color:#d6d8de; font:14px/1.5 Consolas, monospace; margin:0; padding:24px; }
|
||||
h1 { font-size:18px; margin:0 0 16px; color:#e8c65a; }
|
||||
.controls { display:flex; flex-wrap:wrap; gap:16px; align-items:center; margin-bottom:16px;
|
||||
background:#1e2128; border:1px solid #2c3038; border-radius:6px; padding:12px 16px; }
|
||||
.controls label { display:flex; align-items:center; gap:6px; cursor:pointer; white-space:nowrap; }
|
||||
.controls input[type=number] { width:56px; background:#111318; color:#d6d8de; border:1px solid #3a3f48; border-radius:4px; padding:3px 6px; font:inherit; }
|
||||
button { background:#e8c65a; color:#16181d; border:0; border-radius:4px; padding:6px 18px; font:bold 14px Consolas, monospace; cursor:pointer; }
|
||||
button:hover { background:#f5d878; }
|
||||
button.sec { background:#2c3038; color:#d6d8de; }
|
||||
button.sec:hover { background:#3a3f48; }
|
||||
#grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(180px,1fr)); gap:6px; }
|
||||
.nick { background:#1e2128; border:1px solid #2c3038; border-radius:4px; padding:6px 10px; cursor:pointer; }
|
||||
.nick:hover { border-color:#e8c65a; }
|
||||
.nick small { color:#6b7280; float:right; }
|
||||
#status { color:#6b7280; margin:10px 0; min-height:1.5em; }
|
||||
.weights { display:flex; gap:8px; align-items:center; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>NickGen — генератор ников для ботов</h1>
|
||||
|
||||
<div class="controls">
|
||||
<label>Кол-во <input type="number" id="count" value="60" min="1" max="5000"></label>
|
||||
<div class="weights">Части 1/2/3:
|
||||
<input type="number" id="w1" value="25" min="0"><input type="number" id="w2" value="55" min="0"><input type="number" id="w3" value="20" min="0">
|
||||
</div>
|
||||
<label><input type="checkbox" id="optTranslit" checked> транслит</label>
|
||||
<label><input type="checkbox" id="optFakeCyr" checked> псевдокириллица</label>
|
||||
<label><input type="checkbox" id="optLeet" checked> l33t-цифры</label>
|
||||
<label><input type="checkbox" id="optDigits" checked> цифровой суффикс</label>
|
||||
<label><input type="checkbox" id="optWrap" checked> xX…Xx</label>
|
||||
<button id="go">Генерировать</button>
|
||||
<button id="copyAll" class="sec">Скопировать все</button>
|
||||
</div>
|
||||
|
||||
<div id="status"></div>
|
||||
<div id="grid"></div>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
// ============================================================================
|
||||
// Вся логика ниже — самодостаточная и переносимая в Java как есть:
|
||||
// пулы (массивы строк), карты (switch/Map), генерация (Random).
|
||||
// ============================================================================
|
||||
|
||||
// --- Пулы слов (русские — в кириллице, рендер решает транслит/псевдокириллицу) ---
|
||||
const RU_ADJ = ['злой','добрый','старый','дикий','мелкий','жирный','хитрый','бешеный','мамкин','просто','лысый','грозный','тихий','сонный','голодный','кривой','ржавый','бодрый','унылый','модный','четкий','дерзкий','борзый','лютый','шустрый','реальный','угарный','наглый'];
|
||||
const RU_NOUN = ['гном','пес','кот','волк','сухарь','травка','пельмень','колбаса','мармелад','чума','ведьмак','сквозняк','холодок','бомж','топор','кабан','хомяк','огурец','батон','чеснок','валенок','тапок','кефир','компот','барсук','ежик','мухомор','лопата','кирпич','шашлык','беляш','танкист','дед','сосед','медоед','каратель','монах','гопник','чебурек','шаурма','семки','пацан','браток','кент','батя','гараж','подъезд','чушпан','задрот','нуб','читер','красавчик','нагибатор','убиватор','терминатор'];
|
||||
const RU_NAME = ['олег','вася','дашка','ленка','федор','санек','толик','серега','витек','петруха','колян','димон','настя','машка','гриша','степан','юрец','макс','жека','вован','толян','саня','диман','леха','андрюха','кирюха','паша','стас','руслан','тимур','натаха','светка','танюха','ирка','вовчик','петрович','палыч'];
|
||||
const RU_SURNAME = ['пупкин','сидоров','петров','иванов','смирнов','кузнецов','козлов','волков','зайцев','медведев'];
|
||||
const PREFIXES = ['MC','Dj','Mr'];
|
||||
const EN_ADJ = ['Dark','Shadow','Storm','Night','Blood','Ghost','Crazy','Old','Swift','Silent','Grim','Mad','Evil','Frost','Iron','Black','Wild','Lone','Sweet','True'];
|
||||
const EN_NOUN = ['Slayer','Reaper','Hunter','Killer','Knight','Rogue','Monk','Rider','Arrow','Blade','Master','Lord','King','Sniper','Mage','Angel','Demon','Raven','Wolf','Dragon','Fire','Ice','Death','Star','Dream','Soul','Fang','Claw','Bishop','Titan'];
|
||||
|
||||
// --- Транслит: кириллица -> латиница ---
|
||||
const TRANSLIT = { 'а':'a','б':'b','в':'v','г':'g','д':'d','е':'e','ё':'e','ж':'zh','з':'z','и':'i','й':'j','к':'k','л':'l','м':'m','н':'n','о':'o','п':'p','р':'r','с':'s','т':'t','у':'u','ф':'f','х':'h','ц':'c','ч':'ch','ш':'sh','щ':'sch','ъ':'','ы':'y','ь':'','э':'e','ю':'yu','я':'ya' };
|
||||
|
||||
// --- Псевдокириллица: латинские символы, похожие на кириллицу (KpucuK, TpaBka, IIeJIbMeHb) ---
|
||||
// null = нет похожего, берём транслит этой буквы.
|
||||
const FAKE_CYR = { 'а':'a','б':'6','в':'B','г':'r','д':null,'е':'e','ё':'e','ж':null,'з':'3','и':'u','й':'u','к':'K','л':'JI','м':'M','н':'H','о':'o','п':'II','р':'p','с':'c','т':'T','у':'y','ф':null,'х':'x','ц':null,'ч':'4','ш':'LLI','щ':null,'ъ':'','ы':'bI','ь':'b','э':'3','ю':'IO','я':'9I' };
|
||||
|
||||
// --- l33t для латинских слов (Ki4iga, OlegBI4) ---
|
||||
const LEET = { 'e':'3','o':'0','a':'4','i':'1','s':'5' };
|
||||
|
||||
const rnd = (n) => Math.floor(Math.random() * n);
|
||||
const pick = (arr) => arr[rnd(arr.length)];
|
||||
const chance = (pct) => rnd(100) < pct;
|
||||
|
||||
// Транслит слова, с вариативностью окончаний (zloj/zloy)
|
||||
function translitWord(w) {
|
||||
let out = '';
|
||||
for (const ch of w) {
|
||||
let t = TRANSLIT[ch] ?? ch;
|
||||
if (ch === 'й' && chance(50)) t = 'y';
|
||||
if (ch === 'в' && chance(15)) t = 'w'; // Wowan-стиль
|
||||
if (ch === 'х') t = chance(40) ? 'x' : (chance(30) ? 'kh' : 'h'); // Xyligan-стиль
|
||||
out += t;
|
||||
}
|
||||
return out.charAt(0).toUpperCase() + out.slice(1);
|
||||
}
|
||||
|
||||
// Псевдокириллица слова
|
||||
function fakeCyrWord(w) {
|
||||
let out = '';
|
||||
for (const ch of w) {
|
||||
const f = FAKE_CYR[ch];
|
||||
out += (f !== null && f !== undefined) ? f : (TRANSLIT[ch] ?? ch);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// l33t: до 2 замен на слово, каждая с шансом 45%
|
||||
function leetWord(w) {
|
||||
let out = '', used = 0;
|
||||
for (const ch of w) {
|
||||
const l = LEET[ch.toLowerCase()];
|
||||
if (l && used < 2 && chance(45)) { out += l; used++; }
|
||||
else out += ch;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// --- Сборка частей: язык + число частей -> массив пар [слово, isSurname] ---
|
||||
function buildParts(lang, n) {
|
||||
const w = (x) => [x, false], s = (x) => [x, true];
|
||||
if (lang === 'ru') {
|
||||
if (n === 1) {
|
||||
const v = rnd(100);
|
||||
if (v < 45) return [w(pick(RU_NOUN))];
|
||||
if (v < 80) return [w(pick(RU_NAME))];
|
||||
return [s(pick(RU_SURNAME))];
|
||||
}
|
||||
if (n === 2) {
|
||||
const v = rnd(4);
|
||||
if (v === 0) return [w(pick(RU_ADJ)), w(pick(RU_NOUN))];
|
||||
if (v === 1) return [w(pick(RU_ADJ)), w(pick(RU_NAME))];
|
||||
if (v === 2) return [w(pick(RU_NOUN)), w(pick(RU_NOUN))];
|
||||
return [w(pick(RU_NAME)), s(pick(RU_SURNAME))]; // VasyaPupkin
|
||||
}
|
||||
if (chance(50)) return [w(pick(RU_ADJ)), w(pick(RU_NOUN)), w(pick(RU_NOUN))];
|
||||
return [w(pick(RU_ADJ)), w(pick(RU_NAME)), s(pick(RU_SURNAME))];
|
||||
}
|
||||
if (n === 1) return [w(pick(EN_NOUN))];
|
||||
if (n === 2) return [w(pick(EN_ADJ)), w(pick(EN_NOUN))];
|
||||
const first = pick(EN_ADJ);
|
||||
const second = chance(50) ? pick(EN_ADJ.filter(x => x !== first)) : pick(EN_NOUN);
|
||||
return [w(first), w(second), w(pick(EN_NOUN))];
|
||||
}
|
||||
|
||||
const isRu = (w) => /[а-яё]/.test(w);
|
||||
|
||||
// --- Один ник. opts: {translit, fakeCyr, leet, digits, wrap, weights:[w1,w2,w3]} ---
|
||||
function generateOne(opts) {
|
||||
// число частей по весам
|
||||
const total = opts.weights[0] + opts.weights[1] + opts.weights[2];
|
||||
let roll = rnd(Math.max(total, 1)), n = 3;
|
||||
if (roll < opts.weights[0]) n = 1;
|
||||
else if (roll < opts.weights[0] + opts.weights[1]) n = 2;
|
||||
|
||||
const lang = chance(70) ? 'ru' : 'en';
|
||||
const parts = buildParts(lang, n);
|
||||
// редкая смесь языков в 2-3-частных никах
|
||||
if (n > 1 && chance(15)) parts[parts.length - 1] = (lang === 'ru') ? [pick(EN_NOUN), false] : [translitWord(pick(RU_NOUN)), false];
|
||||
|
||||
// режим рендера русских слов — один на весь ник
|
||||
const modes = [];
|
||||
if (opts.translit) modes.push('translit');
|
||||
if (opts.fakeCyr) modes.push('fakeCyr');
|
||||
const ruMode = modes.length ? pick(modes) : 'translit';
|
||||
|
||||
let nick = parts.map(([w, isSurname]) => {
|
||||
if (isRu(w)) {
|
||||
if (ruMode === 'fakeCyr') return fakeCyrWord(w);
|
||||
let t = translitWord(w);
|
||||
// фамилии на -ov: SmirnOFF / Smirnoff
|
||||
if (isSurname && t.toLowerCase().endsWith('ov') && chance(50)) t = t.slice(0, -2) + (chance(40) ? 'OFF' : 'off');
|
||||
return t;
|
||||
}
|
||||
return (opts.leet && chance(20)) ? leetWord(w) : w;
|
||||
}).join('');
|
||||
|
||||
// декорации (стиль сида: dashka, ZloyPES, HolodOK, OldRogue38, MCVovan95, xXDarkSlayerXx)
|
||||
if (ruMode === 'translit') {
|
||||
if (chance(12)) nick = nick.toLowerCase(); // dashka
|
||||
else if (chance(12) && nick.length > 4) { // ZloyPES / HolodOK
|
||||
const k = 2 + rnd(2);
|
||||
nick = nick.slice(0, -k) + nick.slice(-k).toUpperCase();
|
||||
}
|
||||
}
|
||||
if (opts.digits && chance(28) && nick.length <= 14) {
|
||||
const v = rnd(100);
|
||||
let suf;
|
||||
if (v < 45) suf = chance(50) ? String(1 + rnd(9)) : String(10 + rnd(90)); // OlegBI4-стиль
|
||||
else if (v < 80) suf = String((85 + rnd(23)) % 100).padStart(2, '0'); // год рождения 85..07
|
||||
else suf = String(1985 + rnd(23)); // 1985..2007
|
||||
if (nick.length + suf.length <= 16) nick += suf;
|
||||
}
|
||||
if (chance(4) && nick.length <= 13) nick += 'RUS';
|
||||
let prefixed = false;
|
||||
if (chance(6) && nick.length <= 14) { nick = pick(PREFIXES) + nick; prefixed = true; } // MCVovan
|
||||
if (opts.wrap && !prefixed && chance(4) && nick.length <= 12) nick = 'xX' + nick + 'Xx';
|
||||
return nick;
|
||||
}
|
||||
|
||||
// Валидный для клиента L2: [A-Za-z0-9], 3-16 символов
|
||||
const VALID = /^[A-Za-z0-9]{3,16}$/;
|
||||
|
||||
function generateBatch(count, opts, taken) {
|
||||
const out = [];
|
||||
let guard = count * 50;
|
||||
while (out.length < count && guard-- > 0) {
|
||||
const nick = generateOne(opts);
|
||||
if (VALID.test(nick) && !taken.has(nick.toLowerCase())) {
|
||||
taken.add(nick.toLowerCase());
|
||||
out.push(nick);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// UI
|
||||
// ============================================================================
|
||||
const $ = (id) => document.getElementById(id);
|
||||
let current = [];
|
||||
|
||||
function run() {
|
||||
const opts = {
|
||||
translit: $('optTranslit').checked,
|
||||
fakeCyr: $('optFakeCyr').checked,
|
||||
leet: $('optLeet').checked,
|
||||
digits: $('optDigits').checked,
|
||||
wrap: $('optWrap').checked,
|
||||
weights: [+$('w1').value || 0, +$('w2').value || 0, +$('w3').value || 0],
|
||||
};
|
||||
const count = Math.min(+$('count').value || 60, 5000);
|
||||
current = generateBatch(count, opts, new Set());
|
||||
const grid = $('grid');
|
||||
grid.innerHTML = '';
|
||||
for (const nick of current) {
|
||||
const d = document.createElement('div');
|
||||
d.className = 'nick';
|
||||
d.innerHTML = nick + ' <small>' + nick.length + '</small>';
|
||||
d.title = 'Кликни — скопировать';
|
||||
d.onclick = () => { navigator.clipboard.writeText(nick); $('status').textContent = 'Скопировано: ' + nick; };
|
||||
grid.appendChild(d);
|
||||
}
|
||||
$('status').textContent = 'Сгенерировано: ' + current.length + ' (уникальные, ≤16 символов, [A-Za-z0-9])';
|
||||
}
|
||||
|
||||
$('go').onclick = run;
|
||||
$('copyAll').onclick = () => {
|
||||
navigator.clipboard.writeText(current.join('\n'));
|
||||
$('status').textContent = 'Скопировано в буфер: ' + current.length + ' ников';
|
||||
};
|
||||
run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user