Глупые статусы, окно настроек
This commit is contained in:
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
declare module "*.html" {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<button class="april-fools__button">🎉</button>
|
||||
@@ -0,0 +1,66 @@
|
||||
<style class="april-fools__styles">
|
||||
.april-fools__button {
|
||||
position: fixed;
|
||||
bottom: 0.2rem;
|
||||
right: 0.2rem;
|
||||
padding: 0;
|
||||
font-size: 3rem;
|
||||
border: 0 solid;
|
||||
background: transparent none;
|
||||
opacity: 0.3;
|
||||
transition: 0.4s all;
|
||||
cursor: pointer;
|
||||
}
|
||||
.april-fools__button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.april-fools__joke-row {
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
.april-fools__joke-row:first-of-type {
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
.april-fools__joke {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
padding: 10px;
|
||||
opacity: 0.5;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1ch;
|
||||
cursor: pointer;
|
||||
}
|
||||
.april-fools__joke:hover {
|
||||
text-shadow: 0 0 black;
|
||||
}
|
||||
.april-fools__joke:before {
|
||||
display: block;
|
||||
content: "";
|
||||
flex: 0 0 2ch;
|
||||
text-align: center;
|
||||
content: "✔";
|
||||
opacity: 0;
|
||||
}
|
||||
input.april-fools__joke-input:checked + .april-fools__joke {
|
||||
opacity: 1;
|
||||
}
|
||||
input.april-fools__joke-input:checked + .april-fools__joke:before {
|
||||
opacity: 1;
|
||||
}
|
||||
.april-fools__joke .april-fools__joke-title {
|
||||
flex: 1 auto;
|
||||
font-weight: bold;
|
||||
}
|
||||
.april-fools__joke .april-fools__joke-description {
|
||||
flex: 1 auto;
|
||||
text-align: right;
|
||||
}
|
||||
.april-fools__joke .april-fools__joke-chance {
|
||||
flex: 0 0 4ch;
|
||||
text-align: right;
|
||||
}
|
||||
.april-fools__content .april-fools__reset-button {
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="april-fools__content">
|
||||
<div class="april-fools__jokes"></div>
|
||||
|
||||
<button class="april-fools__reset-button">Вернуться к настройкам форума (страница будет перезагружена!)</button>
|
||||
</div>
|
||||
<template class="april-fools__template" id="april-fools__window-row">
|
||||
<div class="april-fools__joke-row">
|
||||
<input type="checkbox" class="april-fools__joke-input" name="april-fools__joke-${joke.id}" id="april-fools__joke-${joke.id}" style="display: none;" />
|
||||
<label class="april-fools__joke" for="april-fools__joke-${joke.id}">
|
||||
<p class="april-fools__joke-title">${joke.title}</p>
|
||||
<p class="april-fools__joke-description">${joke.description}</p>
|
||||
<p class="april-fools__joke-chance">${joke.settings.chance}%</p>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
+10
@@ -22,6 +22,16 @@ export abstract class Joke {
|
||||
*/
|
||||
abstract id: string;
|
||||
|
||||
/**
|
||||
* Заголовок шутки
|
||||
*/
|
||||
abstract title: string;
|
||||
|
||||
/**
|
||||
* Описание шутки
|
||||
*/
|
||||
abstract description: string;
|
||||
|
||||
/**
|
||||
* Настройки шутки
|
||||
*/
|
||||
|
||||
+103
-5
@@ -1,4 +1,6 @@
|
||||
import { Joke, JokeSettings } from "./joke";
|
||||
import { stat } from "fs";
|
||||
import { Joke, JokeSettings, StopableJoke } from "./joke";
|
||||
import { JokerUI } from "./ui";
|
||||
|
||||
/**
|
||||
* Блок обработки перво-апрельских шуток
|
||||
@@ -6,6 +8,8 @@ import { Joke, JokeSettings } from "./joke";
|
||||
* @author Kozhilya
|
||||
*/
|
||||
export class JokerClass {
|
||||
ui: JokerUI = new JokerUI(this);
|
||||
|
||||
/**
|
||||
* Проверка вероятности
|
||||
*
|
||||
@@ -32,10 +36,14 @@ export class JokerClass {
|
||||
* @param handler Метод, выполняющий шутку
|
||||
* @param settings Объект настроек шутки
|
||||
*/
|
||||
addCustom(id: string, handler: Function, settings: JokeSettings|null = null) {
|
||||
addCustom(id: string, handler: Function, settings: JokeSettings|null = null): Joke {
|
||||
const joke = new class extends Joke {
|
||||
id = id;
|
||||
|
||||
title = 'Пользовательская шутка';
|
||||
|
||||
description = 'Для шутки не определено описание';
|
||||
|
||||
settings: JokeSettings = { chance: 10, enabled: true };
|
||||
|
||||
start() {
|
||||
@@ -46,6 +54,8 @@ export class JokerClass {
|
||||
Object.assign(joke.settings, settings ?? {});
|
||||
|
||||
this.add(joke);
|
||||
|
||||
return joke;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,6 +123,74 @@ export class JokerClass {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Переключение шутки
|
||||
*/
|
||||
toggleJoke(joke_id: string, state: boolean) {
|
||||
const joke = this.jokes[joke_id];
|
||||
joke.settings.enabled = state;
|
||||
|
||||
if (joke instanceof StopableJoke && !state) {
|
||||
joke.stop();
|
||||
}
|
||||
|
||||
this.saveUserStates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Сохранение пользовательских настроек
|
||||
*/
|
||||
saveUserStates() {
|
||||
const states: any = {};
|
||||
|
||||
for (const key of Object.keys(this.jokes)) {
|
||||
states[key] = this.jokes[key].settings.enabled;
|
||||
}
|
||||
|
||||
fetch('/api.php?' + $.param({
|
||||
method: 'storage.set',
|
||||
user_id: (<any> window).UserID,
|
||||
key: 'april-fools',
|
||||
token: (<any> window).ForumAPITicket,
|
||||
value: JSON.stringify(states),
|
||||
timer: 24 * 60
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Загрузка пользовательских настроек
|
||||
*/
|
||||
async loadUserStates() {
|
||||
const response = await fetch('/api.php?' + $.param({
|
||||
method: 'storage.get',
|
||||
user_id: (<any> window).UserID,
|
||||
key: 'april-fools',
|
||||
}));
|
||||
const json = await response.json();
|
||||
|
||||
if (json.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = JSON.parse(json.response.storage.data['april-fools']);
|
||||
|
||||
for (const key of Object.keys(this.jokes)) {
|
||||
this.jokes[key].settings.enabled = data[key];
|
||||
}
|
||||
}
|
||||
|
||||
async clearUserStates() {
|
||||
await fetch('/api.php?' + $.param({
|
||||
method: 'storage.delete',
|
||||
user_id: (<any> window).UserID,
|
||||
key: 'april-fools',
|
||||
token: (<any> window).ForumAPITicket,
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Запуск шутки
|
||||
*
|
||||
@@ -141,15 +219,33 @@ export class JokerClass {
|
||||
}
|
||||
}
|
||||
|
||||
regularStart(): void {
|
||||
regularCheck(): boolean {
|
||||
if (!this.core_settings.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.core_settings.testers.indexOf((<any> window).UserID) >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const today = new Date();
|
||||
const month = today.getMonth() + 1; // Note that getMonth() returns 0-indexed month, so we need to add 1
|
||||
const month = today.getMonth() + 1;
|
||||
const day = today.getDate();
|
||||
|
||||
if (month !== 4 || day !== 1 || !this.core_settings.enabled || !this.check(this.core_settings.chance)) {
|
||||
if (month !== 4 || day !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.check(this.core_settings.chance);
|
||||
}
|
||||
|
||||
async regularStart() {
|
||||
if (!this.regularCheck()) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.loadUserStates();
|
||||
this.ui.show();
|
||||
this.startAll();
|
||||
}
|
||||
|
||||
@@ -181,4 +277,6 @@ interface SettingsMap {
|
||||
class CoreSettings implements JokeSettings {
|
||||
chance = 100;
|
||||
enabled = true;
|
||||
|
||||
testers: number[] = [];
|
||||
}
|
||||
@@ -10,7 +10,11 @@ import { JokerClass } from "../joker";
|
||||
* @author Kozhilya
|
||||
*/
|
||||
export class CarnivalJoke extends Joke {
|
||||
id = 'carnival'
|
||||
id = 'carnival';
|
||||
|
||||
title = 'Карнавал';
|
||||
|
||||
description = 'Аватарки приобретают интересные цвета';
|
||||
|
||||
settings = new CarnivalJokeSettings;
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ import $ from "jquery";
|
||||
export class CrazyLettersJoke extends Joke {
|
||||
id = 'crazy_letters';
|
||||
|
||||
title = 'Мама, Я сОшЛа С уМа!';
|
||||
|
||||
description = 'иМеНа ЗаБоРчИкОм';
|
||||
|
||||
settings = new CrazyLettersJokeSettings;
|
||||
|
||||
start(): void {
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import { Joke, JokeSettings, StopableJoke } from "../joke";
|
||||
import $ from "jquery";
|
||||
|
||||
/**
|
||||
* **Бешеные запятые**
|
||||
*
|
||||
* Запятые после слов
|
||||
*
|
||||
* @author Kozhilya
|
||||
*/
|
||||
export class CrazyPunctuationJoke extends Joke {
|
||||
id = 'crazy_punctuation';
|
||||
|
||||
settings = new CrazyPunctuationJokeSettings;
|
||||
|
||||
punctuationSymbols: string[]|null = null;
|
||||
|
||||
private shufflePunctuation(text: string): string {
|
||||
if (this.punctuationSymbols === null) {
|
||||
this.punctuationSymbols = this.settings.symbols.split('');
|
||||
}
|
||||
const words = text.split(" ");
|
||||
|
||||
const shuffledWords = words.map(word => {
|
||||
const characters = word.split("");
|
||||
|
||||
// Filter out any non-punctuation characters
|
||||
const punctuation = characters.filter(char => this.punctuationSymbols.includes(char));
|
||||
|
||||
// Shuffle the punctuation array
|
||||
const shuffledPunctuation = punctuation.sort(() => Math.random() - 0.5);
|
||||
|
||||
// Loop through each character in the word and replace punctuation with shuffled punctuation
|
||||
let index = 0;
|
||||
return characters.map(char => {
|
||||
if (this.punctuationSymbols.includes(char)) {
|
||||
return shuffledPunctuation[index++];
|
||||
}
|
||||
return char;
|
||||
}).join("");
|
||||
});
|
||||
|
||||
// Join the shuffled words array into a single string with spaces
|
||||
return shuffledWords.join(" ");
|
||||
}
|
||||
|
||||
start(): void {
|
||||
const items = $(this.settings.selector).find('*').contents().filter((_, node) => node.nodeType === Node.TEXT_NODE);
|
||||
|
||||
items.each((_, node) => {
|
||||
node.textContent = this.shufflePunctuation(node.textContent);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export class CrazyPunctuationJokeSettings implements JokeSettings {
|
||||
enabled: boolean = true;
|
||||
|
||||
chance: number = 20;
|
||||
|
||||
/**
|
||||
* Селектор всех элементов, которые будут затронуты
|
||||
*/
|
||||
selector: string = '.post-content p';
|
||||
|
||||
/**
|
||||
* Мигрирующие знаки
|
||||
*/
|
||||
symbols: string = ',.;:?!-()[]{}\'"';
|
||||
|
||||
|
||||
}
|
||||
+5
-1
@@ -15,6 +15,10 @@ const cursor_effects = require("cursor-effects");
|
||||
export class CursorEffectsJoke extends StopableJoke {
|
||||
id = 'cursor_effects';
|
||||
|
||||
title = 'Красивый курсор';
|
||||
|
||||
description = 'Эффекты, следующие за курсором';
|
||||
|
||||
settings = new CursorEffectsJokeSettings;
|
||||
|
||||
active_cursor_effect: any;
|
||||
@@ -43,7 +47,7 @@ export class CursorEffectsJoke extends StopableJoke {
|
||||
}
|
||||
|
||||
getRandomEffect(): CursorEffectsEnum {
|
||||
const elements = Object.keys(CursorEffectsEnum).map(e => <CursorEffectsEnum>e);
|
||||
const elements = Object.values(CursorEffectsEnum).map(e => <CursorEffectsEnum>e);
|
||||
const totalWeight = elements.reduce((sum, element) => sum + this.weight(element), 0);
|
||||
const randomWeight = Math.random() * totalWeight;
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ import $ from "jquery";
|
||||
*/
|
||||
export class HumanitarianHellJoke extends Joke {
|
||||
id = 'humanitarian_hell';
|
||||
|
||||
title = 'Ад гуманитария';
|
||||
|
||||
description = 'Все "тся" заменяются на "ться", а все "ться" на "тся"';
|
||||
|
||||
settings = new HumanitarianHellJokeSettings;
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ import { JokerClass } from "../joker";
|
||||
export class LetterChaosJoke extends Joke {
|
||||
id = 'letter_chaos';
|
||||
|
||||
title = 'Буквенный хаос';
|
||||
|
||||
description = 'Все буквы в словах, кроме первой и последней, перемешены.';
|
||||
|
||||
settings = new LetterChaosJokeSettings;
|
||||
|
||||
punctuationSymbols: string[] | null = null;
|
||||
|
||||
@@ -10,6 +10,10 @@ import $ from "jquery";
|
||||
*/
|
||||
export class MirrorJoke extends Joke {
|
||||
id = 'mirror';
|
||||
|
||||
title = 'Зеркало';
|
||||
|
||||
description = 'Элементы форума отражаются (по крайней мере, пытаются)';
|
||||
|
||||
settings = new MirrorJokeSettings;
|
||||
|
||||
|
||||
+5
-1
@@ -11,6 +11,10 @@ import $ from "jquery";
|
||||
export class ShakeJoke extends StopableJoke {
|
||||
id = 'shake';
|
||||
|
||||
title = 'Форумо-трясение';
|
||||
|
||||
description = 'Страница форума начинает трястись';
|
||||
|
||||
settings = new ShakeJokeSettings;
|
||||
|
||||
private interval_id: NodeJS.Timer;
|
||||
@@ -63,7 +67,7 @@ export class ShakeJoke extends StopableJoke {
|
||||
}
|
||||
|
||||
export class ShakeJokeSettings implements JokeSettings {
|
||||
enabled: boolean = true;
|
||||
enabled: boolean = false;
|
||||
|
||||
chance: number = 1;
|
||||
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
import { Joke, JokeSettings, StopableJoke } from "../joke";
|
||||
import $ from "jquery";
|
||||
|
||||
/**
|
||||
* **Глупые статусы**
|
||||
*
|
||||
* Каждому пользователю даётся новый глупый статус.
|
||||
*
|
||||
* @author Kozhilya
|
||||
*/
|
||||
export class StupidTitleJoke extends Joke {
|
||||
id = 'stupid_title';
|
||||
|
||||
title = 'Глупые статусы';
|
||||
|
||||
description = 'Каждому пользователю даётся новый глупый статус.';
|
||||
|
||||
settings = new StupidTitleJokeSettings;
|
||||
|
||||
private loadedGenders: any = null;
|
||||
|
||||
async loadGenders(): Promise<void> {
|
||||
const names = $('.pa-author a')
|
||||
.map((_, elem) => elem.innerText).toArray()
|
||||
.reduce((arr: string[], name: string) => {
|
||||
if (arr.indexOf(name) < 0){
|
||||
arr.push(name);
|
||||
}
|
||||
return arr
|
||||
}, []);
|
||||
|
||||
const url = '/api.php?' + $.param({ method: 'users.get', fields: 'username,sex', username: names });
|
||||
const response = await fetch(url);
|
||||
const json = await response.json();
|
||||
|
||||
this.loadedGenders = {};
|
||||
|
||||
if (json.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
json.response.users.forEach((element: any) => {
|
||||
if (element.sex === '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadedGenders[element.username] = element.sex === '1';
|
||||
});
|
||||
}
|
||||
|
||||
resolveGender(name: string): boolean {
|
||||
if (this.settings.gender_resolver !== null) {
|
||||
return !!this.settings.gender_resolver.call(this, name);
|
||||
}
|
||||
|
||||
if (name in this.loadedGenders) {
|
||||
return !!this.loadedGenders[name];
|
||||
}
|
||||
|
||||
this.resetSeed();
|
||||
return this.selectRandom(name, { 'm': 1, 'f': 1 }) === 'm';
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
await this.loadGenders();
|
||||
|
||||
const cache: any = {};
|
||||
|
||||
$('.post-author').each((_, root) => {
|
||||
const name = $('.pa-author a', root).text();
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(name in cache)) {
|
||||
this.resetSeed();
|
||||
cache[name] = this.generatePhrase(name);
|
||||
}
|
||||
|
||||
$('.pa-title', root).text(cache[name]);
|
||||
});
|
||||
}
|
||||
|
||||
private prng(name: string, seed: number, limit: number): number {
|
||||
/*
|
||||
https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
|
||||
|
||||
cyrb53 (c) 2018 bryc (github.com/bryc)
|
||||
A fast and simple hash function with decent collision resistance.
|
||||
Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity.
|
||||
Public domain. Attribution appreciated.
|
||||
*/
|
||||
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < name.length; i++) {
|
||||
ch = name.charCodeAt(i);
|
||||
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||
}
|
||||
h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909);
|
||||
h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909);
|
||||
|
||||
const value = 4294967296 * (2097151 & h2) + (h1>>>0);
|
||||
|
||||
return Math.floor(Math.pow(Math.sin(value), 2) * limit) % limit;
|
||||
}
|
||||
|
||||
private seed = 0;
|
||||
|
||||
private resetSeed(): void {
|
||||
const date = new Date();
|
||||
const time = new Date().getUTCHours() * 60 + new Date().getUTCMinutes();
|
||||
this.seed = Math.floor(time / this.settings.change_frequency);
|
||||
|
||||
console.log('Seed reset:', time, this.seed);
|
||||
}
|
||||
|
||||
private selectRandom(name: string, variants: StupidTitleWeightedVariants): string {
|
||||
const elements = Object.keys(variants);
|
||||
const totalWeight = elements.reduce((sum, element) => sum + variants[element], 0);
|
||||
const randomWeight = this.prng(name, this.seed++, totalWeight);
|
||||
|
||||
let currentWeight = 0;
|
||||
for (const element of elements) {
|
||||
currentWeight += variants[element];
|
||||
if (randomWeight <= currentWeight) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Тебя быть тут не должно...");
|
||||
}
|
||||
|
||||
private buildVariants(type: string, gender: boolean): StupidTitleWeightedVariants {
|
||||
const result: StupidTitleWeightedVariants = {};
|
||||
const variants: StupidTitleVariant = this.settings.variants[type];
|
||||
|
||||
for (const iterator of Object.entries(variants)) {
|
||||
const word = iterator[0];
|
||||
const wordSettings = iterator[1];
|
||||
|
||||
if (!wordSettings.enabled || (wordSettings.gender === !gender)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.settings.rude && wordSettings.rude) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result[word] = wordSettings.weight;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private capitalizeFirst(str: string): string {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
generatePhrase(name: string): string {
|
||||
const gender = this.resolveGender(name);
|
||||
const prhase = this.selectRandom(name, this.settings.schemas);
|
||||
|
||||
return this.capitalizeFirst(prhase.replace(/\{(.+?)\}/g, (_, type: string) => {
|
||||
const variants = this.buildVariants(type, gender);
|
||||
|
||||
return this.selectRandom(name, variants);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class StupidTitleJokeSettings implements JokeSettings {
|
||||
enabled: boolean = true;
|
||||
chance: number = 100;
|
||||
|
||||
/**
|
||||
* Определение пола по имени.
|
||||
* По умолчанию род устанавливается случайным образом
|
||||
*
|
||||
* Если установлено значение `null`, система попытается загрузить пол, установленный в настройках аккаунта. Если этот пол определить невозможно, то он будет выбран случайно. Эта настройка позволяет изменить это поведение, если ваш форум обладает ролевой системой, в которой пол определяется иным образом.
|
||||
*
|
||||
* @param name Имя персонажа
|
||||
* @returns true, если мужской род; false, если женский род
|
||||
*/
|
||||
gender_resolver: Function | null = null;
|
||||
|
||||
/**
|
||||
* Разрешить возможно оскорбительные варианты
|
||||
*/
|
||||
rude: boolean = false;
|
||||
|
||||
/**
|
||||
* Частота смены статусов (в минутах)
|
||||
*/
|
||||
change_frequency: number = 5;
|
||||
|
||||
/**
|
||||
* Разрешённые схемы формирования статусов
|
||||
*
|
||||
* {adj} - прилагательное
|
||||
* {noun} - имя существительно
|
||||
* {verb} - глагол
|
||||
* {adv} - наречие
|
||||
* {place} - дополнение места
|
||||
* {p} - знак препинания
|
||||
*/
|
||||
schemas: StupidTitleWeightedVariants = {
|
||||
'{adj} {noun}{p}': 10,
|
||||
'{noun} {adj}{p}': 3,
|
||||
'{adj}, {adj} {noun}{p}': 10,
|
||||
'{adj} и очень {adj} {noun}{p}': 10,
|
||||
'{adj} {noun} {verb}{p}': 10,
|
||||
'{adj} {noun} {adv} {verb}{p}': 5,
|
||||
'{adj} {noun} {verb} {place}{p}': 5,
|
||||
'{adj} {noun} {adv} {verb} {place}{p}': 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* Вариант слов
|
||||
* Смотрите раздел описания скрипта, что бы настроить это поле
|
||||
*/
|
||||
variants: StupidTitleVariants = {
|
||||
adj: {
|
||||
...buildVariant(true, 'жесткий,^удачливый,низкий,знакомый,откровенный,^мирный,грамотный,вкусный,виртуальный,пышный,провинциальный,$жирный,заинтересованный,объективный,^оригинальный,пожилой,чистый,особенный,выгодный,громадный,обыкновенный,чужой,ударный,^солнечный,истинный,посторонний,южный,седой,$бесполезный,острый,пестрый,формальный,повседневный,невозможный,$жалкий,целый,$глупый,последний,выходной,серьезный,подземный,небесный,любимый,былой,семейный,далекий,северный,суровый,гигантский,иностранный,родной,конструктивный,показательный,нужный,чрезвычайный,гордый,банальный,открытый,независимый,запасной,мстительный,грубый,алчный,мелочный,хладнокровный,спокойный,терпеливый,креативный,активный,адекватный,застенчивый,опрятный,безнадёжный,уверенный в себе,доброжелательный,ласковый,робкий,воспитанный,самовлюблённый,деятельный,двуличный,верный'),
|
||||
...buildVariant(false, 'жесткая,^удачливая,низкая,знакомая,откровенная,^мирная,грамотная,вкусная,виртуальная,пышная,провинциальная,$жирная,заинтересованная,объективная,^оригинальная,пожилая,чистая,особенная,выгодная,громадная,обыкновенная,чужая,ударная,^солнечная,истинная,посторонняя,южная,седая,$бесполезная,острая,пестрая,формальная,повседневная,невозможная,$жалкая,целая,$глупая,последняя,выходная,серьезная,подземная,небесная,любимая,былая,семейная,далекая,северная,суровая,гигантская,иностранная,родная,конструктивная,показательная,нужная,чрезвычайная,гордая,банальная,открытая,независимая,запасная,мстительная,грубая,алчная,мелочная,хладнокровная,спокаяная,терпеливая,креативная,активная,адекватная,застенчивая,опрятная,безнадёжная,уверенная в себе,доброжелательная,ласковая,робкая,воспитанная,самовлюблённая,деятельная,двуличная,верная'),
|
||||
},
|
||||
noun: {
|
||||
...buildVariant(null, ''),
|
||||
|
||||
...buildVariant(true, 'орёл, ниндзя, манекен, пузырь, бродяга, рыцарь, кентавр, зайц, диван, наследник, сын, джентльмен, басурманин, карасик, $злоумышленник, $раб, хоббит, одиночка, отец, кролик, бруталище, дворф, актёр, %дед, спортсмен, $балбес, %мальчег, лев, ёж, организм, монах, хоббит, борец, тигр, монстр, массажист, мачо, эльф, ледник, жук, кот, зомби, проказник, дракон, носорог, волк, лесоруб, кит, %дедушка, динозавр, бард, кулак, принц, %сынок, мальчик, товарищ, ёжик, сурикат'),
|
||||
|
||||
...buildVariant(false, 'заноза, волторна, $личинка, детка, %бабушка, простуда, черепашка, мышь, волчица, деревяшка, пиранья, каруселька, красотка, леди, %дочка, орлица, принцесса, $ведьма, травка, актриса, наследница, %деффачка, горгулья, белочка, акула, машинка, конфетка, знаменитость, косточка, спортсменка, панда, мать, львица, эльфийка, $злоумышленница, чертовка, дворфиха, кошка, $рабыня, скамеечка, дочь, монашка, бактерия, рыбка, бусинка, $бабка, девочка, валькирия, килька, бабочка, милашка, крышка, тигрица, рыбка, русалочка'),
|
||||
},
|
||||
verb: {
|
||||
...buildVariant(null, 'встаёт, снимает, приказывает, указывает, собирается, чувствует опасность, орёт, болеет, поздравляет, освобождает, поздравляет, бежит, берёт и делает, молчит, радуется, прощает, читает, снимает, снимается в фильме, что-то скрывает, думает, имеет план и придерживается его, тянет, работает, меняется, ловит, отказаться куда-то идти, заходит, замирает, оформляет, нарушает, отказывается что-то делать, шепчет, снимается в сериале, скрывается, учит, спрашивает, идёт, отказывается вставать, прибывает, отказывается, забывает, получает, плывёт, отвечает, поглядывает, говорит, просыпается, соединяет, оглядывается'),
|
||||
|
||||
...buildVariant(true, 'женится, женился, успел, не успел, смог, скрылся, заработался, познал дзен, присел, обиделся, проснулся, взял и сделал, додумался, не спал'),
|
||||
|
||||
...buildVariant(false, 'выходит замуж, вышла замуж, успела, не успела, смогла, скрылась, заработалась, познала дзен, присела, обиделась, проснулась, взяла и сделала, додумалась, не спала'),
|
||||
},
|
||||
place: {
|
||||
...buildVariant(null, 'где-то, в пустыне, на пляже, под дождём, %под проливным дождём, в квартире, %в тёплой и уютной квартире, в космосе, в театре, в филармонии, на заснеженной вершине, на конференции, на форуме, в очереди, в лесу, в джунглях, под водой'),
|
||||
},
|
||||
adv: {
|
||||
...buildVariant(null, 'счастливо, уныло, грустно, позже, немедленно, регулярно, вновь, опять, уже, внезапно, предсказуемо, медленно, быстро, %молниеносно, $грубо, безрассудно, осмысленно, расчётливо'),
|
||||
},
|
||||
p: {
|
||||
'': new StupidTitleSetting({ weight: 10 }),
|
||||
'.': new StupidTitleSetting({ weight: 10 }),
|
||||
'...': new StupidTitleSetting({ weight: 5 }),
|
||||
'!': new StupidTitleSetting({ weight: 5 }),
|
||||
'!!!': new StupidTitleSetting({ weight: 2 }),
|
||||
'?': new StupidTitleSetting({ weight: 2 }),
|
||||
'?!': new StupidTitleSetting({ weight: 1 }),
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
interface StupidTitleVariants {
|
||||
[key: string]: StupidTitleVariant
|
||||
}
|
||||
|
||||
interface StupidTitleVariant {
|
||||
[key: string]: StupidTitleSetting
|
||||
}
|
||||
|
||||
interface StupidTitleWeightedVariants {
|
||||
[key: string]: number
|
||||
}
|
||||
|
||||
class StupidTitleSetting {
|
||||
weight: number = 10;
|
||||
|
||||
enabled: boolean = true;
|
||||
|
||||
rude: boolean = false;
|
||||
|
||||
gender: boolean|null = null;
|
||||
|
||||
constructor(options: any = new Object) {
|
||||
for (const iterator of Object.entries(options)) {
|
||||
if (iterator[0] in this) {
|
||||
(<any> this)[iterator[0]] = iterator[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildVariant(gender: boolean|null, input: string): StupidTitleVariant
|
||||
{
|
||||
const result: StupidTitleVariant = {};
|
||||
const words = input.split(',').map(word => word.trim());
|
||||
|
||||
words.forEach(word => {
|
||||
const clean_word = word.replace(/[^А-ЯЁа-яёA-Za-z\- ]/g, '');
|
||||
|
||||
if (clean_word === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
result[clean_word] = new StupidTitleSetting({
|
||||
gender,
|
||||
rude: word.indexOf('$') >= 0,
|
||||
enabled: word.indexOf('!') < 0,
|
||||
weight: 10 * ((word.indexOf('$') >= 0) ? 0.5 : 1) * ((word.indexOf('%') >= 0) ? 0.5 : 1) * ((word.indexOf('^') >= 0) ? 2 : 1)
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
(window as any).BuildStupdiTitleVariant = buildVariant;
|
||||
+4
-4
@@ -5,9 +5,9 @@ import { HumanitarianHellJoke } from "./jokes/humanitarian_hell";
|
||||
import { MirrorJoke } from "./jokes/mirror";
|
||||
import { CarnivalJoke } from "./jokes/carnival";
|
||||
import { CrazyLettersJoke } from "./jokes/crazy_letters";
|
||||
import { CrazyPunctuationJoke } from "./jokes/crazy_punctuation";
|
||||
import { LetterChaosJoke } from "./jokes/letter_chaos";
|
||||
import { CursorEffectsJoke } from "./jokes/cursor"
|
||||
import { CursorEffectsJoke } from "./jokes/cursor";
|
||||
import { StupidTitleJoke } from "./jokes/stupid_title";
|
||||
|
||||
(window as any).AprilJokes = ((jokes: JokeClassList): JokerClass => {
|
||||
const cl = new JokerClass();
|
||||
@@ -16,7 +16,7 @@ import { CursorEffectsJoke } from "./jokes/cursor"
|
||||
cl.add(new joke());
|
||||
});
|
||||
|
||||
cl.regularStart();
|
||||
$(() => cl.regularStart());
|
||||
|
||||
return cl;
|
||||
})([
|
||||
@@ -25,9 +25,9 @@ import { CursorEffectsJoke } from "./jokes/cursor"
|
||||
MirrorJoke,
|
||||
CarnivalJoke,
|
||||
CrazyLettersJoke,
|
||||
CrazyPunctuationJoke,
|
||||
LetterChaosJoke,
|
||||
CursorEffectsJoke,
|
||||
StupidTitleJoke,
|
||||
]);
|
||||
|
||||
interface JokeClassList extends Array<new () => Joke> {}
|
||||
@@ -0,0 +1,62 @@
|
||||
/// <reference path="html.d.ts"/>
|
||||
import { JokerClass } from "./joker";
|
||||
import $ from "jquery";
|
||||
import button_html from "./html/button.html";
|
||||
import styles_html from "./html/styles.html";
|
||||
import window_html from "./html/window.html";
|
||||
|
||||
|
||||
export class JokerUI {
|
||||
joker: JokerClass;
|
||||
|
||||
constructor(joker: JokerClass) {
|
||||
this.joker = joker;
|
||||
|
||||
$('link[rel="stylesheet"]').eq(0).before(styles_html);
|
||||
|
||||
const button = this.button;
|
||||
|
||||
button.hide();
|
||||
(<any>button).mybbModal({
|
||||
title: "Настройки первоапрельских шуток",
|
||||
content: () => this.render(),
|
||||
closer: true,
|
||||
noscroll: true,
|
||||
escClose: true,
|
||||
});
|
||||
}
|
||||
|
||||
get button() {
|
||||
let button = $('.april-fools__button');
|
||||
|
||||
if (button.length === 0) {
|
||||
button = $(button_html).appendTo('body');
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
show() {
|
||||
this.button.show();
|
||||
}
|
||||
|
||||
render(): JQuery {
|
||||
const result: JQuery = $('<div></div>').html(window_html);
|
||||
const row_template = $('#april-fools__window-row', result).html();
|
||||
const joke_container = $('.april-fools__jokes', result);
|
||||
|
||||
for (const joke of Object.values(this.joker.jokes)) {
|
||||
const row = $(eval('`' + row_template + '`'));
|
||||
$('input[type="checkbox"]', row).prop('checked', joke.settings.enabled)
|
||||
.on('click', e => this.joker.toggleJoke(joke.id, (<any>e).currentTarget.checked));
|
||||
joke_container.append(row);
|
||||
}
|
||||
|
||||
$('button', result).on('click', async () => {
|
||||
await this.joker.clearUserStates();
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
return $('.april-fools__content', result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user