zischenstand
This commit is contained in:
38
src/modules/visual-active-effects/lang/cs.json
Normal file
38
src/modules/visual-active-effects/lang/cs.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DETAILS": "Detaily",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DISABLED": "Zakázané",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.PASSIVE": "Pasivní",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.TEMPORARY": "Dočasné",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.HINT": "Počet dnů v týdnu.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.NAME": "Dnů v týdnu",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.HINT": "Počet dnů navíc v roce.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.NAME": "Navíc dnů v roce",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.HINT": "If enabled, any disabled effects will not show up.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.NAME": "Hide Disabled Effects",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.HINT": "If enabled, any passive effects will not show up.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.NAME": "Hide Passive Effects",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.HINT": "Změte velikost ikony v pixelech. Výchozí: 50.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.NAME": "Velikost ikony",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.HINT": "Počet měsíců v roce.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.NAME": "Měsíců v roce",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.HINT": "Počet týdnů v měsíci.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.NAME": "Týdnů v měsíci",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAY": "1 den",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAYS": "{qty} dnů",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.EXPIRED": "Vypršelo",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOUR": "1 hodinu",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOURS": "{qty} hodin",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTE": "1 minuta",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTES": "{qty} minut",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTH": "1 měsíc",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTHS": "{qty} měsíců",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECOND": "1 vteřina",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECONDS": "{qty} vteřin",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURN": "1 tah",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURNS": "{qty} tahů",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED": "Neomezeně",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEK": "1 týden",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEKS": "{qty} týdnů",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEAR": "1 rok",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEARS": "{qty} let"
|
||||
}
|
||||
52
src/modules/visual-active-effects/lang/de.json
Normal file
52
src/modules/visual-active-effects/lang/de.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"VISUAL_ACTIVE_EFFECTS.CONTENT": "Inhalt",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_SAVED": "Textinhalte wurden gespeichert.",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_TITLE": "Visual Active Effects Editor: {name}",
|
||||
"VISUAL_ACTIVE_EFFECTS.FORCE_INCLUDE": "Effekt immer anzeigen:",
|
||||
"VISUAL_ACTIVE_EFFECTS.INTRO": "Intro",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DETAILS": "Details",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DISABLED": "Deaktiviert",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.PASSIVE": "Passiv",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.SOURCE": "Quelle",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.TEMPORARY": "Vorübergehend",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.HINT": "Anzahl der Tage in der Woche.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.NAME": "Tage pro Woche",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.HINT": "Jeder zusätzliche Tag im Jahr.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.NAME": "Zusätzliche Tage im Jahr",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.HINT": "Ändert die Schriftgröße vom Text der Effekte. Default: 16.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.NAME": "Schriftgröße",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.HINT": "Wenn aktiviert, werden unterbrochene Effekte nicht angezeigt.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.NAME": "Verstecke unterbrochene Effekte",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.HINT": "Wenn aktiv, werden passive Effekte nicht angezeigt.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.NAME": "Passive Effekte verbergen",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.HINT": "Ändere die Größe des Icons (in Pixel). Default: 50.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.NAME": "Icon Größe",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.HINT": "Anzahl der Monate im Jahr.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.NAME": "Monat pro Jahr",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.HINT": "Wenn deaktiviert können Nicht-SL-Nutzer Effekte nicht direkt im Panel umschalten oder löschen.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.NAME": "Spielerinteraktion erlauben",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.HINT": "Ändert den Abstand zwischen dem Effektpanel und dem oberen Fensterrand. Default: 25.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.NAME": "Abstand oben",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.HINT": "Anzahl der Wochen im Monat.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.NAME": "Wochen pro Monat",
|
||||
"VISUAL_ACTIVE_EFFECTS.STATUS_ID": "Status:",
|
||||
"VISUAL_ACTIVE_EFFECTS.Statuses": "Stati",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAY": "1 Tag",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAYS": "{qty} Tage",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.EXPIRED": "Abgelaufen",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOUR": "1 Stunde",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOURS": "{qty} Stunden",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTE": "1 Minute",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTES": "{qty} Minuten",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTH": "1 Monat",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTHS": "{qty} Monate",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECOND": "1 Sekunde",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECONDS": "{qty} Sekunden",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURN": "1 Zug",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURNS": "{qty} Züge",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED": "Unbegrenzt",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEK": "1 Woche",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEKS": "{qty} Wochen",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEAR": "1 Jahr",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEARS": "{qty} Jahre"
|
||||
}
|
||||
55
src/modules/visual-active-effects/lang/en.json
Normal file
55
src/modules/visual-active-effects/lang/en.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"VISUAL_ACTIVE_EFFECTS.CONTENT": "Content",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_SAVED": "Text contents have been saved.",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_TITLE": "Visual Active Effects Editor: {name}",
|
||||
"VISUAL_ACTIVE_EFFECTS.FORCE_INCLUDE": "Always show this effect:",
|
||||
"VISUAL_ACTIVE_EFFECTS.INCLUSION": "Always include or exclude this effect:",
|
||||
"VISUAL_ACTIVE_EFFECTS.INCLUSION_INCLUDE": "Always Include",
|
||||
"VISUAL_ACTIVE_EFFECTS.INCLUSION_EXCLUDE": "Always Exclude",
|
||||
"VISUAL_ACTIVE_EFFECTS.INTRO": "Intro",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DETAILS": "Details",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DISABLED": "Disabled",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.PASSIVE": "Passive",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.SOURCE": "Source",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.TEMPORARY": "Temporary",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.HINT": "The number of days in a week.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.NAME": "Days per Week",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.HINT": "Any extra days per year.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.NAME": "Extra Days per Year",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.HINT": "Change the font size of the text in the effects. Default: 16.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.NAME": "Font Size",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.HINT": "If enabled, any disabled effects will not show up.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.NAME": "Hide Disabled Effects",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.HINT": "If enabled, any passive effects will not show up.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.NAME": "Hide Passive Effects",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.HINT": "Change the pixel size of the icons. Default: 50.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.NAME": "Icon Size",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.HINT": "The number of months in a year.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.NAME": "Months per Year",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.HINT": "If unchecked, non-GM users will not be able to toggle or delete effects directly in the panel.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.NAME": "Allow Player Interaction",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.HINT": "Change the space between the panel of effects and the top of the window. Default: 25.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.NAME": "Top Offset",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.HINT": "The number of weeks in a month.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.NAME": "Weeks per Month",
|
||||
"VISUAL_ACTIVE_EFFECTS.STATUS_ID": "Status:",
|
||||
"VISUAL_ACTIVE_EFFECTS.Statuses": "Statuses",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAY": "1 day",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAYS": "{qty} days",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.EXPIRED": "Expired",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOUR": "1 hour",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOURS": "{qty} hours",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTE": "1 minute",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTES": "{qty} minutes",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTH": "1 month",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTHS": "{qty} months",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECOND": "1 second",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECONDS": "{qty} seconds",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURN": "1 turn",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURNS": "{qty} turns",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED": "Unlimited",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEK": "1 week",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEKS": "{qty} weeks",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEAR": "1 year",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEARS": "{qty} years"
|
||||
}
|
||||
52
src/modules/visual-active-effects/lang/pl.json
Normal file
52
src/modules/visual-active-effects/lang/pl.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"VISUAL_ACTIVE_EFFECTS.CONTENT": "Zawartość",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_SAVED": "Zawartość została zaktualizowana.",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_TITLE": "Autor Visual Active Effects: {name}",
|
||||
"VISUAL_ACTIVE_EFFECTS.FORCE_INCLUDE": "Zawsze pokazuj ten efektt:",
|
||||
"VISUAL_ACTIVE_EFFECTS.INTRO": "Wprowadzenie",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DETAILS": "Szczegóły",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DISABLED": "Nieaktywny",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.PASSIVE": "Pasywny",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.SOURCE": "Żródło",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.TEMPORARY": "Tymczasowy",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.HINT": "Liczba dni w tygodniu.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.NAME": "Dni tygodnia",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.HINT": "Dodatkowe dni w roku",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.NAME": "Dodatkowe dni w roku",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.HINT": "Zmień rozmiar czcionki w opisie efektu. Domyślnie: 16.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.NAME": "Rozmiar Czcionki",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.HINT": "Gdy zaznaczone, nieaktywne efekty nie będą wyświetlane.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.NAME": "Ukryj Nieaktywne Efekty",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.HINT": "Gdy zaznaczone, pasywne efekty nie będą wyświetlane.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.NAME": "Ukryj Pasywne Efekty",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.HINT": "Zmień liczbę pikseli ikony efektu. Domyślnie: 50.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.NAME": "Rozmiar Ikony",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.HINT": "Liczba miesięcy w roku.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.NAME": "Miesiące w Roku",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.HINT": "Gdy niezaznaczone, gracze będą mogli przełączać efekty lub je usuwać bezpośrednio z panelu.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.NAME": "Zezwól na interakcje graczy",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.HINT": "Zmień odległość pomiędzy panelem efektów a górną krawędzią okna foundry. Domyślnie: 25.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.NAME": "Odległość od Krawędzi",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.HINT": "Liczba tygodni w miesiącu.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.NAME": "Tygodnie w miesiącu",
|
||||
"VISUAL_ACTIVE_EFFECTS.STATUS_ID": "Status:",
|
||||
"VISUAL_ACTIVE_EFFECTS.Statuses": "Statusy",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAY": "1 dzień",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAYS": "{qty} dni",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.EXPIRED": "Wygasły",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOUR": "1 godzina",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOURS": "{qty} godzin",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTE": "1 minuta",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTES": "{qty} minut",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTH": "1 miesiąc",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTHS": "{qty} miesięcy",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECOND": "1 sekunda",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECONDS": "{qty} sekund",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURN": "1 Tura",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURNS": "{qty} Tur(y)",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED": "Nieograniczony",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEK": "1 tydzień",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEKS": "{qty} tygodni(e)",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEAR": "1 rok",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEARS": "{qty} lat(a)"
|
||||
}
|
||||
51
src/modules/visual-active-effects/lang/pt_BR.json
Normal file
51
src/modules/visual-active-effects/lang/pt_BR.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"VISUAL_ACTIVE_EFFECTS.CONTENT": "Conteúdo",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_SAVED": "O conteúdo do texto foi salvo.",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_TITLE": "Editor de efeitos visuais ativos: {name}",
|
||||
"VISUAL_ACTIVE_EFFECTS.FORCE_INCLUDE": "Sempre mostre este efeito:",
|
||||
"VISUAL_ACTIVE_EFFECTS.INTRO": "Introdução",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DETAILS": "Detalhes",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DISABLED": "Desabilitado",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.PASSIVE": "Passivo",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.SOURCE": "Fonte",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.TEMPORARY": "Temporário",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.HINT": "O número de dias em uma semana.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.NAME": "Dias por semana",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.HINT": "Qualquer dia extra por ano.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.NAME": "Dias extras por ano",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.HINT": "Altere o tamanho da fonte do texto nos efeitos. Padrão: 16.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.NAME": "Tamanho da fonte",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.HINT": "Se ativado, quaisquer efeitos desativados não aparecerão.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.NAME": "Ocultar efeitos desativados",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.HINT": "Se habilitado, quaisquer efeitos passivos não aparecerão.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.NAME": "Ocultar efeitos passivos",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.HINT": "Altere o tamanho do pixel dos ícones. Padrão: 50.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.NAME": "Tamanho do Ícone",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.HINT": "O número de meses em um ano.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.NAME": "Meses por ano",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.HINT": "Se desmarcado, os usuários não-GM não poderão alternar ou excluir efeitos diretamente no painel.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.NAME": "Permitir interação do jogador",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.HINT": "Altere o espaço entre os efeitos do painel desativado e a parte superior da janela. Padrão: 25.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.NAME": "Deslocamento superior",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.HINT": "O número de semanas em um mês.",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.NAME": "Semanas por mês",
|
||||
"VISUAL_ACTIVE_EFFECTS.STATUS_ID": "Identificação do estado:",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAY": "1 dia",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAYS": "{qty} dias",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.EXPIRED": "Expirado",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOUR": "1 hora",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOURS": "{qty} horas",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTE": "1 minuto",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTES": "{qty} minutos",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTH": "1 mês",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTHS": "{qty} meses",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECOND": "1 segundo",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECONDS": "{qty} segundos",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURN": "1 turno",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURNS": "{qty} turnos",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED": "Ilimitado",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEK": "1 semana",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEKS": "{qty} semanas",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEAR": "1 ano",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEARS": "{qty} anos"
|
||||
}
|
||||
53
src/modules/visual-active-effects/lang/zh_Hans.json
Normal file
53
src/modules/visual-active-effects/lang/zh_Hans.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"VISUAL_ACTIVE_EFFECTS.CONTENT": "详述",
|
||||
"VISUAL_ACTIVE_EFFECTS.FORCE_INCLUDE": "总是显示该效果:",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.NAME": "每年的额外天数",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.HINT": "如果勾选,任何被动效果都不会显示。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.NAME": "允许玩家互动",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_SAVED": "文本内容已保存。",
|
||||
"VISUAL_ACTIVE_EFFECTS.EDITOR_TITLE": "Visual Active Effects 编辑器: {name}",
|
||||
"VISUAL_ACTIVE_EFFECTS.INTRO": "简述",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DETAILS": "详细信息",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.DISABLED": "已禁用",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.PASSIVE": "被动",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.SOURCE": "来源",
|
||||
"VISUAL_ACTIVE_EFFECTS.LABELS.TEMPORARY": "临时效果",
|
||||
"VISUAL_ACTIVE_EFFECTS.MISC.DELETE_EFFECT": "删除效果",
|
||||
"VISUAL_ACTIVE_EFFECTS.MISC.DELETE_ME": "是否删除 {label}?",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.HINT": "配置一周有多少天。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.NAME": "每周的天数",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.HINT": "一年的任何额外天数。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.HINT": "修改效果文本的字体尺寸。默认16。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.NAME": "字体大小",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.HINT": "如果勾选,任何已禁用的效果都不会显示。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.NAME": "隐藏已禁用的效果",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.NAME": "隐藏被动效果",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.HINT": "修改图标的像素尺寸。默认50。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.NAME": "图标大小",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.HINT": "配置一年有多少个月。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.NAME": "每年的月数",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.HINT": "修改效果面板距离窗口顶部的空间。默认25。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.NAME": "顶部偏移量",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.HINT": "配置一个月有多少周。",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.NAME": "每月的周数",
|
||||
"VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.HINT": "如果不勾选,非GM用户将不能直接在面板中切换或删除效果。",
|
||||
"VISUAL_ACTIVE_EFFECTS.STATUS_ID": "状态 Id:",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAY": "1 天",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.DAYS": "{qty} 天",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.EXPIRED": "已过期",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOUR": "1 小时",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.HOURS": "{qty} 小时",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTE": "1 分钟",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MINUTES": "{qty} 分钟",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTH": "1 月",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.MONTHS": "{qty} 月",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECOND": "1 秒",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.SECONDS": "{qty} 秒",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURN": "1 轮",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.TURNS": "{qty} 轮",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED": "持续",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEK": "1 周",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.WEEKS": "{qty} 周",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEAR": "1 年",
|
||||
"VISUAL_ACTIVE_EFFECTS.TIME.YEARS": "{qty} 年"
|
||||
}
|
||||
66
src/modules/visual-active-effects/module.json
Normal file
66
src/modules/visual-active-effects/module.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"id": "visual-active-effects",
|
||||
"title": "Visual Active Effects",
|
||||
"version": "11.1.2",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Zhell",
|
||||
"url": "https://github.com/krbz999",
|
||||
"discord": "zhell9201",
|
||||
"ko-fi": "https://ko-fi.com/zhell",
|
||||
"patreon": "https://patreon.com/zhell"
|
||||
}
|
||||
],
|
||||
"compatibility": {
|
||||
"minimum": "11",
|
||||
"maximum": "11",
|
||||
"verified": "11"
|
||||
},
|
||||
"esmodules": [
|
||||
"scripts/setup.mjs"
|
||||
],
|
||||
"styles": [
|
||||
"styles/visual-active-effects.css"
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en.json",
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"lang": "cs",
|
||||
"name": "Česky",
|
||||
"path": "lang/cs.json",
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"lang": "de",
|
||||
"name": "Deutsch",
|
||||
"path": "lang/de.json",
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"lang": "pt-BR",
|
||||
"name": "Português (Brasil)",
|
||||
"path": "lang/pt_BR.json"
|
||||
},
|
||||
{
|
||||
"lang": "zh-Hans",
|
||||
"name": "中文(简体)",
|
||||
"path": "lang/zh_Hans.json"
|
||||
},
|
||||
{
|
||||
"lang": "pl",
|
||||
"name": "Polski",
|
||||
"path": "lang/pl.json"
|
||||
}
|
||||
],
|
||||
"flags": {
|
||||
"hotReload": false
|
||||
},
|
||||
"url": "https://github.com/krbz999/visual-active-effects",
|
||||
"manifest": "https://github.com/krbz999/visual-active-effects/releases/latest/download/module.json",
|
||||
"download": "https://github.com/krbz999/visual-active-effects/releases/download/v11.1.2/module.zip"
|
||||
}
|
||||
12
src/modules/visual-active-effects/scripts/constants.mjs
Normal file
12
src/modules/visual-active-effects/scripts/constants.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
export const DAYS_PER_WEEK = "daysPerWeek";
|
||||
export const EXTRA_DAYS_PER_YEAR = "extraDaysPerYear";
|
||||
export const FONT_SIZE = "fontSize";
|
||||
export const HIDE_DISABLED = "hideDisabled";
|
||||
export const HIDE_PASSIVE = "hidePassive";
|
||||
export const PLAYER_CLICKS = "playerClicks";
|
||||
export const ICON = "fa-solid fa-pen-fancy";
|
||||
export const ICON_SIZE = "iconSize";
|
||||
export const MODULE = "visual-active-effects";
|
||||
export const MONTHS_PER_YEAR = "monthsPerYear";
|
||||
export const TOP_OFFSET = "topOffset";
|
||||
export const WEEKS_PER_MONTH = "weeksPerMonth";
|
||||
160
src/modules/visual-active-effects/scripts/helpers.mjs
Normal file
160
src/modules/visual-active-effects/scripts/helpers.mjs
Normal file
@@ -0,0 +1,160 @@
|
||||
import {
|
||||
DAYS_PER_WEEK,
|
||||
EXTRA_DAYS_PER_YEAR,
|
||||
FONT_SIZE,
|
||||
ICON_SIZE,
|
||||
MODULE,
|
||||
MONTHS_PER_YEAR,
|
||||
TOP_OFFSET,
|
||||
WEEKS_PER_MONTH
|
||||
} from "./constants.mjs";
|
||||
import VisualActiveEffectsEditor from "./textEditor.mjs";
|
||||
|
||||
/**
|
||||
* Helper function to get remaining duration.
|
||||
* @param {ActiveEffect} effect
|
||||
* @returns {string|null}
|
||||
*/
|
||||
export function remainingTimeLabel(effect) {
|
||||
|
||||
// Case 1: Duration measured in rounds and turns.
|
||||
if (effect.duration.type === "turns") {
|
||||
if (effect.duration.remaining === null) return game.i18n.localize("VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED");
|
||||
else if (effect.duration.remaining === 0) return game.i18n.localize("VISUAL_ACTIVE_EFFECTS.TIME.EXPIRED");
|
||||
return effect.duration.label;
|
||||
}
|
||||
|
||||
// Case 2: Duration measured in seconds.
|
||||
else if (effect.duration.type === "seconds") {
|
||||
const SECONDS = {
|
||||
IN_ONE_ROUND: 6,
|
||||
IN_ONE_MINUTE: 60,
|
||||
IN_TWO_MINUTES: 120,
|
||||
IN_ONE_HOUR: 3600,
|
||||
IN_TWO_HOURS: 7200,
|
||||
IN_ONE_DAY: 86400,
|
||||
IN_TWO_DAYS: 172800
|
||||
};
|
||||
|
||||
const daysPerWeek = game.settings.get(MODULE, DAYS_PER_WEEK) ?? 9;
|
||||
const weeksPerMonth = game.settings.get(MODULE, WEEKS_PER_MONTH) ?? 3;
|
||||
const monthsPerYear = game.settings.get(MODULE, MONTHS_PER_YEAR) ?? 12;
|
||||
const extraDaysPerYear = game.settings.get(MODULE, EXTRA_DAYS_PER_YEAR) ?? 1;
|
||||
|
||||
SECONDS.IN_ONE_WEEK = SECONDS.IN_ONE_DAY * daysPerWeek;
|
||||
SECONDS.IN_TWO_WEEKS = SECONDS.IN_ONE_WEEK * 2;
|
||||
SECONDS.IN_ONE_MONTH = SECONDS.IN_ONE_WEEK * weeksPerMonth;
|
||||
SECONDS.IN_TWO_MONTHS = SECONDS.IN_ONE_MONTH * 2;
|
||||
SECONDS.IN_ONE_YEAR = SECONDS.IN_ONE_MONTH * monthsPerYear + SECONDS.IN_ONE_DAY * extraDaysPerYear;
|
||||
SECONDS.IN_TWO_YEARS = SECONDS.IN_ONE_YEAR * 2;
|
||||
|
||||
const remainingSeconds = effect.duration.remaining;
|
||||
|
||||
let string = "";
|
||||
let qty = 1;
|
||||
|
||||
if (remainingSeconds >= SECONDS.IN_TWO_YEARS) {
|
||||
qty = Math.floor(remainingSeconds / SECONDS.IN_ONE_YEAR);
|
||||
string = "YEARS";
|
||||
} else if (remainingSeconds >= SECONDS.IN_ONE_YEAR) {
|
||||
string = "YEAR";
|
||||
} else if (remainingSeconds >= SECONDS.IN_TWO_MONTHS) {
|
||||
qty = Math.floor(remainingSeconds / SECONDS.IN_ONE_MONTH);
|
||||
string = "MONTHS";
|
||||
} else if (remainingSeconds >= SECONDS.IN_ONE_MONTH) {
|
||||
string = "MONTH";
|
||||
} else if (remainingSeconds >= SECONDS.IN_TWO_WEEKS) {
|
||||
qty = Math.floor(remainingSeconds / SECONDS.IN_ONE_WEEK);
|
||||
string = "WEEKS";
|
||||
} else if (remainingSeconds >= SECONDS.IN_ONE_WEEK) {
|
||||
string = "WEEK";
|
||||
} else if (remainingSeconds >= SECONDS.IN_TWO_DAYS) {
|
||||
qty = Math.floor(remainingSeconds / SECONDS.IN_ONE_DAY);
|
||||
string = "DAYS";
|
||||
} else if (remainingSeconds >= SECONDS.IN_ONE_DAY) {
|
||||
string = "DAY";
|
||||
} else if (remainingSeconds >= SECONDS.IN_TWO_HOURS) {
|
||||
qty = Math.floor(remainingSeconds / SECONDS.IN_ONE_HOUR);
|
||||
string = "HOURS";
|
||||
} else if (remainingSeconds >= SECONDS.IN_ONE_HOUR) {
|
||||
string = "HOUR";
|
||||
} else if (remainingSeconds >= SECONDS.IN_TWO_MINUTES) {
|
||||
qty = Math.floor(remainingSeconds / SECONDS.IN_ONE_MINUTE);
|
||||
string = "MINUTES";
|
||||
} else if (remainingSeconds >= SECONDS.IN_ONE_MINUTE) {
|
||||
string = "MINUTE";
|
||||
} else if (remainingSeconds >= 2) {
|
||||
qty = remainingSeconds;
|
||||
string = "SECONDS";
|
||||
} else if (remainingSeconds === 1) {
|
||||
string = "SECOND";
|
||||
} else {
|
||||
string = "EXPIRED";
|
||||
}
|
||||
|
||||
return game.i18n.format(`VISUAL_ACTIVE_EFFECTS.TIME.${string}`, {qty});
|
||||
}
|
||||
|
||||
// Case 3: Neither rounds, turns, or seconds, so just return unlimited.
|
||||
return game.i18n.localize("VISUAL_ACTIVE_EFFECTS.TIME.UNLIMITED");
|
||||
}
|
||||
|
||||
/** Render the editor. */
|
||||
export function _renderEditor() {
|
||||
const editor = Object.values(this.apps).find(e => e instanceof VisualActiveEffectsEditor);
|
||||
if (editor) return editor.render();
|
||||
return new VisualActiveEffectsEditor(this).render(true);
|
||||
}
|
||||
|
||||
/** Refreshes the style sheet when a user changes the various css-related module settings. */
|
||||
export function applyStyleSettings() {
|
||||
const data = {};
|
||||
data["icon-size"] = Math.max(10, Math.round(game.settings.get(MODULE, ICON_SIZE) || 50));
|
||||
data["font-size"] = Math.max(6, Math.round(game.settings.get(MODULE, FONT_SIZE) || 16));
|
||||
data["max-width"] = Math.round(300 * data["font-size"] / 16);
|
||||
data["top-offset"] = Math.max(0, Math.round(game.settings.get(MODULE, TOP_OFFSET) || 25));
|
||||
const root = document.querySelector(":root");
|
||||
Object.entries(data).forEach(([key, val]) => root.style.setProperty(`--${MODULE}-${key}`, `${val}px`));
|
||||
}
|
||||
|
||||
/** Register API functions. */
|
||||
export function registerAPI() {
|
||||
game.modules.get(MODULE).api = {
|
||||
migrateWorldDescriptions: async function() {
|
||||
ui.notifications.info(`${MODULE.toUpperCase()} | Migrating actors and items in the sidebar. Please be patient.`);
|
||||
for (const item of game.items) await _migrateDocumentWithEffects(item);
|
||||
for (const actor of game.actors) await _migrateActor(actor);
|
||||
ui.notifications.info(`${MODULE.toUpperCase()} | Finished migrating sidebar actors and items.`);
|
||||
},
|
||||
migratePackDescriptions: async function(pack) {
|
||||
const isActor = pack.metadata.type === "Actor";
|
||||
const isItem = pack.metadata.type === "Item";
|
||||
if (!(isActor || isItem)) {
|
||||
console.warn(`${MODULE.toUpperCase()} | ${pack.metadata.label} (${pack.metadata.id}) is not a valid compendium type.`);
|
||||
return null;
|
||||
}
|
||||
ui.notifications.info(`${MODULE.toUpperCase()} | Migrating ${pack.metadata.label} (${pack.metadata.id}). Please be patient.`);
|
||||
const docs = await pack.getDocuments();
|
||||
const mig = isActor ? _migrateActor : _migrateDocumentWithEffects;
|
||||
for (const doc of docs) await mig(doc);
|
||||
ui.notifications.info(`${MODULE.toUpperCase()} | Finished migrating ${pack.metadata.label} (${pack.metadata.id}).`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function _migrateActor(actor) {
|
||||
await _migrateDocumentWithEffects(actor);
|
||||
for (const item of actor.items) {
|
||||
await _migrateDocumentWithEffects(item);
|
||||
}
|
||||
}
|
||||
|
||||
async function _migrateDocumentWithEffects(doc) {
|
||||
const updates = [];
|
||||
for (const effect of doc.effects) {
|
||||
const data = effect.flags[MODULE]?.data?.intro;
|
||||
if (data) updates.push({_id: effect.id, description: data});
|
||||
}
|
||||
if (updates.length) console.log(`${MODULE.toUpperCase()} | Migrating ${doc.name} (${doc.uuid})`);
|
||||
return doc.updateEmbeddedDocuments("ActiveEffect", updates);
|
||||
}
|
||||
119
src/modules/visual-active-effects/scripts/settings.mjs
Normal file
119
src/modules/visual-active-effects/scripts/settings.mjs
Normal file
@@ -0,0 +1,119 @@
|
||||
import {
|
||||
DAYS_PER_WEEK,
|
||||
EXTRA_DAYS_PER_YEAR,
|
||||
ICON_SIZE,
|
||||
MODULE,
|
||||
MONTHS_PER_YEAR,
|
||||
WEEKS_PER_MONTH,
|
||||
HIDE_DISABLED,
|
||||
HIDE_PASSIVE,
|
||||
FONT_SIZE,
|
||||
TOP_OFFSET,
|
||||
PLAYER_CLICKS
|
||||
} from "./constants.mjs";
|
||||
import {applyStyleSettings} from "./helpers.mjs";
|
||||
|
||||
export function registerSettings() {
|
||||
game.settings.register(MODULE, ICON_SIZE, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.ICON_SIZE.HINT",
|
||||
scope: "client",
|
||||
config: true,
|
||||
type: Number,
|
||||
default: 50,
|
||||
requiresReload: false,
|
||||
onChange: applyStyleSettings
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, FONT_SIZE, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.FONT_SIZE.HINT",
|
||||
scope: "client",
|
||||
config: true,
|
||||
type: Number,
|
||||
default: 16,
|
||||
requiresReload: false,
|
||||
onChange: applyStyleSettings
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, TOP_OFFSET, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.TOP_OFFSET.HINT",
|
||||
scope: "client",
|
||||
config: true,
|
||||
type: Number,
|
||||
default: 25,
|
||||
requiresReload: false,
|
||||
onChange: applyStyleSettings
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, HIDE_DISABLED, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_DISABLED.HINT",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
requiresReload: true
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, HIDE_PASSIVE, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.HIDE_PASSIVE.HINT",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: true,
|
||||
requiresReload: true
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, PLAYER_CLICKS, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.PLAYER_CLICKS.HINT",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: true,
|
||||
requiresReload: true
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, DAYS_PER_WEEK, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.DAYS_PER_WEEK.HINT",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Number,
|
||||
default: 9,
|
||||
requiresReload: true
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, WEEKS_PER_MONTH, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.WEEKS_PER_MONTH.HINT",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Number,
|
||||
default: 3,
|
||||
requiresReload: true
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, MONTHS_PER_YEAR, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.MONTHS_PER_YEAR.HINT",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Number,
|
||||
default: 12,
|
||||
requiresReload: true
|
||||
});
|
||||
|
||||
game.settings.register(MODULE, EXTRA_DAYS_PER_YEAR, {
|
||||
name: "VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.NAME",
|
||||
hint: "VISUAL_ACTIVE_EFFECTS.SETTINGS.EXTRA_DAYS_PER_YEAR.HINT",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Number,
|
||||
default: 1,
|
||||
requiresReload: true
|
||||
});
|
||||
}
|
||||
32
src/modules/visual-active-effects/scripts/setup.mjs
Normal file
32
src/modules/visual-active-effects/scripts/setup.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import {ICON, MODULE} from "./constants.mjs";
|
||||
import {_renderEditor, applyStyleSettings, registerAPI} from "./helpers.mjs";
|
||||
import {registerSettings} from "./settings.mjs";
|
||||
import {VisualActiveEffects} from "./visual-active-effects.mjs";
|
||||
|
||||
Hooks.once("init", registerSettings);
|
||||
Hooks.once("ready", async function() {
|
||||
await loadTemplates([
|
||||
"modules/visual-active-effects/templates/effect.hbs",
|
||||
"modules/visual-active-effects/templates/status.hbs"
|
||||
]);
|
||||
registerAPI();
|
||||
applyStyleSettings();
|
||||
const panel = new VisualActiveEffects();
|
||||
await panel.render(true);
|
||||
Hooks.on("collapseSidebar", panel.handleExpand.bind(panel));
|
||||
Hooks.on("updateWorldTime", panel.refresh.bind(panel, false));
|
||||
Hooks.on("controlToken", panel.refresh.bind(panel, true));
|
||||
for (const hook of ["createActiveEffect", "updateActiveEffect", "deleteActiveEffect"]) {
|
||||
Hooks.on(hook, function(effect) {
|
||||
if (effect.target === panel.actor) panel.refresh(true);
|
||||
});
|
||||
}
|
||||
Hooks.on("updateCombat", function(combat, update, context) {
|
||||
if (context.advanceTime !== 0) return;
|
||||
if (!context.direction) return;
|
||||
panel.refresh(false);
|
||||
});
|
||||
});
|
||||
Hooks.on("getActiveEffectConfigHeaderButtons", function(app, array) {
|
||||
array.unshift({class: MODULE, icon: ICON, onclick: _renderEditor.bind(app.document)});
|
||||
});
|
||||
124
src/modules/visual-active-effects/scripts/textEditor.mjs
Normal file
124
src/modules/visual-active-effects/scripts/textEditor.mjs
Normal file
@@ -0,0 +1,124 @@
|
||||
import {ICON, MODULE} from "./constants.mjs";
|
||||
|
||||
export default class VisualActiveEffectsEditor extends FormApplication {
|
||||
constructor(effect, ...T) {
|
||||
super(effect, ...T);
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
width: 450,
|
||||
height: 500,
|
||||
classes: [MODULE, "sheet"],
|
||||
resizable: true,
|
||||
scrollY: [],
|
||||
tabs: [{navSelector: ".tabs", contentSelector: "form", initial: "intro"}],
|
||||
dragDrop: [],
|
||||
closeOnSubmit: false
|
||||
});
|
||||
}
|
||||
|
||||
get title() {
|
||||
return game.i18n.format("VISUAL_ACTIVE_EFFECTS.EDITOR_TITLE", {name: this.effect.name});
|
||||
}
|
||||
|
||||
get template() {
|
||||
return `modules/${MODULE}/templates/vae-editor.hbs`;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return `${MODULE}-editor-${this.effect.uuid.replaceAll(".", "-")}`;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData() {
|
||||
const data = await super.getData();
|
||||
const flag = this.effect.getFlag(MODULE, "data") ?? {};
|
||||
|
||||
// Backwards compatibility.
|
||||
let inclusion;
|
||||
if ("inclusion" in flag) inclusion = flag.inclusion;
|
||||
else if (data.forceInclude === true) inclusion = 1;
|
||||
else inclusion = 0;
|
||||
|
||||
foundry.utils.mergeObject(data, {
|
||||
statuses: this.effect.statuses.size ? this.effect.statuses.toObject() : [""],
|
||||
inclusion: inclusion,
|
||||
content: await TextEditor.enrichHTML(flag.content || ""),
|
||||
intro: await TextEditor.enrichHTML(this.effect.description || ""),
|
||||
editable: this.isEditable,
|
||||
ICON: ICON
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
html[0].querySelector("[data-action='add-status']").addEventListener("click", this._onAddStatus.bind(this));
|
||||
html[0].querySelectorAll("[data-action='delete-status']").forEach(n => n.addEventListener("click", this._onDeleteStatus.bind(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle removing an old row for a status.
|
||||
* @param {PointerEvent} event The initiating click event.
|
||||
*/
|
||||
_onDeleteStatus(event) {
|
||||
event.currentTarget.closest(".form-group").remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle adding a new row for a status.
|
||||
* @param {PointerEvent} event The initiating click event.
|
||||
*/
|
||||
async _onAddStatus(event) {
|
||||
const force = event.currentTarget.closest(".config").querySelector(".form-group:last-child");
|
||||
const div = document.createElement("DIV");
|
||||
div.innerHTML = await renderTemplate("modules/visual-active-effects/templates/status.hbs", []);
|
||||
div.querySelector("[data-action='delete-status']").addEventListener("click", this._onDeleteStatus.bind(this));
|
||||
force.before(div.firstElementChild);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _updateObject(event, formData) {
|
||||
if (!formData.statuses) formData.statuses = [];
|
||||
else if (typeof formData.statuses === "string") formData.statuses = [formData.statuses];
|
||||
formData.statuses = formData.statuses.reduce((acc, s) => {
|
||||
s = s.trim();
|
||||
if (s) acc.push(s);
|
||||
return acc;
|
||||
}, []);
|
||||
ui.notifications.info("VISUAL_ACTIVE_EFFECTS.EDITOR_SAVED", {localize: true});
|
||||
if (event.submitter) this.close();
|
||||
const sheet = this.effect.sheet;
|
||||
if (sheet) formData = sheet._getSubmitData(formData);
|
||||
return this.effect.update(formData);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async activateEditor(name, options = {}, initialContent = "") {
|
||||
options.relativeLinks = false;
|
||||
options.plugins = {
|
||||
menu: ProseMirror.ProseMirrorMenu.build(ProseMirror.defaultSchema, {
|
||||
compact: true,
|
||||
destroyOnSave: false,
|
||||
onSave: () => this.saveEditor(name, {remove: true})
|
||||
})
|
||||
};
|
||||
return super.activateEditor(name, options, initialContent);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_render(...T) {
|
||||
this.effect.apps[this.appId] = this;
|
||||
return super._render(...T);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
close(...T) {
|
||||
delete this.effect.apps[this.appId];
|
||||
return super.close(...T);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
import {HIDE_DISABLED, HIDE_PASSIVE, MODULE, PLAYER_CLICKS} from "./constants.mjs";
|
||||
import {remainingTimeLabel} from "./helpers.mjs";
|
||||
|
||||
export class VisualActiveEffects extends Application {
|
||||
/**
|
||||
* Array of buttons for other modules.
|
||||
* @type {object[]}
|
||||
*/
|
||||
buttons = [];
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
id: MODULE,
|
||||
popOut: false,
|
||||
template: `modules/${MODULE}/templates/${MODULE}.hbs`,
|
||||
minimizable: false
|
||||
});
|
||||
}
|
||||
|
||||
/** @constructor */
|
||||
constructor() {
|
||||
super();
|
||||
this._initialSidebarWidth = ui.sidebar.element.outerWidth();
|
||||
this._playerClicks = game.settings.get(MODULE, PLAYER_CLICKS);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData() {
|
||||
const enabledEffects = [];
|
||||
const disabledEffects = [];
|
||||
const passiveEffects = [];
|
||||
|
||||
const fromActor = this._getEffectsFromActor();
|
||||
if (!fromActor) return {};
|
||||
const hideDisabled = game.settings.get(MODULE, HIDE_DISABLED);
|
||||
const hidePassive = game.settings.get(MODULE, HIDE_PASSIVE);
|
||||
|
||||
// Set up effects.
|
||||
for (const entry of fromActor) {
|
||||
|
||||
// Set up the various text (intro and content).
|
||||
const desc = entry.effect.flags["dfreds-convenient-effects"]?.description;
|
||||
const data = entry.effect.flags[MODULE]?.data ?? {};
|
||||
|
||||
// Get the effect rollData to populate enrichers within the descriptions.
|
||||
let rollData;
|
||||
try {
|
||||
if (entry.effect.origin) {
|
||||
let origin = fromUuidSync(entry.effect.origin);
|
||||
if (origin?.documentName === ActiveEffect.documentName) {
|
||||
// Change the origin to the parent of the ActiveEffect - the originating item or actor.
|
||||
origin = origin.parent;
|
||||
}
|
||||
if (origin?.pack) {
|
||||
// Origin references a compendium, change the origin to the effect's parent - the local item or actor.
|
||||
origin = entry.effect.parent;
|
||||
}
|
||||
if (typeof origin?.getRollData === "function") {
|
||||
rollData = origin.getRollData();
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to the parent if there's no rollData.
|
||||
if (!rollData) rollData = entry.effect.parent.getRollData();
|
||||
} catch (_) {
|
||||
// Fallback to just an empty object - enrichers will show empty values in this case.
|
||||
rollData = {};
|
||||
}
|
||||
|
||||
// Backwards compatibility.
|
||||
let inclusion = 0;
|
||||
if ("inclusion" in data) inclusion = data.inclusion;
|
||||
else if (data.forceInclude) inclusion = 1;
|
||||
|
||||
// Always exclude?
|
||||
const forceExclude = data.inclusion === -1;
|
||||
if (forceExclude) continue;
|
||||
|
||||
// Set up intro if it exists.
|
||||
const intro = entry.effect.description || desc;
|
||||
if (intro) entry.context.strings.intro = await TextEditor.enrichHTML(intro, {rollData});
|
||||
|
||||
// Set up content if it exists.
|
||||
if (data.content?.length) {
|
||||
// The 'header' for the collapsible's header with default 'Details'.
|
||||
entry.context.strings.header = data.header || game.i18n.localize("VISUAL_ACTIVE_EFFECTS.LABELS.DETAILS");
|
||||
// The collapsible content.
|
||||
entry.context.strings.content = await TextEditor.enrichHTML(data.content, {rollData});
|
||||
}
|
||||
|
||||
entry.context.hasText = !!intro || !!data.content?.length || !!entry.context.buttons.length;
|
||||
|
||||
// Add to either disabled array, enabled array, or passive array.
|
||||
if (entry.effect.disabled) {
|
||||
if (!hideDisabled || (inclusion === 1)) disabledEffects.push(entry);
|
||||
}
|
||||
else if (entry.effect.isTemporary) enabledEffects.push(entry);
|
||||
else if (!hidePassive || (inclusion === 1)) passiveEffects.push(entry);
|
||||
}
|
||||
return {enabledEffects, disabledEffects, passiveEffects};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getData, extracting each effect, filtering the suppressed, and returning it with additional context.
|
||||
* @returns {object[]} An array with 'effect' and 'context'.
|
||||
*/
|
||||
_getEffectsFromActor() {
|
||||
if (!this.actor) return;
|
||||
const data = [];
|
||||
const effects = this.actor.allApplicableEffects();
|
||||
for (const effect of effects) {
|
||||
if (effect.isSuppressed) continue;
|
||||
const context = {strings: {intro: "", content: ""}};
|
||||
if (effect.isTemporary) {
|
||||
const rem = effect.duration.remaining;
|
||||
context.isExpired = Number.isNumeric(rem) && (rem <= 0);
|
||||
context.isInfinite = rem === null;
|
||||
context.durationLabel = remainingTimeLabel(effect);
|
||||
}
|
||||
const buttons = [];
|
||||
|
||||
/**
|
||||
* A hook that is called such that other modules can add buttons to the description of an effect
|
||||
* on the panel. Each object pushed into the array must have 'label' and a function 'callback'.
|
||||
* @param {ActiveEffect} effect The original effect.
|
||||
* @param {Array} buttons An array of buttons.
|
||||
*/
|
||||
Hooks.callAll("visual-active-effects.createEffectButtons", effect, buttons);
|
||||
|
||||
// Filter out invalid buttons and push valid ones into this.buttons in one go.
|
||||
context.buttons = buttons.reduce((acc, b) => {
|
||||
if (!(typeof b.label === "string") || !(b.callback instanceof Function)) return acc;
|
||||
b.id = foundry.utils.randomID();
|
||||
this.buttons.push(b);
|
||||
acc.push(b);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
data.push({effect, context});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getData.
|
||||
* @param {object} duration An effect's duration object.
|
||||
* @returns {number} The time remaining.
|
||||
*/
|
||||
_getSecondsRemaining(duration) {
|
||||
if (duration.seconds || duration.rounds) {
|
||||
const seconds = duration.seconds ?? duration.rounds * (CONFIG.time.roundTime ?? 6);
|
||||
return duration.startTime + seconds - game.time.worldTime;
|
||||
} else return Infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* The currently selected token's actor, otherwise the user's assigned actor.
|
||||
* @type {Actor|null}
|
||||
*/
|
||||
get actor() {
|
||||
return canvas.tokens.controlled[0]?.actor ?? game.user.character;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _render(force = false, options = {}) {
|
||||
if (!force && this.element[0].closest(".panel").classList.contains("hovered")) {
|
||||
this._needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
await super._render(force, options);
|
||||
this._needsRefresh = false;
|
||||
if (ui.sidebar._collapsed) this.element.css("right", "50px");
|
||||
else this.element.css("right", `${this._initialSidebarWidth + 18}px`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounce rendering of the app.
|
||||
* @param {boolean} force Whether to force the rendering of the app.
|
||||
* @returns {Promise<VisualActiveEffects>} This application.
|
||||
*/
|
||||
async refresh(force) {
|
||||
return foundry.utils.debounce(this.render.bind(this, force), 100)();
|
||||
}
|
||||
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
if (this._playerClicks || game.user.isGM) {
|
||||
html[0].querySelectorAll(".effect-icon").forEach(n => n.addEventListener("contextmenu", this.onIconRightClick.bind(this)));
|
||||
html[0].querySelectorAll(".effect-icon").forEach(n => n.addEventListener("dblclick", this.onIconDoubleClick.bind(this)));
|
||||
}
|
||||
html[0].querySelectorAll(".collapsible-header").forEach(n => n.addEventListener("click", this.onCollapsibleClick.bind(this)));
|
||||
html[0].querySelectorAll("[data-action='custom-button']").forEach(n => n.addEventListener("click", this.onClickCustomButton.bind(this)));
|
||||
html[0].addEventListener("mouseover", this._onMouseOver.bind(this));
|
||||
html[0].addEventListener("mouseout", this._onMouseOver.bind(this));
|
||||
html[0].addEventListener("mouseover", this.bringToTop.bind(this));
|
||||
html[0].querySelectorAll(".effect-item").forEach(n => n.addEventListener("mouseenter", this._onMouseEnter.bind(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum height of effect descriptions.
|
||||
* @param {Event} event Initiating hover event.
|
||||
*/
|
||||
_onMouseEnter(event) {
|
||||
const info = event.currentTarget.querySelector(".effect-intro");
|
||||
if (!info) return;
|
||||
const win = window.innerHeight;
|
||||
info.style.maxHeight = `${win - info.getBoundingClientRect().top - 350}px`;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
bringToTop(event) {
|
||||
const element = event.currentTarget;
|
||||
const z = document.defaultView.getComputedStyle(element).zIndex;
|
||||
if (z < _maxZ) {
|
||||
element.style.zIndex = Math.min(++_maxZ, 99999);
|
||||
ui.activeWindow = this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save whether the application is being moused over.
|
||||
* @param {Event} event The initiating mouseover or mouseout event.
|
||||
* @returns {Promise<void|VisualActiveEffects>}
|
||||
*/
|
||||
_onMouseOver(event) {
|
||||
const state = event.type === "mouseover";
|
||||
const target = event.currentTarget;
|
||||
target.classList.toggle("hovered", state);
|
||||
if (!state && (this._needsRefresh === true)) return this.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* When a button on the panel is clicked.
|
||||
* @param {Event} event The initiating click event.
|
||||
* @returns {Promise} Result of the callback function.
|
||||
*/
|
||||
async onClickCustomButton(event) {
|
||||
const id = event.currentTarget.dataset.id;
|
||||
const button = this.buttons.find(b => b.id === id);
|
||||
return button.callback(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to move the panel when the sidebar is collapsed or expanded.
|
||||
* @param {Sidebar} _ The sidebar.
|
||||
* @param {boolean} bool Whether it was collapsed.
|
||||
*/
|
||||
handleExpand(_, bool) {
|
||||
if (!bool) {
|
||||
const right = `${this._initialSidebarWidth + 18}px`;
|
||||
this.element.css("right", right);
|
||||
} else this.element.delay(50).animate({right: "50px"}, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle deleting an effect when right-clicked.
|
||||
* @param {Event} event The initiating click event.
|
||||
* @returns {Promise<ActiveEffect|boolean>} Either the deleted effect, or the result of the prompt.
|
||||
*/
|
||||
async onIconRightClick(event) {
|
||||
const alt = event.shiftKey;
|
||||
const effect = await fromUuid(event.currentTarget.closest("[data-effect-uuid]").dataset.effectUuid);
|
||||
return (alt && game.user.isGM) ? effect.delete() : effect.deleteDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle enabling/disabling an effect when double-clicked, or showing its sheet.
|
||||
* @param {Event} event The initiating click event.
|
||||
* @returns {Promise<ActiveEffect|ActiveEffectConfig>} The updated effect or its sheet.
|
||||
*/
|
||||
async onIconDoubleClick(event) {
|
||||
const alt = event.ctrlKey;
|
||||
const effect = await fromUuid(event.currentTarget.closest("[data-effect-uuid]").dataset.effectUuid);
|
||||
return alt ? effect.sheet.render(true) : effect.update({disabled: !effect.disabled});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle collapsing the description of an effect.
|
||||
* @param {Event} event The initiating click event.
|
||||
*/
|
||||
onCollapsibleClick(event) {
|
||||
const section = event.currentTarget.closest(".collapsible-section");
|
||||
section.classList.toggle("active");
|
||||
const div = section.querySelector(".collapsible-content");
|
||||
const header = event.currentTarget;
|
||||
const win = window.innerHeight;
|
||||
div.style.maxHeight = `${win - (150 + header.getBoundingClientRect().bottom)}px`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
:root {
|
||||
--vae-border-color-temporary: rgba(158, 192, 255, 0.705);
|
||||
--vae-border-color-passive: rgba(255, 242, 167, 0.664);
|
||||
--vae-border-color-disabled: rgba(194, 0, 0, 0.61);
|
||||
--vae-dropshadow: drop-shadow(3px 3px 4px rgb(83, 83, 83));
|
||||
--vae-backdrop-color: rgb(49, 49, 49);
|
||||
--vae-button-color-font: rgba(255, 255, 255, 0.664);
|
||||
--vae-button-color-backdrop: rgb(100, 100, 100);
|
||||
--vae-name-color: rgb(255, 255, 255);
|
||||
--vae-name-border: 1px dashed rgba(133, 133, 133, 0.582);
|
||||
--vae-name-font: 'Amiri';
|
||||
--vae-tag-border: 1px solid rgb(197, 197, 197);
|
||||
--vae-tag-color-duration: rgba(100, 100, 255, 0.5);
|
||||
--vae-tag-color-disabled: rgba(255, 100, 100, 0.5);
|
||||
--vae-tag-color-source: rgba(255, 100, 255, 0.5);
|
||||
}
|
||||
|
||||
/* ------------------------- */
|
||||
/* */
|
||||
/* EDITOR */
|
||||
/* */
|
||||
/* ------------------------- */
|
||||
.visual-active-effects.sheet {
|
||||
min-width: 450px;
|
||||
min-height: 400px;
|
||||
|
||||
& form {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr 0fr;
|
||||
|
||||
.inputs {
|
||||
display: grid;
|
||||
grid-template-rows: 0fr 0fr 1fr;
|
||||
}
|
||||
|
||||
.sections {
|
||||
position: relative;
|
||||
|
||||
.tab {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.inclusion label {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.inclusion select {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-action="delete-status"] {
|
||||
flex: 0;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
& label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.status-header {
|
||||
height: 28px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid var(--color-border-light-tertiary);
|
||||
font-weight: bold;
|
||||
padding: 3px 7px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------- */
|
||||
/* */
|
||||
/* EFFECTS PANEL */
|
||||
/* */
|
||||
/* ------------------------- */
|
||||
.visual-active-effects.panel {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
top: var(--visual-active-effects-top-offset);
|
||||
filter: var(--vae-dropshadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: calc(var(--visual-active-effects-icon-size)/5);
|
||||
overflow: visible;
|
||||
max-height: calc(100% - 50px);
|
||||
|
||||
.effect-item {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
height: var(--visual-active-effects-icon-size);
|
||||
max-width: var(--visual-active-effects-icon-size);
|
||||
|
||||
&:hover {
|
||||
max-width: unset;
|
||||
|
||||
.effect-info {
|
||||
height: fit-content;
|
||||
margin: 0 calc(max(1.5rem, var(--visual-active-effects-icon-size)/5)) 0 0;
|
||||
padding: 8px;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
max-width: var(--visual-active-effects-max-width);
|
||||
min-width: var(--visual-active-effects-max-width);
|
||||
}
|
||||
|
||||
.effect-icon {
|
||||
transform: scale(1.2);
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
|
||||
.effect-info {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
max-width: 0;
|
||||
min-width: 0;
|
||||
filter: var(--vae-dropshadow);
|
||||
background-color: var(--vae-backdrop-color);
|
||||
transition: opacity 0.15s linear;
|
||||
border-left: 10px solid;
|
||||
border-radius: 2px;
|
||||
overflow: hidden auto;
|
||||
|
||||
&.temporary {
|
||||
border-color: var(--vae-border-color-temporary);
|
||||
}
|
||||
&.passive {
|
||||
border-color: var(--vae-border-color-passive);
|
||||
}
|
||||
&.disabled {
|
||||
border-color: var(--vae-border-color-disabled);
|
||||
}
|
||||
|
||||
.effect-info-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: var(--vae-name-border);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: var(--vae-name-color);
|
||||
text-align: center;
|
||||
padding: 0 4px;
|
||||
margin: 0;
|
||||
font-size: 1.6rem;
|
||||
font-family: var(--vae-name-font);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
&.simple .effect-tags {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.effect-icon {
|
||||
background-size: contain;
|
||||
box-shadow: 0 0 0 1px silver, 0 0 0 2px gray, inset 0 0 4px rgba(0, 0, 0, 0.5);
|
||||
height: var(--visual-active-effects-icon-size);
|
||||
width: var(--visual-active-effects-icon-size);
|
||||
min-width: var(--visual-active-effects-icon-size);
|
||||
position: relative;
|
||||
transition: transform 0.15s;
|
||||
|
||||
&.disabled {
|
||||
filter: brightness(0.25) grayscale(1);
|
||||
}
|
||||
|
||||
.badge {
|
||||
bottom: 5%;
|
||||
color: white;
|
||||
display: inline-block;
|
||||
left: 5%;
|
||||
position: absolute;
|
||||
text-shadow: 0 0 5px black;
|
||||
font-size: calc(var(--visual-active-effects-icon-size)/3);
|
||||
pointer-events: none;
|
||||
|
||||
&.unlimited {
|
||||
font-size: calc(var(--visual-active-effects-icon-size)/4);
|
||||
}
|
||||
&.expired {
|
||||
color: orange;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.effect-info-details {
|
||||
gap: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0.5em 0;
|
||||
overflow: hidden;
|
||||
|
||||
.inline-roll, .content-link {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.effect-intro,
|
||||
.collapsible-content {
|
||||
color: rgb(192, 192, 192);
|
||||
padding: 0 0.5rem;
|
||||
font-style: italic;
|
||||
font-family: sans-serif;
|
||||
overflow: hidden auto;
|
||||
font-size: var(--visual-active-effects-font-size);
|
||||
}
|
||||
|
||||
.collapsible-section {
|
||||
|
||||
.collapsible-header {
|
||||
cursor: pointer;
|
||||
background-color: var(--vae-button-color-backdrop);
|
||||
border: 1px solid #e2ffca50;
|
||||
border-bottom: none;
|
||||
border-radius: 2px 2px 0 0;
|
||||
color: var(--vae-button-color-font);
|
||||
font-weight: bold;
|
||||
font-family: "Modesto Condensed";
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
padding: 4px;
|
||||
padding-left: 10px;
|
||||
|
||||
&::after {
|
||||
content: "\02795";
|
||||
float: right;
|
||||
filter: brightness(10);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.collapsible-content {
|
||||
overflow: hidden;
|
||||
border: 1px solid #e2ffca50;
|
||||
border-top: none;
|
||||
border-radius: 0 0 2px 2px;
|
||||
transition: max-height 0.15s ease-out, opacity 0.15s ease-out;
|
||||
font-size: calc(var(--visual-active-effects-font-size) - 2px);
|
||||
}
|
||||
|
||||
&.active {
|
||||
.collapsible-header::after {
|
||||
content: "\2796";
|
||||
}
|
||||
|
||||
.collapsible-content {
|
||||
opacity: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.active) {
|
||||
.collapsible-content {
|
||||
max-height: 0 !important;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.effect-tags {
|
||||
display: flex;
|
||||
gap: 3px;
|
||||
color: white;
|
||||
margin-bottom: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
.effect-tag {
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
text-transform: uppercase;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
font-size: 11px;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 1px;
|
||||
border-radius: 2px;
|
||||
border: var(--vae-tag-border);
|
||||
}
|
||||
|
||||
&.temporary {
|
||||
background-color: var(--vae-tag-color-duration);
|
||||
}
|
||||
&.disabled {
|
||||
background-color: var(--vae-tag-color-disabled);
|
||||
}
|
||||
&.source {
|
||||
background-color: var(--vae-tag-color-source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& hr.divider {
|
||||
margin-right: 0;
|
||||
width: var(--visual-active-effects-icon-size);
|
||||
}
|
||||
|
||||
.vae-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
|
||||
.vae-button {
|
||||
z-index: 1;
|
||||
background-color: var(--vae-button-color-backdrop);
|
||||
color: var(--vae-button-color-font);
|
||||
font-family: 'Modesto Condensed';
|
||||
font-size: 20px;
|
||||
transition: box-shadow 150ms;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 5px white;
|
||||
}
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/modules/visual-active-effects/templates/effect.hbs
Normal file
68
src/modules/visual-active-effects/templates/effect.hbs
Normal file
@@ -0,0 +1,68 @@
|
||||
<div class="effect-item" data-effect-id="{{effect._id}}" data-effect-uuid="{{effect.uuid}}">
|
||||
<div class="effect-info {{cssClass}} {{#unless context.hasText}} simple {{/unless}}">
|
||||
<h1 class="effect-info-header">
|
||||
<span class="name">{{effect.name}}</span>
|
||||
<div class="effect-tags">
|
||||
<div class="effect-tag temporary">
|
||||
{{#if context.durationLabel}}
|
||||
<i class="fa-solid fa-hourglass"></i>
|
||||
{{context.durationLabel}}
|
||||
{{else}}
|
||||
<i class="fa-solid fa-feather"></i>
|
||||
{{localize "VISUAL_ACTIVE_EFFECTS.LABELS.PASSIVE"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if effect.disabled}}
|
||||
<div class="effect-tag disabled">
|
||||
<i class="fa-solid fa-ban"></i>
|
||||
{{localize "VISUAL_ACTIVE_EFFECTS.LABELS.DISABLED"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if effect.sourceName}}
|
||||
<div class="effect-tag source">
|
||||
<i class="fa-solid fa-tree"></i>
|
||||
{{localize "VISUAL_ACTIVE_EFFECTS.LABELS.SOURCE"}}: {{effect.sourceName}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
{{#if (or context.strings.intro context.strings.content)}}
|
||||
<div class="effect-info-details">
|
||||
{{#if context.strings.intro}}
|
||||
<div class="effect-intro">{{{context.strings.intro}}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if context.strings.content}}
|
||||
<section class="collapsible-section">
|
||||
<header class="collapsible-header">{{context.strings.header}}</header>
|
||||
<div class="collapsible-content">{{{context.strings.content}}}</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if context.buttons.length}}
|
||||
<div class="vae-buttons">
|
||||
{{#each context.buttons}}
|
||||
<button type="button" class="vae-button" data-action="custom-button" data-id="{{id}}">{{label}}</button>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="effect-icon {{#if effect.disabled}}disabled{{/if}}" style="background-image: url({{effect.icon}})">
|
||||
{{#if effect.isTemporary}}
|
||||
{{#if context.isExpired}}
|
||||
<i class="expired badge fa-solid fa-clock"></i>
|
||||
{{else if context.isInfinite}}
|
||||
<i class="unlimited badge fa-solid fa-infinity"></i>
|
||||
{{else}}
|
||||
<i class="badge fa-solid fa-clock"></i>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
7
src/modules/visual-active-effects/templates/status.hbs
Normal file
7
src/modules/visual-active-effects/templates/status.hbs
Normal file
@@ -0,0 +1,7 @@
|
||||
<div class="form-group status">
|
||||
<label>{{localize "VISUAL_ACTIVE_EFFECTS.STATUS_ID"}}</label>
|
||||
<div class="form-fields">
|
||||
<input type="text" name="statuses" value="{{this}}">
|
||||
<a data-action="delete-status"><i class="fa-solid fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
52
src/modules/visual-active-effects/templates/vae-editor.hbs
Normal file
52
src/modules/visual-active-effects/templates/vae-editor.hbs
Normal file
@@ -0,0 +1,52 @@
|
||||
<form class="visual-active-effects" autocomplete="off">
|
||||
<div class="inputs">
|
||||
<div class="config">
|
||||
<div class="status-header">
|
||||
{{localize "VISUAL_ACTIVE_EFFECTS.Statuses"}}
|
||||
<a data-action="add-status"><i class="fa-solid fa-plus-square"></i></a>
|
||||
</div>
|
||||
{{#each statuses}}
|
||||
|
||||
{{> "modules/visual-active-effects/templates/status.hbs"}}
|
||||
|
||||
{{/each}}
|
||||
<div class="form-group">
|
||||
<label>{{localize "VISUAL_ACTIVE_EFFECTS.INCLUSION"}}</label>
|
||||
<div class="form-fields inclusion">
|
||||
<select data-dtype="Number" name="flags.visual-active-effects.data.inclusion">
|
||||
{{#select inclusion}}
|
||||
<option value="0">—</option>
|
||||
<option value="1">{{localize "VISUAL_ACTIVE_EFFECTS.INCLUSION_INCLUDE"}}</option>
|
||||
<option value="-1">{{localize "VISUAL_ACTIVE_EFFECTS.INCLUSION_EXCLUDE"}}</option>
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="sheet-tabs tabs" aria-role="Form Tab Navigation">
|
||||
<a class="item" data-tab="intro">
|
||||
<i class="{{ICON}}"></i>
|
||||
{{localize "VISUAL_ACTIVE_EFFECTS.INTRO"}}
|
||||
</a>
|
||||
<a class="item" data-tab="content">
|
||||
<i class="{{ICON}}"></i>
|
||||
{{localize "VISUAL_ACTIVE_EFFECTS.CONTENT"}}
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="sections">
|
||||
<div class="tab flexrow" data-tab="intro">
|
||||
{{editor intro target="description" button=true editable=editable engine="prosemirror" collaborate=false}}
|
||||
</div>
|
||||
<div class="tab flexrow" data-tab="content">
|
||||
{{editor content target="flags.visual-active-effects.data.content" button=true editable=editable engine="prosemirror" collaborate=false}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="sheet-footer">
|
||||
<button type="submit"><i class="fa-solid fa-save"></i> {{localize "Save"}}</button>
|
||||
</footer>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,23 @@
|
||||
<section id="visual-active-effects" class="panel visual-active-effects">
|
||||
|
||||
{{#each enabledEffects}}
|
||||
{{> "modules/visual-active-effects/templates/effect.hbs" cssClass="temporary"}}
|
||||
{{/each}}
|
||||
|
||||
{{#if (and passiveEffects.length enabledEffects.length)}}
|
||||
<hr class="divider">
|
||||
{{/if}}
|
||||
|
||||
{{#each passiveEffects}}
|
||||
{{> "modules/visual-active-effects/templates/effect.hbs" cssClass="passive"}}
|
||||
{{/each}}
|
||||
|
||||
{{#if (and disabledEffects.length (or enabledEffects.length passiveEffects.length))}}
|
||||
<hr class="divider">
|
||||
{{/if}}
|
||||
|
||||
{{#each disabledEffects}}
|
||||
{{> "modules/visual-active-effects/templates/effect.hbs" cssClass="disabled"}}
|
||||
{{/each}}
|
||||
|
||||
</section>
|
||||
Reference in New Issue
Block a user