Курсоры, обновление документации

This commit is contained in:
2023-03-29 00:36:23 +04:00
parent 0ca319ae0f
commit 1ec33d6a80
20 changed files with 1118 additions and 106 deletions
+36 -3
View File
@@ -2,6 +2,11 @@
* Объект настроек шутки
*/
export interface JokeSettings {
/**
* Флаг блокировки срабатывания
*/
enabled: boolean;
/**
* Вероятность срабатывания в процентах
*/
@@ -23,9 +28,36 @@ export abstract class Joke {
settings: JokeSettings;
/**
* Флаг, указывающий, должна ли шутка быть запущена
* Проверка вероятности
*
* @param {number} chance Вероятность срабатывания
* @returns {boolean} Флаг срабатывания (true - сработало)
*/
enabled: boolean = true;
check(chance: number): boolean {
return Math.random() < 0.01 * chance;
}
/**
* Разблокировать шутку
*/
enable() {
this.settings.enabled = true;
}
/**
* Заблокировать шутку
*/
disable() {
this.settings.enabled = false;
}
/**
* Переключить блокировку шутки
* @param value Новое значение
*/
toggle(value: boolean|null = null) {
this.settings.enabled = (value === null) ? !this.settings.enabled : value;
}
/**
* Запуск шутки
@@ -42,4 +74,5 @@ export abstract class StopableJoke extends Joke
* Остановка шутки, если возможно
*/
abstract stop(): void;
}
}
+57 -12
View File
@@ -5,31 +5,38 @@ import { Joke, JokeSettings } from "./joke";
*
* @author Kozhilya
*/
export class AprilFoolsJokeClass {
export class JokerClass {
/**
* Проверка вероятности
*
* @param {number} chance Вероятность срабатывания
* @returns {boolean} Флаг срабатывания (true - сработало)
*/
static check(chance: number): boolean {
check(chance: number): boolean {
return Math.random() < 0.01 * chance;
}
/**
* Добавление шутки
*
* @param joke
* @param joke Объект шутки
*/
add(joke: Joke): void {
this.jokes[joke.id] = joke;
}
/**
* Регистрация новой шутки
*
* @param id Идентификатор шутки
* @param handler Метод, выполняющий шутку
* @param settings Объект настроек шутки
*/
addCustom(id: string, handler: Function, settings: JokeSettings|null = null) {
const joke = new class extends Joke {
id = id;
settings: JokeSettings = { chance: 10 };
settings: JokeSettings = { chance: 10, enabled: true };
start() {
handler.call(this, this.settings);
@@ -41,8 +48,9 @@ export class AprilFoolsJokeClass {
this.add(joke);
}
core_settings = new CoreSettings;
/**
* Получение полного списка настроек
*/
get settings(): SettingsMap {
const result: SettingsMap = {};
@@ -72,6 +80,38 @@ export class AprilFoolsJokeClass {
Object.assign(targetSettings, jokeSettings);
}
}
/**
* Разблокировать систему
*/
enable() {
this.core_settings.enabled = true;
}
/**
* Заблокировать систему
*/
disable() {
this.core_settings.enabled = false;
}
/**
* Разблокировать все шутки
*/
enableAll() {
for (const key of Object.keys(this.jokes)) {
this.jokes[key].enable();
}
}
/**
* Заблокировать все шутки
*/
disableAll() {
for (const key of Object.keys(this.jokes)) {
this.jokes[key].disable();
}
}
/**
* Запуск шутки
@@ -85,7 +125,7 @@ export class AprilFoolsJokeClass {
const joke = this.jokes[id];
if (!forced && !AprilFoolsJokeClass.check(joke.settings.chance)) {
if (!forced && (!joke.settings.enabled || !this.check(joke.settings.chance))) {
return;
}
@@ -106,11 +146,18 @@ export class AprilFoolsJokeClass {
const month = today.getMonth() + 1; // Note that getMonth() returns 0-indexed month, so we need to add 1
const day = today.getDate();
if (month === 4 && day === 1 && AprilFoolsJokeClass.check(this.core_settings.chance)) {
this.startAll();
if (month !== 4 || day !== 1 || !this.core_settings.enabled || !this.check(this.core_settings.chance)) {
return;
}
this.startAll();
}
/**
* Общие настройки системы
*/
core_settings = new CoreSettings;
/**
* Перечисление всех шуток
*/
@@ -131,9 +178,7 @@ interface SettingsMap {
[key: string]: JokeSettings;
}
/**
*
*/
class CoreSettings implements JokeSettings {
chance = 100;
enabled = true;
}
+4 -2
View File
@@ -1,6 +1,6 @@
import { Joke, JokeSettings, StopableJoke } from "../joke";
import $ from "jquery";
import { AprilFoolsJokeClass } from "../handler";
import { JokerClass } from "../joker";
/**
* **Карнавал**
@@ -19,7 +19,7 @@ export class CarnivalJoke extends Joke {
const filters: string[] = [];
for (const entry of Object.entries(this.settings.variants)) {
if (!AprilFoolsJokeClass.check(this.settings.variant_chance)) {
if (!this.check(this.settings.variant_chance)) {
continue;
}
@@ -34,6 +34,8 @@ export class CarnivalJoke extends Joke {
}
export class CarnivalJokeSettings implements JokeSettings {
enabled: boolean = true;
chance: number = 30;
/**
+2
View File
@@ -28,6 +28,8 @@ export class CrazyLettersJoke extends Joke {
}
export class CrazyLettersJokeSettings implements JokeSettings {
enabled: boolean = true;
chance: number = 20;
/**
+2
View File
@@ -54,6 +54,8 @@ export class CrazyPunctuationJoke extends Joke {
}
export class CrazyPunctuationJokeSettings implements JokeSettings {
enabled: boolean = true;
chance: number = 20;
/**
+320
View File
@@ -0,0 +1,320 @@
import { Joke, JokeSettings, StopableJoke } from "../joke";
import $ from "jquery";
import { Interface } from "readline";
// import * as cursor_effects from "cursor-effects";
const cursor_effects = require("cursor-effects");
/**
* **Красивый курсор**
*
* Эффекты, следующие за курсором
*
* @author Tim Holman
* @link https://tholman.com/cursor-effects/
*/
export class CursorEffectsJoke extends StopableJoke {
id = 'cursor_effects';
settings = new CursorEffectsJokeSettings;
active_cursor_effect: any;
/**
* Разблокировать все варианты курсоров
*/
enableAll() {
for (const key of Object.keys(this.settings.effects)) {
this.settings.effects[<CursorEffectsEnum> key].enabled = true;
}
}
/**
* Заблокировать все варианты курсоров
*/
disableAll() {
for (const key of Object.keys(this.settings.effects)) {
this.settings.effects[<CursorEffectsEnum> key].enabled = false;
}
}
private weight(effect: CursorEffectsEnum): number {
const s = this.settings.effects[effect];
return s.enabled ? s.weight : 0;
}
getRandomEffect(): CursorEffectsEnum {
const elements = Object.keys(CursorEffectsEnum).map(e => <CursorEffectsEnum>e);
const totalWeight = elements.reduce((sum, element) => sum + this.weight(element), 0);
const randomWeight = Math.random() * totalWeight;
let currentWeight = 0;
for (const element of elements) {
currentWeight += this.weight(element);
if (randomWeight <= currentWeight) {
return element;
}
}
throw new Error("Тебя быть тут не должно...");
}
start(): void {
const effect = this.getRandomEffect();
const settings = this.settings.effects[effect];
this.active_cursor_effect = resolveCursorEffectsEnum(effect, settings);
}
stop(): void {
this.active_cursor_effect.destroy();
}
}
enum CursorEffectsEnum {
Rainbow = 'rainbow',
FairyDust = 'fairy_dust',
SpringyEmoji = 'springy_emoji',
Emoji = 'emoji',
Ghost = 'ghost',
Trailing = 'trailing',
TextFlag = 'text_flag',
FollowingDot = 'following_dot',
Bubbles = 'bubbles',
Snowflake = 'snowflake',
Clock = 'clock'
}
function resolveCursorEffectsEnum(effect: CursorEffectsEnum|string, options: CursorEffectsSetting): any {
switch (effect) {
case CursorEffectsEnum.Rainbow:
return cursor_effects.rainbowCursor(options);
case CursorEffectsEnum.FairyDust:
return cursor_effects.fairyDustCursor(options);
case CursorEffectsEnum.SpringyEmoji:
return cursor_effects.springyEmojiCursor(options);
case CursorEffectsEnum.Emoji:
return cursor_effects.emojiCursor(options);
case CursorEffectsEnum.Ghost:
return cursor_effects.ghostCursor(options);
case CursorEffectsEnum.Trailing:
return cursor_effects.trailingCursor(options);
case CursorEffectsEnum.TextFlag:
return cursor_effects.textFlag(options);
case CursorEffectsEnum.FollowingDot:
return cursor_effects.followingDotCursor(options);
case CursorEffectsEnum.Bubbles:
return cursor_effects.bubbleCursor(options);
case CursorEffectsEnum.Snowflake:
return cursor_effects.snowflakeCursor(options);
case CursorEffectsEnum.Clock:
return cursor_effects.clockCursor(options);
}
}
export class CursorEffectsJokeSettings implements JokeSettings {
enabled: boolean = true;
chance: number = 100;
effects: { [key in CursorEffectsEnum]?: CursorEffectsSetting } = {
/**
* Радужный след за курсором
*/
[CursorEffectsEnum.Rainbow]: new class extends DefaultCursorEffectsSetting {
/**
* Длина полосы
*/
length: number = 20;
/**
* Ширина полосы
*/
size: number = 3;
/**
* Цвета полос (сверху вниз)
*/
colors: string[] = [
"#9400D3",
"#4B0082",
"#0000FF",
"#00FF00",
"#FFFF00",
"#FF7F00",
"#FF0000"
];
},
/**
* Цепочка из эмодзи "на резинке" под курсором
*/
[CursorEffectsEnum.SpringyEmoji]: new class extends DefaultCursorEffectsSetting {
/**
* Висящий эмодзи
*/
emoji: string = "🤪"
},
/**
* Падающие от курсора эмодзи
*/
[CursorEffectsEnum.Emoji]: new class extends DefaultCursorEffectsSetting {
/**
* Падающие эмодзи
*/
emoji: string[] = ["🔥", "🐬", "🦆"]
},
/**
* Падающие от курсора пылинки
*/
[CursorEffectsEnum.FairyDust]: new class extends DefaultCursorEffectsSetting {
/**
* Цвет пылинок
*/
colors: string[] = ["#ff0000", "#00ff00", "#0000ff"];
},
/**
* След "зависших" курсоров
*/
[CursorEffectsEnum.Ghost]: new DefaultCursorEffectsSetting,
/**
* След курсоров "на резинке"
*/
[CursorEffectsEnum.Trailing]: new class extends DefaultCursorEffectsSetting {
/**
* Количество элементов
*/
particles: number = 15;
/**
* Скорость частиц
*/
rate: number = 0.4;
/**
* Ссылка на картинку с курсором
* Используйте `null`, что бы использовать картинку курсора по умолчанию
*/
baseImageSrc: string | null = null;
},
/**
* Текст, развивающийся флагом от курсора
*/
[CursorEffectsEnum.TextFlag]: new class extends DefaultCursorEffectsSetting {
/**
* Отображаемый текст
*/
text: string = "С днём смеха!";
/**
* Цвет текста
*/
color: string = "#000000";
/**
* Шрифт текста
*/
font: string = "monospace";
/**
* Размер текста
*/
textSize: number = 12;
/**
* Растояние между бквами
*/
gap: number = 14;
/**
* Размер... чего-то.
*/
size: number = 3;
},
/**
* Точка, преследующая курсор
*/
[CursorEffectsEnum.FollowingDot]: new class extends DefaultCursorEffectsSetting {
/**
* Цвет догоняющей точки
*/
color: string = "#323232a6";
},
/**
* Пузырьки от курсора
*/
[CursorEffectsEnum.Bubbles]: new DefaultCursorEffectsSetting,
/**
* Снежинки, летящие от курсора
*
* Отключено, потому что сейчас не зима :D
*/
[CursorEffectsEnum.Snowflake]: new class extends DefaultCursorEffectsSetting {
weight: number = 0;
},
/**
* Циферблат вокруг курсора
*/
[CursorEffectsEnum.Clock]: new class extends DefaultCursorEffectsSetting {
/**
* Цвет даты
*/
dateColor: string = "blue";
/**
* Цвет циферблата
*/
faceColor: string = "black";
/**
* Цвет секундной стрелки
*/
secondsColor: string = "red";
/**
* Цвет минутной стрелки
*/
minutesColor: string = "black";
/**
* Цвет часовой стрелки
*/
hoursColor: string = "black";
},
};
}
interface CursorEffectsSetting {
[key: string]: any;
}
class DefaultCursorEffectsSetting implements CursorEffectsSetting {
/**
* Флаг возможности срабатывания
*/
enabled: boolean = true;
/**
* Весовой коэффициент вероятности курсора
*/
weight: number = 50;
}
+2
View File
@@ -23,6 +23,8 @@ export class HumanitarianHellJoke extends Joke {
}
export class HumanitarianHellJokeSettings implements JokeSettings {
enabled: boolean = true;
chance: number = 20;
/**
+4 -2
View File
@@ -1,6 +1,6 @@
import { Joke, JokeSettings, StopableJoke } from "../joke";
import $ from "jquery";
import { AprilFoolsJokeClass } from "../handler";
import { JokerClass } from "../joker";
/**
* **Буквенный хаос**
@@ -18,7 +18,7 @@ export class LetterChaosJoke extends Joke {
private shuffleLetters(word: string): string {
// Check if the word has two or more letters
if ((word.length < 3) || !AprilFoolsJokeClass.check(this.settings.shuffle_chance)) {
if ((word.length < 3) || !this.check(this.settings.shuffle_chance)) {
return word;
}
@@ -48,6 +48,8 @@ export class LetterChaosJoke extends Joke {
}
export class LetterChaosJokeSettings implements JokeSettings {
enabled: boolean = true;
chance: number = 20;
/**
+2
View File
@@ -22,5 +22,7 @@ export class MirrorJoke extends Joke {
}
export class MirrorJokeSettings implements JokeSettings {
enabled: boolean = false;
chance: number = 30;
}
+8 -6
View File
@@ -63,13 +63,20 @@ export class ShakeJoke extends StopableJoke {
}
export class ShakeJokeSettings implements JokeSettings {
enabled: boolean = true;
chance: number = 1;
/**
* Направление тряски
* Направление тряски (тряска происходит путём изменения перечисленных направлений margin на значение ±force от стандартного значения)
*/
directions: string[] = ['top', 'left', 'bottom', 'left'];
/**
* Сила тряски - насколько отклоняется элемент от стандартного значения
*/
force: number = 0.5;
/**
* Селектор всех элементов, которые будут трястись
*/
@@ -79,11 +86,6 @@ export class ShakeJokeSettings implements JokeSettings {
* Частота тряски
*/
interval: number = 100;
/**
* Сила тряски
*/
force: number = 0.5;
}
export interface ShakeJokeMargin {
+5 -3
View File
@@ -1,4 +1,4 @@
import { AprilFoolsJokeClass } from "./handler";
import { JokerClass } from "./joker";
import { Joke } from "./joke";
import { ShakeJoke } from "./jokes/shake";
import { HumanitarianHellJoke } from "./jokes/humanitarian_hell";
@@ -7,9 +7,10 @@ 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"
(window as any).AprilJokes = ((jokes: JokeClassList): AprilFoolsJokeClass => {
const cl = new AprilFoolsJokeClass();
(window as any).AprilJokes = ((jokes: JokeClassList): JokerClass => {
const cl = new JokerClass();
jokes.forEach(joke => {
cl.add(new joke());
@@ -26,6 +27,7 @@ import { LetterChaosJoke } from "./jokes/letter_chaos";
CrazyLettersJoke,
CrazyPunctuationJoke,
LetterChaosJoke,
CursorEffectsJoke,
]);
interface JokeClassList extends Array<new () => Joke> {}