burrow and boost lower trait
This commit is contained in:
parent
cf30214502
commit
f50a81a329
@ -25,12 +25,12 @@ export class PowerFormApplication extends FormApplication {
|
|||||||
if (a.isGlobal !== b.isGlobal) {
|
if (a.isGlobal !== b.isGlobal) {
|
||||||
return a.isGlobal ? -1 : 1;
|
return a.isGlobal ? -1 : 1;
|
||||||
}
|
}
|
||||||
if (a.type !== b.type) {
|
|
||||||
return a.type === 'checkbox' ? -1 : 1;
|
|
||||||
}
|
|
||||||
if ((a.sortOrder ?? 0) !== (b.sortOrder ?? 0)) {
|
if ((a.sortOrder ?? 0) !== (b.sortOrder ?? 0)) {
|
||||||
return (a.sortOrder ?? 0) < (b.sortOrder ?? 0) ? -1 : 1;
|
return (a.sortOrder ?? 0) < (b.sortOrder ?? 0) ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
if (a.type !== b.type) {
|
||||||
|
return a.type === 'checkbox' ? -1 : 1;
|
||||||
|
}
|
||||||
return a.name === b.name ? 0 : a.name < b.name ? -1 : 1;
|
return a.name === b.name ? 0 : a.name < b.name ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
204
src/module/powers/boostLowerTrait.js
Normal file
204
src/module/powers/boostLowerTrait.js
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
import { moduleName } from '../globals.js';
|
||||||
|
import { PowerEffect } from './basePowers.js';
|
||||||
|
|
||||||
|
export class BoostLowerTraitEffect extends PowerEffect {
|
||||||
|
get name() {
|
||||||
|
return 'Boost/Lower Trait';
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasAdditionalRecipients() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get additionalRecipientCost() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
get icon() {
|
||||||
|
return this?.data?.direction === 'Boost'
|
||||||
|
? 'icons/magic/life/cross-embers-glow-yellow-purple.webp'
|
||||||
|
: 'icons/magic/movement/chevrons-down-yellow.webp';
|
||||||
|
}
|
||||||
|
|
||||||
|
get duration() {
|
||||||
|
return this?.data?.direction === 'Boost' ? 5 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isTargeted() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get basePowerPoints() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrimaryEffectChanges() {
|
||||||
|
let modValue = '2';
|
||||||
|
if (this.data.raise) {
|
||||||
|
modValue = '4';
|
||||||
|
}
|
||||||
|
modValue = (this.data.direction === 'Boost' ? '+' : '-') + modValue;
|
||||||
|
const changes = [
|
||||||
|
{
|
||||||
|
key: this.data.trait.diekey,
|
||||||
|
value: modValue,
|
||||||
|
priority: 0,
|
||||||
|
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (this.data.direction === 'Lower' && this.data.greater) {
|
||||||
|
changes.push({
|
||||||
|
key: this.data.trait.modkey,
|
||||||
|
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||||
|
value: -2,
|
||||||
|
priority: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createSecondaryEffects(maintId) {
|
||||||
|
const docs = await super.createSecondaryEffects(maintId);
|
||||||
|
if (this.data.raise && this.data.direction === 'Lower') {
|
||||||
|
const name = 'major ' + this.effectName;
|
||||||
|
const modValue = this.data.direction === 'Boost' ? '+2' : '-2';
|
||||||
|
const changes = [
|
||||||
|
{
|
||||||
|
key: this.data.trait.diekey,
|
||||||
|
value: modValue,
|
||||||
|
priority: 0,
|
||||||
|
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const doc = this.createEffectDocument(this.icon, name, changes);
|
||||||
|
doc.duration.seconds = 594;
|
||||||
|
doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>';
|
||||||
|
doc.flags[moduleName].maintId = maintId;
|
||||||
|
docs.push(doc);
|
||||||
|
}
|
||||||
|
return docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
get effectName() {
|
||||||
|
let name = `${this.data.direction} ${this.data.trait.name}`;
|
||||||
|
const nameMods = [];
|
||||||
|
if (this.data.greater) {
|
||||||
|
nameMods.push('Greater');
|
||||||
|
}
|
||||||
|
if (this.data.direction === 'Lower' && this.data.strong) {
|
||||||
|
nameMods.push('Strong');
|
||||||
|
}
|
||||||
|
if (nameMods.length > 0) {
|
||||||
|
name += ` (${nameMods.join(', ')})`;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get description() {
|
||||||
|
let desc = super.description;
|
||||||
|
const amount = `${this.data.raise ? 2 : 1} die type${this.data.raise ? 's' : ''}`;
|
||||||
|
desc += `<p>${this.data.direction === 'Boost' ? 'Raise' : 'Lower'} the
|
||||||
|
target's ${this.data.trait.name} die type ${amount}.`;
|
||||||
|
if (this.data.greater) {
|
||||||
|
if (this.data.direction === 'Boost') {
|
||||||
|
desc += ` Additionally, the target gains a free ${this.data.trait.name}
|
||||||
|
reroll once per ${this.data.raise ? 'action' : 'round'}.`;
|
||||||
|
} else {
|
||||||
|
desc += ` Additionally, the target suffers a -2 penalty to their
|
||||||
|
${this.data.trait.name} rolls.`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
desc += '</p>';
|
||||||
|
if (this.data.direction === 'Lower') {
|
||||||
|
desc += `<p>At the end of the target's following turns, they attempt to shake off
|
||||||
|
the affect with a Spirit${this.data.strong ? ' -2' : ''}
|
||||||
|
roll as a free action. Success reduces the effect one die type. A raise
|
||||||
|
completely shakes off the effect.</p>`;
|
||||||
|
}
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
get modifiers() {
|
||||||
|
const mods = super.modifiers;
|
||||||
|
let traitOptions = ['Agility', 'Smarts', 'Spirit', 'Strength', 'Vigor'];
|
||||||
|
const allSkills = new Set();
|
||||||
|
const traits = {};
|
||||||
|
for (const traitName of traitOptions) {
|
||||||
|
const lower = traitName.toLowerCase();
|
||||||
|
traits[traitName] = {
|
||||||
|
name: traitName,
|
||||||
|
type: 'attribute',
|
||||||
|
modkey: `system.attributes.${lower}.die.modifier`,
|
||||||
|
diekey: `system.attributes.${lower}.die.sides`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (const token of this.targets) {
|
||||||
|
const skills = token.actor.items.filter((item) => item.type === 'skill');
|
||||||
|
for (const skill of skills) {
|
||||||
|
const name = skill.name;
|
||||||
|
traits[name] = {
|
||||||
|
name,
|
||||||
|
type: 'skill',
|
||||||
|
modkey: `@Skill{${name}}[system.die.modifier]`,
|
||||||
|
diekey: `@Skill{${name}}[system.die.sides]`,
|
||||||
|
};
|
||||||
|
if (name !== 'Unskilled') {
|
||||||
|
allSkills.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
traitOptions = traitOptions.concat(Array.from(allSkills).sort());
|
||||||
|
const traitChoices = {};
|
||||||
|
const traitValues = {};
|
||||||
|
const traitEffects = {};
|
||||||
|
for (const trait of traitOptions) {
|
||||||
|
traitChoices[trait] = trait;
|
||||||
|
traitValues[trait] = 0;
|
||||||
|
traitEffects[trait] = null;
|
||||||
|
}
|
||||||
|
this.data.traits = traits;
|
||||||
|
mods.push({
|
||||||
|
sortOrder: -2,
|
||||||
|
name: 'Boost or Lower?',
|
||||||
|
id: 'direction',
|
||||||
|
type: 'radio',
|
||||||
|
default: 'Boost',
|
||||||
|
epic: false,
|
||||||
|
choices: { Boost: 'Boost', Lower: 'Lower' },
|
||||||
|
effects: { Boost: null, Lower: null },
|
||||||
|
values: { Boost: 0, Lower: 0 },
|
||||||
|
});
|
||||||
|
mods.push({
|
||||||
|
sortOrder: -1,
|
||||||
|
name: 'Trait',
|
||||||
|
id: 'traitName',
|
||||||
|
type: 'select',
|
||||||
|
epic: false,
|
||||||
|
choices: traitChoices,
|
||||||
|
values: traitValues,
|
||||||
|
effects: traitEffects,
|
||||||
|
});
|
||||||
|
mods.push({
|
||||||
|
name: 'Greater Boost/Lower Trailt',
|
||||||
|
type: 'checkbox',
|
||||||
|
value: 2,
|
||||||
|
id: 'greater',
|
||||||
|
epic: true,
|
||||||
|
effect: false,
|
||||||
|
});
|
||||||
|
mods.push({
|
||||||
|
name: 'Strong (lower only)',
|
||||||
|
type: 'checkbox',
|
||||||
|
value: 1,
|
||||||
|
id: 'strong',
|
||||||
|
epic: false,
|
||||||
|
effect: false,
|
||||||
|
});
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
async parseValues() {
|
||||||
|
await super.parseValues();
|
||||||
|
this.data.trait = this.data.traits[this.data.traitName];
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/module/powers/burrow.js
Normal file
58
src/module/powers/burrow.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { PowerEffect } from './basePowers.js';
|
||||||
|
|
||||||
|
export class BurrowEffect extends PowerEffect {
|
||||||
|
get name() {
|
||||||
|
return 'Burrow';
|
||||||
|
}
|
||||||
|
|
||||||
|
get duration() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
get icon() {
|
||||||
|
return 'icons/magic/earth/projectile-stone-landslide.webp';
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasAdditionalRecipients() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get additionalRecipientCost() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
get basePowerPoints() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isTargeted() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get modifiers() {
|
||||||
|
const mods = super.modifiers;
|
||||||
|
mods.push({
|
||||||
|
name: 'Power',
|
||||||
|
type: 'checkbox',
|
||||||
|
id: 'power',
|
||||||
|
value: 1,
|
||||||
|
epic: false,
|
||||||
|
effect: false,
|
||||||
|
});
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
get effectName() {
|
||||||
|
return `${this.name} ${this.data.power ? '[Power] ' : ''}` + `(${this.data.raise ? 'full' : 'half'} pace)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get description() {
|
||||||
|
let text =
|
||||||
|
super.description +
|
||||||
|
`<p>Meld into the ground. Move at ${this.data.raise ? 'full' : 'half'} pace. May not run.</p>`;
|
||||||
|
if (this.data.power) {
|
||||||
|
text += '<p>Can <em>burrow</em> through solid stone, concrete, etc</p>';
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,251 +8,8 @@ import { BeastFriendEffect } from './beastFriend.js';
|
|||||||
import { BlastEffect } from './blast.js';
|
import { BlastEffect } from './blast.js';
|
||||||
import { BlindEffect } from './blind.js';
|
import { BlindEffect } from './blind.js';
|
||||||
import { BoltEffect } from './bolt.js';
|
import { BoltEffect } from './bolt.js';
|
||||||
|
import { BurrowEffect } from './burrow.js';
|
||||||
class BurrowEffect extends PowerEffect {
|
import { BoostLowerTraitEffect } from './boostLowerTrait.js';
|
||||||
get name() {
|
|
||||||
return 'Burrow';
|
|
||||||
}
|
|
||||||
|
|
||||||
get duration() {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return 'icons/magic/earth/projectile-stone-landslide.webp';
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasAdditionalRecipients() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get additionalRecipientCost() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
get basePowerPoints() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isTargeted() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get modifiers() {
|
|
||||||
const mods = super.modifiers;
|
|
||||||
mods.push({
|
|
||||||
name: 'Power',
|
|
||||||
id: 'power',
|
|
||||||
value: 1,
|
|
||||||
epic: false,
|
|
||||||
effect: false,
|
|
||||||
});
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
|
|
||||||
get effectName() {
|
|
||||||
return (
|
|
||||||
`${this.name} ${this.data.mods.has('power') ? '[Power] ' : ''}` + `(${this.data.raise ? 'full' : 'half'} pace)`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get description() {
|
|
||||||
let text =
|
|
||||||
super.description +
|
|
||||||
`<p>Meld into the ground. Move at ${this.data.raise ? 'full' : 'half'} pace. May not run.</p>`;
|
|
||||||
if (this.data.mods.has('power')) {
|
|
||||||
text += '<p>Can <em>burrow</em> through solid stone, concrete, etc</p>';
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BoostLowerTraitEffect extends PowerEffect {
|
|
||||||
get name() {
|
|
||||||
return 'Boost/Lower Trait';
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasAdditionalRecipients() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get additionalRecipientCost() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return this?.data?.direction === 'Boost'
|
|
||||||
? 'icons/magic/life/cross-embers-glow-yellow-purple.webp'
|
|
||||||
: 'icons/magic/movement/chevrons-down-yellow.webp';
|
|
||||||
}
|
|
||||||
|
|
||||||
get duration() {
|
|
||||||
return this?.data?.direction === 'Boost' ? 5 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isTargeted() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get basePowerPoints() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPrimaryEffectChanges() {
|
|
||||||
let modValue = '2';
|
|
||||||
if (this.data.raise && this.data.direction === 'Boost') {
|
|
||||||
modValue = '4';
|
|
||||||
}
|
|
||||||
modValue = (this.data.direction === 'Boost' ? '+' : '-') + modValue;
|
|
||||||
const changes = [
|
|
||||||
{
|
|
||||||
key: this.data.trait.diekey,
|
|
||||||
value: modValue,
|
|
||||||
priority: 0,
|
|
||||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (this.data.direction === 'Lower' && this.data.mods.has('greater')) {
|
|
||||||
changes.push({
|
|
||||||
key: this.data.trait.modkey,
|
|
||||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
|
||||||
value: -2,
|
|
||||||
priority: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return changes;
|
|
||||||
}
|
|
||||||
|
|
||||||
async createSecondaryEffects(maintId) {
|
|
||||||
const docs = await super.createSecondaryEffects(maintId);
|
|
||||||
if (this.data.raise && this.data.direction === 'Lower') {
|
|
||||||
const name = 'major ' + this.effectName;
|
|
||||||
const modValue = this.data.direction === 'Boost' ? '+2' : '-2';
|
|
||||||
const changes = [
|
|
||||||
{
|
|
||||||
key: this.data.trait.diekey,
|
|
||||||
value: modValue,
|
|
||||||
priority: 0,
|
|
||||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const doc = this.createEffectDocument(this.icon, name, changes);
|
|
||||||
doc.duration.seconds = 594;
|
|
||||||
doc.description = this.description + '<p>This is the raise effect which can be shaken off separately.</p>';
|
|
||||||
doc.flags[moduleName].maintId = maintId;
|
|
||||||
docs.push(doc);
|
|
||||||
}
|
|
||||||
return docs;
|
|
||||||
}
|
|
||||||
|
|
||||||
get effectName() {
|
|
||||||
let name = `${this.data.direction} ${this.data.trait.name}`;
|
|
||||||
const nameMods = [];
|
|
||||||
if (this.data.mods.has('greater')) {
|
|
||||||
nameMods.push('Greater');
|
|
||||||
}
|
|
||||||
if (this.data.direction === 'Lower' && this.data.mods.has('strong')) {
|
|
||||||
nameMods.push('Strong');
|
|
||||||
}
|
|
||||||
if (nameMods.length > 0) {
|
|
||||||
name += ` (${nameMods.join(', ')})`;
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get description() {
|
|
||||||
let desc = super.description;
|
|
||||||
const amount = `${this.data.raise ? 2 : 1} die type${this.data.raise ? 's' : ''}`;
|
|
||||||
desc += `<p>${this.data.direction === 'Boost' ? 'Raise' : 'Lower'} the
|
|
||||||
target's ${this.data.trait.name} die type ${amount}.`;
|
|
||||||
if (this.data.mods.has('greater')) {
|
|
||||||
if (this.data.direction === 'Boost') {
|
|
||||||
desc += ` Additionally, the target gains a free ${this.data.trait.name}
|
|
||||||
reroll once per ${this.data.raise ? 'action' : 'round'}.`;
|
|
||||||
} else {
|
|
||||||
desc += ` Additionally, the target suffers a -2 penalty to their
|
|
||||||
${this.data.trait.name} rolls.`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
desc += '</p>';
|
|
||||||
if (this.data.direction === 'Lower') {
|
|
||||||
desc += `<p>At the end of the target's following turns, they attempt to shake off
|
|
||||||
the affect with a Spirit${this.data.mods.has('strong') ? ' -2' : ''}
|
|
||||||
roll as a free action. Success reduces the effect one die type. A raise
|
|
||||||
completely shakes off the effect.</p>`;
|
|
||||||
}
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
get modifiers() {
|
|
||||||
const mods = super.modifiers;
|
|
||||||
mods.push({
|
|
||||||
name: 'Greater Boost/Lower Trailt',
|
|
||||||
value: 2,
|
|
||||||
id: 'greater',
|
|
||||||
epic: true,
|
|
||||||
effect: false,
|
|
||||||
});
|
|
||||||
mods.push({
|
|
||||||
name: 'Strong (lower only)',
|
|
||||||
value: 1,
|
|
||||||
id: 'strong',
|
|
||||||
epic: false,
|
|
||||||
effect: false,
|
|
||||||
});
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
|
|
||||||
get menuInputs() {
|
|
||||||
const inputs = super.menuInputs;
|
|
||||||
let traitOptions = ['Agility', 'Smarts', 'Spirit', 'Strength', 'Vigor'];
|
|
||||||
const allSkills = new Set();
|
|
||||||
const traits = {};
|
|
||||||
for (const traitName of traitOptions) {
|
|
||||||
const lower = traitName.toLowerCase();
|
|
||||||
traits[traitName] = {
|
|
||||||
name: traitName,
|
|
||||||
type: 'attribute',
|
|
||||||
modkey: `system.attributes.${lower}.die.modifier`,
|
|
||||||
diekey: `system.attributes.${lower}.die.sides`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
for (const token of this.targets) {
|
|
||||||
const skills = token.actor.items.filter((item) => item.type === 'skill');
|
|
||||||
for (const skill of skills) {
|
|
||||||
const name = skill.name;
|
|
||||||
traits[name] = {
|
|
||||||
name,
|
|
||||||
type: 'skill',
|
|
||||||
modkey: `@Skill{${name}}[system.die.modifier]`,
|
|
||||||
diekey: `@Skill{${name}}[system.die.sides]`,
|
|
||||||
};
|
|
||||||
if (name !== 'Unskilled') {
|
|
||||||
allSkills.add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
traitOptions = traitOptions.concat(Array.from(allSkills).sort());
|
|
||||||
this.data.traits = traits;
|
|
||||||
inputs.push({ type: 'select', label: 'Trait', options: traitOptions });
|
|
||||||
inputs.push({ type: 'info', label: 'Boost or Lower?' });
|
|
||||||
inputs.push({ type: 'radio', label: 'Boost', options: ['isBoost', true] });
|
|
||||||
inputs.push({ type: 'radio', label: 'Lower', options: ['isBoost', false] });
|
|
||||||
return inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
async parseValues() {
|
|
||||||
await super.parseValues();
|
|
||||||
this.data.trait = this.data.traits[this.data.values.shift()];
|
|
||||||
this.data.values.shift();
|
|
||||||
this.data.direction = this.data.values.shift() ? 'Boost' : 'Lower';
|
|
||||||
}
|
|
||||||
|
|
||||||
get powerPoints() {
|
|
||||||
const total = super.powerPoints;
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BurstEffect extends PowerEffect {
|
class BurstEffect extends PowerEffect {
|
||||||
get name() {
|
get name() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user