Second round de corrections et améliorations
This commit is contained in:
82
lang/en.json
82
lang/en.json
@@ -54,20 +54,20 @@
|
|||||||
"Gender": "Gender",
|
"Gender": "Gender",
|
||||||
"Pronouns": "Pronouns",
|
"Pronouns": "Pronouns",
|
||||||
"Actor": {
|
"Actor": {
|
||||||
"StudyPeriod":"Study Period",
|
"StudyPeriod": "Study Period",
|
||||||
"TrainingInSkill":"Training In Skill",
|
"TrainingInSkill": "Training In Skill",
|
||||||
"Completed":"Completed",
|
"Completed": "Completed",
|
||||||
"Weeks":"Weeks",
|
"Weeks": "Weeks",
|
||||||
"NewCareer":"New Career",
|
"NewCareer": "New Career",
|
||||||
"AddCareer":"Add Career",
|
"AddCareer": "Add Career",
|
||||||
"EditCareer":"Edit Career",
|
"EditCareer": "Edit Career",
|
||||||
"EditTrait":"Éditer Trait",
|
"EditTrait": "Éditer Trait",
|
||||||
"DeleteTrait": "Supprimer Trait",
|
"DeleteTrait": "Supprimer Trait",
|
||||||
"DeleteCareer":"Delete Career",
|
"DeleteCareer": "Delete Career",
|
||||||
"NewSkill":"New Skill",
|
"NewSkill": "New Skill",
|
||||||
"DeleteSkill":"Delete Skill",
|
"DeleteSkill": "Delete Skill",
|
||||||
"EditSkill":"EditSkill",
|
"EditSkill": "EditSkill",
|
||||||
"PsionicTalents":"Psionic Talents",
|
"PsionicTalents": "Psionic Talents",
|
||||||
"NewPsionicTalent": "New Psionic Talent",
|
"NewPsionicTalent": "New Psionic Talent",
|
||||||
"AddPsionicTalent": "Add Psionic Talent",
|
"AddPsionicTalent": "Add Psionic Talent",
|
||||||
"EditPsionic": "Edit Psionic",
|
"EditPsionic": "Edit Psionic",
|
||||||
@@ -447,6 +447,60 @@
|
|||||||
"Seconds": "Seconds",
|
"Seconds": "Seconds",
|
||||||
"Minutes": "Minutes",
|
"Minutes": "Minutes",
|
||||||
"Heures": "Hours"
|
"Heures": "Hours"
|
||||||
|
},
|
||||||
|
"Creature": {
|
||||||
|
"Name": "Name",
|
||||||
|
"Life": "HP",
|
||||||
|
"Speed": "Speed",
|
||||||
|
"Armor": "Armor",
|
||||||
|
"Psi": "PSI",
|
||||||
|
"Initiative": "Initiative",
|
||||||
|
"SizeHint": "Estimated size based on HP",
|
||||||
|
"Behavior": "Behavior",
|
||||||
|
"TabSkills": "Skills",
|
||||||
|
"TabAttacks": "Attacks",
|
||||||
|
"TabTraits": "Traits",
|
||||||
|
"TabInfo": "Information",
|
||||||
|
"SkillName": "Skill",
|
||||||
|
"SkillLevel": "Level",
|
||||||
|
"SkillNote": "Note",
|
||||||
|
"AttackName": "Attack",
|
||||||
|
"AttackDamage": "Damage",
|
||||||
|
"TraitName": "Trait",
|
||||||
|
"TraitValue": "Value",
|
||||||
|
"AddSkill": "Add a skill",
|
||||||
|
"AddAttack": "Add an attack",
|
||||||
|
"AddTrait": "Add a trait",
|
||||||
|
"NoSkills": "No skills",
|
||||||
|
"NoAttacks": "No attacks",
|
||||||
|
"NoTraits": "No traits",
|
||||||
|
"Delete": "Delete",
|
||||||
|
"RollSkill": "Skill roll",
|
||||||
|
"RollAttack": "Attack roll",
|
||||||
|
"SkillLabel": "Skill",
|
||||||
|
"RollTitle": "Creature roll"
|
||||||
|
},
|
||||||
|
"CreatureBehaviorType": {
|
||||||
|
"herbivore": "Herbivore",
|
||||||
|
"carnivore": "Carnivore",
|
||||||
|
"charognard": "Scavenger",
|
||||||
|
"omnivore": "Omnivore"
|
||||||
|
},
|
||||||
|
"CreatureBehaviorSubType": {
|
||||||
|
"accumulateur": "Gatherer",
|
||||||
|
"brouteur": "Grazer",
|
||||||
|
"filtreur": "Filter",
|
||||||
|
"intermittent": "Intermittent",
|
||||||
|
"chasseur": "Hunter",
|
||||||
|
"detourneux": "Hijacker",
|
||||||
|
"guetteur": "Pouncer",
|
||||||
|
"mangeur": "Eater",
|
||||||
|
"piegeur": "Trapper",
|
||||||
|
"intimidateur": "Intimidator",
|
||||||
|
"necrophage": "Carrion-eater",
|
||||||
|
"reducteur": "Reducer",
|
||||||
|
"opportuniste": "Opportunist"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"TYPES.Actor.creature": "Creature"
|
||||||
}
|
}
|
||||||
82
lang/fr.json
82
lang/fr.json
@@ -54,20 +54,20 @@
|
|||||||
"Gender": "Genre",
|
"Gender": "Genre",
|
||||||
"Pronouns": "Pronoms",
|
"Pronouns": "Pronoms",
|
||||||
"Actor": {
|
"Actor": {
|
||||||
"StudyPeriod":"Période d'étude",
|
"StudyPeriod": "Période d'étude",
|
||||||
"TrainingInSkill":"Compétence en formation",
|
"TrainingInSkill": "Compétence en formation",
|
||||||
"Completed":"Completée",
|
"Completed": "Completée",
|
||||||
"Weeks":"Semaines",
|
"Weeks": "Semaines",
|
||||||
"NewCareer":"Nouvelle Carrière",
|
"NewCareer": "Nouvelle Carrière",
|
||||||
"AddCareer":"Ajouter Carrière",
|
"AddCareer": "Ajouter Carrière",
|
||||||
"EditCareer":"Éditer Carrière",
|
"EditCareer": "Éditer Carrière",
|
||||||
"EditTrait":"Éditer Trait",
|
"EditTrait": "Éditer Trait",
|
||||||
"DeleteTrait": "Supprimer Trait",
|
"DeleteTrait": "Supprimer Trait",
|
||||||
"DeleteCareer":"Supprimer Carrière",
|
"DeleteCareer": "Supprimer Carrière",
|
||||||
"NewSkill":"Nouvelle Compétence",
|
"NewSkill": "Nouvelle Compétence",
|
||||||
"DeleteSkill":"Supprimer Compétence",
|
"DeleteSkill": "Supprimer Compétence",
|
||||||
"EditSkill":"Éditer Compétence",
|
"EditSkill": "Éditer Compétence",
|
||||||
"PsionicTalents":"Talents Psionique",
|
"PsionicTalents": "Talents Psionique",
|
||||||
"NewPsionicTalent": "Nouveau Talent Psionique",
|
"NewPsionicTalent": "Nouveau Talent Psionique",
|
||||||
"AddPsionicTalent": "Ajouter Talent Psionique",
|
"AddPsionicTalent": "Ajouter Talent Psionique",
|
||||||
"EditPsionic": "Éditer Talent Psionique",
|
"EditPsionic": "Éditer Talent Psionique",
|
||||||
@@ -447,6 +447,60 @@
|
|||||||
"Seconds": "Secondes",
|
"Seconds": "Secondes",
|
||||||
"Minutes": "Minutes",
|
"Minutes": "Minutes",
|
||||||
"Heures": "Heures"
|
"Heures": "Heures"
|
||||||
|
},
|
||||||
|
"Creature": {
|
||||||
|
"Name": "Nom",
|
||||||
|
"Life": "PdV",
|
||||||
|
"Speed": "Vitesse",
|
||||||
|
"Armor": "Armure",
|
||||||
|
"Psi": "PSI",
|
||||||
|
"Initiative": "Initiative",
|
||||||
|
"SizeHint": "Taille estimée selon les PdV",
|
||||||
|
"Behavior": "Comportement",
|
||||||
|
"TabSkills": "Compétences",
|
||||||
|
"TabAttacks": "Attaques",
|
||||||
|
"TabTraits": "Traits",
|
||||||
|
"TabInfo": "Informations",
|
||||||
|
"SkillName": "Compétence",
|
||||||
|
"SkillLevel": "Niveau",
|
||||||
|
"SkillNote": "Note",
|
||||||
|
"AttackName": "Attaque",
|
||||||
|
"AttackDamage": "Dommages",
|
||||||
|
"TraitName": "Trait",
|
||||||
|
"TraitValue": "Valeur",
|
||||||
|
"AddSkill": "Ajouter une compétence",
|
||||||
|
"AddAttack": "Ajouter une attaque",
|
||||||
|
"AddTrait": "Ajouter un trait",
|
||||||
|
"NoSkills": "Aucune compétence",
|
||||||
|
"NoAttacks": "Aucune attaque",
|
||||||
|
"NoTraits": "Aucun trait",
|
||||||
|
"Delete": "Supprimer",
|
||||||
|
"RollSkill": "Jet de compétence",
|
||||||
|
"RollAttack": "Jet d'attaque",
|
||||||
|
"SkillLabel": "Compétence",
|
||||||
|
"RollTitle": "Jet de créature"
|
||||||
|
},
|
||||||
|
"CreatureBehaviorType": {
|
||||||
|
"herbivore": "Herbivore",
|
||||||
|
"carnivore": "Carnivore",
|
||||||
|
"charognard": "Charognard",
|
||||||
|
"omnivore": "Omnivore"
|
||||||
|
},
|
||||||
|
"CreatureBehaviorSubType": {
|
||||||
|
"accumulateur": "Accumulateur",
|
||||||
|
"brouteur": "Brouteur",
|
||||||
|
"filtreur": "Filtreur",
|
||||||
|
"intermittent": "Intermittent",
|
||||||
|
"chasseur": "Chasseur",
|
||||||
|
"detourneux": "Détourneux",
|
||||||
|
"guetteur": "Guetteur",
|
||||||
|
"mangeur": "Mangeur",
|
||||||
|
"piegeur": "Piégeur",
|
||||||
|
"intimidateur": "Intimidateur",
|
||||||
|
"necrophage": "Nécrophage",
|
||||||
|
"reducteur": "Réducteur",
|
||||||
|
"opportuniste": "Opportuniste"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"TYPES.Actor.creature": "Créature"
|
||||||
}
|
}
|
||||||
647
mgt2.bundle.js
647
mgt2.bundle.js
@@ -1,20 +1,20 @@
|
|||||||
const fields$d = foundry.data.fields;
|
const fields$e = foundry.data.fields;
|
||||||
|
|
||||||
function createCharacteristicField(show = true, showMax = false) {
|
function createCharacteristicField(show = true, showMax = false) {
|
||||||
return new fields$d.SchemaField({
|
return new fields$e.SchemaField({
|
||||||
value: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
value: new fields$e.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
max: new fields$d.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
max: new fields$e.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
||||||
dm: new fields$d.NumberField({ required: false, initial: 0, integer: true }),
|
dm: new fields$e.NumberField({ required: false, initial: 0, integer: true }),
|
||||||
show: new fields$d.BooleanField({ required: false, initial: show }),
|
show: new fields$e.BooleanField({ required: false, initial: show }),
|
||||||
showMax: new fields$d.BooleanField({ required: false, initial: showMax })
|
showMax: new fields$e.BooleanField({ required: false, initial: showMax })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemBaseData extends foundry.abstract.TypeDataModel {
|
class ItemBaseData extends foundry.abstract.TypeDataModel {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
description: new fields$d.StringField({ required: false, blank: true, trim: true, nullable: true }),
|
description: new fields$e.StringField({ required: false, blank: true, trim: true, nullable: true }),
|
||||||
subType: new fields$d.StringField({ required: false, blank: false, nullable: true })
|
subType: new fields$e.StringField({ required: false, blank: false, nullable: true })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,57 +22,57 @@ class ItemBaseData extends foundry.abstract.TypeDataModel {
|
|||||||
class PhysicalItemData extends ItemBaseData {
|
class PhysicalItemData extends ItemBaseData {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const schema = super.defineSchema();
|
const schema = super.defineSchema();
|
||||||
schema.quantity = new fields$d.NumberField({ required: true, initial: 1, min: 0, integer: true });
|
schema.quantity = new fields$e.NumberField({ required: true, initial: 1, min: 0, integer: true });
|
||||||
schema.weight = new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: false });
|
schema.weight = new fields$e.NumberField({ required: true, initial: 0, min: 0, integer: false });
|
||||||
schema.weightless = new fields$d.BooleanField({ required: false, initial: false });
|
schema.weightless = new fields$e.BooleanField({ required: false, initial: false });
|
||||||
schema.cost = new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true });
|
schema.cost = new fields$e.NumberField({ required: true, initial: 0, min: 0, integer: true });
|
||||||
schema.tl = new fields$d.StringField({ required: true, blank: false, initial: "TL12" });
|
schema.tl = new fields$e.StringField({ required: true, blank: false, initial: "TL12" });
|
||||||
schema.container = new fields$d.SchemaField({
|
schema.container = new fields$e.SchemaField({
|
||||||
id: new fields$d.StringField({ required: false, blank: true })
|
id: new fields$e.StringField({ required: false, blank: true })
|
||||||
});
|
});
|
||||||
schema.roll = new fields$d.SchemaField({
|
schema.roll = new fields$e.SchemaField({
|
||||||
characteristic: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
characteristic: new fields$e.StringField({ required: false, blank: true, trim: true }),
|
||||||
skill: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
skill: new fields$e.StringField({ required: false, blank: true, trim: true }),
|
||||||
difficulty: new fields$d.StringField({ required: false, blank: true, trim: true })
|
difficulty: new fields$e.StringField({ required: false, blank: true, trim: true })
|
||||||
});
|
});
|
||||||
schema.trash = new fields$d.BooleanField({ required: false, initial: false });
|
schema.trash = new fields$e.BooleanField({ required: false, initial: false });
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields$c = foundry.data.fields;
|
const fields$d = foundry.data.fields;
|
||||||
|
|
||||||
class CharacterData extends foundry.abstract.TypeDataModel {
|
class CharacterData extends foundry.abstract.TypeDataModel {
|
||||||
|
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
name: new fields$c.StringField({ required: false, blank: false, trim: true }),
|
name: new fields$d.StringField({ required: false, blank: false, trim: true }),
|
||||||
life: new fields$c.SchemaField({
|
life: new fields$d.SchemaField({
|
||||||
value: new fields$c.NumberField({ required: false, initial: 0, integer: true }),
|
value: new fields$d.NumberField({ required: false, initial: 0, integer: true }),
|
||||||
max: new fields$c.NumberField({ required: true, initial: 0, integer: true })
|
max: new fields$d.NumberField({ required: true, initial: 0, integer: true })
|
||||||
}),
|
}),
|
||||||
personal: new fields$c.SchemaField({
|
personal: new fields$d.SchemaField({
|
||||||
title: new fields$c.StringField({ required: false, blank: true, trim: true }),
|
title: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
||||||
species: new fields$c.StringField({ required: false, blank: true, trim: true }),
|
species: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
||||||
speciesText: new fields$c.SchemaField({
|
speciesText: new fields$d.SchemaField({
|
||||||
description: new fields$c.StringField({ required: false, blank: true, trim: true, nullable: true }),
|
description: new fields$d.StringField({ required: false, blank: true, trim: true, nullable: true }),
|
||||||
descriptionLong: new fields$c.HTMLField({ required: false, blank: true, trim: true })
|
descriptionLong: new fields$d.HTMLField({ required: false, blank: true, trim: true })
|
||||||
}),
|
}),
|
||||||
age: new fields$c.StringField({ required: false, blank: true, trim: true }),
|
age: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
||||||
gender: new fields$c.StringField({ required: false, blank: true, trim: true }),
|
gender: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
||||||
pronouns: new fields$c.StringField({ required: false, blank: true, trim: true }),
|
pronouns: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
||||||
homeworld: new fields$c.StringField({ required: false, blank: true, trim: true }),
|
homeworld: new fields$d.StringField({ required: false, blank: true, trim: true }),
|
||||||
ucp: new fields$c.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
ucp: new fields$d.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
traits: new fields$c.ArrayField(
|
traits: new fields$d.ArrayField(
|
||||||
new fields$c.SchemaField({
|
new fields$d.SchemaField({
|
||||||
name: new fields$c.StringField({ required: true, blank: true, trim: true }),
|
name: new fields$d.StringField({ required: true, blank: true, trim: true }),
|
||||||
description: new fields$c.StringField({ required: false, blank: true, trim: true })
|
description: new fields$d.StringField({ required: false, blank: true, trim: true })
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
biography: new fields$c.HTMLField({ required: false, blank: true, trim: true }),
|
biography: new fields$d.HTMLField({ required: false, blank: true, trim: true }),
|
||||||
|
|
||||||
characteristics: new fields$c.SchemaField({
|
characteristics: new fields$d.SchemaField({
|
||||||
strength: createCharacteristicField(true, true),
|
strength: createCharacteristicField(true, true),
|
||||||
dexterity: createCharacteristicField(true, true),
|
dexterity: createCharacteristicField(true, true),
|
||||||
endurance: createCharacteristicField(true, true),
|
endurance: createCharacteristicField(true, true),
|
||||||
@@ -87,87 +87,184 @@ class CharacterData extends foundry.abstract.TypeDataModel {
|
|||||||
other: createCharacteristicField(true, false)
|
other: createCharacteristicField(true, false)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
health: new fields$c.SchemaField({
|
health: new fields$d.SchemaField({
|
||||||
radiations: new fields$c.NumberField({ required: false, initial: 0, min: 0, integer: true })
|
radiations: new fields$d.NumberField({ required: false, initial: 0, min: 0, integer: true })
|
||||||
}),
|
}),
|
||||||
study: new fields$c.SchemaField({
|
study: new fields$d.SchemaField({
|
||||||
skill: new fields$c.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
skill: new fields$d.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
total: new fields$c.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
total: new fields$d.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
||||||
completed: new fields$c.NumberField({ required: false, initial: 0, min: 0, integer: true })
|
completed: new fields$d.NumberField({ required: false, initial: 0, min: 0, integer: true })
|
||||||
}),
|
}),
|
||||||
finance: new fields$c.SchemaField({
|
finance: new fields$d.SchemaField({
|
||||||
pension: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
pension: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
credits: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
credits: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
cashOnHand: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
cashOnHand: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
debt: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
debt: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
livingCost: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
livingCost: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
monthlyShipPayments: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
monthlyShipPayments: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
notes: new fields$c.StringField({ required: false, blank: true, trim: true, initial: "" })
|
notes: new fields$d.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
}),
|
}),
|
||||||
containerView: new fields$c.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
containerView: new fields$d.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
containerDropIn: new fields$c.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
containerDropIn: new fields$d.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
notes: new fields$c.HTMLField({ required: false, blank: true, trim: true }),
|
notes: new fields$d.HTMLField({ required: false, blank: true, trim: true }),
|
||||||
|
|
||||||
inventory: new fields$c.SchemaField({
|
inventory: new fields$d.SchemaField({
|
||||||
armor: new fields$c.NumberField({ required: true, initial: 0, integer: true }),
|
armor: new fields$d.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
weight: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: false }),
|
weight: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: false }),
|
||||||
encumbrance: new fields$c.SchemaField({
|
encumbrance: new fields$d.SchemaField({
|
||||||
normal: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
normal: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
heavy: new fields$c.NumberField({ required: true, initial: 0, min: 0, integer: true })
|
heavy: new fields$d.NumberField({ required: true, initial: 0, min: 0, integer: true })
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
states: new fields$c.SchemaField({
|
states: new fields$d.SchemaField({
|
||||||
encumbrance: new fields$c.BooleanField({ required: false, initial: false }),
|
encumbrance: new fields$d.BooleanField({ required: false, initial: false }),
|
||||||
fatigue: new fields$c.BooleanField({ required: false, initial: false }),
|
fatigue: new fields$d.BooleanField({ required: false, initial: false }),
|
||||||
unconscious: new fields$c.BooleanField({ required: false, initial: false }),
|
unconscious: new fields$d.BooleanField({ required: false, initial: false }),
|
||||||
surgeryRequired: new fields$c.BooleanField({ required: false, initial: false })
|
surgeryRequired: new fields$d.BooleanField({ required: false, initial: false })
|
||||||
}),
|
}),
|
||||||
|
|
||||||
config: new fields$c.SchemaField({
|
config: new fields$d.SchemaField({
|
||||||
psionic: new fields$c.BooleanField({ required: false, initial: true }),
|
psionic: new fields$d.BooleanField({ required: false, initial: true }),
|
||||||
initiative: new fields$c.StringField({ required: false, blank: true, initial: "dexterity" }),
|
initiative: new fields$d.StringField({ required: false, blank: true, initial: "dexterity" }),
|
||||||
damages: new fields$c.SchemaField({
|
damages: new fields$d.SchemaField({
|
||||||
rank1: new fields$c.StringField({ required: false, blank: true, initial: "strength" }),
|
rank1: new fields$d.StringField({ required: false, blank: true, initial: "strength" }),
|
||||||
rank2: new fields$c.StringField({ required: false, blank: true, initial: "dexterity" }),
|
rank2: new fields$d.StringField({ required: false, blank: true, initial: "dexterity" }),
|
||||||
rank3: new fields$c.StringField({ required: false, blank: true, initial: "endurance" })
|
rank3: new fields$d.StringField({ required: false, blank: true, initial: "endurance" })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fields$c = foundry.data.fields;
|
||||||
|
|
||||||
|
class VehiculeData extends foundry.abstract.TypeDataModel {
|
||||||
|
|
||||||
|
static defineSchema() {
|
||||||
|
return {
|
||||||
|
name: new fields$c.StringField({ required: false, blank: false, trim: true }),
|
||||||
|
skillId: new fields$c.StringField({ required: false, initial: "", blank: true, trim: true }),
|
||||||
|
speed: new fields$c.SchemaField({
|
||||||
|
cruise: new fields$c.StringField({ required: false, initial: "Slow", blank: true }),
|
||||||
|
maximum: new fields$c.StringField({ required: false, initial: "Medium", blank: true })
|
||||||
|
}),
|
||||||
|
agility: new fields$c.NumberField({ required: false, min: 0, integer: true }),
|
||||||
|
crew: new fields$c.NumberField({ required: false, min: 0, integer: true }),
|
||||||
|
passengers: new fields$c.NumberField({ required: false, min: 0, integer: true }),
|
||||||
|
cargo: new fields$c.NumberField({ required: false, min: 0, integer: false }),
|
||||||
|
life: new fields$c.SchemaField({
|
||||||
|
value: new fields$c.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
|
max: new fields$c.NumberField({ required: true, initial: 0, integer: true })
|
||||||
|
}),
|
||||||
|
shipping: new fields$c.NumberField({ required: false, min: 0, integer: true }),
|
||||||
|
cost: new fields$c.NumberField({ required: false, min: 0, integer: true }),
|
||||||
|
armor: new fields$c.SchemaField({
|
||||||
|
front: new fields$c.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
|
rear: new fields$c.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
|
sides: new fields$c.NumberField({ required: true, initial: 0, integer: true })
|
||||||
|
}),
|
||||||
|
skills: new fields$c.SchemaField({
|
||||||
|
autopilot: new fields$c.NumberField({ required: true, initial: 0, integer: true })
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fields$b = foundry.data.fields;
|
const fields$b = foundry.data.fields;
|
||||||
|
|
||||||
class VehiculeData extends foundry.abstract.TypeDataModel {
|
class CreatureData extends foundry.abstract.TypeDataModel {
|
||||||
|
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
name: new fields$b.StringField({ required: false, blank: false, trim: true }),
|
|
||||||
skillId: new fields$b.StringField({ required: false, initial: "", blank: true, trim: true }),
|
|
||||||
speed: new fields$b.SchemaField({
|
|
||||||
cruise: new fields$b.StringField({ required: false, initial: "Slow", blank: true }),
|
|
||||||
maximum: new fields$b.StringField({ required: false, initial: "Medium", blank: true })
|
|
||||||
}),
|
|
||||||
agility: new fields$b.NumberField({ required: false, min: 0, integer: true }),
|
|
||||||
crew: new fields$b.NumberField({ required: false, min: 0, integer: true }),
|
|
||||||
passengers: new fields$b.NumberField({ required: false, min: 0, integer: true }),
|
|
||||||
cargo: new fields$b.NumberField({ required: false, min: 0, integer: false }),
|
|
||||||
life: new fields$b.SchemaField({
|
life: new fields$b.SchemaField({
|
||||||
value: new fields$b.NumberField({ required: true, initial: 0, integer: true }),
|
value: new fields$b.NumberField({ required: true, initial: 10, min: 0, integer: true }),
|
||||||
max: new fields$b.NumberField({ required: true, initial: 0, integer: true })
|
max: new fields$b.NumberField({ required: true, initial: 10, min: 0, integer: true })
|
||||||
}),
|
}),
|
||||||
shipping: new fields$b.NumberField({ required: false, min: 0, integer: true }),
|
|
||||||
cost: new fields$b.NumberField({ required: false, min: 0, integer: true }),
|
speed: new fields$b.NumberField({ required: true, initial: 6, min: 0, integer: true }),
|
||||||
armor: new fields$b.SchemaField({
|
|
||||||
front: new fields$b.NumberField({ required: true, initial: 0, integer: true }),
|
armor: new fields$b.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
rear: new fields$b.NumberField({ required: true, initial: 0, integer: true }),
|
|
||||||
sides: new fields$b.NumberField({ required: true, initial: 0, integer: true })
|
psi: new fields$b.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
|
|
||||||
|
initiativeBonus: new fields$b.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
|
|
||||||
|
skills: new fields$b.ArrayField(
|
||||||
|
new fields$b.SchemaField({
|
||||||
|
name: new fields$b.StringField({ required: true, blank: true, trim: true, initial: "" }),
|
||||||
|
level: new fields$b.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
|
note: new fields$b.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
attacks: new fields$b.ArrayField(
|
||||||
|
new fields$b.SchemaField({
|
||||||
|
name: new fields$b.StringField({ required: true, blank: true, trim: true, initial: "" }),
|
||||||
|
damage: new fields$b.StringField({ required: true, blank: true, trim: true, initial: "1D" }),
|
||||||
|
description: new fields$b.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
traits: new fields$b.ArrayField(
|
||||||
|
new fields$b.SchemaField({
|
||||||
|
name: new fields$b.StringField({ required: true, blank: true, trim: true, initial: "" }),
|
||||||
|
value: new fields$b.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
|
description: new fields$b.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
behavior: new fields$b.SchemaField({
|
||||||
|
type: new fields$b.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
|
subtype: new fields$b.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
}),
|
}),
|
||||||
skills: new fields$b.SchemaField({
|
|
||||||
autopilot: new fields$b.NumberField({ required: true, initial: 0, integer: true })
|
biography: new fields$b.HTMLField({ required: false, blank: true, trim: true }),
|
||||||
})
|
notes: new fields$b.HTMLField({ required: false, blank: true, trim: true }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
prepareDerivedData() {
|
||||||
|
// Compute initiative bonus from Métabolisme traits
|
||||||
|
let bonus = 0;
|
||||||
|
for (const trait of this.traits) {
|
||||||
|
const nameLower = trait.name.toLowerCase();
|
||||||
|
if (nameLower.includes("métabolisme rapide") || nameLower.includes("metabolisme rapide")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) bonus += val;
|
||||||
|
} else if (nameLower.includes("métabolisme lent") || nameLower.includes("metabolisme lent")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) bonus -= val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.initiativeBonus = bonus;
|
||||||
|
|
||||||
|
// Compute armor from Armure trait if not set manually
|
||||||
|
if (this.armor === 0) {
|
||||||
|
for (const trait of this.traits) {
|
||||||
|
if (trait.name.toLowerCase().startsWith("armure")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
this.armor = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute PSI from Psionique trait
|
||||||
|
if (this.psi === 0) {
|
||||||
|
for (const trait of this.traits) {
|
||||||
|
if (trait.name.toLowerCase().startsWith("psionique")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
this.psi = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields$a = foundry.data.fields;
|
const fields$a = foundry.data.fields;
|
||||||
@@ -555,6 +652,29 @@ MGT2.Durations = Object.freeze({
|
|||||||
Heures: "MGT2.Durations.Heures"
|
Heures: "MGT2.Durations.Heures"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MGT2.CreatureBehaviorType = Object.freeze({
|
||||||
|
herbivore: "MGT2.CreatureBehaviorType.herbivore",
|
||||||
|
carnivore: "MGT2.CreatureBehaviorType.carnivore",
|
||||||
|
charognard: "MGT2.CreatureBehaviorType.charognard",
|
||||||
|
omnivore: "MGT2.CreatureBehaviorType.omnivore"
|
||||||
|
});
|
||||||
|
|
||||||
|
MGT2.CreatureBehaviorSubType = Object.freeze({
|
||||||
|
accumulateur: "MGT2.CreatureBehaviorSubType.accumulateur",
|
||||||
|
brouteur: "MGT2.CreatureBehaviorSubType.brouteur",
|
||||||
|
filtreur: "MGT2.CreatureBehaviorSubType.filtreur",
|
||||||
|
intermittent: "MGT2.CreatureBehaviorSubType.intermittent",
|
||||||
|
chasseur: "MGT2.CreatureBehaviorSubType.chasseur",
|
||||||
|
detourneur: "MGT2.CreatureBehaviorSubType.detourneux",
|
||||||
|
guetteur: "MGT2.CreatureBehaviorSubType.guetteur",
|
||||||
|
mangeur: "MGT2.CreatureBehaviorSubType.mangeur",
|
||||||
|
piegeur: "MGT2.CreatureBehaviorSubType.piegeur",
|
||||||
|
intimidateur: "MGT2.CreatureBehaviorSubType.intimidateur",
|
||||||
|
necrophage: "MGT2.CreatureBehaviorSubType.necrophage",
|
||||||
|
reducteur: "MGT2.CreatureBehaviorSubType.reducteur",
|
||||||
|
opportuniste: "MGT2.CreatureBehaviorSubType.opportuniste"
|
||||||
|
});
|
||||||
|
|
||||||
class ActorCharacter {
|
class ActorCharacter {
|
||||||
static preCreate($this, data, options, user) {
|
static preCreate($this, data, options, user) {
|
||||||
$this.updateSource({ prototypeToken: { actorLink: true } }); // QoL
|
$this.updateSource({ prototypeToken: { actorLink: true } }); // QoL
|
||||||
@@ -1374,18 +1494,9 @@ class MGT2Helper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getDifficultyDisplay(difficulty) {
|
static getDifficultyDisplay(difficulty) {
|
||||||
switch(difficulty) {
|
const key = `MGT2.Difficulty.${difficulty}`;
|
||||||
case "Simple": return game.i18n.localize("MGT2.Difficulty.Simple") + " (2+)";
|
const label = game.i18n.localize(key);
|
||||||
case "Easy": return game.i18n.localize("MGT2.Difficulty.Easy") + " (4+)";
|
return label !== key ? label : null;
|
||||||
case "Routine": return game.i18n.localize("MGT2.Difficulty.Routine") + " (6+)";
|
|
||||||
case "Average": return game.i18n.localize("MGT2.Difficulty.Average") + " (8+)";
|
|
||||||
case "Difficult": return game.i18n.localize("MGT2.Difficulty.Difficult") + " (10+)";
|
|
||||||
case "VeryDifficult": return game.i18n.localize("MGT2.Difficulty.VeryDifficult") + " (12+)";
|
|
||||||
case "Formidable": return game.i18n.localize("MGT2.Difficulty.Formidable") + " (14+)";
|
|
||||||
case "Impossible": return game.i18n.localize("MGT2.Difficulty.Impossible") + " (16+)";
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getRangeDisplay(range) {
|
static getRangeDisplay(range) {
|
||||||
@@ -1494,13 +1605,13 @@ class MGT2Helper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { DialogV2: DialogV2$1 } = foundry.applications.api;
|
const { DialogV2: DialogV2$1 } = foundry.applications.api;
|
||||||
const { renderTemplate: renderTemplate$1 } = foundry.applications.handlebars;
|
const { renderTemplate: renderTemplate$2 } = foundry.applications.handlebars;
|
||||||
const { FormDataExtended: FormDataExtended$1 } = foundry.applications.ux;
|
const { FormDataExtended: FormDataExtended$1 } = foundry.applications.ux;
|
||||||
|
|
||||||
class RollPromptHelper {
|
class RollPromptHelper {
|
||||||
|
|
||||||
static async roll(options) {
|
static async roll(options) {
|
||||||
const htmlContent = await renderTemplate$1('systems/mgt2/templates/roll-prompt.html', {
|
const htmlContent = await renderTemplate$2('systems/mgt2/templates/roll-prompt.html', {
|
||||||
config: CONFIG.MGT2,
|
config: CONFIG.MGT2,
|
||||||
characteristics: options.characteristics,
|
characteristics: options.characteristics,
|
||||||
characteristic: options.characteristic,
|
characteristic: options.characteristic,
|
||||||
@@ -1515,6 +1626,7 @@ class RollPromptHelper {
|
|||||||
|
|
||||||
return await DialogV2$1.wait({
|
return await DialogV2$1.wait({
|
||||||
window: { title: options.title ?? options.rollTypeName ?? game.i18n.localize("MGT2.RollPrompt.Roll") },
|
window: { title: options.title ?? options.rollTypeName ?? game.i18n.localize("MGT2.RollPrompt.Roll") },
|
||||||
|
classes: ["mgt2-roll-dialog"],
|
||||||
content: htmlContent,
|
content: htmlContent,
|
||||||
rejectClose: false,
|
rejectClose: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
@@ -1551,11 +1663,11 @@ class RollPromptHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { DialogV2 } = foundry.applications.api;
|
const { DialogV2 } = foundry.applications.api;
|
||||||
const { renderTemplate } = foundry.applications.handlebars;
|
const { renderTemplate: renderTemplate$1 } = foundry.applications.handlebars;
|
||||||
const { FormDataExtended } = foundry.applications.ux;
|
const { FormDataExtended } = foundry.applications.ux;
|
||||||
|
|
||||||
async function _dialogWithForm(title, templatePath, templateData) {
|
async function _dialogWithForm(title, templatePath, templateData) {
|
||||||
const htmlContent = await renderTemplate(templatePath, templateData);
|
const htmlContent = await renderTemplate$1(templatePath, templateData);
|
||||||
game.settings.get("mgt2", "theme");
|
game.settings.get("mgt2", "theme");
|
||||||
return await DialogV2.wait({
|
return await DialogV2.wait({
|
||||||
window: { title },
|
window: { title },
|
||||||
@@ -1603,7 +1715,7 @@ class CharacterPrompts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async openEditorFullView(title, html) {
|
static async openEditorFullView(title, html) {
|
||||||
const htmlContent = await renderTemplate("systems/mgt2/templates/editor-fullview.html", {
|
const htmlContent = await renderTemplate$1("systems/mgt2/templates/editor-fullview.html", {
|
||||||
config: CONFIG.MGT2,
|
config: CONFIG.MGT2,
|
||||||
html
|
html
|
||||||
});
|
});
|
||||||
@@ -1903,7 +2015,7 @@ class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
const html = this.element;
|
const html = this.element;
|
||||||
if (!this.isEditable) return;
|
if (!this.isEditable) return;
|
||||||
|
|
||||||
this._bindClassEvent(html, ".roll", "click", TravellerCharacterSheet.#onRoll);
|
this._bindClassEvent(html, "a[data-roll]", "click", TravellerCharacterSheet.#onRoll);
|
||||||
this._bindClassEvent(html, ".cfg-characteristic", "click", TravellerCharacterSheet.#onOpenCharacteristic);
|
this._bindClassEvent(html, ".cfg-characteristic", "click", TravellerCharacterSheet.#onOpenCharacteristic);
|
||||||
this._bindClassEvent(html, ".item-create", "click", TravellerCharacterSheet.#onCreateItem);
|
this._bindClassEvent(html, ".item-create", "click", TravellerCharacterSheet.#onCreateItem);
|
||||||
this._bindClassEvent(html, ".item-edit", "click", TravellerCharacterSheet.#onEditItem);
|
this._bindClassEvent(html, ".item-edit", "click", TravellerCharacterSheet.#onEditItem);
|
||||||
@@ -1994,26 +2106,22 @@ class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
let sourceItem = this.actor.getEmbeddedDocument("Item", sourceItemData.id);
|
let sourceItem = this.actor.getEmbeddedDocument("Item", sourceItemData.id);
|
||||||
if (sourceItem) {
|
if (sourceItem) {
|
||||||
if (!targetItem) return false;
|
if (!targetItem) return false;
|
||||||
sourceItem = foundry.utils.deepClone(sourceItem);
|
if (sourceItem.id === targetId) return false;
|
||||||
if (sourceItem._id === targetId) return false;
|
|
||||||
|
|
||||||
if (targetItem.type === "item" || targetItem.type === "equipment") {
|
if (targetItem.type === "item" || targetItem.type === "equipment") {
|
||||||
if (targetItem.system.subType === "software")
|
if (targetItem.system.subType === "software")
|
||||||
sourceItem.system.software.computerId = targetItem.system.software.computerId;
|
await sourceItem.update({ "system.software.computerId": targetItem.system.software.computerId });
|
||||||
else
|
else
|
||||||
sourceItem.system.container.id = targetItem.system.container.id;
|
await sourceItem.update({ "system.container.id": targetItem.system.container.id });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
|
||||||
return true;
|
return true;
|
||||||
} else if (targetItem.type === "computer") {
|
} else if (targetItem.type === "computer") {
|
||||||
sourceItem.system.software.computerId = targetId;
|
await sourceItem.update({ "system.software.computerId": targetId });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
|
||||||
return true;
|
return true;
|
||||||
} else if (targetItem.type === "container") {
|
} else if (targetItem.type === "container") {
|
||||||
if (targetItem.system.locked && !game.user.isGM) {
|
if (targetItem.system.locked && !game.user.isGM) {
|
||||||
ui.notifications.error("Verrouillé");
|
ui.notifications.error("Verrouillé");
|
||||||
} else {
|
} else {
|
||||||
sourceItem.system.container.id = targetId;
|
await sourceItem.update({ "system.container.id": targetId });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2086,20 +2194,19 @@ class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
static async #onEquipItem(event, target) {
|
static async #onEquipItem(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
item.system.equipped = !item.system.equipped;
|
await item.update({ "system.equipped": !item.system.equipped });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onItemStorageIn(event, target) {
|
static async #onItemStorageIn(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
if (item.type === "container") {
|
if (item.type === "container") {
|
||||||
item.system.onHand = false;
|
await item.update({ "system.onHand": false });
|
||||||
} else {
|
} else {
|
||||||
const containers = this.actor.getContainers();
|
const containers = this.actor.getContainers();
|
||||||
let container;
|
let container;
|
||||||
@@ -2117,27 +2224,24 @@ class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
ui.notifications.error("Objet verrouillé");
|
ui.notifications.error("Objet verrouillé");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
item.system.container.id = container._id;
|
await item.update({ "system.container.id": container._id });
|
||||||
}
|
}
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onItemStorageOut(event, target) {
|
static async #onItemStorageOut(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
item.system.container.id = "";
|
await item.update({ "system.container.id": "" });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onSoftwareEject(event, target) {
|
static async #onSoftwareEject(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
item.system.software.computerId = "";
|
await item.update({ "system.software.computerId": "" });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onContainerCreate(event) {
|
static async #onContainerCreate(event) {
|
||||||
@@ -2163,23 +2267,19 @@ class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (containerItems.length > 0) {
|
if (containerItems.length > 0) {
|
||||||
for (let item of containerItems) {
|
const updates = containerItems.map(item => ({ _id: item.id, "system.container.id": "" }));
|
||||||
let clone = foundry.utils.deepClone(item);
|
await this.actor.updateEmbeddedDocuments("Item", updates);
|
||||||
clone.system.container.id = "";
|
|
||||||
this.actor.updateEmbeddedDocuments("Item", [clone]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloneActor = foundry.utils.deepClone(this.actor);
|
const actorUpdate = { "system.containerView": "" };
|
||||||
cloneActor.system.containerView = "";
|
if (this.actor.system.containerDropIn === container._id) {
|
||||||
if (cloneActor.system.containerDropIn === container._id) {
|
actorUpdate["system.containerDropIn"] = "";
|
||||||
cloneActor.system.containerDropIn = "";
|
|
||||||
const remaining = containers.filter(x => x._id !== container._id);
|
const remaining = containers.filter(x => x._id !== container._id);
|
||||||
if (remaining.length > 0) cloneActor.system.containerDropIn = remaining[0]._id;
|
if (remaining.length > 0) actorUpdate["system.containerDropIn"] = remaining[0]._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.actor.deleteEmbeddedDocuments("Item", [container._id]);
|
await this.actor.deleteEmbeddedDocuments("Item", [container._id]);
|
||||||
this.actor.update(cloneActor);
|
await this.actor.update(actorUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onRoll(event, target) {
|
static async #onRoll(event, target) {
|
||||||
@@ -2489,6 +2589,236 @@ class TravellerVehiculeSheet extends MGT2ActorSheet {
|
|||||||
tabGroups = { primary: "stats" }
|
tabGroups = { primary: "stats" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convert Traveller dice notation (e.g. "2D", "4D+2", "3D6") to FoundryVTT formula */
|
||||||
|
function normalizeDice(formula) {
|
||||||
|
if (!formula) return "1d6";
|
||||||
|
return formula
|
||||||
|
.replace(/(\d*)D(\d*)([+-]\d+)?/gi, (_, count, sides, mod) => {
|
||||||
|
const n = count || "1";
|
||||||
|
const d = sides || "6";
|
||||||
|
return mod ? `${n}d${d}${mod}` : `${n}d${d}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class TravellerCreatureSheet extends MGT2ActorSheet {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes, "creature", "nopad"],
|
||||||
|
position: {
|
||||||
|
width: 720,
|
||||||
|
height: 600,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
...super.DEFAULT_OPTIONS.window,
|
||||||
|
title: "TYPES.Actor.creature",
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
...super.DEFAULT_OPTIONS.actions,
|
||||||
|
rollAttack: TravellerCreatureSheet.#onRollAttack,
|
||||||
|
rollSkill: TravellerCreatureSheet.#onRollSkill,
|
||||||
|
addSkill: TravellerCreatureSheet.#onAddRow,
|
||||||
|
deleteSkill: TravellerCreatureSheet.#onDeleteRow,
|
||||||
|
addAttack: TravellerCreatureSheet.#onAddRow,
|
||||||
|
deleteAttack: TravellerCreatureSheet.#onDeleteRow,
|
||||||
|
addTrait: TravellerCreatureSheet.#onAddRow,
|
||||||
|
deleteTrait: TravellerCreatureSheet.#onDeleteRow,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
sheet: {
|
||||||
|
template: "systems/mgt2/templates/actors/creature-sheet.html",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
tabGroups = { primary: "skills" }
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext();
|
||||||
|
const actor = this.document;
|
||||||
|
|
||||||
|
context.sizeLabel = this._getSizeLabel(actor.system.life.max);
|
||||||
|
context.sizeTraitLabel = this._getSizeTrait(actor.system.life.max);
|
||||||
|
context.config = CONFIG.MGT2;
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSizeLabel(pdv) {
|
||||||
|
if (pdv <= 2) return "Souris / Rat";
|
||||||
|
if (pdv <= 5) return "Chat";
|
||||||
|
if (pdv <= 7) return "Blaireau / Chien";
|
||||||
|
if (pdv <= 13) return "Chimpanzé / Chèvre";
|
||||||
|
if (pdv <= 28) return "Humain";
|
||||||
|
if (pdv <= 35) return "Vache / Cheval";
|
||||||
|
if (pdv <= 49) return "Requin";
|
||||||
|
if (pdv <= 70) return "Rhinocéros";
|
||||||
|
if (pdv <= 90) return "Éléphant";
|
||||||
|
if (pdv <= 125) return "Carnosaure";
|
||||||
|
return "Sauropode / Baleine";
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSizeTrait(pdv) {
|
||||||
|
if (pdv <= 2) return "Petit (−4)";
|
||||||
|
if (pdv <= 5) return "Petit (−3)";
|
||||||
|
if (pdv <= 7) return "Petit (−2)";
|
||||||
|
if (pdv <= 13) return "Petit (−1)";
|
||||||
|
if (pdv <= 28) return "—";
|
||||||
|
if (pdv <= 35) return "Grand (+1)";
|
||||||
|
if (pdv <= 49) return "Grand (+2)";
|
||||||
|
if (pdv <= 70) return "Grand (+3)";
|
||||||
|
if (pdv <= 90) return "Grand (+4)";
|
||||||
|
if (pdv <= 125) return "Grand (+5)";
|
||||||
|
return "Grand (+6)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────── Roll Handlers
|
||||||
|
|
||||||
|
/** Roll an attack (damage) with optional difficulty dialog */
|
||||||
|
static async #onRollAttack(event, target) {
|
||||||
|
const index = parseInt(target.dataset.index ?? 0);
|
||||||
|
const actor = this.document;
|
||||||
|
const attack = actor.system.attacks[index];
|
||||||
|
if (!attack) return;
|
||||||
|
|
||||||
|
const rollFormula = normalizeDice(attack.damage);
|
||||||
|
|
||||||
|
const roll = await new Roll(rollFormula).evaluate();
|
||||||
|
roll.total;
|
||||||
|
|
||||||
|
await roll.toMessage({
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor }),
|
||||||
|
flavor: `<strong>${actor.name}</strong> — ${attack.name}`,
|
||||||
|
rollMode: game.settings.get("core", "rollMode"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Roll a skill check (2d6 + level vs difficulty) */
|
||||||
|
static async #onRollSkill(event, target) {
|
||||||
|
const index = parseInt(target.dataset.index ?? 0);
|
||||||
|
const actor = this.document;
|
||||||
|
const skill = actor.system.skills[index];
|
||||||
|
if (!skill) return;
|
||||||
|
|
||||||
|
const htmlContent = await renderTemplate(
|
||||||
|
"systems/mgt2/templates/actors/creature-roll-prompt.html",
|
||||||
|
{
|
||||||
|
skillName: skill.name,
|
||||||
|
skillLevel: skill.level,
|
||||||
|
config: CONFIG.MGT2
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: game.i18n.localize("MGT2.Creature.RollSkill") + " — " + skill.name },
|
||||||
|
content: htmlContent,
|
||||||
|
rejectClose: false,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
action: "boon",
|
||||||
|
label: game.i18n.localize("MGT2.RollPrompt.Boon"),
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
|
const fd = new foundry.applications.ux.FormDataExtended(dialog.element.querySelector("form")).object;
|
||||||
|
fd.diceModifier = "dl";
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "roll",
|
||||||
|
label: game.i18n.localize("MGT2.RollPrompt.Roll"),
|
||||||
|
icon: '<i class="fa-solid fa-dice"></i>',
|
||||||
|
default: true,
|
||||||
|
callback: (event, button, dialog) =>
|
||||||
|
new foundry.applications.ux.FormDataExtended(dialog.element.querySelector("form")).object
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "bane",
|
||||||
|
label: game.i18n.localize("MGT2.RollPrompt.Bane"),
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
|
const fd = new foundry.applications.ux.FormDataExtended(dialog.element.querySelector("form")).object;
|
||||||
|
fd.diceModifier = "dh";
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
const dm = parseInt(result.dm ?? 0) + (skill.level ?? 0);
|
||||||
|
const modifier = result.diceModifier ?? "";
|
||||||
|
const difficultyTarget = parseInt(result.difficulty ?? 8);
|
||||||
|
const difficultyLabel = result.difficultyLabel ?? "";
|
||||||
|
|
||||||
|
const diceFormula = modifier ? `3d6${modifier}` : "2d6";
|
||||||
|
const fullFormula = dm !== 0 ? `${diceFormula} + ${dm}` : diceFormula;
|
||||||
|
|
||||||
|
const roll = await new Roll(fullFormula).evaluate();
|
||||||
|
const success = roll.total >= difficultyTarget;
|
||||||
|
|
||||||
|
const chatData = {
|
||||||
|
creatureName: actor.name,
|
||||||
|
creatureImg: actor.img,
|
||||||
|
rollLabel: skill.name.toUpperCase(),
|
||||||
|
formula: fullFormula,
|
||||||
|
total: roll.total,
|
||||||
|
tooltip: await roll.getTooltip(),
|
||||||
|
difficulty: difficultyTarget,
|
||||||
|
difficultyLabel,
|
||||||
|
success,
|
||||||
|
failure: !success,
|
||||||
|
modifiers: dm !== 0 ? [`DM ${dm >= 0 ? "+" : ""}${dm}`] : [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const chatContent = await renderTemplate(
|
||||||
|
"systems/mgt2/templates/chat/creature-roll.html",
|
||||||
|
chatData
|
||||||
|
);
|
||||||
|
|
||||||
|
await ChatMessage.create({
|
||||||
|
content: chatContent,
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor }),
|
||||||
|
rolls: [roll],
|
||||||
|
rollMode: game.settings.get("core", "rollMode"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────── CRUD Handlers
|
||||||
|
|
||||||
|
static async #onAddRow(event, target) {
|
||||||
|
const prop = target.dataset.prop;
|
||||||
|
if (!prop) return;
|
||||||
|
const actor = this.document;
|
||||||
|
const arr = foundry.utils.deepClone(actor.system[prop] ?? []);
|
||||||
|
arr.push(this._getDefaultRow(prop));
|
||||||
|
await actor.update({ [`system.${prop}`]: arr });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onDeleteRow(event, target) {
|
||||||
|
const prop = target.dataset.prop;
|
||||||
|
const index = parseInt(target.dataset.index);
|
||||||
|
if (!prop || isNaN(index)) return;
|
||||||
|
const actor = this.document;
|
||||||
|
const arr = foundry.utils.deepClone(actor.system[prop] ?? []);
|
||||||
|
arr.splice(index, 1);
|
||||||
|
await actor.update({ [`system.${prop}`]: arr });
|
||||||
|
}
|
||||||
|
|
||||||
|
_getDefaultRow(prop) {
|
||||||
|
switch (prop) {
|
||||||
|
case "skills": return { name: "", level: 0, note: "" };
|
||||||
|
case "attacks": return { name: "", damage: "1D", description: "" };
|
||||||
|
case "traits": return { name: "", value: "", description: "" };
|
||||||
|
default: return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||||
|
|
||||||
class TravellerItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
class TravellerItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||||
@@ -2774,6 +3104,9 @@ const preloadHandlebarsTemplates = async function() {
|
|||||||
"systems/mgt2/templates/actors/actor-config-sheet.html",
|
"systems/mgt2/templates/actors/actor-config-sheet.html",
|
||||||
"systems/mgt2/templates/actors/actor-config-characteristic-sheet.html",
|
"systems/mgt2/templates/actors/actor-config-characteristic-sheet.html",
|
||||||
"systems/mgt2/templates/actors/trait-sheet.html",
|
"systems/mgt2/templates/actors/trait-sheet.html",
|
||||||
|
"systems/mgt2/templates/actors/creature-sheet.html",
|
||||||
|
"systems/mgt2/templates/actors/creature-roll-prompt.html",
|
||||||
|
"systems/mgt2/templates/chat/creature-roll.html",
|
||||||
"systems/mgt2/templates/editor-fullview.html"
|
"systems/mgt2/templates/editor-fullview.html"
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -2849,7 +3182,7 @@ class ChatHelper {
|
|||||||
speaker = game.user.character;
|
speaker = game.user.character;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rollTypeName = message.flags.mgt2.damage.rollTypeName ? message.flags.mgt2.damage.rollTypeName + " DAMAGE" : null;
|
let rollTypeName = message.flags.mgt2.damage.rollTypeName ? message.flags.mgt2.damage.rollTypeName + " " + game.i18n.localize("MGT2.Actor.Damage") : null;
|
||||||
|
|
||||||
const chatData = {
|
const chatData = {
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
@@ -3011,6 +3344,10 @@ Hooks.once("init", async function () {
|
|||||||
"characteristics.charm.value",
|
"characteristics.charm.value",
|
||||||
"characteristics.psionic.value",
|
"characteristics.psionic.value",
|
||||||
"characteristics.other.value"]
|
"characteristics.other.value"]
|
||||||
|
},
|
||||||
|
creature: {
|
||||||
|
bar: ["life"],
|
||||||
|
value: ["life.value", "life.max", "speed", "armor", "psi"]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3029,13 +3366,15 @@ Hooks.once("init", async function () {
|
|||||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||||
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerCharacterSheet, { types: ["character"], makeDefault: true, label: "Traveller Sheet" });
|
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerCharacterSheet, { types: ["character"], makeDefault: true, label: "Traveller Sheet" });
|
||||||
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerVehiculeSheet, { types: ["vehicule"], makeDefault: true, label: "Vehicule Sheet" });
|
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerVehiculeSheet, { types: ["vehicule"], makeDefault: true, label: "Vehicule Sheet" });
|
||||||
|
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerCreatureSheet, { types: ["creature"], makeDefault: true, label: "Creature Sheet" });
|
||||||
|
|
||||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||||
foundry.documents.collections.Items.registerSheet("mgt2", TravellerItemSheet, { makeDefault: true });
|
foundry.documents.collections.Items.registerSheet("mgt2", TravellerItemSheet, { makeDefault: true });
|
||||||
|
|
||||||
Object.assign(CONFIG.Actor.dataModels, {
|
Object.assign(CONFIG.Actor.dataModels, {
|
||||||
"character": CharacterData,
|
"character": CharacterData,
|
||||||
"vehicule": VehiculeData
|
"vehicule": VehiculeData,
|
||||||
|
"creature": CreatureData
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.assign(CONFIG.Item.dataModels, {
|
Object.assign(CONFIG.Item.dataModels, {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,5 @@
|
|||||||
export { default as MGT2ActorSheet } from "./base-actor-sheet.mjs";
|
export { default as MGT2ActorSheet } from "./base-actor-sheet.mjs";
|
||||||
export { default as TravellerCharacterSheet } from "./character-sheet.mjs";
|
export { default as TravellerCharacterSheet } from "./character-sheet.mjs";
|
||||||
export { default as TravellerVehiculeSheet } from "./vehicule-sheet.mjs";
|
export { default as TravellerVehiculeSheet } from "./vehicule-sheet.mjs";
|
||||||
|
export { default as TravellerCreatureSheet } from "./creature-sheet.mjs";
|
||||||
export { default as TravellerItemSheet } from "./item-sheet.mjs";
|
export { default as TravellerItemSheet } from "./item-sheet.mjs";
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
const html = this.element;
|
const html = this.element;
|
||||||
if (!this.isEditable) return;
|
if (!this.isEditable) return;
|
||||||
|
|
||||||
this._bindClassEvent(html, ".roll", "click", TravellerCharacterSheet.#onRoll);
|
this._bindClassEvent(html, "a[data-roll]", "click", TravellerCharacterSheet.#onRoll);
|
||||||
this._bindClassEvent(html, ".cfg-characteristic", "click", TravellerCharacterSheet.#onOpenCharacteristic);
|
this._bindClassEvent(html, ".cfg-characteristic", "click", TravellerCharacterSheet.#onOpenCharacteristic);
|
||||||
this._bindClassEvent(html, ".item-create", "click", TravellerCharacterSheet.#onCreateItem);
|
this._bindClassEvent(html, ".item-create", "click", TravellerCharacterSheet.#onCreateItem);
|
||||||
this._bindClassEvent(html, ".item-edit", "click", TravellerCharacterSheet.#onEditItem);
|
this._bindClassEvent(html, ".item-edit", "click", TravellerCharacterSheet.#onEditItem);
|
||||||
@@ -374,26 +374,22 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
let sourceItem = this.actor.getEmbeddedDocument("Item", sourceItemData.id);
|
let sourceItem = this.actor.getEmbeddedDocument("Item", sourceItemData.id);
|
||||||
if (sourceItem) {
|
if (sourceItem) {
|
||||||
if (!targetItem) return false;
|
if (!targetItem) return false;
|
||||||
sourceItem = foundry.utils.deepClone(sourceItem);
|
if (sourceItem.id === targetId) return false;
|
||||||
if (sourceItem._id === targetId) return false;
|
|
||||||
|
|
||||||
if (targetItem.type === "item" || targetItem.type === "equipment") {
|
if (targetItem.type === "item" || targetItem.type === "equipment") {
|
||||||
if (targetItem.system.subType === "software")
|
if (targetItem.system.subType === "software")
|
||||||
sourceItem.system.software.computerId = targetItem.system.software.computerId;
|
await sourceItem.update({ "system.software.computerId": targetItem.system.software.computerId });
|
||||||
else
|
else
|
||||||
sourceItem.system.container.id = targetItem.system.container.id;
|
await sourceItem.update({ "system.container.id": targetItem.system.container.id });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
|
||||||
return true;
|
return true;
|
||||||
} else if (targetItem.type === "computer") {
|
} else if (targetItem.type === "computer") {
|
||||||
sourceItem.system.software.computerId = targetId;
|
await sourceItem.update({ "system.software.computerId": targetId });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
|
||||||
return true;
|
return true;
|
||||||
} else if (targetItem.type === "container") {
|
} else if (targetItem.type === "container") {
|
||||||
if (targetItem.system.locked && !game.user.isGM) {
|
if (targetItem.system.locked && !game.user.isGM) {
|
||||||
ui.notifications.error("Verrouillé");
|
ui.notifications.error("Verrouillé");
|
||||||
} else {
|
} else {
|
||||||
sourceItem.system.container.id = targetId;
|
await sourceItem.update({ "system.container.id": targetId });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -466,20 +462,19 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
static async #onEquipItem(event, target) {
|
static async #onEquipItem(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
item.system.equipped = !item.system.equipped;
|
await item.update({ "system.equipped": !item.system.equipped });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onItemStorageIn(event, target) {
|
static async #onItemStorageIn(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
if (item.type === "container") {
|
if (item.type === "container") {
|
||||||
item.system.onHand = false;
|
await item.update({ "system.onHand": false });
|
||||||
} else {
|
} else {
|
||||||
const containers = this.actor.getContainers();
|
const containers = this.actor.getContainers();
|
||||||
let container;
|
let container;
|
||||||
@@ -497,27 +492,24 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
ui.notifications.error("Objet verrouillé");
|
ui.notifications.error("Objet verrouillé");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
item.system.container.id = container._id;
|
await item.update({ "system.container.id": container._id });
|
||||||
}
|
}
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onItemStorageOut(event, target) {
|
static async #onItemStorageOut(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
item.system.container.id = "";
|
await item.update({ "system.container.id": "" });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onSoftwareEject(event, target) {
|
static async #onSoftwareEject(event, target) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const li = target.closest("[data-item-id]");
|
const li = target.closest("[data-item-id]");
|
||||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
const item = this.actor.getEmbeddedDocument("Item", li?.dataset.itemId);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
item.system.software.computerId = "";
|
await item.update({ "system.software.computerId": "" });
|
||||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onContainerCreate(event) {
|
static async #onContainerCreate(event) {
|
||||||
@@ -543,23 +535,19 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (containerItems.length > 0) {
|
if (containerItems.length > 0) {
|
||||||
for (let item of containerItems) {
|
const updates = containerItems.map(item => ({ _id: item.id, "system.container.id": "" }));
|
||||||
let clone = foundry.utils.deepClone(item);
|
await this.actor.updateEmbeddedDocuments("Item", updates);
|
||||||
clone.system.container.id = "";
|
|
||||||
this.actor.updateEmbeddedDocuments("Item", [clone]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloneActor = foundry.utils.deepClone(this.actor);
|
const actorUpdate = { "system.containerView": "" };
|
||||||
cloneActor.system.containerView = "";
|
if (this.actor.system.containerDropIn === container._id) {
|
||||||
if (cloneActor.system.containerDropIn === container._id) {
|
actorUpdate["system.containerDropIn"] = "";
|
||||||
cloneActor.system.containerDropIn = "";
|
|
||||||
const remaining = containers.filter(x => x._id !== container._id);
|
const remaining = containers.filter(x => x._id !== container._id);
|
||||||
if (remaining.length > 0) cloneActor.system.containerDropIn = remaining[0]._id;
|
if (remaining.length > 0) actorUpdate["system.containerDropIn"] = remaining[0]._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.actor.deleteEmbeddedDocuments("Item", [container._id]);
|
await this.actor.deleteEmbeddedDocuments("Item", [container._id]);
|
||||||
this.actor.update(cloneActor);
|
await this.actor.update(actorUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onRoll(event, target) {
|
static async #onRoll(event, target) {
|
||||||
|
|||||||
231
src/module/applications/sheets/creature-sheet.mjs
Normal file
231
src/module/applications/sheets/creature-sheet.mjs
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
import MGT2ActorSheet from "./base-actor-sheet.mjs";
|
||||||
|
|
||||||
|
/** Convert Traveller dice notation (e.g. "2D", "4D+2", "3D6") to FoundryVTT formula */
|
||||||
|
function normalizeDice(formula) {
|
||||||
|
if (!formula) return "1d6";
|
||||||
|
return formula
|
||||||
|
.replace(/(\d*)D(\d*)([+-]\d+)?/gi, (_, count, sides, mod) => {
|
||||||
|
const n = count || "1";
|
||||||
|
const d = sides || "6";
|
||||||
|
return mod ? `${n}d${d}${mod}` : `${n}d${d}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TravellerCreatureSheet extends MGT2ActorSheet {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes, "creature", "nopad"],
|
||||||
|
position: {
|
||||||
|
width: 720,
|
||||||
|
height: 600,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
...super.DEFAULT_OPTIONS.window,
|
||||||
|
title: "TYPES.Actor.creature",
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
...super.DEFAULT_OPTIONS.actions,
|
||||||
|
rollAttack: TravellerCreatureSheet.#onRollAttack,
|
||||||
|
rollSkill: TravellerCreatureSheet.#onRollSkill,
|
||||||
|
addSkill: TravellerCreatureSheet.#onAddRow,
|
||||||
|
deleteSkill: TravellerCreatureSheet.#onDeleteRow,
|
||||||
|
addAttack: TravellerCreatureSheet.#onAddRow,
|
||||||
|
deleteAttack: TravellerCreatureSheet.#onDeleteRow,
|
||||||
|
addTrait: TravellerCreatureSheet.#onAddRow,
|
||||||
|
deleteTrait: TravellerCreatureSheet.#onDeleteRow,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
sheet: {
|
||||||
|
template: "systems/mgt2/templates/actors/creature-sheet.html",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
tabGroups = { primary: "skills" }
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext();
|
||||||
|
const actor = this.document;
|
||||||
|
|
||||||
|
context.sizeLabel = this._getSizeLabel(actor.system.life.max);
|
||||||
|
context.sizeTraitLabel = this._getSizeTrait(actor.system.life.max);
|
||||||
|
context.config = CONFIG.MGT2;
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSizeLabel(pdv) {
|
||||||
|
if (pdv <= 2) return "Souris / Rat";
|
||||||
|
if (pdv <= 5) return "Chat";
|
||||||
|
if (pdv <= 7) return "Blaireau / Chien";
|
||||||
|
if (pdv <= 13) return "Chimpanzé / Chèvre";
|
||||||
|
if (pdv <= 28) return "Humain";
|
||||||
|
if (pdv <= 35) return "Vache / Cheval";
|
||||||
|
if (pdv <= 49) return "Requin";
|
||||||
|
if (pdv <= 70) return "Rhinocéros";
|
||||||
|
if (pdv <= 90) return "Éléphant";
|
||||||
|
if (pdv <= 125) return "Carnosaure";
|
||||||
|
return "Sauropode / Baleine";
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSizeTrait(pdv) {
|
||||||
|
if (pdv <= 2) return "Petit (−4)";
|
||||||
|
if (pdv <= 5) return "Petit (−3)";
|
||||||
|
if (pdv <= 7) return "Petit (−2)";
|
||||||
|
if (pdv <= 13) return "Petit (−1)";
|
||||||
|
if (pdv <= 28) return "—";
|
||||||
|
if (pdv <= 35) return "Grand (+1)";
|
||||||
|
if (pdv <= 49) return "Grand (+2)";
|
||||||
|
if (pdv <= 70) return "Grand (+3)";
|
||||||
|
if (pdv <= 90) return "Grand (+4)";
|
||||||
|
if (pdv <= 125) return "Grand (+5)";
|
||||||
|
return "Grand (+6)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────── Roll Handlers
|
||||||
|
|
||||||
|
/** Roll an attack (damage) with optional difficulty dialog */
|
||||||
|
static async #onRollAttack(event, target) {
|
||||||
|
const index = parseInt(target.dataset.index ?? 0);
|
||||||
|
const actor = this.document;
|
||||||
|
const attack = actor.system.attacks[index];
|
||||||
|
if (!attack) return;
|
||||||
|
|
||||||
|
const rollFormula = normalizeDice(attack.damage);
|
||||||
|
|
||||||
|
const roll = await new Roll(rollFormula).evaluate();
|
||||||
|
const total = roll.total;
|
||||||
|
|
||||||
|
await roll.toMessage({
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor }),
|
||||||
|
flavor: `<strong>${actor.name}</strong> — ${attack.name}`,
|
||||||
|
rollMode: game.settings.get("core", "rollMode"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Roll a skill check (2d6 + level vs difficulty) */
|
||||||
|
static async #onRollSkill(event, target) {
|
||||||
|
const index = parseInt(target.dataset.index ?? 0);
|
||||||
|
const actor = this.document;
|
||||||
|
const skill = actor.system.skills[index];
|
||||||
|
if (!skill) return;
|
||||||
|
|
||||||
|
const htmlContent = await renderTemplate(
|
||||||
|
"systems/mgt2/templates/actors/creature-roll-prompt.html",
|
||||||
|
{
|
||||||
|
skillName: skill.name,
|
||||||
|
skillLevel: skill.level,
|
||||||
|
config: CONFIG.MGT2
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: game.i18n.localize("MGT2.Creature.RollSkill") + " — " + skill.name },
|
||||||
|
content: htmlContent,
|
||||||
|
rejectClose: false,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
action: "boon",
|
||||||
|
label: game.i18n.localize("MGT2.RollPrompt.Boon"),
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
|
const fd = new foundry.applications.ux.FormDataExtended(dialog.element.querySelector("form")).object;
|
||||||
|
fd.diceModifier = "dl";
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "roll",
|
||||||
|
label: game.i18n.localize("MGT2.RollPrompt.Roll"),
|
||||||
|
icon: '<i class="fa-solid fa-dice"></i>',
|
||||||
|
default: true,
|
||||||
|
callback: (event, button, dialog) =>
|
||||||
|
new foundry.applications.ux.FormDataExtended(dialog.element.querySelector("form")).object
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "bane",
|
||||||
|
label: game.i18n.localize("MGT2.RollPrompt.Bane"),
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
|
const fd = new foundry.applications.ux.FormDataExtended(dialog.element.querySelector("form")).object;
|
||||||
|
fd.diceModifier = "dh";
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
const dm = parseInt(result.dm ?? 0) + (skill.level ?? 0);
|
||||||
|
const modifier = result.diceModifier ?? "";
|
||||||
|
const difficultyTarget = parseInt(result.difficulty ?? 8);
|
||||||
|
const difficultyLabel = result.difficultyLabel ?? "";
|
||||||
|
|
||||||
|
const diceFormula = modifier ? `3d6${modifier}` : "2d6";
|
||||||
|
const fullFormula = dm !== 0 ? `${diceFormula} + ${dm}` : diceFormula;
|
||||||
|
|
||||||
|
const roll = await new Roll(fullFormula).evaluate();
|
||||||
|
const success = roll.total >= difficultyTarget;
|
||||||
|
|
||||||
|
const chatData = {
|
||||||
|
creatureName: actor.name,
|
||||||
|
creatureImg: actor.img,
|
||||||
|
rollLabel: skill.name.toUpperCase(),
|
||||||
|
formula: fullFormula,
|
||||||
|
total: roll.total,
|
||||||
|
tooltip: await roll.getTooltip(),
|
||||||
|
difficulty: difficultyTarget,
|
||||||
|
difficultyLabel,
|
||||||
|
success,
|
||||||
|
failure: !success,
|
||||||
|
modifiers: dm !== 0 ? [`DM ${dm >= 0 ? "+" : ""}${dm}`] : [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const chatContent = await renderTemplate(
|
||||||
|
"systems/mgt2/templates/chat/creature-roll.html",
|
||||||
|
chatData
|
||||||
|
);
|
||||||
|
|
||||||
|
await ChatMessage.create({
|
||||||
|
content: chatContent,
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor }),
|
||||||
|
rolls: [roll],
|
||||||
|
rollMode: game.settings.get("core", "rollMode"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────── CRUD Handlers
|
||||||
|
|
||||||
|
static async #onAddRow(event, target) {
|
||||||
|
const prop = target.dataset.prop;
|
||||||
|
if (!prop) return;
|
||||||
|
const actor = this.document;
|
||||||
|
const arr = foundry.utils.deepClone(actor.system[prop] ?? []);
|
||||||
|
arr.push(this._getDefaultRow(prop));
|
||||||
|
await actor.update({ [`system.${prop}`]: arr });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onDeleteRow(event, target) {
|
||||||
|
const prop = target.dataset.prop;
|
||||||
|
const index = parseInt(target.dataset.index);
|
||||||
|
if (!prop || isNaN(index)) return;
|
||||||
|
const actor = this.document;
|
||||||
|
const arr = foundry.utils.deepClone(actor.system[prop] ?? []);
|
||||||
|
arr.splice(index, 1);
|
||||||
|
await actor.update({ [`system.${prop}`]: arr });
|
||||||
|
}
|
||||||
|
|
||||||
|
_getDefaultRow(prop) {
|
||||||
|
switch (prop) {
|
||||||
|
case "skills": return { name: "", level: 0, note: "" };
|
||||||
|
case "attacks": return { name: "", damage: "1D", description: "" };
|
||||||
|
case "traits": return { name: "", value: "", description: "" };
|
||||||
|
default: return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ export class ChatHelper {
|
|||||||
speaker = game.user.character;
|
speaker = game.user.character;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rollTypeName = message.flags.mgt2.damage.rollTypeName ? message.flags.mgt2.damage.rollTypeName + " DAMAGE" : null;
|
let rollTypeName = message.flags.mgt2.damage.rollTypeName ? message.flags.mgt2.damage.rollTypeName + " " + game.i18n.localize("MGT2.Actor.Damage") : null;
|
||||||
|
|
||||||
const chatData = {
|
const chatData = {
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
|
|||||||
@@ -154,4 +154,27 @@ MGT2.Durations = Object.freeze({
|
|||||||
Seconds: "MGT2.Durations.Seconds",
|
Seconds: "MGT2.Durations.Seconds",
|
||||||
Minutes: "MGT2.Durations.Minutes",
|
Minutes: "MGT2.Durations.Minutes",
|
||||||
Heures: "MGT2.Durations.Heures"
|
Heures: "MGT2.Durations.Heures"
|
||||||
|
});
|
||||||
|
|
||||||
|
MGT2.CreatureBehaviorType = Object.freeze({
|
||||||
|
herbivore: "MGT2.CreatureBehaviorType.herbivore",
|
||||||
|
carnivore: "MGT2.CreatureBehaviorType.carnivore",
|
||||||
|
charognard: "MGT2.CreatureBehaviorType.charognard",
|
||||||
|
omnivore: "MGT2.CreatureBehaviorType.omnivore"
|
||||||
|
});
|
||||||
|
|
||||||
|
MGT2.CreatureBehaviorSubType = Object.freeze({
|
||||||
|
accumulateur: "MGT2.CreatureBehaviorSubType.accumulateur",
|
||||||
|
brouteur: "MGT2.CreatureBehaviorSubType.brouteur",
|
||||||
|
filtreur: "MGT2.CreatureBehaviorSubType.filtreur",
|
||||||
|
intermittent: "MGT2.CreatureBehaviorSubType.intermittent",
|
||||||
|
chasseur: "MGT2.CreatureBehaviorSubType.chasseur",
|
||||||
|
detourneur: "MGT2.CreatureBehaviorSubType.detourneux",
|
||||||
|
guetteur: "MGT2.CreatureBehaviorSubType.guetteur",
|
||||||
|
mangeur: "MGT2.CreatureBehaviorSubType.mangeur",
|
||||||
|
piegeur: "MGT2.CreatureBehaviorSubType.piegeur",
|
||||||
|
intimidateur: "MGT2.CreatureBehaviorSubType.intimidateur",
|
||||||
|
necrophage: "MGT2.CreatureBehaviorSubType.necrophage",
|
||||||
|
reducteur: "MGT2.CreatureBehaviorSubType.reducteur",
|
||||||
|
opportuniste: "MGT2.CreatureBehaviorSubType.opportuniste"
|
||||||
});
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
CharacterData,
|
CharacterData,
|
||||||
VehiculeData,
|
VehiculeData,
|
||||||
|
CreatureData,
|
||||||
ItemData,
|
ItemData,
|
||||||
EquipmentData,
|
EquipmentData,
|
||||||
DiseaseData,
|
DiseaseData,
|
||||||
@@ -17,7 +18,7 @@ import {
|
|||||||
import { MGT2 } from "./config.js";
|
import { MGT2 } from "./config.js";
|
||||||
import { TravellerActor, MGT2Combatant } from "./actors/actor.js";
|
import { TravellerActor, MGT2Combatant } from "./actors/actor.js";
|
||||||
import { TravellerItem } from "./item.js";
|
import { TravellerItem } from "./item.js";
|
||||||
import { TravellerItemSheet, TravellerCharacterSheet, TravellerVehiculeSheet } from "./applications/sheets/_module.mjs";
|
import { TravellerItemSheet, TravellerCharacterSheet, TravellerVehiculeSheet, TravellerCreatureSheet } from "./applications/sheets/_module.mjs";
|
||||||
import { preloadHandlebarsTemplates } from "./templates.js";
|
import { preloadHandlebarsTemplates } from "./templates.js";
|
||||||
//import { MGT2Helper } from "./helper.js";
|
//import { MGT2Helper } from "./helper.js";
|
||||||
import {ChatHelper} from "./chatHelper.js";
|
import {ChatHelper} from "./chatHelper.js";
|
||||||
@@ -73,6 +74,10 @@ Hooks.once("init", async function () {
|
|||||||
"characteristics.charm.value",
|
"characteristics.charm.value",
|
||||||
"characteristics.psionic.value",
|
"characteristics.psionic.value",
|
||||||
"characteristics.other.value"]
|
"characteristics.other.value"]
|
||||||
|
},
|
||||||
|
creature: {
|
||||||
|
bar: ["life"],
|
||||||
|
value: ["life.value", "life.max", "speed", "armor", "psi"]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,13 +96,15 @@ Hooks.once("init", async function () {
|
|||||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||||
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerCharacterSheet, { types: ["character"], makeDefault: true, label: "Traveller Sheet" });
|
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerCharacterSheet, { types: ["character"], makeDefault: true, label: "Traveller Sheet" });
|
||||||
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerVehiculeSheet, { types: ["vehicule"], makeDefault: true, label: "Vehicule Sheet" });
|
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerVehiculeSheet, { types: ["vehicule"], makeDefault: true, label: "Vehicule Sheet" });
|
||||||
|
foundry.documents.collections.Actors.registerSheet("mgt2", TravellerCreatureSheet, { types: ["creature"], makeDefault: true, label: "Creature Sheet" });
|
||||||
|
|
||||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||||
foundry.documents.collections.Items.registerSheet("mgt2", TravellerItemSheet, { makeDefault: true });
|
foundry.documents.collections.Items.registerSheet("mgt2", TravellerItemSheet, { makeDefault: true });
|
||||||
|
|
||||||
Object.assign(CONFIG.Actor.dataModels, {
|
Object.assign(CONFIG.Actor.dataModels, {
|
||||||
"character": CharacterData,
|
"character": CharacterData,
|
||||||
"vehicule": VehiculeData
|
"vehicule": VehiculeData,
|
||||||
|
"creature": CreatureData
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.assign(CONFIG.Item.dataModels, {
|
Object.assign(CONFIG.Item.dataModels, {
|
||||||
|
|||||||
@@ -109,18 +109,9 @@ export class MGT2Helper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getDifficultyDisplay(difficulty) {
|
static getDifficultyDisplay(difficulty) {
|
||||||
switch(difficulty) {
|
const key = `MGT2.Difficulty.${difficulty}`;
|
||||||
case "Simple": return game.i18n.localize("MGT2.Difficulty.Simple") + " (2+)";
|
const label = game.i18n.localize(key);
|
||||||
case "Easy": return game.i18n.localize("MGT2.Difficulty.Easy") + " (4+)";
|
return label !== key ? label : null;
|
||||||
case "Routine": return game.i18n.localize("MGT2.Difficulty.Routine") + " (6+)";
|
|
||||||
case "Average": return game.i18n.localize("MGT2.Difficulty.Average") + " (8+)";
|
|
||||||
case "Difficult": return game.i18n.localize("MGT2.Difficulty.Difficult") + " (10+)";
|
|
||||||
case "VeryDifficult": return game.i18n.localize("MGT2.Difficulty.VeryDifficult") + " (12+)";
|
|
||||||
case "Formidable": return game.i18n.localize("MGT2.Difficulty.Formidable") + " (14+)";
|
|
||||||
case "Impossible": return game.i18n.localize("MGT2.Difficulty.Impossible") + " (16+)";
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getRangeDisplay(range) {
|
static getRangeDisplay(range) {
|
||||||
|
|||||||
96
src/module/models/creature.mjs
Normal file
96
src/module/models/creature.mjs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
export default class CreatureData extends foundry.abstract.TypeDataModel {
|
||||||
|
|
||||||
|
static defineSchema() {
|
||||||
|
return {
|
||||||
|
life: new fields.SchemaField({
|
||||||
|
value: new fields.NumberField({ required: true, initial: 10, min: 0, integer: true }),
|
||||||
|
max: new fields.NumberField({ required: true, initial: 10, min: 0, integer: true })
|
||||||
|
}),
|
||||||
|
|
||||||
|
speed: new fields.NumberField({ required: true, initial: 6, min: 0, integer: true }),
|
||||||
|
|
||||||
|
armor: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
|
|
||||||
|
psi: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||||
|
|
||||||
|
initiativeBonus: new fields.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
|
|
||||||
|
skills: new fields.ArrayField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
name: new fields.StringField({ required: true, blank: true, trim: true, initial: "" }),
|
||||||
|
level: new fields.NumberField({ required: true, initial: 0, integer: true }),
|
||||||
|
note: new fields.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
attacks: new fields.ArrayField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
name: new fields.StringField({ required: true, blank: true, trim: true, initial: "" }),
|
||||||
|
damage: new fields.StringField({ required: true, blank: true, trim: true, initial: "1D" }),
|
||||||
|
description: new fields.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
traits: new fields.ArrayField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
name: new fields.StringField({ required: true, blank: true, trim: true, initial: "" }),
|
||||||
|
value: new fields.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
|
description: new fields.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
behavior: new fields.SchemaField({
|
||||||
|
type: new fields.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||||
|
subtype: new fields.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||||
|
}),
|
||||||
|
|
||||||
|
biography: new fields.HTMLField({ required: false, blank: true, trim: true }),
|
||||||
|
notes: new fields.HTMLField({ required: false, blank: true, trim: true }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
prepareDerivedData() {
|
||||||
|
// Compute initiative bonus from Métabolisme traits
|
||||||
|
let bonus = 0;
|
||||||
|
for (const trait of this.traits) {
|
||||||
|
const nameLower = trait.name.toLowerCase();
|
||||||
|
if (nameLower.includes("métabolisme rapide") || nameLower.includes("metabolisme rapide")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) bonus += val;
|
||||||
|
} else if (nameLower.includes("métabolisme lent") || nameLower.includes("metabolisme lent")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) bonus -= val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.initiativeBonus = bonus;
|
||||||
|
|
||||||
|
// Compute armor from Armure trait if not set manually
|
||||||
|
if (this.armor === 0) {
|
||||||
|
for (const trait of this.traits) {
|
||||||
|
if (trait.name.toLowerCase().startsWith("armure")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
this.armor = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute PSI from Psionique trait
|
||||||
|
if (this.psi === 0) {
|
||||||
|
for (const trait of this.traits) {
|
||||||
|
if (trait.name.toLowerCase().startsWith("psionique")) {
|
||||||
|
const val = parseInt(trait.value);
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
this.psi = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// Actor DataModels
|
// Actor DataModels
|
||||||
export { default as CharacterData } from "./character.mjs";
|
export { default as CharacterData } from "./character.mjs";
|
||||||
export { default as VehiculeData } from "./vehicule.mjs";
|
export { default as VehiculeData } from "./vehicule.mjs";
|
||||||
|
export { default as CreatureData } from "./creature.mjs";
|
||||||
|
|
||||||
// Item DataModels
|
// Item DataModels
|
||||||
export { default as ItemData } from "./items/item.mjs";
|
export { default as ItemData } from "./items/item.mjs";
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export class RollPromptHelper {
|
|||||||
|
|
||||||
return await DialogV2.wait({
|
return await DialogV2.wait({
|
||||||
window: { title: options.title ?? options.rollTypeName ?? game.i18n.localize("MGT2.RollPrompt.Roll") },
|
window: { title: options.title ?? options.rollTypeName ?? game.i18n.localize("MGT2.RollPrompt.Roll") },
|
||||||
|
classes: ["mgt2-roll-dialog"],
|
||||||
content: htmlContent,
|
content: htmlContent,
|
||||||
rejectClose: false,
|
rejectClose: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ export const preloadHandlebarsTemplates = async function() {
|
|||||||
"systems/mgt2/templates/actors/actor-config-sheet.html",
|
"systems/mgt2/templates/actors/actor-config-sheet.html",
|
||||||
"systems/mgt2/templates/actors/actor-config-characteristic-sheet.html",
|
"systems/mgt2/templates/actors/actor-config-characteristic-sheet.html",
|
||||||
"systems/mgt2/templates/actors/trait-sheet.html",
|
"systems/mgt2/templates/actors/trait-sheet.html",
|
||||||
|
"systems/mgt2/templates/actors/creature-sheet.html",
|
||||||
|
"systems/mgt2/templates/actors/creature-roll-prompt.html",
|
||||||
|
"systems/mgt2/templates/chat/creature-roll.html",
|
||||||
"systems/mgt2/templates/editor-fullview.html"
|
"systems/mgt2/templates/editor-fullview.html"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
font-weight: 600
|
font-weight: 600
|
||||||
font-style: italic
|
font-style: italic
|
||||||
text-align: center
|
text-align: center
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
position: relative
|
position: relative
|
||||||
& > a
|
& > a
|
||||||
&.roll
|
&.roll
|
||||||
@@ -122,7 +123,7 @@
|
|||||||
background-color: transparent
|
background-color: transparent
|
||||||
text-align: center
|
text-align: center
|
||||||
font-size: 1.5rem
|
font-size: 1.5rem
|
||||||
width: 2rem
|
width: 3rem
|
||||||
height: 2rem
|
height: 2rem
|
||||||
border: none
|
border: none
|
||||||
outline: none
|
outline: none
|
||||||
@@ -183,13 +184,14 @@ ul
|
|||||||
float: left
|
float: left
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
color: var(--mgt2-color-primary-light)
|
color: var(--mgt2-color-form)
|
||||||
input
|
input
|
||||||
display: block
|
display: block
|
||||||
border: none
|
border: none
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
font-family: "Roboto Condensed", sans-serif
|
font-family: "Roboto Condensed", sans-serif
|
||||||
background-color: #fff
|
background-color: #fff
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
font-size: 0.8rem
|
font-size: 0.8rem
|
||||||
border: 1px solid #fff
|
border: 1px solid #fff
|
||||||
&:hover
|
&:hover
|
||||||
@@ -203,6 +205,7 @@ ul
|
|||||||
font-size: 0.7rem
|
font-size: 0.7rem
|
||||||
text-transform: uppercase
|
text-transform: uppercase
|
||||||
text-wrap: nowrap
|
text-wrap: nowrap
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
i
|
i
|
||||||
margin-right: 0.25rem
|
margin-right: 0.25rem
|
||||||
.character-body
|
.character-body
|
||||||
@@ -236,7 +239,7 @@ ul
|
|||||||
display: flex
|
display: flex
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
color: #4b4a44
|
color: var(--mgt2-color-form)
|
||||||
justify-content: space-between
|
justify-content: space-between
|
||||||
align-items: center
|
align-items: center
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|||||||
@@ -1,47 +1,331 @@
|
|||||||
.chat-sidebar,
|
// ─── MGT2 Chat Roll Cards ──────────────────────────────────────────────────
|
||||||
.mgt2-buttons button
|
|
||||||
background: rgba(0, 0, 0, 0.1)
|
// Light theme for ALL chat messages - matching character sheet
|
||||||
border: 1px solid var(--color-border-light-2)
|
li.chat-message
|
||||||
border-radius: 3px
|
background: #ffffff !important
|
||||||
box-shadow: 0 0 2px #FFF inset
|
border: 1px solid #ccbbbb !important
|
||||||
//.chat-message
|
box-shadow: 0 2px 8px rgba(0,0,0,0.18) !important
|
||||||
// &.message
|
color: #0A0405
|
||||||
// color: #0A0405
|
padding: 0 !important
|
||||||
// background-color: #fff
|
|
||||||
// background-image: none
|
.message-header
|
||||||
.dice-formula,
|
background: #0A0405
|
||||||
.dice-total
|
border-bottom: 3px solid #EE4050
|
||||||
background-color: #fff
|
padding: 4px 10px
|
||||||
.mgt2-buttons
|
|
||||||
display: flex
|
.message-sender
|
||||||
justify-content: center
|
color: #EE4050
|
||||||
align-items: center
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
flex-wrap: nowrap
|
font-weight: 700
|
||||||
color: #0A0405
|
font-size: 0.75rem
|
||||||
margin-top: 5px
|
text-transform: uppercase
|
||||||
button
|
letter-spacing: 1.5px
|
||||||
i
|
margin: 0
|
||||||
font-size: 1.1rem
|
|
||||||
padding: 0
|
.message-timestamp
|
||||||
margin: 0
|
color: #888888
|
||||||
.roll-info
|
font-size: 0.68rem
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
.message-delete i
|
||||||
.roll-type-group
|
color: #888888
|
||||||
flex-direction: row
|
|
||||||
flex-wrap: wrap
|
&:hover .message-delete i
|
||||||
justify-content: space-between
|
color: #EE4050
|
||||||
display: flex
|
|
||||||
.roll-type-name
|
// Plain Foundry roll cards (without .mgt2-chat-roll wrapper)
|
||||||
font-size: 11px
|
.message-content > .dice-roll
|
||||||
text-transform: uppercase
|
background: #fdf8f8
|
||||||
color: #515151
|
padding: 6px 12px
|
||||||
.roll-object-name
|
|
||||||
font-weight: 400
|
.dice-formula
|
||||||
font-size: 1.4rem
|
background: #f5eeee
|
||||||
.roll-success
|
border: 1px solid #ddc8c8
|
||||||
font-size: 1.2rem
|
border-radius: 3px
|
||||||
font-weight: bold
|
color: #664444
|
||||||
text-transform: uppercase
|
font-size: 0.78rem
|
||||||
margin-top: 1rem
|
padding: 2px 10px
|
||||||
text-align: center
|
text-align: center
|
||||||
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
|
display: inline-block
|
||||||
|
margin: 0 auto 4px auto
|
||||||
|
|
||||||
|
.dice-result
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
align-items: center
|
||||||
|
gap: 3px
|
||||||
|
|
||||||
|
h4.dice-total
|
||||||
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
|
font-size: 2.2rem !important
|
||||||
|
font-weight: 900
|
||||||
|
color: #0A0405 !important
|
||||||
|
margin: 2px 0
|
||||||
|
line-height: 1
|
||||||
|
text-align: center
|
||||||
|
background: transparent !important
|
||||||
|
width: 100% !important
|
||||||
|
display: block !important
|
||||||
|
|
||||||
|
.dice-tooltip
|
||||||
|
.part-header
|
||||||
|
background: #f5eeee
|
||||||
|
padding: 2px 8px
|
||||||
|
display: flex
|
||||||
|
justify-content: space-between
|
||||||
|
.part-formula, .part-total
|
||||||
|
color: #EE4050
|
||||||
|
font-weight: 700
|
||||||
|
font-size: 0.78rem
|
||||||
|
.dice-rolls
|
||||||
|
display: flex
|
||||||
|
flex-wrap: wrap
|
||||||
|
justify-content: center
|
||||||
|
gap: 4px
|
||||||
|
padding: 6px 8px
|
||||||
|
list-style: none
|
||||||
|
margin: 0
|
||||||
|
.roll.die
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
width: 26px
|
||||||
|
height: 26px
|
||||||
|
background: #f5eeee
|
||||||
|
border: 1.5px solid #ddc8c8
|
||||||
|
border-radius: 4px
|
||||||
|
color: #3a2020
|
||||||
|
font-weight: 700
|
||||||
|
font-size: 0.9rem
|
||||||
|
|
||||||
|
// ─── Inner roll card structure ────────────────────────────────────────────
|
||||||
|
|
||||||
|
.mgt2-chat-roll
|
||||||
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
|
|
||||||
|
// ── Header: characteristic name + roll type ──
|
||||||
|
.mgt2-roll-header
|
||||||
|
background: #0A0405 !important
|
||||||
|
border-left: 4px solid #EE4050 !important
|
||||||
|
padding: 5px 10px 4px 10px !important
|
||||||
|
|
||||||
|
.mgt2-roll-char-name
|
||||||
|
display: block
|
||||||
|
color: #ffffff
|
||||||
|
font-size: 1.2rem
|
||||||
|
font-weight: 800
|
||||||
|
text-transform: uppercase
|
||||||
|
letter-spacing: 1px
|
||||||
|
line-height: 1
|
||||||
|
|
||||||
|
.mgt2-roll-meta
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
gap: 6px
|
||||||
|
margin-top: 2px
|
||||||
|
|
||||||
|
.mgt2-roll-type
|
||||||
|
color: #EE4050
|
||||||
|
font-size: 0.68rem
|
||||||
|
font-weight: 700
|
||||||
|
text-transform: uppercase
|
||||||
|
letter-spacing: 2px
|
||||||
|
|
||||||
|
.mgt2-roll-sep
|
||||||
|
color: #888888
|
||||||
|
|
||||||
|
.mgt2-roll-difficulty
|
||||||
|
color: #bbbbbb
|
||||||
|
font-size: 0.68rem
|
||||||
|
text-transform: uppercase
|
||||||
|
letter-spacing: 1px
|
||||||
|
|
||||||
|
// ── Modifier line ──
|
||||||
|
.mgt2-roll-modifier
|
||||||
|
background: #f5eeee
|
||||||
|
border-bottom: 1px solid #e8dada
|
||||||
|
padding: 3px 14px
|
||||||
|
color: #664444
|
||||||
|
font-size: 0.8rem
|
||||||
|
|
||||||
|
.mgt2-roll-modifiers
|
||||||
|
display: flex
|
||||||
|
gap: 6px
|
||||||
|
flex-wrap: wrap
|
||||||
|
background: #f5eeee
|
||||||
|
border-bottom: 1px solid #e8dada
|
||||||
|
padding: 3px 14px
|
||||||
|
|
||||||
|
.mgt2-roll-mod-tag
|
||||||
|
color: #664444
|
||||||
|
font-size: 0.8rem
|
||||||
|
|
||||||
|
// ── Dice block (Foundry .dice-roll structure preserved for tooltip click) ──
|
||||||
|
.dice-roll
|
||||||
|
background: #fdf8f8
|
||||||
|
padding: 4px 10px
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
.dice-flavor
|
||||||
|
color: #888
|
||||||
|
font-size: 0.73rem
|
||||||
|
text-align: center
|
||||||
|
margin-bottom: 3px
|
||||||
|
|
||||||
|
.dice-result
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
align-items: center
|
||||||
|
gap: 3px
|
||||||
|
|
||||||
|
.dice-formula
|
||||||
|
background: #f5eeee
|
||||||
|
border: 1px solid #ddc8c8
|
||||||
|
border-radius: 3px
|
||||||
|
color: #664444
|
||||||
|
font-size: 0.78rem
|
||||||
|
padding: 2px 14px
|
||||||
|
font-family: 'DM Sans', sans-serif
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
// Tooltip (individual dice — shown on click by Foundry)
|
||||||
|
.dice-tooltip
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
.wrapper
|
||||||
|
background: transparent
|
||||||
|
|
||||||
|
.tooltip-part
|
||||||
|
background: #fdf8f8
|
||||||
|
border: 1px solid #e8dada
|
||||||
|
border-radius: 4px
|
||||||
|
margin-bottom: 6px
|
||||||
|
overflow: hidden
|
||||||
|
|
||||||
|
.part-header
|
||||||
|
background: #f5eeee
|
||||||
|
padding: 3px 8px
|
||||||
|
|
||||||
|
.part-formula, .part-total
|
||||||
|
color: #EE4050
|
||||||
|
font-weight: 700
|
||||||
|
font-size: 0.8rem
|
||||||
|
|
||||||
|
.dice-rolls
|
||||||
|
display: flex
|
||||||
|
flex-wrap: wrap
|
||||||
|
justify-content: center
|
||||||
|
gap: 5px
|
||||||
|
padding: 8px 10px
|
||||||
|
list-style: none
|
||||||
|
margin: 0
|
||||||
|
|
||||||
|
.roll.die
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
width: 30px
|
||||||
|
height: 30px
|
||||||
|
background: #f5eeee
|
||||||
|
border: 1.5px solid #ddc8c8
|
||||||
|
border-radius: 5px
|
||||||
|
color: #3a2020
|
||||||
|
font-weight: 700
|
||||||
|
font-size: 1rem
|
||||||
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
|
|
||||||
|
&.max
|
||||||
|
border-color: #EE4050
|
||||||
|
color: #EE4050
|
||||||
|
background: #fde8ea
|
||||||
|
box-shadow: 0 0 8px rgba(238,64,80,0.2)
|
||||||
|
|
||||||
|
&.min
|
||||||
|
border-color: #ccbbbb
|
||||||
|
color: #999999
|
||||||
|
|
||||||
|
// ── Total: prominent number ──
|
||||||
|
h4.dice-total
|
||||||
|
font-size: 1.6rem !important
|
||||||
|
font-weight: 900
|
||||||
|
color: #0A0405 !important
|
||||||
|
margin: 3px 0 2px 0
|
||||||
|
line-height: 1
|
||||||
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
|
text-align: center
|
||||||
|
text-shadow: none
|
||||||
|
background: #f5eeee !important
|
||||||
|
border: 1px solid #ddc8c8 !important
|
||||||
|
border-radius: 4px !important
|
||||||
|
padding: 2px 14px !important
|
||||||
|
width: auto !important
|
||||||
|
display: inline-block !important
|
||||||
|
min-width: 60px
|
||||||
|
|
||||||
|
&.success
|
||||||
|
color: #1a8840 !important
|
||||||
|
background: rgba(82,232,122,0.1) !important
|
||||||
|
border-color: rgba(26,136,64,0.35) !important
|
||||||
|
|
||||||
|
&.failure
|
||||||
|
color: #EE4050 !important
|
||||||
|
background: rgba(238,64,80,0.07) !important
|
||||||
|
border-color: rgba(238,64,80,0.3) !important
|
||||||
|
|
||||||
|
// ── Outcome badge ──
|
||||||
|
.mgt2-outcome
|
||||||
|
text-align: center
|
||||||
|
font-size: 0.75rem
|
||||||
|
font-weight: 700
|
||||||
|
text-transform: uppercase
|
||||||
|
letter-spacing: 2px
|
||||||
|
padding: 3px 10px
|
||||||
|
|
||||||
|
i
|
||||||
|
margin-right: 5px
|
||||||
|
|
||||||
|
&.is-success
|
||||||
|
background: rgba(26,136,64,0.08)
|
||||||
|
color: #1a8840
|
||||||
|
border-top: 1px solid rgba(26,136,64,0.2)
|
||||||
|
|
||||||
|
&.is-failure
|
||||||
|
background: rgba(238,64,80,0.07)
|
||||||
|
color: #EE4050
|
||||||
|
border-top: 1px solid rgba(238,64,80,0.2)
|
||||||
|
|
||||||
|
// ── Action buttons ──
|
||||||
|
.mgt2-buttons
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
flex-wrap: wrap
|
||||||
|
gap: 4px
|
||||||
|
padding: 5px 10px
|
||||||
|
background: #f5eeee
|
||||||
|
border-top: 1px solid #ddc8c8
|
||||||
|
|
||||||
|
button
|
||||||
|
background: #ffffff
|
||||||
|
border: 1px solid #ccbbbb
|
||||||
|
color: #3a2020
|
||||||
|
border-radius: 3px
|
||||||
|
padding: 4px 14px
|
||||||
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
|
font-size: 0.78rem
|
||||||
|
font-weight: 700
|
||||||
|
text-transform: uppercase
|
||||||
|
letter-spacing: 1px
|
||||||
|
cursor: pointer
|
||||||
|
transition: background 0.15s ease, box-shadow 0.15s ease
|
||||||
|
box-shadow: none
|
||||||
|
|
||||||
|
i
|
||||||
|
font-size: 1rem
|
||||||
|
padding: 0
|
||||||
|
margin: 0
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background: #EE4050
|
||||||
|
border-color: #EE4050
|
||||||
|
color: #fff
|
||||||
|
box-shadow: 0 0 8px rgba(238,64,80,0.25)
|
||||||
201
src/sass/components/_creature.sass
Normal file
201
src/sass/components/_creature.sass
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
// ─────────────────────────────────────────────────
|
||||||
|
// Creature Sheet Styles
|
||||||
|
// ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
.creature-sheet
|
||||||
|
|
||||||
|
// ── Header ────────────────────────────────────────
|
||||||
|
.creature-header
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
align-items: flex-start
|
||||||
|
gap: 0.75rem
|
||||||
|
padding: 0.5rem 0.75rem 0.5rem
|
||||||
|
background: var(--mgt2-bgcolor-form)
|
||||||
|
border-bottom: 2px solid var(--mgt2-color-primary)
|
||||||
|
|
||||||
|
.creature-header-img
|
||||||
|
flex: 0 0 80px
|
||||||
|
img.profile
|
||||||
|
width: 80px
|
||||||
|
height: 80px
|
||||||
|
object-fit: cover
|
||||||
|
border: 2px solid var(--mgt2-color-primary)
|
||||||
|
border-radius: 4px
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
.creature-header-body
|
||||||
|
flex: 1
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
gap: 0.4rem
|
||||||
|
|
||||||
|
.creature-name
|
||||||
|
font-family: "Barlow Condensed", sans-serif
|
||||||
|
font-size: 1.6rem
|
||||||
|
font-weight: 700
|
||||||
|
font-style: italic
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
|
background: transparent
|
||||||
|
border: none
|
||||||
|
border-bottom: 1px solid var(--mgt2-color-primary)
|
||||||
|
width: 100%
|
||||||
|
padding: 0
|
||||||
|
&:focus
|
||||||
|
outline: none
|
||||||
|
border-bottom-color: var(--mgt2-color-secondary)
|
||||||
|
|
||||||
|
// ── Stat boxes ────────────────────────────────────
|
||||||
|
.creature-stats-row
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
flex-wrap: wrap
|
||||||
|
gap: 0.5rem
|
||||||
|
|
||||||
|
.creature-stat
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
align-items: center
|
||||||
|
background: var(--mgt2-bgcolor-primary)
|
||||||
|
border: 1px solid var(--mgt2-color-primary)
|
||||||
|
border-radius: 4px
|
||||||
|
padding: 2px 6px
|
||||||
|
min-width: 4rem
|
||||||
|
|
||||||
|
label
|
||||||
|
font-family: "Barlow Condensed", sans-serif
|
||||||
|
font-size: 0.7rem
|
||||||
|
font-weight: 700
|
||||||
|
text-transform: uppercase
|
||||||
|
color: var(--mgt2-color-primary)
|
||||||
|
line-height: 1.2
|
||||||
|
|
||||||
|
.creature-stat-value
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
gap: 2px
|
||||||
|
input
|
||||||
|
width: 2.5rem
|
||||||
|
text-align: center
|
||||||
|
background: transparent
|
||||||
|
border: none
|
||||||
|
color: var(--mgt2-bgcolor-form)
|
||||||
|
font-size: 1rem
|
||||||
|
font-weight: 700
|
||||||
|
padding: 0
|
||||||
|
&:focus
|
||||||
|
outline: none
|
||||||
|
border-bottom: 1px solid var(--mgt2-color-primary)
|
||||||
|
.stat-max
|
||||||
|
width: 2.5rem
|
||||||
|
.stat-unit
|
||||||
|
font-size: 0.7rem
|
||||||
|
color: var(--mgt2-bgcolor-form)
|
||||||
|
opacity: 0.7
|
||||||
|
.stat-readonly
|
||||||
|
font-size: 1rem
|
||||||
|
font-weight: 700
|
||||||
|
color: var(--mgt2-bgcolor-form)
|
||||||
|
min-width: 2.5rem
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
// ── Behavior row ──────────────────────────────────
|
||||||
|
.creature-behavior-row
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
align-items: center
|
||||||
|
gap: 0.5rem
|
||||||
|
flex-wrap: wrap
|
||||||
|
|
||||||
|
label
|
||||||
|
font-size: 0.75rem
|
||||||
|
text-transform: uppercase
|
||||||
|
color: var(--mgt2-color-primary)
|
||||||
|
font-weight: 700
|
||||||
|
|
||||||
|
.behavior-select
|
||||||
|
background: var(--mgt2-bgcolor-form)
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
|
border: 1px solid var(--mgt2-color-primary)
|
||||||
|
border-radius: 3px
|
||||||
|
font-size: 0.85rem
|
||||||
|
padding: 1px 4px
|
||||||
|
|
||||||
|
.behavior-sep
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
|
opacity: 0.5
|
||||||
|
|
||||||
|
.creature-size-badge
|
||||||
|
margin-left: auto
|
||||||
|
font-size: 0.75rem
|
||||||
|
font-style: italic
|
||||||
|
color: var(--mgt2-color-secondary)
|
||||||
|
background: var(--mgt2-bgcolor-primary)
|
||||||
|
border: 1px solid var(--mgt2-color-secondary)
|
||||||
|
border-radius: 3px
|
||||||
|
padding: 1px 6px
|
||||||
|
|
||||||
|
// ── Body / Tabs ────────────────────────────────────
|
||||||
|
.creature-body
|
||||||
|
flex: 1
|
||||||
|
overflow-y: auto
|
||||||
|
padding: 0.5rem 0.75rem
|
||||||
|
|
||||||
|
.tab
|
||||||
|
display: none
|
||||||
|
&.active
|
||||||
|
display: block
|
||||||
|
|
||||||
|
// ── Info tab ──────────────────────────────────────
|
||||||
|
.creature-info-tab
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
gap: 0.5rem
|
||||||
|
|
||||||
|
.creature-description
|
||||||
|
width: 100%
|
||||||
|
background: var(--mgt2-bgcolor-form)
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
|
border: 1px solid var(--mgt2-color-primary)
|
||||||
|
border-radius: 3px
|
||||||
|
padding: 4px
|
||||||
|
resize: vertical
|
||||||
|
font-size: 0.9rem
|
||||||
|
|
||||||
|
// ── Damage formula ────────────────────────────────
|
||||||
|
.creature-damage
|
||||||
|
.damage-formula
|
||||||
|
font-family: "Barlow Condensed", sans-serif
|
||||||
|
font-weight: 700
|
||||||
|
color: var(--mgt2-color-primary)
|
||||||
|
font-size: 1rem
|
||||||
|
|
||||||
|
.trait-name
|
||||||
|
font-weight: 600
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
|
|
||||||
|
.trait-value
|
||||||
|
font-style: italic
|
||||||
|
color: var(--mgt2-color-secondary)
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────
|
||||||
|
// Chat card – creature skill roll
|
||||||
|
// ─────────────────────────────────────────────────
|
||||||
|
.mgt2-creature-roll
|
||||||
|
|
||||||
|
.mgt2-roll-header
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
align-items: center
|
||||||
|
gap: 0.6rem
|
||||||
|
|
||||||
|
.creature-chat-img
|
||||||
|
width: 36px
|
||||||
|
height: 36px
|
||||||
|
object-fit: cover
|
||||||
|
border: 1px solid var(--mgt2-color-primary)
|
||||||
|
border-radius: 3px
|
||||||
|
flex: 0 0 36px
|
||||||
|
|
||||||
|
.mgt2-roll-header-text
|
||||||
|
flex: 1
|
||||||
@@ -1,4 +1,150 @@
|
|||||||
.mgt2
|
.mgt2
|
||||||
.dialog-button
|
.dialog-button
|
||||||
color: var(--mgt2-color-primary)
|
color: var(--mgt2-color-primary)
|
||||||
background-color: var(--mgt2-bgcolor-primary) !important
|
background-color: var(--mgt2-bgcolor-primary) !important
|
||||||
|
|
||||||
|
// ─── MGT2 Roll Dialog (DialogV2) ──────────────────────────────────────────────
|
||||||
|
.mgt2-roll-dialog
|
||||||
|
background: #ffffff !important
|
||||||
|
border: 1px solid #ccbbbb !important
|
||||||
|
box-shadow: 0 8px 32px rgba(0,0,0,0.35) !important
|
||||||
|
border-radius: 6px !important
|
||||||
|
overflow: hidden !important
|
||||||
|
|
||||||
|
.window-header
|
||||||
|
background: #0A0405 !important
|
||||||
|
border-bottom: 3px solid #EE4050 !important
|
||||||
|
padding: 10px 14px !important
|
||||||
|
position: relative !important
|
||||||
|
.window-title
|
||||||
|
color: #ffffff !important
|
||||||
|
font-family: 'Barlow Condensed', sans-serif !important
|
||||||
|
font-weight: 700 !important
|
||||||
|
font-size: 1rem !important
|
||||||
|
text-transform: uppercase !important
|
||||||
|
letter-spacing: 2px !important
|
||||||
|
|
||||||
|
.window-content
|
||||||
|
background: #ffffff !important
|
||||||
|
color: #0A0405 !important
|
||||||
|
padding: 0 !important
|
||||||
|
|
||||||
|
.dialog-content, .standard-form
|
||||||
|
background: #ffffff !important
|
||||||
|
padding: 14px 18px 10px !important
|
||||||
|
|
||||||
|
// Form group rows
|
||||||
|
.form-group
|
||||||
|
display: flex !important
|
||||||
|
align-items: center !important
|
||||||
|
gap: 10px !important
|
||||||
|
margin-bottom: 8px !important
|
||||||
|
padding: 4px 0 !important
|
||||||
|
border-bottom: 1px solid #e8e0e0 !important
|
||||||
|
|
||||||
|
&:last-child
|
||||||
|
border-bottom: none !important
|
||||||
|
|
||||||
|
label
|
||||||
|
color: #0A0405 !important
|
||||||
|
font-family: 'Barlow Condensed', sans-serif !important
|
||||||
|
font-weight: 700 !important
|
||||||
|
font-size: 0.72rem !important
|
||||||
|
text-transform: uppercase !important
|
||||||
|
letter-spacing: 1.2px !important
|
||||||
|
flex: 0 0 110px !important
|
||||||
|
line-height: 1.2 !important
|
||||||
|
|
||||||
|
select, input[type="number"], input[type="text"]
|
||||||
|
flex: 1 !important
|
||||||
|
background: #ffffff !important
|
||||||
|
border: 1px solid #ccbbbb !important
|
||||||
|
color: #0A0405 !important
|
||||||
|
border-radius: 3px !important
|
||||||
|
padding: 5px 10px !important
|
||||||
|
font-family: 'Barlow Condensed', sans-serif !important
|
||||||
|
font-size: 0.9rem !important
|
||||||
|
transition: border-color 150ms ease !important
|
||||||
|
|
||||||
|
&:focus
|
||||||
|
border-color: #EE4050 !important
|
||||||
|
outline: none !important
|
||||||
|
background: rgba(238,64,80,0.04) !important
|
||||||
|
|
||||||
|
option
|
||||||
|
background: #ffffff !important
|
||||||
|
color: #0A0405 !important
|
||||||
|
|
||||||
|
// Fieldset / ÉTATS section
|
||||||
|
fieldset, .form-fields
|
||||||
|
background: #fdf8f8 !important
|
||||||
|
border: 1px solid #e0c8c8 !important
|
||||||
|
border-radius: 5px !important
|
||||||
|
padding: 10px 14px !important
|
||||||
|
margin-bottom: 8px !important
|
||||||
|
|
||||||
|
legend
|
||||||
|
color: #EE4050 !important
|
||||||
|
font-family: 'Barlow Condensed', sans-serif !important
|
||||||
|
font-weight: 700 !important
|
||||||
|
font-size: 0.72rem !important
|
||||||
|
text-transform: uppercase !important
|
||||||
|
letter-spacing: 2px !important
|
||||||
|
padding: 0 8px !important
|
||||||
|
background: #ffffff !important
|
||||||
|
|
||||||
|
// Checkboxes inside fieldset
|
||||||
|
.form-group
|
||||||
|
border-bottom: none !important
|
||||||
|
margin-bottom: 4px !important
|
||||||
|
padding: 2px 0 !important
|
||||||
|
|
||||||
|
label
|
||||||
|
color: #3a2020 !important
|
||||||
|
flex: 1 !important
|
||||||
|
|
||||||
|
input[type="checkbox"]
|
||||||
|
accent-color: #EE4050 !important
|
||||||
|
width: 14px !important
|
||||||
|
height: 14px !important
|
||||||
|
|
||||||
|
// Footer buttons
|
||||||
|
.dialog-buttons, .form-footer, footer
|
||||||
|
background: #f5eeee !important
|
||||||
|
border-top: 2px solid #EE4050 !important
|
||||||
|
padding: 10px 14px !important
|
||||||
|
display: flex !important
|
||||||
|
gap: 8px !important
|
||||||
|
justify-content: center !important
|
||||||
|
|
||||||
|
button
|
||||||
|
flex: 1 !important
|
||||||
|
max-width: 140px !important
|
||||||
|
background: #ffffff !important
|
||||||
|
border: 1px solid #ccbbbb !important
|
||||||
|
color: #3a2020 !important
|
||||||
|
border-radius: 4px !important
|
||||||
|
padding: 7px 14px !important
|
||||||
|
font-family: 'Barlow Condensed', sans-serif !important
|
||||||
|
font-size: 0.82rem !important
|
||||||
|
font-weight: 700 !important
|
||||||
|
text-transform: uppercase !important
|
||||||
|
letter-spacing: 1.5px !important
|
||||||
|
cursor: pointer !important
|
||||||
|
transition: all 150ms ease !important
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background: #fdf0f0 !important
|
||||||
|
border-color: #EE4050 !important
|
||||||
|
color: #EE4050 !important
|
||||||
|
|
||||||
|
// Primary action button (DialogV2: data-action="submit", autofocus)
|
||||||
|
&.default, &[data-action="submit"], &[autofocus]
|
||||||
|
background: #EE4050 !important
|
||||||
|
border-color: #EE4050 !important
|
||||||
|
color: #fff !important
|
||||||
|
box-shadow: 0 2px 12px rgba(238,64,80,0.3) !important
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background: #ff5060 !important
|
||||||
|
box-shadow: 0 4px 18px rgba(238,64,80,0.45) !important
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
font-size: 13px
|
font-size: 13px
|
||||||
&.field-name
|
&.field-name
|
||||||
background-color: var(--mgt2-input-bgcolor)
|
background-color: var(--mgt2-input-bgcolor)
|
||||||
|
color: var(--mgt2-color-primary)
|
||||||
font-size: 2rem
|
font-size: 2rem
|
||||||
border: none
|
border: none
|
||||||
font-weight: 700
|
font-weight: 700
|
||||||
@@ -58,6 +59,7 @@
|
|||||||
padding: 0
|
padding: 0
|
||||||
&.field-item-name
|
&.field-item-name
|
||||||
background-color: var(--mgt2-input-bgcolor)
|
background-color: var(--mgt2-input-bgcolor)
|
||||||
|
color: var(--mgt2-color-primary)
|
||||||
height: auto
|
height: auto
|
||||||
font-size: 2rem
|
font-size: 2rem
|
||||||
font-weight: 700
|
font-weight: 700
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
.itemsheet-header
|
.itemsheet-header
|
||||||
display: flex
|
display: flex
|
||||||
background-color: var(--mgt2-bgcolor-primary)
|
background-color: var(--mgt2-bgcolor-primary)
|
||||||
color: red
|
color: var(--mgt2-color-primary)
|
||||||
padding: 0.5rem
|
padding: 0.5rem
|
||||||
align-items: center
|
align-items: center
|
||||||
flex: 0 0 2rem
|
flex: 0 0 2rem
|
||||||
|
|||||||
@@ -1,40 +1,108 @@
|
|||||||
.mgt2
|
// ── Overflow fixes: allow sidebar nav to protrude OUTSIDE the window frame ──
|
||||||
.sheet-sidebar
|
// All ancestors of nav.sheet-sidebar need overflow:visible so absolute-positioned
|
||||||
.item
|
// nav (left: 100% of character-body) can extend to the right of the window border.
|
||||||
margin: 0 1rem
|
// Layered !important beats Foundry's unlayered overflow:hidden per CSS cascade spec.
|
||||||
|
|
||||||
nav[data-group="sidebar"].tabs
|
.mgt2.character, .mgt2.creature
|
||||||
position: absolute
|
overflow: visible !important
|
||||||
left: 100%
|
> .window-content
|
||||||
top: 172px
|
overflow: visible !important
|
||||||
display: flex
|
.editable, .locked
|
||||||
flex-direction: column
|
overflow: visible !important
|
||||||
z-index: -1
|
|
||||||
& > .item
|
.mgt2.character .character-body
|
||||||
height: 40px
|
position: relative !important
|
||||||
position: relative
|
overflow: visible !important
|
||||||
display: flex
|
|
||||||
justify-content: end
|
.mgt2.creature .creature-body
|
||||||
align-items: center
|
position: relative !important
|
||||||
padding-right: 0.75rem
|
overflow: visible !important
|
||||||
background: var(--mgt2-bgcolor-primary)
|
|
||||||
color: var(--mgt2-color-primary)
|
// ── Vertical sidebar tab navigation (outside window, right side) ──
|
||||||
border: 1px solid transparent
|
.mgt2
|
||||||
font-size: 1rem
|
nav.sheet-sidebar.tabs
|
||||||
transition: all 250ms ease
|
position: absolute !important
|
||||||
margin-left: 0
|
left: 100% !important
|
||||||
&.active
|
top: 0 !important
|
||||||
text-shadow: none
|
bottom: 0 !important
|
||||||
margin: 0
|
width: 62px !important
|
||||||
border-color: var(--mgt2-color-primary)
|
flex: none !important
|
||||||
&::after
|
display: flex !important
|
||||||
border-left: none
|
flex-direction: column
|
||||||
inset: 0.25rem 0.25rem 0.25rem 0
|
// Rich dark gradient matching MGT2 theme
|
||||||
&::after
|
background: linear-gradient(180deg, #1e0507 0%, #110304 40%, #0a0202 100%)
|
||||||
content: ""
|
border-top: 1px solid rgba(238,64,80,0.35)
|
||||||
position: absolute
|
border-right: 1px solid rgba(238,64,80,0.25)
|
||||||
inset: 0.25rem
|
border-bottom: 1px solid rgba(238,64,80,0.2)
|
||||||
border: 1px solid var(--mgt2-color-primary)
|
border-left: 3px solid var(--mgt2-color-primary)
|
||||||
pointer-events: none
|
border-radius: 0 10px 10px 0
|
||||||
i
|
box-shadow: 6px 0 24px rgba(0,0,0,0.75), 0 0 0 0 transparent, inset 1px 0 16px rgba(238,64,80,0.05)
|
||||||
margin-left: 0.8rem
|
z-index: 10
|
||||||
|
overflow: hidden !important
|
||||||
|
padding: 2px 0
|
||||||
|
|
||||||
|
& > .item
|
||||||
|
position: relative
|
||||||
|
display: flex !important
|
||||||
|
flex-direction: column !important
|
||||||
|
justify-content: center !important
|
||||||
|
align-items: center !important
|
||||||
|
gap: 4px !important
|
||||||
|
min-height: 54px
|
||||||
|
padding: 8px 4px
|
||||||
|
color: rgba(238,64,80,0.45)
|
||||||
|
border-bottom: 1px solid rgba(238,64,80,0.07)
|
||||||
|
cursor: pointer
|
||||||
|
transition: background 180ms ease, color 180ms ease, box-shadow 180ms ease
|
||||||
|
user-select: none
|
||||||
|
text-decoration: none !important
|
||||||
|
|
||||||
|
// Left accent bar
|
||||||
|
&::before
|
||||||
|
content: ''
|
||||||
|
position: absolute
|
||||||
|
left: -3px
|
||||||
|
top: 18%
|
||||||
|
bottom: 18%
|
||||||
|
width: 3px
|
||||||
|
background: transparent
|
||||||
|
border-radius: 0 3px 3px 0
|
||||||
|
transition: background 180ms ease, top 180ms ease, bottom 180ms ease, box-shadow 180ms ease
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
color: var(--mgt2-color-primary)
|
||||||
|
background: rgba(238,64,80,0.07)
|
||||||
|
&::before
|
||||||
|
background: rgba(238,64,80,0.5)
|
||||||
|
.tab-label
|
||||||
|
color: rgba(238,64,80,0.7)
|
||||||
|
|
||||||
|
&.active
|
||||||
|
color: var(--mgt2-color-primary)
|
||||||
|
background: linear-gradient(90deg, rgba(238,64,80,0.16) 0%, rgba(238,64,80,0.03) 100%)
|
||||||
|
box-shadow: inset 0 1px 0 rgba(238,64,80,0.12), inset 0 -1px 0 rgba(238,64,80,0.08)
|
||||||
|
&::before
|
||||||
|
background: var(--mgt2-color-primary)
|
||||||
|
top: 10%
|
||||||
|
bottom: 10%
|
||||||
|
box-shadow: 0 0 10px rgba(238,64,80,0.7), 0 0 20px rgba(238,64,80,0.3)
|
||||||
|
i
|
||||||
|
filter: drop-shadow(0 0 5px rgba(238,64,80,0.55))
|
||||||
|
.tab-label
|
||||||
|
color: rgba(238,64,80,0.85)
|
||||||
|
|
||||||
|
i
|
||||||
|
font-size: 1.15rem
|
||||||
|
pointer-events: none
|
||||||
|
line-height: 1
|
||||||
|
|
||||||
|
.tab-label
|
||||||
|
font-family: 'Barlow Condensed', sans-serif
|
||||||
|
font-size: 0.52rem
|
||||||
|
font-weight: 700
|
||||||
|
text-transform: uppercase
|
||||||
|
letter-spacing: 0.8px
|
||||||
|
color: rgba(238,64,80,0.3)
|
||||||
|
line-height: 1
|
||||||
|
pointer-events: none
|
||||||
|
transition: color 180ms ease
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
&:not(:last-child)
|
&:not(:last-child)
|
||||||
margin-right: 0.4rem
|
margin-right: 0.4rem
|
||||||
i
|
i
|
||||||
color: black
|
color: var(--mgt2-color-form)
|
||||||
a[data-roll]
|
a[data-roll]
|
||||||
margin-right: 0.5rem
|
margin-right: 0.5rem
|
||||||
.heading
|
.heading
|
||||||
|
|||||||
@@ -12,4 +12,5 @@
|
|||||||
|
|
||||||
@import 'components/_tabs'
|
@import 'components/_tabs'
|
||||||
@import 'components/_tab-sidebar'
|
@import 'components/_tab-sidebar'
|
||||||
@import 'components/_tables'
|
@import 'components/_tables'
|
||||||
|
@import 'components/_creature'
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
&.sheet
|
&.sheet
|
||||||
.window-content
|
.window-content
|
||||||
background: var(--mgt2-bgcolor-form)
|
background: var(--mgt2-bgcolor-form)
|
||||||
|
color: var(--mgt2-color-form)
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
.nopad
|
.nopad
|
||||||
|
|||||||
2
styles/mgt2.min.css
vendored
2
styles/mgt2.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,11 +2,13 @@
|
|||||||
"Actor": {
|
"Actor": {
|
||||||
"types": [
|
"types": [
|
||||||
"character",
|
"character",
|
||||||
"vehicule"
|
"vehicule",
|
||||||
|
"creature"
|
||||||
],
|
],
|
||||||
"htmlFields": ["notes"],
|
"htmlFields": ["notes"],
|
||||||
"character": {},
|
"character": {},
|
||||||
"vehicule": {}
|
"vehicule": {},
|
||||||
|
"creature": {}
|
||||||
},
|
},
|
||||||
"Item": {
|
"Item": {
|
||||||
"types": [
|
"types": [
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
<div class="{{cssClass}} flexcol" style="align-content: flex-start;align-items: baseline;overflow: hidden;height: 100%;">
|
<div class="{{cssClass}} flexcol" style="align-content: flex-start;align-items: baseline;overflow: hidden;height: 100%;">
|
||||||
<nav class="sheet-sidebar tabs" data-group="sidebar">
|
|
||||||
<!-- <a class="item tab-select" data-tab="personal" title="Personal"><i class="fa-solid fa-id-card"></i></a> -->
|
|
||||||
<a class="item tab-select" data-tab="health" title="{{ localize 'MGT2.Actor.Health' }}"><i class="fa-solid fa-heart-pulse"></i></a>
|
|
||||||
<a class="item tab-select" data-tab="skills" title="{{ localize 'MGT2.Actor.TabSkills' }}"><i class="fa-solid fa-head-side"></i></a>
|
|
||||||
<a class="item tab-select" data-tab="inventory" title="{{ localize 'MGT2.Actor.Inventory' }}"><i class="fa-solid fa-briefcase-blank"></i></a>
|
|
||||||
<a class="item tab-select" data-tab="relations" title="{{ localize 'MGT2.Actor.Contacts' }}"><i class="fa-solid fa-users"></i></a>
|
|
||||||
<a class="item tab-select" data-tab="notes" title="{{ localize 'MGT2.Actor.Notes' }}"><i class="fa-solid fa-books"></i></a>
|
|
||||||
<a class="item tab-select" data-tab="biography" title="{{ localize 'MGT2.Actor.Biography' }}"><i class="fa-solid fa-book-user"></i></a>
|
|
||||||
</nav>
|
|
||||||
<section class="character-header">
|
<section class="character-header">
|
||||||
<div class="character-header-img">
|
<div class="character-header-img">
|
||||||
<img class="profile" src="{{img}}" data-edit="img" title="{{name}}" height="130" width="100" />
|
<img class="profile" src="{{img}}" data-edit="img" title="{{name}}" height="130" width="100" />
|
||||||
@@ -387,7 +378,7 @@
|
|||||||
{{#each skills as |skill id|}}
|
{{#each skills as |skill id|}}
|
||||||
<div class="table-row" data-item-id="{{skill._id}}" role="rowgroup">
|
<div class="table-row" data-item-id="{{skill._id}}" role="rowgroup">
|
||||||
<div class="row-item row-item-30 row-item-left flex-fix">
|
<div class="row-item row-item-30 row-item-left flex-fix">
|
||||||
<a data-roll="skill" data-roll-skill="{{skill._id}}"><i class="fa-solid fa-dice"></i></a>{{skill.name}}{{#if skill.system.skill.speciality}} ({{skill.system.skill.speciality}}){{/if}}
|
<a class="roll" data-roll="skill" data-roll-skill="{{skill._id}}"><i class="fa-solid fa-dice"></i></a>{{skill.name}}{{#if skill.system.skill.speciality}} ({{skill.system.skill.speciality}}){{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row-item row-item-center">{{skill.system.level}}</div>
|
<div class="row-item row-item-center">{{skill.system.level}}</div>
|
||||||
<div class="row-item item-controls">
|
<div class="row-item item-controls">
|
||||||
@@ -410,7 +401,7 @@
|
|||||||
{{#each psionics as |psionic id|}}
|
{{#each psionics as |psionic id|}}
|
||||||
<div class="table-row" data-item-id="{{psionic._id}}" role="rowgroup">
|
<div class="table-row" data-item-id="{{psionic._id}}" role="rowgroup">
|
||||||
<div class="row-item row-item-left">
|
<div class="row-item row-item-left">
|
||||||
<a data-roll="psionic" data-item-id="{{psionic._id}}"><i class="fa-solid fa-dice"></i></a>{{psionic.name}}
|
<a class="roll" data-roll="psionic" data-item-id="{{psionic._id}}"><i class="fa-solid fa-dice"></i></a>{{psionic.name}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.level}}</div>
|
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.level}}</div>
|
||||||
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.psionic.cost}}</div>
|
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.psionic.cost}}</div>
|
||||||
@@ -446,7 +437,7 @@
|
|||||||
{{#each weapons as |weapon id|}}
|
{{#each weapons as |weapon id|}}
|
||||||
<div class="table-row{{#if weapon.subInfo}} table-row-mb-4{{/if}} drag-item-list" data-item-id="{{weapon._id}}" role="rowgroup">
|
<div class="table-row{{#if weapon.subInfo}} table-row-mb-4{{/if}} drag-item-list" data-item-id="{{weapon._id}}" role="rowgroup">
|
||||||
<div class="row-item row-item-30 row-item-left flex-3 row-large">
|
<div class="row-item row-item-30 row-item-left flex-3 row-large">
|
||||||
<a data-roll="item" data-item-id="{{weapon._id}}"><i class="fa-solid fa-dice"></i></a>{{weapon.name}}{{#if weapon.subInfo}}<div class="item-options">{{weapon.subInfo}}</div>{{/if}}
|
<a class="roll" data-roll="item" data-item-id="{{weapon._id}}"><i class="fa-solid fa-dice"></i></a>{{weapon.name}}{{#if weapon.subInfo}}<div class="item-options">{{weapon.subInfo}}</div>{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row-item row-item-2 row-item-center">{{weapon.range}}</div>
|
<div class="row-item row-item-2 row-item-center">{{weapon.range}}</div>
|
||||||
<div class="row-item row-item-20 row-item-center">{{weapon.system.damage}}</div>
|
<div class="row-item row-item-20 row-item-center">{{weapon.system.damage}}</div>
|
||||||
@@ -471,7 +462,7 @@
|
|||||||
{{#each armors as |armor id|}}
|
{{#each armors as |armor id|}}
|
||||||
<div class="table-row{{#if armor.subInfo}} table-row-mb-4{{/if}} drag-item-list" data-item-id="{{armor._id}}" role="rowgroup">
|
<div class="table-row{{#if armor.subInfo}} table-row-mb-4{{/if}} drag-item-list" data-item-id="{{armor._id}}" role="rowgroup">
|
||||||
<div class="row-item row-item-40 row-item-left">
|
<div class="row-item row-item-40 row-item-left">
|
||||||
<a data-roll="item" data-item-id="{{armor._id}}"><i class="fa-solid fa-dice"></i></a>{{armor.name}}{{#if armor.subInfo}}<div class="item-options">{{armor.subInfo}}</div>{{/if}}
|
<a class="roll" data-roll="item" data-item-id="{{armor._id}}"><i class="fa-solid fa-dice"></i></a>{{armor.name}}{{#if armor.subInfo}}<div class="item-options">{{armor.subInfo}}</div>{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row-item row-item-10 row-item-center">{{armor.system.radiations}}</div>
|
<div class="row-item row-item-10 row-item-center">{{armor.system.radiations}}</div>
|
||||||
<div class="row-item row-item-10 row-item-center">{{armor.system.protection}}</div>
|
<div class="row-item row-item-10 row-item-center">{{armor.system.protection}}</div>
|
||||||
@@ -514,7 +505,7 @@
|
|||||||
{{#each computers as |computer id|}}
|
{{#each computers as |computer id|}}
|
||||||
<div class="table-row drop-item-list" data-item-id="{{computer._id}}" role="rowgroup">
|
<div class="table-row drop-item-list" data-item-id="{{computer._id}}" role="rowgroup">
|
||||||
<div class="row-item row-item-50 row-item-left">
|
<div class="row-item row-item-50 row-item-left">
|
||||||
<a data-roll="item" data-item-id="{{computer._id}}"><i class="fa-solid fa-dice"></i></a>{{computer.name}}{{#if computer.subInfo}}<div class="item-options">{{computer.subInfo}}</div>{{/if}}
|
<a class="roll" data-roll="item" data-item-id="{{computer._id}}"><i class="fa-solid fa-dice"></i></a>{{computer.name}}{{#if computer.subInfo}}<div class="item-options">{{computer.subInfo}}</div>{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row-item row-item-2 row-item-center {{overloadClass}}">{{computer.system.processingUsed}}/{{computer.system.processing}}
|
<div class="row-item row-item-2 row-item-center {{overloadClass}}">{{computer.system.processingUsed}}/{{computer.system.processing}}
|
||||||
{{#if computer.system.overload}}<a title="Overload"><i class="fa-solid fa-triangle-exclamation"></i></a>{{/if}}
|
{{#if computer.system.overload}}<a title="Overload"><i class="fa-solid fa-triangle-exclamation"></i></a>{{/if}}
|
||||||
@@ -740,9 +731,16 @@
|
|||||||
<p>À FAIRE</p>
|
<p>À FAIRE</p>
|
||||||
</div> -->
|
</div> -->
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
<nav class="sheet-sidebar tabs" data-group="sidebar">
|
||||||
|
<a class="item tab-select" data-tab="health" title="{{ localize 'MGT2.Actor.Health' }}"><i class="fa-solid fa-heart-pulse"></i><span class="tab-label">SANTÉ</span></a>
|
||||||
|
<a class="item tab-select" data-tab="skills" title="{{ localize 'MGT2.Actor.TabSkills' }}"><i class="fa-solid fa-head-side"></i><span class="tab-label">COMP.</span></a>
|
||||||
|
<a class="item tab-select" data-tab="inventory" title="{{ localize 'MGT2.Actor.Inventory' }}"><i class="fa-solid fa-briefcase-blank"></i><span class="tab-label">ÉQUIP.</span></a>
|
||||||
|
<a class="item tab-select" data-tab="relations" title="{{ localize 'MGT2.Actor.Contacts' }}"><i class="fa-solid fa-users"></i><span class="tab-label">CONT.</span></a>
|
||||||
|
<a class="item tab-select" data-tab="notes" title="{{ localize 'MGT2.Actor.Notes' }}"><i class="fa-solid fa-books"></i><span class="tab-label">NOTES</span></a>
|
||||||
|
<a class="item tab-select" data-tab="biography" title="{{ localize 'MGT2.Actor.Biography' }}"><i class="fa-solid fa-book-user"></i><span class="tab-label">BIO</span></a>
|
||||||
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<section class="actor-footer">
|
<section class="actor-footer">
|
||||||
<div><a name="config" title="Config" style="margin-right: 0.5rem;"><i class="fa-solid fa-gear"></i></a></div>
|
<div><a name="config" title="Config" style="margin-right: 0.5rem;"><i class="fa-solid fa-gear"></i></a></div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
26
templates/actors/creature-roll-prompt.html
Normal file
26
templates/actors/creature-roll-prompt.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<form class="flexcol" autocomplete="off" style="padding: 0 6px;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{ localize 'MGT2.Creature.SkillLabel' }}: <strong>{{skillName}}</strong>
|
||||||
|
({{ localize 'MGT2.Creature.SkillLevel' }} {{skillLevel}})</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{ localize 'MGT2.RollPrompt.CustomDM' }}</label>
|
||||||
|
<input type="number" name="dm" value="0" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{ localize 'MGT2.RollPrompt.Difficulty' }}</label>
|
||||||
|
<select name="difficulty">
|
||||||
|
{{selectOptions config.Difficulty selected="Average" localize=true}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{ localize 'MGT2.RollPrompt.RollMode' }}</label>
|
||||||
|
<select name="rollMode">
|
||||||
|
<option value="publicroll">{{ localize 'MGT2.RollPrompt.PublicRoll' }}</option>
|
||||||
|
<option value="gmroll">{{ localize 'MGT2.RollPrompt.PrivateGMRoll' }}</option>
|
||||||
|
<option value="blindroll">{{ localize 'MGT2.RollPrompt.BlindGMRoll' }}</option>
|
||||||
|
<option value="selfroll">{{ localize 'MGT2.RollPrompt.SelfRoll' }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="difficultyLabel" value="" />
|
||||||
|
</form>
|
||||||
267
templates/actors/creature-sheet.html
Normal file
267
templates/actors/creature-sheet.html
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
<div class="{{cssClass}} flexcol creature-sheet">
|
||||||
|
|
||||||
|
{{!-- ── HEADER ── --}}
|
||||||
|
<header class="creature-header">
|
||||||
|
<div class="creature-header-img">
|
||||||
|
<img class="profile" src="{{img}}" data-edit="img" title="{{name}}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="creature-header-body">
|
||||||
|
<input class="creature-name" name="name" type="text" value="{{name}}" placeholder="{{ localize 'MGT2.Creature.Name' }}" />
|
||||||
|
|
||||||
|
<div class="creature-stats-row">
|
||||||
|
{{!-- PdV --}}
|
||||||
|
<div class="creature-stat">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Creature.Life' }}</label>
|
||||||
|
<div class="creature-stat-value">
|
||||||
|
<input type="number" name="system.life.value" value="{{system.life.value}}" min="0" class="stat-current" />
|
||||||
|
<span>/</span>
|
||||||
|
<input type="number" name="system.life.max" value="{{system.life.max}}" min="0" class="stat-max" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Vitesse --}}
|
||||||
|
<div class="creature-stat">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Creature.Speed' }}</label>
|
||||||
|
<div class="creature-stat-value">
|
||||||
|
<input type="number" name="system.speed" value="{{system.speed}}" min="0" class="stat-current" />
|
||||||
|
<span class="stat-unit">m</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Armure --}}
|
||||||
|
<div class="creature-stat">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Creature.Armor' }}</label>
|
||||||
|
<div class="creature-stat-value">
|
||||||
|
<input type="number" name="system.armor" value="{{system.armor}}" min="0" class="stat-current" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Initiative (calculated) --}}
|
||||||
|
<div class="creature-stat">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Creature.Initiative' }}</label>
|
||||||
|
<div class="creature-stat-value">
|
||||||
|
<span class="stat-readonly">{{showDM system.initiativeBonus}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- PSI (shown only if > 0) --}}
|
||||||
|
{{#if system.psi}}
|
||||||
|
<div class="creature-stat">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Creature.Psi' }}</label>
|
||||||
|
<div class="creature-stat-value">
|
||||||
|
<input type="number" name="system.psi" value="{{system.psi}}" min="0" class="stat-current" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Comportement --}}
|
||||||
|
<div class="creature-behavior-row">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Creature.Behavior' }}</label>
|
||||||
|
<select name="system.behavior.type" class="behavior-select">
|
||||||
|
<option value="">—</option>
|
||||||
|
{{selectOptions config.CreatureBehaviorType selected=system.behavior.type localize=true}}
|
||||||
|
</select>
|
||||||
|
<span class="behavior-sep">,</span>
|
||||||
|
<select name="system.behavior.subtype" class="behavior-select">
|
||||||
|
<option value="">—</option>
|
||||||
|
{{selectOptions config.CreatureBehaviorSubType selected=system.behavior.subtype localize=true}}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
{{!-- Taille indicative --}}
|
||||||
|
<span class="creature-size-badge" title="{{ localize 'MGT2.Creature.SizeHint' }}">
|
||||||
|
{{sizeTraitLabel}} — {{sizeLabel}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{{!-- ── TAB CONTENT ── --}}
|
||||||
|
<div class="creature-body">
|
||||||
|
|
||||||
|
|
||||||
|
{{!-- ── TAB : COMPÉTENCES ── --}}
|
||||||
|
<div class="tab" data-group="primary" data-tab="skills">
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-row heading color-1">
|
||||||
|
<div class="row-item row-item-left upcase" style="flex: 3">{{ localize 'MGT2.Creature.SkillName' }}</div>
|
||||||
|
<div class="row-item row-item-center upcase" style="flex: 1">{{ localize 'MGT2.Creature.SkillLevel' }}</div>
|
||||||
|
<div class="row-item row-item-left upcase" style="flex: 3">{{ localize 'MGT2.Creature.SkillNote' }}</div>
|
||||||
|
<div class="row-item row-item-right" style="flex: 0 0 3rem">
|
||||||
|
<a data-action="addSkill" data-prop="skills" title="{{ localize 'MGT2.Creature.AddSkill' }}"><i class="fas fa-plus"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#each system.skills as |skill i|}}
|
||||||
|
<div class="table-row">
|
||||||
|
<div class="row-item row-item-left" style="flex: 3">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.skills.{{i}}.name" value="{{skill.name}}" placeholder="{{ localize 'MGT2.Creature.SkillName' }}" />
|
||||||
|
{{else}}
|
||||||
|
<span>{{skill.name}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-center" style="flex: 1">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="number" name="system.skills.{{i}}.level" value="{{skill.level}}" min="-3" max="6" class="text-center" />
|
||||||
|
{{else}}
|
||||||
|
<span>{{showDM skill.level}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-left" style="flex: 3">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.skills.{{i}}.note" value="{{skill.note}}" placeholder="{{ localize 'MGT2.Creature.SkillNote' }}" />
|
||||||
|
{{else}}
|
||||||
|
<span class="text-muted">{{skill.note}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-right item-controls" style="flex: 0 0 3rem">
|
||||||
|
<a data-action="rollSkill" data-index="{{i}}" title="{{ localize 'MGT2.Creature.RollSkill' }}"><i class="fas fa-dice-d6"></i></a>
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<a data-action="deleteSkill" data-prop="skills" data-index="{{i}}" title="{{ localize 'MGT2.Creature.Delete' }}"><i class="fas fa-trash"></i></a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#unless system.skills.length}}
|
||||||
|
<div class="table-row">
|
||||||
|
<div class="row-item row-item-center text-muted" style="flex:1">{{ localize 'MGT2.Creature.NoSkills' }}</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- ── TAB : ATTAQUES ── --}}
|
||||||
|
<div class="tab" data-group="primary" data-tab="attacks">
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-row heading color-1">
|
||||||
|
<div class="row-item row-item-left upcase" style="flex: 3">{{ localize 'MGT2.Creature.AttackName' }}</div>
|
||||||
|
<div class="row-item row-item-center upcase" style="flex: 2">{{ localize 'MGT2.Creature.AttackDamage' }}</div>
|
||||||
|
<div class="row-item row-item-left upcase" style="flex: 3">{{ localize 'MGT2.Items.Description' }}</div>
|
||||||
|
<div class="row-item row-item-right" style="flex: 0 0 4rem">
|
||||||
|
{{#if isEditable}}
|
||||||
|
<a data-action="addAttack" data-prop="attacks" title="{{ localize 'MGT2.Creature.AddAttack' }}"><i class="fas fa-plus"></i></a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#each system.attacks as |atk i|}}
|
||||||
|
<div class="table-row">
|
||||||
|
<div class="row-item row-item-left" style="flex: 3">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.attacks.{{i}}.name" value="{{atk.name}}" placeholder="{{ localize 'MGT2.Creature.AttackName' }}" />
|
||||||
|
{{else}}
|
||||||
|
<span>{{atk.name}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-center creature-damage" style="flex: 2">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.attacks.{{i}}.damage" value="{{atk.damage}}" class="text-center" />
|
||||||
|
{{else}}
|
||||||
|
<span class="damage-formula">{{atk.damage}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-left" style="flex: 3">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.attacks.{{i}}.description" value="{{atk.description}}" />
|
||||||
|
{{else}}
|
||||||
|
<span class="text-muted">{{atk.description}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-right item-controls" style="flex: 0 0 4rem">
|
||||||
|
<a data-action="rollAttack" data-index="{{i}}" title="{{ localize 'MGT2.Creature.RollAttack' }}"><i class="fas fa-dice-d6 color-primary"></i></a>
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<a data-action="deleteAttack" data-prop="attacks" data-index="{{i}}" title="{{ localize 'MGT2.Creature.Delete' }}"><i class="fas fa-trash"></i></a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#unless system.attacks.length}}
|
||||||
|
<div class="table-row">
|
||||||
|
<div class="row-item row-item-center text-muted" style="flex:1">{{ localize 'MGT2.Creature.NoAttacks' }}</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- ── TAB : TRAITS ── --}}
|
||||||
|
<div class="tab" data-group="primary" data-tab="traits">
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-row heading color-1">
|
||||||
|
<div class="row-item row-item-left upcase" style="flex: 3">{{ localize 'MGT2.Creature.TraitName' }}</div>
|
||||||
|
<div class="row-item row-item-center upcase" style="flex: 1">{{ localize 'MGT2.Creature.TraitValue' }}</div>
|
||||||
|
<div class="row-item row-item-left upcase" style="flex: 4">{{ localize 'MGT2.Items.Description' }}</div>
|
||||||
|
<div class="row-item row-item-right" style="flex: 0 0 3rem">
|
||||||
|
{{#if isEditable}}
|
||||||
|
<a data-action="addTrait" data-prop="traits" title="{{ localize 'MGT2.Creature.AddTrait' }}"><i class="fas fa-plus"></i></a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#each system.traits as |trait i|}}
|
||||||
|
<div class="table-row">
|
||||||
|
<div class="row-item row-item-left" style="flex: 3">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.traits.{{i}}.name" value="{{trait.name}}" placeholder="{{ localize 'MGT2.Creature.TraitName' }}" />
|
||||||
|
{{else}}
|
||||||
|
<span class="trait-name">{{trait.name}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-center" style="flex: 1">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.traits.{{i}}.value" value="{{trait.value}}" class="text-center" />
|
||||||
|
{{else}}
|
||||||
|
<span class="trait-value">{{trait.value}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-left" style="flex: 4">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<input type="text" name="system.traits.{{i}}.description" value="{{trait.description}}" />
|
||||||
|
{{else}}
|
||||||
|
<span class="text-muted">{{trait.description}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="row-item row-item-right item-controls" style="flex: 0 0 3rem">
|
||||||
|
{{#if ../isEditable}}
|
||||||
|
<a data-action="deleteTrait" data-prop="traits" data-index="{{i}}" title="{{ localize 'MGT2.Creature.Delete' }}"><i class="fas fa-trash"></i></a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#unless system.traits.length}}
|
||||||
|
<div class="table-row">
|
||||||
|
<div class="row-item row-item-center text-muted" style="flex:1">{{ localize 'MGT2.Creature.NoTraits' }}</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- ── TAB : INFORMATIONS ── --}}
|
||||||
|
<div class="tab" data-group="primary" data-tab="info">
|
||||||
|
<div class="creature-info-tab">
|
||||||
|
<div class="field-group mt-1">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Items.Description' }}</label>
|
||||||
|
<textarea name="system.biography" rows="8" class="creature-description">{{system.biography}}</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="field-group mt-1">
|
||||||
|
<label class="upcase">{{ localize 'MGT2.Items.Notes' }}</label>
|
||||||
|
<textarea name="system.notes" rows="4" class="creature-description">{{system.notes}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- ── VERTICAL SIDEBAR TABS (outside window, right side) ── --}}
|
||||||
|
<nav class="sheet-sidebar tabs" data-group="primary">
|
||||||
|
<a class="item tab-select" data-tab="skills" title="{{ localize 'MGT2.Creature.TabSkills' }}"><i class="fa-solid fa-head-side"></i><span class="tab-label">COMP.</span></a>
|
||||||
|
<a class="item tab-select" data-tab="attacks" title="{{ localize 'MGT2.Creature.TabAttacks' }}"><i class="fa-solid fa-bolt"></i><span class="tab-label">ATT.</span></a>
|
||||||
|
<a class="item tab-select" data-tab="traits" title="{{ localize 'MGT2.Creature.TabTraits' }}"><i class="fa-solid fa-star"></i><span class="tab-label">TRAITS</span></a>
|
||||||
|
<a class="item tab-select" data-tab="info" title="{{ localize 'MGT2.Creature.TabInfo' }}"><i class="fa-solid fa-circle-info"></i><span class="tab-label">INFO</span></a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>{{!-- .creature-body --}}
|
||||||
|
|
||||||
|
</div>
|
||||||
37
templates/chat/creature-roll.html
Normal file
37
templates/chat/creature-roll.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<div class="mgt2-chat-roll mgt2-creature-roll">
|
||||||
|
<div class="mgt2-roll-header">
|
||||||
|
<img class="creature-chat-img" src="{{creatureImg}}" title="{{creatureName}}" />
|
||||||
|
<div class="mgt2-roll-header-text">
|
||||||
|
<span class="mgt2-roll-char-name">{{creatureName}}</span>
|
||||||
|
<div class="mgt2-roll-meta">
|
||||||
|
<span class="mgt2-roll-type">{{rollLabel}}</span>
|
||||||
|
{{#if difficulty}}
|
||||||
|
<span class="mgt2-roll-sep">•</span>
|
||||||
|
<span class="mgt2-roll-difficulty">{{difficultyLabel}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if modifiers}}
|
||||||
|
<div class="mgt2-roll-modifiers">
|
||||||
|
{{#each modifiers as |mod|}}
|
||||||
|
<span class="mgt2-roll-mod-tag">{{mod}}</span>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="dice-roll">
|
||||||
|
<div class="dice-result">
|
||||||
|
<div class="dice-formula">{{formula}}</div>
|
||||||
|
{{{tooltip}}}
|
||||||
|
<h4 class="dice-total {{#if success}}success{{else if failure}}failure{{/if}}">{{total}}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if success}}
|
||||||
|
<div class="mgt2-outcome is-success"><i class="fa-solid fa-check"></i> {{ localize 'MGT2.Chat.Roll.Success' }}</div>
|
||||||
|
{{else if failure}}
|
||||||
|
<div class="mgt2-outcome is-failure"><i class="fa-solid fa-xmark"></i> {{ localize 'MGT2.Chat.Roll.Failure' }}</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
@@ -1,46 +1,56 @@
|
|||||||
<div class="roll-info">
|
<div class="mgt2-chat-roll">
|
||||||
<div class="roll-object-name">{{rollObjectName}}</div>
|
<div class="mgt2-roll-header">
|
||||||
{{#if rollTypeName}}
|
<span class="mgt2-roll-char-name">{{rollObjectName}}</span>
|
||||||
{{#if rollDifficulty}}
|
{{#if rollTypeName}}
|
||||||
<div class="roll-type-group"><div class="roll-type-name">{{rollTypeName}}</div><div class="roll-type-name">{{ localize rollDifficultyLabel }}</div></div>
|
<div class="mgt2-roll-meta">
|
||||||
{{else}}
|
<span class="mgt2-roll-type">{{rollTypeName}}</span>
|
||||||
<div class="roll-type-name">{{rollTypeName}}</div>
|
{{#if rollDifficulty}}
|
||||||
|
<span class="mgt2-roll-sep">•</span>
|
||||||
|
<span class="mgt2-roll-difficulty">{{rollDifficultyLabel}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
</div>
|
||||||
|
|
||||||
{{#if rollMessage}}
|
{{#if rollMessage}}
|
||||||
<div>{{rollMessage}}</div>
|
<div class="mgt2-roll-modifier">{{rollMessage}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if rollModifiers}}
|
{{#if rollModifiers}}
|
||||||
{{#each rollModifiers as |rollModifier i| }}
|
<div class="mgt2-roll-modifiers">
|
||||||
<div>{{rollModifier}}</div>
|
{{#each rollModifiers as |mod i|}}
|
||||||
{{/each}}
|
<span class="mgt2-roll-mod-tag">{{mod}}</span>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
|
||||||
<div class="dice-roll">
|
<div class="dice-roll">
|
||||||
{{#if flavor}}
|
{{#if flavor}}
|
||||||
<div class="dice-flavor">{{flavor}}</div>
|
<div class="dice-flavor">{{flavor}}</div>
|
||||||
|
{{/if}}
|
||||||
|
<div class="dice-result">
|
||||||
|
<div class="dice-formula">{{formula}}</div>
|
||||||
|
{{{tooltip}}}
|
||||||
|
<h4 class="dice-total {{#if rollSuccess}}success{{else if rollFailure}}failure{{/if}}">{{total}}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if rollSuccess}}
|
||||||
|
<div class="mgt2-outcome is-success"><i class="fa-solid fa-check"></i> {{ localize 'MGT2.Chat.Roll.Success' }}</div>
|
||||||
|
{{else if rollFailure}}
|
||||||
|
<div class="mgt2-outcome is-failure"><i class="fa-solid fa-xmark"></i> {{ localize 'MGT2.Chat.Roll.Failure' }}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="dice-result"><div class="dice-formula">{{formula}}</div>{{{tooltip}}}<h4 class="dice-total">{{total}}</h4></div>
|
|
||||||
</div>
|
{{#if showButtons}}
|
||||||
{{#if rollSuccess}}
|
<div class="mgt2-buttons">
|
||||||
<div class="roll-success">{{ localize 'MGT2.Chat.Roll.Success' }}</div>
|
{{#if hasDamage}}
|
||||||
{{else if rollFailure}}
|
<button data-action="damage" title="{{ localize 'MGT2.Chat.Roll.ApplyDamages' }}"><i class="fa-regular fa-heart-circle-minus"></i></button>
|
||||||
<div class="roll-success">{{ localize 'MGT2.Chat.Roll.Failure' }}</div>
|
{{/if}}
|
||||||
{{/if}}
|
{{#if showRollDamage}}
|
||||||
{{#if showButtons}}
|
<button data-action="rollDamage">{{ localize 'MGT2.Chat.Roll.Damages' }}</button>
|
||||||
<div class="mgt2-buttons">
|
{{/if}}
|
||||||
{{#if hasDamage}}
|
{{#each cardButtons as |cardButton i|}}
|
||||||
<button data-action="damage" title="{{ localize 'MGT2.Chat.Roll.ApplyDamages' }}"><i class="fa-regular fa-heart-circle-minus"></i></button>
|
<button data-index="{{i}}" title="{{cardButton.label}}">{{cardButton.label}}</button>
|
||||||
<!-- <button data-action="healing" data-multiplier="1" title="Apply Healing"><i class="fa-regular fa-heart-circle-plus"></i></button> -->
|
{{/each}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if showRollRequest}}
|
</div>
|
||||||
<button data-action="requestRoll" data-roll="characteristic" data-roll-characteristic="strength" title="Roll!"><i class="fa-solid fa-dice"></i></button>
|
|
||||||
{{/if}}
|
|
||||||
{{#if showRollDamage}}
|
|
||||||
<button data-action="rollDamage" title="Roll">{{ localize 'MGT2.Chat.Roll.Damages' }}</button>
|
|
||||||
{{/if}}
|
|
||||||
{{#each cardButtons as |cardButton i| }}
|
|
||||||
<button data-index="{{i}}" title="{{cardButton.label}}">{{cardButton.label}}</button>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
Reference in New Issue
Block a user