Compare commits
9 Commits
783d4a16e6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c5a0a47b25 | |||
| a48f447b99 | |||
| e398b157f4 | |||
| a349402306 | |||
| bdc305abd8 | |||
| 6ef454d533 | |||
| 74f1b581f7 | |||
| df0a93d715 | |||
| d62d14c1da |
81
.gitea/workflows/release.yaml
Normal file
81
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,81 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Substitute the Manifest and Download URLs in the system.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: "system.json"
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
manifest: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/mgt2.zip
|
||||
|
||||
# Install Node.js and build the JS bundle
|
||||
- name: Setup Node.js
|
||||
uses: https://github.com/actions/setup-node@v3
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install JS dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Build JS bundle
|
||||
run: npm run build
|
||||
|
||||
# Install Sass and compile CSS
|
||||
- name: Install Sass
|
||||
run: npm install -g sass
|
||||
|
||||
- name: Build CSS
|
||||
run: sass src/sass/mgt2.sass styles/mgt2.min.css --style=compressed --no-source-map
|
||||
|
||||
# Create a zip file with all files required by the system to add to the release
|
||||
- name: Install zip
|
||||
run: apt update -y && apt install -y zip
|
||||
|
||||
- name: Create release zip
|
||||
run: zip -r ./mgt2.zip system.json README.md LICENSE mgt2.bundle.js assets/ lang/ styles/ templates/
|
||||
|
||||
- name: setup go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: ">=1.20.1"
|
||||
|
||||
- name: Use Go Action
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
./mgt2.zip
|
||||
system.json
|
||||
api_key: "${{secrets.ALLOW_PUSH_RELEASE}}"
|
||||
|
||||
- name: Publish to Foundry server
|
||||
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
|
||||
with:
|
||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
||||
id: "mgt2"
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/latest/system.json"
|
||||
notes: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/mgt2.zip"
|
||||
compatibility-minimum: "13"
|
||||
compatibility-verified: "14"
|
||||
230
lang/en.json
230
lang/en.json
@@ -18,6 +18,12 @@
|
||||
"Save": "Save",
|
||||
"Cancel": "Cancel",
|
||||
"Close": "Close",
|
||||
"Dialog": {
|
||||
"ConfirmDeleteTitle": "Confirm Deletion",
|
||||
"ConfirmDeleteContent": "Are you sure you want to delete \"{name}\"?",
|
||||
"Yes": "Yes",
|
||||
"No": "No"
|
||||
},
|
||||
"Themes": {
|
||||
"BlackAndRed": "Classic Traveller Cover",
|
||||
"Mwamba": "Oppa Mwamba Style",
|
||||
@@ -54,20 +60,21 @@
|
||||
"Gender": "Gender",
|
||||
"Pronouns": "Pronouns",
|
||||
"Actor": {
|
||||
"StudyPeriod":"Study Period",
|
||||
"TrainingInSkill":"Training In Skill",
|
||||
"Completed":"Completed",
|
||||
"Weeks":"Weeks",
|
||||
"NewCareer":"New Career",
|
||||
"AddCareer":"Add Career",
|
||||
"EditCareer":"Edit Career",
|
||||
"EditTrait":"Éditer Trait",
|
||||
"StudyPeriod": "Study Period",
|
||||
"TrainingInSkill": "Training In Skill",
|
||||
"Completed": "Completed",
|
||||
"Weeks": "Weeks",
|
||||
"NewCareer": "New Career",
|
||||
"AddCareer": "Add Career",
|
||||
"ThisTrait": "this trait",
|
||||
"EditCareer": "Edit Career",
|
||||
"EditTrait": "Éditer Trait",
|
||||
"DeleteTrait": "Supprimer Trait",
|
||||
"DeleteCareer":"Delete Career",
|
||||
"NewSkill":"New Skill",
|
||||
"DeleteSkill":"Delete Skill",
|
||||
"EditSkill":"EditSkill",
|
||||
"PsionicTalents":"Psionic Talents",
|
||||
"DeleteCareer": "Delete Career",
|
||||
"NewSkill": "New Skill",
|
||||
"DeleteSkill": "Delete Skill",
|
||||
"EditSkill": "EditSkill",
|
||||
"PsionicTalents": "Psionic Talents",
|
||||
"NewPsionicTalent": "New Psionic Talent",
|
||||
"AddPsionicTalent": "Add Psionic Talent",
|
||||
"EditPsionic": "Edit Psionic",
|
||||
@@ -343,7 +350,36 @@
|
||||
"EncumbranceDM": "Encumbrance (DM -2)",
|
||||
"FatigueDM": "Fatigue (DM -2)",
|
||||
"Boon": "Boon",
|
||||
"Bane": "Bane"
|
||||
"Bane": "Bane",
|
||||
"CreatureSkill": "Skill",
|
||||
"NoSkill": "No skill",
|
||||
"Days": "Days",
|
||||
"RangedModifiers": "Ranged Modifiers",
|
||||
"Range": "Range",
|
||||
"RangeShort": "Short Range",
|
||||
"RangeNormal": "Normal Range",
|
||||
"RangeLong": "Long Range",
|
||||
"RangeExtreme": "Extreme Range",
|
||||
"Aim": "Aim",
|
||||
"LaserSight": "Laser Sight",
|
||||
"FastTarget": "Fast-Moving Target",
|
||||
"Cover": "Cover / Diving",
|
||||
"Prone": "Prone Target",
|
||||
"MeleeModifiers": "Melee Modifiers",
|
||||
"Parry": "Parry (defender's Melee score)",
|
||||
"Dodge": "Target Dodging",
|
||||
"DodgeDM": "Dodge DM",
|
||||
"FireMode": "Fire Mode",
|
||||
"AutoSingle": "Single",
|
||||
"AutoBurst": "Burst",
|
||||
"AutoFull": "Full Auto",
|
||||
"AutoNoAim": "Burst / Full-Auto: all aiming advantages are cancelled.",
|
||||
"AutoBurstInfo": "Burst (Auto {level}) — +{level} damage — ammo: {ammo}",
|
||||
"AutoFullInfo": "Full Auto (Auto {level}) — {level} attacks — ammo: {ammo}",
|
||||
"ScopeActive": "Scope active",
|
||||
"ScopeHint": "Scope trait: ignores the automatic Extreme Range rule beyond 100m, provided the traveller aims before firing. Select the actual range below.",
|
||||
"ZeroGActive": "Zero-G",
|
||||
"ZeroGHint": "Zero-G trait: this weapon has little or no recoil. It can be used in low or zero gravity without requiring an Athletics (DEX) test. No additional DM required in those conditions."
|
||||
},
|
||||
"Timeframes": {
|
||||
"Normal": "Normal",
|
||||
@@ -355,7 +391,26 @@
|
||||
"ApplyDamages": "Apply Damages",
|
||||
"Damages": "Roll damages",
|
||||
"Success": "Success",
|
||||
"Failure": "Failure"
|
||||
"Failure": "Failure",
|
||||
"Effect": "Effect",
|
||||
"Dice": "Dice",
|
||||
"Result": "Result",
|
||||
"DiceModifier": "Dice Modifier",
|
||||
"APIgnore": "AP",
|
||||
"APIgnoreHint": "This weapon ignores {ap} points of armor (AP trait)",
|
||||
"BlastArea": "Blast",
|
||||
"BlastHint": "Blast weapon: damage is applied to all targets within the blast radius (in meters). Dodge reactions cannot be used, but targets may dive for cover. Cover between target and explosion center applies.",
|
||||
"BlastRules": "No dodge — dive for cover possible",
|
||||
"StunWeapon": "Stun Weapon — END damage only",
|
||||
"StunHint": "Stun weapon: damage is only deducted from END (after armor). If END reaches 0, the target is incapacitated for a number of rounds equal to the difference between damage dealt and the target's END. Fully healed after 1 hour of rest."
|
||||
},
|
||||
"Radiation": {
|
||||
"Badge": "Radiation Weapon — RADs",
|
||||
"Hint": "This weapon emits radiation. On a successful attack, the target receives 2D×20 additional rads. Click the button to roll radiation damage.",
|
||||
"Title": "Radiation Damage",
|
||||
"Rads": "RADs",
|
||||
"RollButton": "Roll RADs",
|
||||
"Rules": "See p.78 for radiation effects (nausea, illness, death). ×3 multiplier for starship-scale weapons."
|
||||
}
|
||||
},
|
||||
"Items": {
|
||||
@@ -393,7 +448,7 @@
|
||||
"Informations": "Informations",
|
||||
"Improvement": "Improvement",
|
||||
"Interval": "Interval",
|
||||
"IsMelee": "IsMelee",
|
||||
"IsMelee": "Melee Weapon",
|
||||
"Items": "Items",
|
||||
"Level": "Level",
|
||||
"Location": "Location",
|
||||
@@ -410,6 +465,7 @@
|
||||
"Occupation": "Occupation",
|
||||
"OnHand": "On Hand",
|
||||
"Options": "Options",
|
||||
"PerDay": "per day",
|
||||
"PSICost": "PSI Cost",
|
||||
"Powered": "Powered",
|
||||
"Processing": "Processing",
|
||||
@@ -443,10 +499,150 @@
|
||||
"Weightless": "Weightless",
|
||||
"Quantity": "Quantity"
|
||||
},
|
||||
"WeaponTraits": {
|
||||
"SectionTitle": "Traits",
|
||||
"AP": "AP (Armor Piercing)",
|
||||
"APHint": "Ignores X points of armor protection",
|
||||
"Auto": "Auto",
|
||||
"AutoHint": "Automatic fire — Burst and Full-Auto modes available",
|
||||
"Blast": "Blast",
|
||||
"BlastHint": "Explosion radius in meters",
|
||||
"Bulky": "Bulky",
|
||||
"BulkyHint": "Requires STR 9+ or suffer negative DM",
|
||||
"VeryBulky": "Very Bulky",
|
||||
"VeryBulkyHint": "Requires STR 12+ or suffer negative DM",
|
||||
"Stun": "Stun",
|
||||
"StunHint": "Non-lethal damage — deducted from END only",
|
||||
"Smart": "Smart",
|
||||
"SmartHint": "Guided projectiles — DM = TL difference (min +1, max +6)",
|
||||
"Radiation": "Radiation",
|
||||
"RadiationHint": "Inflicts 2D×20 rads on target",
|
||||
"Scope": "Scope",
|
||||
"ScopeHint": "Ignores extreme range rule (>100m) if aiming",
|
||||
"ZeroG": "Zero-G",
|
||||
"ZeroGHint": "No recoil — no Athletics check needed in microgravity"
|
||||
},
|
||||
"Durations": {
|
||||
"Seconds": "Seconds",
|
||||
"Minutes": "Minutes",
|
||||
"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",
|
||||
"TabCombat": "Combat",
|
||||
"SkillName": "Skill",
|
||||
"SkillLevel": "Level",
|
||||
"SkillNote": "Note",
|
||||
"AttackName": "Attack",
|
||||
"AttackDamage": "Damage",
|
||||
"AttackSkill": "Skill",
|
||||
"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"
|
||||
},
|
||||
"SpeedBands": {
|
||||
"Stoppped": "Stopped",
|
||||
"Idle": "Idle",
|
||||
"VerySlow": "Very Slow",
|
||||
"Slow": "Slow",
|
||||
"Medium": "Medium",
|
||||
"High": "High",
|
||||
"Fast": "Fast",
|
||||
"VeryFast": "Very Fast",
|
||||
"Subsonic": "Subsonic",
|
||||
"Hypersonic": "Hypersonic"
|
||||
},
|
||||
"Vehicule": {
|
||||
"Hull": "Hull",
|
||||
"ArmorFront": "Front",
|
||||
"ArmorSides": "Sides",
|
||||
"ArmorRear": "Rear",
|
||||
"Armor": "Armor",
|
||||
"SpeedCruise": "Cruise Speed",
|
||||
"SpeedMax": "Max Speed",
|
||||
"Agility": "Agility",
|
||||
"Crew": "Crew",
|
||||
"Passengers": "Passengers",
|
||||
"Cargo": "Cargo (t)",
|
||||
"Shipping": "Shipping (t)",
|
||||
"Cost": "Cost (Cr)",
|
||||
"Autopilot": "Autopilot",
|
||||
"TabStats": "Statistics",
|
||||
"TabDescription": "Description"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"Healing": {
|
||||
"Title": "Healing",
|
||||
"FirstAid": "First Aid",
|
||||
"Surgery": "Surgery",
|
||||
"MedicalCare": "Medical Care",
|
||||
"NaturalHealing": "Natural Healing",
|
||||
"WillRestore": "Will restore",
|
||||
"SurgeryFailed": "Surgery failed - patient takes damage",
|
||||
"ApplyHealing": "Apply Healing",
|
||||
"ApplySurgeryDamage": "Apply Surgery Damage",
|
||||
"SurgeryDamage": "surgery damage",
|
||||
"ApplyToTarget": "Apply healing to selected target",
|
||||
"NoMedicineSkill": "No Medicine Skill",
|
||||
"Heals": "heals"
|
||||
},
|
||||
"Notifications": {
|
||||
"HealingApplied": "{name} has been healed for {amount} points.",
|
||||
"DamageApplied": "{name} has taken {amount} damage.",
|
||||
"DamageAppliedAP": "{name} has taken {amount} damage (armor reduced by {ap} from AP trait).",
|
||||
"BulkyPenalty": "Bulky weapon: insufficient STR (DM too low). Penalty {penalty} applied to roll.",
|
||||
"VeryBulkyPenalty": "Very Bulky weapon: insufficient STR (DM too low). Penalty {penalty} applied to roll.",
|
||||
"StunDamageApplied": "{name} took {amount} stun damage (END only).",
|
||||
"StunIncapacitated": "{name} is incapacitated for {rounds} round(s)! (END reduced to 0)",
|
||||
"AmmoUsed": "{weapon}: {used} round(s) expended. Magazine remaining: {remaining}.",
|
||||
"AmmoEmpty": "{weapon}: magazine empty after this shot!",
|
||||
"NoAmmo": "{weapon}: magazine empty! Reload before firing."
|
||||
},
|
||||
"Errors": {
|
||||
"NoTokenSelected": "No active target. Target a token on the scene before applying.",
|
||||
"InvalidRollFormula": "Invalid roll formula."
|
||||
}
|
||||
}
|
||||
},
|
||||
"TYPES.Actor.creature": "Creature"
|
||||
}
|
||||
230
lang/fr.json
230
lang/fr.json
@@ -18,6 +18,12 @@
|
||||
"Save": "Sauvegarder",
|
||||
"Cancel": "Annuler",
|
||||
"Close": "Fermer",
|
||||
"Dialog": {
|
||||
"ConfirmDeleteTitle": "Confirmer la suppression",
|
||||
"ConfirmDeleteContent": "Êtes-vous sûr de vouloir supprimer \"{name}\" ?",
|
||||
"Yes": "Oui",
|
||||
"No": "Non"
|
||||
},
|
||||
"Themes": {
|
||||
"BlackAndRed": "Couverture Classique Traveller",
|
||||
"Mwamba": "Oppa Mwamba Style",
|
||||
@@ -54,20 +60,21 @@
|
||||
"Gender": "Genre",
|
||||
"Pronouns": "Pronoms",
|
||||
"Actor": {
|
||||
"StudyPeriod":"Période d'étude",
|
||||
"TrainingInSkill":"Compétence en formation",
|
||||
"Completed":"Completée",
|
||||
"Weeks":"Semaines",
|
||||
"NewCareer":"Nouvelle Carrière",
|
||||
"AddCareer":"Ajouter Carrière",
|
||||
"EditCareer":"Éditer Carrière",
|
||||
"EditTrait":"Éditer Trait",
|
||||
"StudyPeriod": "Période d'étude",
|
||||
"TrainingInSkill": "Compétence en formation",
|
||||
"Completed": "Completée",
|
||||
"Weeks": "Semaines",
|
||||
"NewCareer": "Nouvelle Carrière",
|
||||
"AddCareer": "Ajouter Carrière",
|
||||
"ThisTrait": "ce trait",
|
||||
"EditCareer": "Éditer Carrière",
|
||||
"EditTrait": "Éditer Trait",
|
||||
"DeleteTrait": "Supprimer Trait",
|
||||
"DeleteCareer":"Supprimer Carrière",
|
||||
"NewSkill":"Nouvelle Compétence",
|
||||
"DeleteSkill":"Supprimer Compétence",
|
||||
"EditSkill":"Éditer Compétence",
|
||||
"PsionicTalents":"Talents Psionique",
|
||||
"DeleteCareer": "Supprimer Carrière",
|
||||
"NewSkill": "Nouvelle Compétence",
|
||||
"DeleteSkill": "Supprimer Compétence",
|
||||
"EditSkill": "Éditer Compétence",
|
||||
"PsionicTalents": "Talents Psionique",
|
||||
"NewPsionicTalent": "Nouveau Talent Psionique",
|
||||
"AddPsionicTalent": "Ajouter Talent Psionique",
|
||||
"EditPsionic": "Éditer Talent Psionique",
|
||||
@@ -343,7 +350,36 @@
|
||||
"EncumbranceDM": "Encombrement (MD -2)",
|
||||
"FatigueDM": "Fatigue (MD -2)",
|
||||
"Boon": "Avantage",
|
||||
"Bane": "Désavantage"
|
||||
"Bane": "Désavantage",
|
||||
"CreatureSkill": "Compétence",
|
||||
"NoSkill": "Aucune compétence",
|
||||
"Days": "Jours",
|
||||
"RangedModifiers": "Modificateurs de tir",
|
||||
"Range": "Portée",
|
||||
"RangeShort": "Courte portée",
|
||||
"RangeNormal": "Portée normale",
|
||||
"RangeLong": "Longue portée",
|
||||
"RangeExtreme": "Portée extrême",
|
||||
"Aim": "Visée",
|
||||
"LaserSight": "Pointeur laser",
|
||||
"FastTarget": "Cible bougeant vite",
|
||||
"Cover": "À couvert / Plongé",
|
||||
"Prone": "À plat ventre",
|
||||
"MeleeModifiers": "Modificateurs de mêlée",
|
||||
"Parry": "Parade (score Mêlée du défenseur)",
|
||||
"Dodge": "Esquive de la cible",
|
||||
"DodgeDM": "MD Esquive",
|
||||
"FireMode": "Mode de tir",
|
||||
"AutoSingle": "Simple",
|
||||
"AutoBurst": "Rafale",
|
||||
"AutoFull": "Auto complet",
|
||||
"AutoNoAim": "Rafale / Auto : les avantages de la visée sont annulés.",
|
||||
"AutoBurstInfo": "Rafale (Auto {level}) — +{level} dégâts — munitions: {ammo}",
|
||||
"AutoFullInfo": "Auto complet (Auto {level}) — {level} attaques — munitions: {ammo}",
|
||||
"ScopeActive": "Viseur actif",
|
||||
"ScopeHint": "Trait Viseur : ignore la règle Portée Extrême automatique au-delà de 100m, à condition de viser avant de tirer. Choisissez la portée réelle dans le sélecteur ci-dessous.",
|
||||
"ZeroGActive": "Zéro-G",
|
||||
"ZeroGHint": "Trait Zéro-G : cette arme a peu ou pas de recul. Elle peut être utilisée en gravité faible ou nulle sans nécessiter de test d'Athlétisme (DEX). Aucun MD supplémentaire requis dans ces conditions."
|
||||
},
|
||||
"Timeframes": {
|
||||
"Normal": "Normal",
|
||||
@@ -355,7 +391,26 @@
|
||||
"ApplyDamages": "Appliquer Dégâts",
|
||||
"Damages": "Lancer les Dégâts",
|
||||
"Success": "Succès",
|
||||
"Failure": "Échec"
|
||||
"Failure": "Échec",
|
||||
"Effect": "Effet",
|
||||
"Dice": "Dés",
|
||||
"Result": "Résultat",
|
||||
"DiceModifier": "Modificateur de dés",
|
||||
"APIgnore": "AP",
|
||||
"APIgnoreHint": "Cette arme ignore {ap} points d'armure (trait AP)",
|
||||
"BlastArea": "Explosion",
|
||||
"BlastHint": "Arme à explosion : les dégâts sont infligés à toutes les cibles dans le rayon indiqué (en mètres). Pas d'esquive possible, mais possibilité de plonger à couvert. Le couvert entre la cible et le centre de l'explosion s'applique.",
|
||||
"BlastRules": "Pas d'esquive — plonger à couvert possible",
|
||||
"StunWeapon": "Arme Incapacitante — dégâts END uniquement",
|
||||
"StunHint": "Arme incapacitante : les dégâts sont déduits uniquement de l'END (après armure). Si l'END atteint 0, la cible est neutralisée pendant un nombre de rounds égal à la différence entre les dégâts et l'END initiale. Guérison complète après 1h de repos."
|
||||
},
|
||||
"Radiation": {
|
||||
"Badge": "Arme à Rayonnement — RADs",
|
||||
"Hint": "Cette arme émet des radiations. En cas d'attaque réussie, la cible reçoit 2D×20 rads supplémentaires. Cliquez le bouton pour lancer les dégâts de RAD.",
|
||||
"Title": "Dégâts de Rayonnement",
|
||||
"Rads": "RADs",
|
||||
"RollButton": "Lancer RADs",
|
||||
"Rules": "Consultez p.78 pour l'effet des radiations (nausées, maladies, mort). Multiplicé ×3 pour une arme à l'échelle spatiale."
|
||||
}
|
||||
},
|
||||
"Items": {
|
||||
@@ -393,7 +448,7 @@
|
||||
"Informations": "Informations",
|
||||
"Improvement": "Améliorations",
|
||||
"Interval": "Intervalle",
|
||||
"IsMelee": "Est Mêlée",
|
||||
"IsMelee": "Arme de Mêlée",
|
||||
"Items": "Objets",
|
||||
"Level": "Niveau",
|
||||
"Location": "Localisation",
|
||||
@@ -410,6 +465,7 @@
|
||||
"Occupation": "Profession",
|
||||
"OnHand": "Sur Soi",
|
||||
"Options": "Options",
|
||||
"PerDay": "par jour",
|
||||
"PSICost": "Coût PSI",
|
||||
"Powered": "Alimenté",
|
||||
"Processing": "Capacité de Traitement",
|
||||
@@ -443,10 +499,150 @@
|
||||
"Weightless": "Aucun Poids",
|
||||
"Quantity": "Quantité"
|
||||
},
|
||||
"WeaponTraits": {
|
||||
"SectionTitle": "Traits",
|
||||
"AP": "AP (Perforant)",
|
||||
"APHint": "Ignore X points de protection d'armure",
|
||||
"Auto": "Auto",
|
||||
"AutoHint": "Tir automatique — Rafale et Auto complet disponibles",
|
||||
"Blast": "Explosion",
|
||||
"BlastHint": "Rayon de l'explosion en mètres",
|
||||
"Bulky": "Encombrant",
|
||||
"BulkyHint": "Requiert FOR 9+ sinon MD négatif",
|
||||
"VeryBulky": "Très Encombrant",
|
||||
"VeryBulkyHint": "Requiert FOR 12+ sinon MD négatif",
|
||||
"Stun": "Incapacitante",
|
||||
"StunHint": "Dégâts non létaux — déduits uniquement de l'END",
|
||||
"Smart": "Intelligente",
|
||||
"SmartHint": "Projectiles guidés — MD = différence de NT (min +1, max +6)",
|
||||
"Radiation": "Rayonnement",
|
||||
"RadiationHint": "Inflige 2D×20 rads à la cible",
|
||||
"Scope": "Viseur",
|
||||
"ScopeHint": "Ignore la règle portée extrême (>100m) si le tireur vise",
|
||||
"ZeroG": "Zéro-G",
|
||||
"ZeroGHint": "Pas de recul — aucun jet d'Athlétisme requis en microgravité"
|
||||
},
|
||||
"Durations": {
|
||||
"Seconds": "Secondes",
|
||||
"Minutes": "Minutes",
|
||||
"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",
|
||||
"TabCombat": "Combat",
|
||||
"SkillName": "Compétence",
|
||||
"SkillLevel": "Niveau",
|
||||
"SkillNote": "Note",
|
||||
"AttackName": "Attaque",
|
||||
"AttackDamage": "Dommages",
|
||||
"AttackSkill": "Compétence",
|
||||
"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"
|
||||
},
|
||||
"SpeedBands": {
|
||||
"Stoppped": "Arrêté",
|
||||
"Idle": "Au ralenti",
|
||||
"VerySlow": "Très lent",
|
||||
"Slow": "Lent",
|
||||
"Medium": "Moyen",
|
||||
"High": "Élevé",
|
||||
"Fast": "Rapide",
|
||||
"VeryFast": "Très rapide",
|
||||
"Subsonic": "Subsonique",
|
||||
"Hypersonic": "Hypersonique"
|
||||
},
|
||||
"Vehicule": {
|
||||
"Hull": "Coque",
|
||||
"ArmorFront": "Av.",
|
||||
"ArmorSides": "Lat.",
|
||||
"ArmorRear": "Arr.",
|
||||
"Armor": "Armure",
|
||||
"SpeedCruise": "Vitesse croisière",
|
||||
"SpeedMax": "Vitesse max",
|
||||
"Agility": "Agilité",
|
||||
"Crew": "Équipage",
|
||||
"Passengers": "Passagers",
|
||||
"Cargo": "Cargo (t)",
|
||||
"Shipping": "Expédition (t)",
|
||||
"Cost": "Coût (Cr)",
|
||||
"Autopilot": "Autopilote",
|
||||
"TabStats": "Statistiques",
|
||||
"TabDescription": "Description"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"Healing": {
|
||||
"Title": "Soins",
|
||||
"FirstAid": "Premiers soins",
|
||||
"Surgery": "Chirurgie",
|
||||
"MedicalCare": "Soins médicaux",
|
||||
"NaturalHealing": "Guérison naturelle",
|
||||
"WillRestore": "Restaurera",
|
||||
"SurgeryFailed": "Chirurgie échouée - patient subit des dégâts",
|
||||
"ApplyHealing": "Appliquer les soins",
|
||||
"ApplySurgeryDamage": "Appliquer les dégâts chirurgicaux",
|
||||
"SurgeryDamage": "dégâts chirurgicaux",
|
||||
"ApplyToTarget": "Appliquer les soins à la cible sélectionnée",
|
||||
"NoMedicineSkill": "Pas de compétence Médecine",
|
||||
"Heals": "soigne"
|
||||
},
|
||||
"Notifications": {
|
||||
"HealingApplied": "{name} a été soigné(e) de {amount} points.",
|
||||
"DamageApplied": "{name} a subi {amount} dégâts.",
|
||||
"DamageAppliedAP": "{name} a subi {amount} dégâts (armure réduite de {ap} par AP).",
|
||||
"BulkyPenalty": "Arme Encombrante : FOR insuffisante (MD FOR trop faible). Pénalité {penalty} appliquée au jet.",
|
||||
"VeryBulkyPenalty": "Arme Très Encombrante : FOR insuffisante (MD FOR trop faible). Pénalité {penalty} appliquée au jet.",
|
||||
"StunDamageApplied": "{name} a subi {amount} dégâts incapacitants (END seulement).",
|
||||
"StunIncapacitated": "{name} est neutralisé(e) pour {rounds} round(s) ! (END réduite à 0)",
|
||||
"AmmoUsed": "{weapon} : {used} munition(s) consommée(s). Chargeur restant : {remaining}.",
|
||||
"AmmoEmpty": "{weapon} : chargeur vide après ce tir !",
|
||||
"NoAmmo": "{weapon} : chargeur vide ! Rechargez avant de tirer."
|
||||
},
|
||||
"Errors": {
|
||||
"NoTokenSelected": "Aucune cible active. Ciblez un token sur la scène avant d'appliquer.",
|
||||
"InvalidRollFormula": "Formule de jet invalide."
|
||||
}
|
||||
}
|
||||
},
|
||||
"TYPES.Actor.creature": "Créature"
|
||||
}
|
||||
1744
mgt2.bundle.js
1744
mgt2.bundle.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -4,5 +4,8 @@
|
||||
"scripts": {
|
||||
"build": "rollup -c rollup.config.mjs",
|
||||
"watch": "rollup -c rollup.config.mjs --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"rollup": "^4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,33 @@ export class TravellerActor extends Actor {
|
||||
}
|
||||
}
|
||||
|
||||
applyDamage(amount) {
|
||||
applyDamage(amount, { ignoreArmor = false, ap = 0, stun = false } = {}) {
|
||||
if (this.type === "character") {
|
||||
ActorCharacter.applyDamage(this, amount);
|
||||
return ActorCharacter.applyDamage(this, amount, { ignoreArmor, ap, stun });
|
||||
} else if (this.type === "creature") {
|
||||
if (isNaN(amount) || amount === 0) return Promise.resolve({ incapRounds: 0 });
|
||||
if (amount < 0) amount = Math.abs(amount);
|
||||
const rawArmor = ignoreArmor ? 0 : (this.system.armor ?? 0);
|
||||
const armorValue = Math.max(0, rawArmor - ap);
|
||||
const effective = Math.max(0, amount - armorValue);
|
||||
if (effective === 0) return Promise.resolve({ incapRounds: 0 });
|
||||
const newValue = Math.max(0, (this.system.life.value ?? 0) - effective);
|
||||
return this.update({ "system.life.value": newValue }).then(() => ({ incapRounds: 0 }));
|
||||
}
|
||||
}
|
||||
|
||||
applyHealing(amount) {
|
||||
if (this.type === "character") {
|
||||
return ActorCharacter.applyHealing(this, amount);
|
||||
} else if (this.type === "creature") {
|
||||
if (isNaN(amount) || amount === 0) return;
|
||||
if (amount < 0) amount = Math.abs(amount);
|
||||
const maxValue = this.system.life.max ?? 0;
|
||||
const current = this.system.life.value ?? 0;
|
||||
const newValue = Math.min(current + amount, maxValue);
|
||||
if (newValue !== current) {
|
||||
return this.update({ "system.life.value": newValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,14 @@ export class CharacterPrompts {
|
||||
}
|
||||
|
||||
static async openEditorFullView(title, html) {
|
||||
const safeTitle = title || game.i18n.localize("MGT2.Actor.Species") || "Species";
|
||||
const htmlContent = await renderTemplate("systems/mgt2/templates/editor-fullview.html", {
|
||||
config: CONFIG.MGT2,
|
||||
html
|
||||
html: html ?? ""
|
||||
});
|
||||
const theme = game.settings.get("mgt2", "theme");
|
||||
await DialogV2.wait({
|
||||
window: { title },
|
||||
window: { title: safeTitle },
|
||||
content: htmlContent,
|
||||
rejectClose: false,
|
||||
buttons: [
|
||||
@@ -70,4 +71,35 @@ export class CharacterPrompts {
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
static async openHealingDays() {
|
||||
return await DialogV2.wait({
|
||||
window: {
|
||||
title: game.i18n.localize("MGT2.Healing.Title")
|
||||
},
|
||||
classes: ["mgt2-roll-dialog"],
|
||||
content: `
|
||||
<form>
|
||||
<div style="padding: 12px;">
|
||||
<div class="form-group">
|
||||
<label>${game.i18n.localize("MGT2.RollPrompt.Days") || "Jours"}</label>
|
||||
<input type="number" name="days" value="1" min="1" max="999" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`,
|
||||
rejectClose: false,
|
||||
buttons: [
|
||||
{
|
||||
action: "submit",
|
||||
label: game.i18n.localize("MGT2.Save"),
|
||||
icon: '<i class="fa-solid fa-floppy-disk"></i>',
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
return new FormDataExtended(dialog.element.querySelector('form')).object;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -254,7 +254,10 @@ export class ActorCharacter {
|
||||
}
|
||||
|
||||
updateData["system.inventory.weight"] = onHandWeight;
|
||||
updateData["system.states.encumbrance"] = onHandWeight > $this.system.inventory.encumbrance.normal;
|
||||
// Use the threshold from updateData if it was just recalculated (e.g. STR/END talent change),
|
||||
// otherwise fall back to the persisted value.
|
||||
const encumbranceThreshold = updateData["system.inventory.encumbrance.normal"] ?? $this.system.inventory.encumbrance.normal;
|
||||
updateData["system.states.encumbrance"] = onHandWeight > encumbranceThreshold;
|
||||
|
||||
await $this.update(updateData);
|
||||
|
||||
@@ -275,6 +278,8 @@ export class ActorCharacter {
|
||||
let heavy = normal * 2;
|
||||
foundry.utils.setProperty(changed, "system.inventory.encumbrance.normal", normal);
|
||||
foundry.utils.setProperty(changed, "system.inventory.encumbrance.heavy", heavy);
|
||||
// Also update the encumbrance state flag against the new threshold
|
||||
foundry.utils.setProperty(changed, "system.states.encumbrance", $this.system.inventory.weight > normal);
|
||||
}
|
||||
|
||||
//console.log(foundry.utils.getProperty(changed, "system.characteristics.strength.value"));
|
||||
@@ -331,19 +336,39 @@ export class ActorCharacter {
|
||||
// $this.update({ system: { characteristics: data } });
|
||||
// }
|
||||
|
||||
static applyDamage($this, amount) {
|
||||
if (isNaN(amount) || amount === 0) return;
|
||||
static async applyDamage($this, amount, { ignoreArmor = false, ap = 0, stun = false } = {}) {
|
||||
if (isNaN(amount) || amount === 0) return { incapRounds: 0 };
|
||||
const rank1 = $this.system.config.damages.rank1;
|
||||
const rank2 = $this.system.config.damages.rank2;
|
||||
const rank3 = $this.system.config.damages.rank3;
|
||||
|
||||
if (amount < 0) amount = Math.abs(amount);
|
||||
|
||||
if (!ignoreArmor) {
|
||||
const rawArmor = $this.system.inventory?.armor ?? 0;
|
||||
const armorValue = Math.max(0, rawArmor - ap);
|
||||
amount = Math.max(0, amount - armorValue);
|
||||
if (amount === 0) return { incapRounds: 0 };
|
||||
}
|
||||
|
||||
// ── Stun / Incapacitating: only deduct from endurance (rank3) ─────────
|
||||
if (stun) {
|
||||
const endKey = rank3; // "endurance" by default
|
||||
const prevEnd = $this.system.characteristics[endKey].value;
|
||||
const newEnd = Math.max(0, prevEnd - amount);
|
||||
const incapRounds = newEnd === 0 ? Math.max(0, amount - prevEnd) : 0;
|
||||
await $this.update({
|
||||
system: { characteristics: { [endKey]: { value: newEnd, dm: this.getModifier(newEnd) } } }
|
||||
});
|
||||
return { incapRounds };
|
||||
}
|
||||
|
||||
// ── Normal damage cascade: rank1 → rank2 → rank3 ────────────────────
|
||||
const data = {};
|
||||
data[rank1] = { value: $this.system.characteristics[rank1].value };
|
||||
data[rank2] = { value: $this.system.characteristics[rank2].value };
|
||||
data[rank3] = { value: $this.system.characteristics[rank3].value };
|
||||
|
||||
if (amount < 0) amount = Math.abs(amount);
|
||||
|
||||
for (const [key, rank] of Object.entries(data)) {
|
||||
if (rank.value > 0) {
|
||||
if (rank.value >= amount) {
|
||||
@@ -358,7 +383,50 @@ export class ActorCharacter {
|
||||
}
|
||||
}
|
||||
|
||||
$this.update({ system: { characteristics: data } });
|
||||
await $this.update({ system: { characteristics: data } });
|
||||
return { incapRounds: 0 };
|
||||
}
|
||||
|
||||
static applyHealing($this, amount, type) {
|
||||
if (isNaN(amount) || amount === 0) return;
|
||||
|
||||
const rank1 = $this.system.config.damages.rank1;
|
||||
const rank2 = $this.system.config.damages.rank2;
|
||||
const rank3 = $this.system.config.damages.rank3;
|
||||
|
||||
// Data to restore (reverse cascade: END → DEX → STR)
|
||||
const data = {};
|
||||
const rankOrder = [rank3, rank2, rank1]; // Reverse order for healing
|
||||
const maxValues = {
|
||||
[rank1]: $this.system.characteristics[rank1].max,
|
||||
[rank2]: $this.system.characteristics[rank2].max,
|
||||
[rank3]: $this.system.characteristics[rank3].max
|
||||
};
|
||||
|
||||
if (amount < 0) amount = Math.abs(amount);
|
||||
|
||||
// Distribute healing from lowest rank first (END → DEX → STR typically)
|
||||
for (const rank of rankOrder) {
|
||||
const current = $this.system.characteristics[rank].value;
|
||||
const max = maxValues[rank];
|
||||
|
||||
if (current < max && amount > 0) {
|
||||
const canRestore = max - current;
|
||||
const restore = Math.min(amount, canRestore);
|
||||
|
||||
if (!data[rank]) {
|
||||
data[rank] = { value: current };
|
||||
}
|
||||
data[rank].value += restore;
|
||||
data[rank].dm = this.getModifier(data[rank].value);
|
||||
amount -= restore;
|
||||
}
|
||||
}
|
||||
|
||||
// Only update if something was restored
|
||||
if (Object.keys(data).length > 0) {
|
||||
return $this.update({ system: { characteristics: data } });
|
||||
}
|
||||
}
|
||||
|
||||
static getContainers($this) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export { default as MGT2ActorSheet } from "./base-actor-sheet.mjs";
|
||||
export { default as TravellerCharacterSheet } from "./character-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";
|
||||
|
||||
@@ -3,6 +3,7 @@ import { MGT2 } from "../../config.js";
|
||||
import { MGT2Helper } from "../../helper.js";
|
||||
import { RollPromptHelper } from "../../roll-prompt.js";
|
||||
import { CharacterPrompts } from "../../actors/character-prompts.js";
|
||||
import WeaponData from "../../models/items/weapon.mjs";
|
||||
|
||||
export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
|
||||
@@ -33,6 +34,7 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
traitEdit: TravellerCharacterSheet.#onTraitEdit,
|
||||
traitDelete: TravellerCharacterSheet.#onTraitDelete,
|
||||
openEditor: TravellerCharacterSheet.#onOpenEditor,
|
||||
heal: TravellerCharacterSheet.#onHeal,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -54,7 +56,11 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext();
|
||||
const actor = this.document;
|
||||
const enrich = (html) => foundry.applications.ux.TextEditor.implementation.enrichHTML(html ?? "", { async: true });
|
||||
|
||||
context.enrichedBiography = await enrich(actor.system.biography);
|
||||
context.enrichedNotes = await enrich(actor.system.notes);
|
||||
context.enrichedFinanceNotes = await enrich(actor.system.finance?.notes);
|
||||
context.settings = {
|
||||
weightUnit: "kg",
|
||||
usePronouns: game.settings.get("mgt2", "usePronouns"),
|
||||
@@ -152,9 +158,10 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
|
||||
if (item.hasOwnProperty("equipped")) {
|
||||
i._canEquip = true;
|
||||
i._toggleClass = item.equipped ? "active" : "";
|
||||
i.toggleClass = item.equipped ? "active" : "";
|
||||
} else {
|
||||
i._canEquip = false;
|
||||
i.toggleClass = "";
|
||||
}
|
||||
|
||||
switch (i.type) {
|
||||
@@ -194,8 +201,7 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
i._range = i.system.range.isMelee
|
||||
? game.i18n.localize("MGT2.Melee")
|
||||
: MGT2Helper.getRangeDisplay(i.system.range);
|
||||
if (i.system.traits?.length > 0)
|
||||
i._subInfo = i.system.traits.map(x => x.name).join(", ");
|
||||
i._subInfo = WeaponData.getTraitsSummary(i.system.traits);
|
||||
weapons.push(i);
|
||||
break;
|
||||
|
||||
@@ -283,12 +289,11 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
const html = this.element;
|
||||
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, ".item-create", "click", TravellerCharacterSheet.#onCreateItem);
|
||||
this._bindClassEvent(html, ".item-edit", "click", TravellerCharacterSheet.#onEditItem);
|
||||
this._bindClassEvent(html, ".item-delete", "click", TravellerCharacterSheet.#onDeleteItem);
|
||||
this._bindClassEvent(html, ".item-equip", "click", TravellerCharacterSheet.#onEquipItem);
|
||||
this._bindClassEvent(html, ".item-storage-in", "click", TravellerCharacterSheet.#onItemStorageIn);
|
||||
this._bindClassEvent(html, ".item-storage-out", "click", TravellerCharacterSheet.#onItemStorageOut);
|
||||
this._bindClassEvent(html, ".software-eject", "click", TravellerCharacterSheet.#onSoftwareEject);
|
||||
@@ -374,26 +379,22 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
let sourceItem = this.actor.getEmbeddedDocument("Item", sourceItemData.id);
|
||||
if (sourceItem) {
|
||||
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.system.subType === "software")
|
||||
sourceItem.system.software.computerId = targetItem.system.software.computerId;
|
||||
await sourceItem.update({ "system.software.computerId": targetItem.system.software.computerId });
|
||||
else
|
||||
sourceItem.system.container.id = targetItem.system.container.id;
|
||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
||||
await sourceItem.update({ "system.container.id": targetItem.system.container.id });
|
||||
return true;
|
||||
} else if (targetItem.type === "computer") {
|
||||
sourceItem.system.software.computerId = targetId;
|
||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
||||
await sourceItem.update({ "system.software.computerId": targetId });
|
||||
return true;
|
||||
} else if (targetItem.type === "container") {
|
||||
if (targetItem.system.locked && !game.user.isGM) {
|
||||
ui.notifications.error("Verrouillé");
|
||||
} else {
|
||||
sourceItem.system.container.id = targetId;
|
||||
this.actor.updateEmbeddedDocuments("Item", [sourceItem]);
|
||||
await sourceItem.update({ "system.container.id": targetId });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -456,30 +457,46 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
if (item) item.sheet.render(true);
|
||||
}
|
||||
|
||||
static async #confirmDelete(name) {
|
||||
return foundry.applications.api.DialogV2.confirm({
|
||||
window: { title: game.i18n.localize("MGT2.Dialog.ConfirmDeleteTitle") },
|
||||
content: `<p>${game.i18n.format("MGT2.Dialog.ConfirmDeleteContent", { name })}</p>`,
|
||||
yes: { label: game.i18n.localize("MGT2.Dialog.Yes"), icon: "fas fa-trash" },
|
||||
no: { label: game.i18n.localize("MGT2.Dialog.No"), icon: "fas fa-times" },
|
||||
rejectClose: false,
|
||||
modal: true
|
||||
});
|
||||
}
|
||||
|
||||
static async #onDeleteItem(event, target) {
|
||||
event.preventDefault();
|
||||
const li = target.closest("[data-item-id]");
|
||||
if (!li?.dataset.itemId) return;
|
||||
const item = this.actor.items.get(li.dataset.itemId);
|
||||
if (!item) return;
|
||||
const confirmed = await TravellerCharacterSheet.#confirmDelete(item.name);
|
||||
if (!confirmed) return;
|
||||
this.actor.deleteEmbeddedDocuments("Item", [li.dataset.itemId]);
|
||||
}
|
||||
|
||||
static async #onEquipItem(event, target) {
|
||||
event.preventDefault();
|
||||
const li = target.closest("[data-item-id]");
|
||||
const item = foundry.utils.deepClone(this.actor.getEmbeddedDocument("Item", li?.dataset.itemId));
|
||||
const itemId = li?.dataset.itemId;
|
||||
if (!itemId) return;
|
||||
const item = this.actor.items.get(itemId);
|
||||
if (!item) return;
|
||||
item.system.equipped = !item.system.equipped;
|
||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
||||
await item.update({ "system.equipped": !item.system.equipped });
|
||||
}
|
||||
|
||||
static async #onItemStorageIn(event, target) {
|
||||
event.preventDefault();
|
||||
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.type === "container") {
|
||||
item.system.onHand = false;
|
||||
await item.update({ "system.onHand": false });
|
||||
} else {
|
||||
const containers = this.actor.getContainers();
|
||||
let container;
|
||||
@@ -497,27 +514,24 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
ui.notifications.error("Objet verrouillé");
|
||||
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) {
|
||||
event.preventDefault();
|
||||
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;
|
||||
item.system.container.id = "";
|
||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
||||
await item.update({ "system.container.id": "" });
|
||||
}
|
||||
|
||||
static async #onSoftwareEject(event, target) {
|
||||
event.preventDefault();
|
||||
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;
|
||||
item.system.software.computerId = "";
|
||||
this.actor.updateEmbeddedDocuments("Item", [item]);
|
||||
await item.update({ "system.software.computerId": "" });
|
||||
}
|
||||
|
||||
static async #onContainerCreate(event) {
|
||||
@@ -538,28 +552,27 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
const container = containers.find(x => x._id === this.actor.system.containerView);
|
||||
if (!container) return;
|
||||
|
||||
const confirmed = await TravellerCharacterSheet.#confirmDelete(container.name);
|
||||
if (!confirmed) return;
|
||||
|
||||
const containerItems = this.actor.items.filter(
|
||||
x => x.system.hasOwnProperty("container") && x.system.container.id === container._id
|
||||
);
|
||||
|
||||
if (containerItems.length > 0) {
|
||||
for (let item of containerItems) {
|
||||
let clone = foundry.utils.deepClone(item);
|
||||
clone.system.container.id = "";
|
||||
this.actor.updateEmbeddedDocuments("Item", [clone]);
|
||||
}
|
||||
const updates = containerItems.map(item => ({ _id: item.id, "system.container.id": "" }));
|
||||
await this.actor.updateEmbeddedDocuments("Item", updates);
|
||||
}
|
||||
|
||||
const cloneActor = foundry.utils.deepClone(this.actor);
|
||||
cloneActor.system.containerView = "";
|
||||
if (cloneActor.system.containerDropIn === container._id) {
|
||||
cloneActor.system.containerDropIn = "";
|
||||
const actorUpdate = { "system.containerView": "" };
|
||||
if (this.actor.system.containerDropIn === container._id) {
|
||||
actorUpdate["system.containerDropIn"] = "";
|
||||
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]);
|
||||
this.actor.update(cloneActor);
|
||||
await this.actor.deleteEmbeddedDocuments("Item", [container._id]);
|
||||
await this.actor.update(actorUpdate);
|
||||
}
|
||||
|
||||
static async #onRoll(event, target) {
|
||||
@@ -576,6 +589,14 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
encumbrance: this.actor.system.states.encumbrance,
|
||||
difficulty: null,
|
||||
damageFormula: null,
|
||||
damageAP: 0,
|
||||
blastRadius: 0,
|
||||
stun: false,
|
||||
radiation: false,
|
||||
isMelee: false,
|
||||
isRanged: false,
|
||||
bulky: false,
|
||||
veryBulky: false,
|
||||
};
|
||||
|
||||
const cardButtons = [];
|
||||
@@ -643,6 +664,21 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
|
||||
if (itemObj?.system.hasOwnProperty("damage")) {
|
||||
rollOptions.damageFormula = itemObj.system.damage;
|
||||
if (itemObj.type === "weapon") {
|
||||
rollOptions.isMelee = itemObj.system.range?.isMelee === true;
|
||||
rollOptions.isRanged = itemObj.type === "weapon" && !itemObj.system.range?.isMelee;
|
||||
rollOptions.damageAP = itemObj.system.traits?.ap ?? 0;
|
||||
rollOptions.blastRadius = itemObj.system.traits?.blast ?? 0;
|
||||
rollOptions.stun = itemObj.system.traits?.stun === true;
|
||||
rollOptions.radiation = itemObj.system.traits?.radiation === true;
|
||||
rollOptions.scope = itemObj.system.traits?.scope === true;
|
||||
rollOptions.zeroG = itemObj.system.traits?.zeroG === true;
|
||||
rollOptions.autoLevel = itemObj.system.traits?.auto ?? 0;
|
||||
rollOptions.itemId = itemObj._id;
|
||||
rollOptions.magazine = itemObj.system.magazine ?? -1; // -1 = not tracked
|
||||
rollOptions.bulky = itemObj.system.traits?.bulky === true;
|
||||
rollOptions.veryBulky = itemObj.system.traits?.veryBulky === true;
|
||||
}
|
||||
if (itemObj.type === "disease") {
|
||||
if (itemObj.system.subType === "disease")
|
||||
rollOptions.rollTypeName = game.i18n.localize("MGT2.DiseaseSubType.disease");
|
||||
@@ -663,6 +699,10 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
const rollModifiers = [];
|
||||
const rollFormulaParts = [];
|
||||
|
||||
// Auto trait — fire mode
|
||||
const autoLevel = rollOptions.autoLevel ?? 0;
|
||||
const autoMode = autoLevel > 0 ? (userRollData.autoMode ?? "single") : "single";
|
||||
|
||||
if (userRollData.diceModifier) {
|
||||
rollFormulaParts.push("3d6", userRollData.diceModifier);
|
||||
} else {
|
||||
@@ -707,13 +747,99 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
rollModifiers.push(game.i18n.localize("MGT2.Actor.Fatigue") + " -2");
|
||||
}
|
||||
|
||||
if (userRollData.customDM) {
|
||||
const s = userRollData.customDM.trim();
|
||||
if (/^[0-9]/.test(s)) rollFormulaParts.push("+");
|
||||
rollFormulaParts.push(s);
|
||||
const customDMVal = parseInt(userRollData.customDM ?? "0", 10);
|
||||
if (!isNaN(customDMVal) && customDMVal !== 0) {
|
||||
rollFormulaParts.push(customDMVal > 0 ? `+${customDMVal}` : `${customDMVal}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.CustomDM") + " " + (customDMVal > 0 ? `+${customDMVal}` : `${customDMVal}`));
|
||||
}
|
||||
|
||||
if (MGT2Helper.hasValue(userRollData, "difficulty")) rollOptions.difficulty = userRollData.difficulty;
|
||||
if (rollOptions.isRanged) {
|
||||
const rangedRange = parseInt(userRollData.rangedRange ?? "0", 10);
|
||||
if (rangedRange === 1) {
|
||||
rollFormulaParts.push("+1");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.RangeShort") + " +1");
|
||||
} else if (rangedRange === -2) {
|
||||
rollFormulaParts.push("-2");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.RangeLong") + " −2");
|
||||
} else if (rangedRange === -4) {
|
||||
rollFormulaParts.push("-4");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.RangeExtreme") + " −4");
|
||||
}
|
||||
|
||||
const rangedAim = parseInt(userRollData.rangedAim ?? "0", 10);
|
||||
// Auto: burst/full-auto cancels all aiming advantages (rules p.75)
|
||||
if (rangedAim > 0 && autoMode === "single") {
|
||||
rollFormulaParts.push(`+${rangedAim}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.Aim") + ` +${rangedAim}`);
|
||||
if (userRollData.rangedLaserSight === true || userRollData.rangedLaserSight === "true") {
|
||||
rollFormulaParts.push("+1");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.LaserSight") + " +1");
|
||||
}
|
||||
}
|
||||
|
||||
const rangedFastTarget = parseInt(userRollData.rangedFastTarget ?? "0", 10);
|
||||
if (rangedFastTarget < 0) {
|
||||
rollFormulaParts.push(`${rangedFastTarget}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.FastTarget") + ` ${rangedFastTarget}`);
|
||||
}
|
||||
|
||||
if (userRollData.rangedCover === true || userRollData.rangedCover === "true") {
|
||||
rollFormulaParts.push("-2");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.Cover") + " −2");
|
||||
}
|
||||
|
||||
if (userRollData.rangedProne === true || userRollData.rangedProne === "true") {
|
||||
rollFormulaParts.push("-1");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.Prone") + " −1");
|
||||
}
|
||||
|
||||
if (userRollData.rangedDodge === true || userRollData.rangedDodge === "true") {
|
||||
const dodgeDM = parseInt(userRollData.rangedDodgeDM ?? "0", 10);
|
||||
if (dodgeDM < 0) {
|
||||
rollFormulaParts.push(`${dodgeDM}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.Dodge") + ` ${dodgeDM}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rollOptions.isMelee) {
|
||||
if (userRollData.meleeDodge === true || userRollData.meleeDodge === "true") {
|
||||
const dodgeDM = parseInt(userRollData.meleeDodgeDM ?? "0", 10);
|
||||
if (dodgeDM < 0) {
|
||||
rollFormulaParts.push(`${dodgeDM}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.Dodge") + ` ${dodgeDM}`);
|
||||
}
|
||||
}
|
||||
if (userRollData.meleeParry === true || userRollData.meleeParry === "true") {
|
||||
const parryDM = parseInt(userRollData.meleeParryDM ?? "0", 10);
|
||||
if (parryDM < 0) {
|
||||
rollFormulaParts.push(`${parryDM}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.RollPrompt.Parry") + ` ${parryDM}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MGT2Helper.hasValue(userRollData, "difficulty") && userRollData.difficulty !== "") rollOptions.difficulty = userRollData.difficulty;
|
||||
|
||||
// ── Bulky / Very Bulky trait: STR penalty ────────────────────────────
|
||||
const strDm = this.actor.system.characteristics.strength?.dm ?? 0;
|
||||
if (rollOptions.veryBulky) {
|
||||
// Very Bulky: requires STR DM ≥ +2
|
||||
if (strDm < 2) {
|
||||
const penalty = strDm - 2;
|
||||
rollFormulaParts.push(`${penalty}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.WeaponTraits.VeryBulky") + ` ${penalty}`);
|
||||
ui.notifications.warn(game.i18n.format("MGT2.Notifications.VeryBulkyPenalty", { penalty }));
|
||||
}
|
||||
} else if (rollOptions.bulky) {
|
||||
// Bulky: requires STR DM ≥ +1
|
||||
if (strDm < 1) {
|
||||
const penalty = strDm - 1;
|
||||
rollFormulaParts.push(`${penalty}`);
|
||||
rollModifiers.push(game.i18n.localize("MGT2.WeaponTraits.Bulky") + ` ${penalty}`);
|
||||
ui.notifications.warn(game.i18n.format("MGT2.Notifications.BulkyPenalty", { penalty }));
|
||||
}
|
||||
}
|
||||
|
||||
const rollFormula = rollFormulaParts.join("");
|
||||
if (!Roll.validate(rollFormula)) {
|
||||
@@ -721,43 +847,120 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Ammo decrement (ranged weapons with magazine tracking) ───────────
|
||||
if (rollOptions.isRanged && rollOptions.itemId && rollOptions.magazine >= 0) {
|
||||
let ammoUsed = 1;
|
||||
if (autoMode === "burst" && autoLevel > 0) ammoUsed = autoLevel;
|
||||
else if (autoMode === "fullAuto" && autoLevel > 0) ammoUsed = autoLevel * 3;
|
||||
|
||||
const currentMag = rollOptions.magazine;
|
||||
if (currentMag <= 0) {
|
||||
ui.notifications.warn(
|
||||
game.i18n.format("MGT2.Notifications.NoAmmo", { weapon: rollOptions.rollObjectName })
|
||||
);
|
||||
} else {
|
||||
const newMag = Math.max(0, currentMag - ammoUsed);
|
||||
const weaponItem = this.actor.getEmbeddedDocument("Item", rollOptions.itemId);
|
||||
if (weaponItem) await weaponItem.update({ "system.magazine": newMag });
|
||||
if (newMag === 0) {
|
||||
ui.notifications.warn(
|
||||
game.i18n.format("MGT2.Notifications.AmmoEmpty", { weapon: rollOptions.rollObjectName })
|
||||
);
|
||||
} else {
|
||||
ui.notifications.info(
|
||||
game.i18n.format("MGT2.Notifications.AmmoUsed", { used: ammoUsed, remaining: newMag, weapon: rollOptions.rollObjectName })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let roll = await new Roll(rollFormula, this.actor.getRollData()).roll({ rollMode: userRollData.rollMode });
|
||||
|
||||
if (isInitiative && this.token?.combatant) {
|
||||
await this.token.combatant.update({ initiative: roll.total });
|
||||
}
|
||||
|
||||
// ── Compute effect and effective damage formula ──────────────────────
|
||||
let rollSuccess = false;
|
||||
let rollFailure = false;
|
||||
let rollEffect = undefined;
|
||||
let rollEffectStr = undefined;
|
||||
let difficultyValue = null;
|
||||
|
||||
if (MGT2Helper.hasValue(rollOptions, "difficulty")) {
|
||||
difficultyValue = MGT2Helper.getDifficultyValue(rollOptions.difficulty);
|
||||
rollEffect = roll.total - difficultyValue;
|
||||
rollEffectStr = (rollEffect >= 0 ? "+" : "") + rollEffect;
|
||||
rollSuccess = rollEffect >= 0;
|
||||
rollFailure = !rollSuccess;
|
||||
}
|
||||
|
||||
// Build effective damage formula: base + effect + STR DM (melee) + Auto burst
|
||||
let effectiveDamageFormula = rollOptions.damageFormula || null;
|
||||
if (effectiveDamageFormula) {
|
||||
if (rollEffect !== undefined && rollEffect !== 0) {
|
||||
effectiveDamageFormula += (rollEffect >= 0 ? "+" : "") + rollEffect;
|
||||
}
|
||||
if (rollOptions.isMelee) {
|
||||
const strDm = this.actor.system.characteristics.strength?.dm ?? 0;
|
||||
if (strDm !== 0) effectiveDamageFormula += (strDm >= 0 ? "+" : "") + strDm;
|
||||
}
|
||||
// Burst: add Auto level to damage
|
||||
if (autoMode === "burst" && autoLevel > 0) {
|
||||
effectiveDamageFormula += `+${autoLevel}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto fire mode chat info
|
||||
let autoInfo = null;
|
||||
if (autoMode === "burst" && autoLevel > 0) {
|
||||
autoInfo = game.i18n.format("MGT2.RollPrompt.AutoBurstInfo", { level: autoLevel, ammo: autoLevel });
|
||||
} else if (autoMode === "fullAuto" && autoLevel > 0) {
|
||||
autoInfo = game.i18n.format("MGT2.RollPrompt.AutoFullInfo", { level: autoLevel, ammo: autoLevel * 3 });
|
||||
}
|
||||
|
||||
// ── Build roll breakdown tooltip ─────────────────────────────────────
|
||||
const diceRawTotal = roll.dice.reduce((s, d) => s + d.total, 0);
|
||||
const breakdownParts = [game.i18n.localize("MGT2.Chat.Roll.Dice") + " " + diceRawTotal];
|
||||
for (const mod of rollModifiers) breakdownParts.push(mod);
|
||||
if (rollEffectStr !== undefined)
|
||||
breakdownParts.push(game.i18n.localize("MGT2.Chat.Roll.Effect") + " " + rollEffectStr);
|
||||
const rollBreakdown = breakdownParts.join(" | ");
|
||||
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: this.actor ? ChatMessage.getSpeaker({ actor: this.actor }) : null,
|
||||
formula: roll._formula,
|
||||
tooltip: await roll.getTooltip(),
|
||||
total: Math.round(roll.total * 100) / 100,
|
||||
rollBreakdown,
|
||||
showButtons: true,
|
||||
showLifeButtons: false,
|
||||
showRollRequest: false,
|
||||
rollTypeName: rollOptions.rollTypeName,
|
||||
rollObjectName: rollOptions.rollObjectName,
|
||||
rollModifiers: rollModifiers,
|
||||
showRollDamage: rollOptions.damageFormula !== null && rollOptions.damageFormula !== "",
|
||||
// Show damage button only if there's a formula AND (no difficulty check OR roll succeeded)
|
||||
showRollDamage: !!effectiveDamageFormula && (!difficultyValue || rollSuccess),
|
||||
cardButtons: cardButtons,
|
||||
autoInfo,
|
||||
};
|
||||
|
||||
if (MGT2Helper.hasValue(rollOptions, "difficulty")) {
|
||||
chatData.rollDifficulty = rollOptions.difficulty;
|
||||
chatData.rollDifficultyLabel = MGT2Helper.getDifficultyDisplay(rollOptions.difficulty);
|
||||
if (roll.total >= MGT2Helper.getDifficultyValue(rollOptions.difficulty))
|
||||
chatData.rollSuccess = true;
|
||||
else
|
||||
chatData.rollFailure = true;
|
||||
chatData.rollEffect = rollEffect;
|
||||
chatData.rollEffectStr = rollEffectStr;
|
||||
chatData.rollSuccess = rollSuccess || undefined;
|
||||
chatData.rollFailure = rollFailure || undefined;
|
||||
}
|
||||
|
||||
const html = await foundry.applications.handlebars.renderTemplate("systems/mgt2/templates/chat/roll.html", chatData);
|
||||
chatData.content = html;
|
||||
|
||||
let flags = null;
|
||||
if (rollOptions.damageFormula) {
|
||||
flags = { mgt2: { damage: { formula: rollOptions.damageFormula, rollObjectName: rollOptions.rollObjectName, rollTypeName: rollOptions.rollTypeName } } };
|
||||
if (effectiveDamageFormula) {
|
||||
flags = { mgt2: { damage: { formula: effectiveDamageFormula, ap: rollOptions.damageAP ?? 0, blast: rollOptions.blastRadius ?? 0, stun: rollOptions.stun ?? false, radiation: rollOptions.radiation ?? false, rollObjectName: rollOptions.rollObjectName, rollTypeName: rollOptions.rollTypeName } } };
|
||||
}
|
||||
if (cardButtons.length > 0) {
|
||||
if (!flags) flags = { mgt2: {} };
|
||||
@@ -828,6 +1031,8 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
|
||||
static async #onTraitDelete(event, target) {
|
||||
event.preventDefault();
|
||||
const confirmed = await TravellerCharacterSheet.#confirmDelete(game.i18n.localize("MGT2.Actor.ThisTrait"));
|
||||
if (!confirmed) return;
|
||||
const element = target.closest("[data-traits-part]");
|
||||
const index = Number(element.dataset.traitsPart);
|
||||
const traits = foundry.utils.deepClone(this.actor.system.personal.traits);
|
||||
@@ -839,9 +1044,329 @@ export default class TravellerCharacterSheet extends MGT2ActorSheet {
|
||||
|
||||
static async #onOpenEditor(event) {
|
||||
event.preventDefault();
|
||||
await CharacterPrompts.openEditorFullView(
|
||||
this.actor.system.personal.species,
|
||||
this.actor.system.personal.speciesText.descriptionLong
|
||||
const title = this.actor.system.personal.species
|
||||
|| game.i18n.localize("MGT2.Actor.Species")
|
||||
|| "Species";
|
||||
const html = this.actor.system.personal.speciesText?.descriptionLong ?? "";
|
||||
await CharacterPrompts.openEditorFullView(title, html);
|
||||
}
|
||||
|
||||
static async #onHeal(event, target) {
|
||||
event.preventDefault();
|
||||
const healType = target.dataset.healType;
|
||||
|
||||
if (game.user.targets.size === 0) {
|
||||
ui.notifications.warn(game.i18n.localize("MGT2.Errors.NoTokenSelected"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (healType === "firstaid") {
|
||||
// Find Medicine skill to pre-select
|
||||
// Use normalized string matching to handle accents
|
||||
const medSkill = this.actor.items.find(i => {
|
||||
if (i.type !== "talent" || i.system.subType !== "skill") return false;
|
||||
const normalized = i.name.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
return normalized.includes("medecin") || normalized.includes("medicine");
|
||||
});
|
||||
|
||||
// Only EDU characteristic available for First Aid
|
||||
const characteristics = [
|
||||
{ _id: "education", name: game.i18n.localize("MGT2.Characteristics.education.name") }
|
||||
];
|
||||
|
||||
const rollOptions = {
|
||||
rollTypeName: game.i18n.localize("MGT2.Healing.FirstAid"),
|
||||
rollObjectName: this.actor.name,
|
||||
characteristics: characteristics, // Only EDU
|
||||
characteristic: "education", // Pre-selected
|
||||
skill: medSkill?.id ?? "", // Medicine skill ID for pre-selection (must match _id in array)
|
||||
skillName: medSkill?.name ?? game.i18n.localize("MGT2.Healing.NoMedicineSkill"), // Display name
|
||||
skillLevel: medSkill?.system.level ?? -3, // -3 if not found
|
||||
skills: medSkill ? [{ _id: medSkill.id, name: medSkill.name, level: medSkill.system.level }] : [],
|
||||
difficulty: "Average", // First Aid difficulty is 8 (Average)
|
||||
showHeal: true,
|
||||
healType: MGT2.HealingType.FIRST_AID,
|
||||
};
|
||||
const userRollData = await RollPromptHelper.roll(rollOptions);
|
||||
if (userRollData) {
|
||||
// Build formula with all DMs — same pattern as standard skill roll
|
||||
const rollFormulaParts = [];
|
||||
const rollModifiers = [];
|
||||
|
||||
if (userRollData.diceModifier) {
|
||||
rollFormulaParts.push("3d6");
|
||||
rollFormulaParts.push(userRollData.diceModifier);
|
||||
} else {
|
||||
rollFormulaParts.push("2d6");
|
||||
}
|
||||
|
||||
if (userRollData.characteristic) {
|
||||
const c = this.actor.system.characteristics[userRollData.characteristic];
|
||||
rollFormulaParts.push(MGT2Helper.getFormulaDM(c.dm));
|
||||
rollModifiers.push(game.i18n.localize(`MGT2.Characteristics.${userRollData.characteristic}.name`) + MGT2Helper.getDisplayDM(c.dm));
|
||||
}
|
||||
|
||||
if (userRollData.skill && userRollData.skill !== "") {
|
||||
if (userRollData.skill === "NP") {
|
||||
rollFormulaParts.push("-3");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.Items.NotProficient"));
|
||||
} else {
|
||||
const skillObj = this.actor.getEmbeddedDocument("Item", userRollData.skill);
|
||||
rollFormulaParts.push(MGT2Helper.getFormulaDM(skillObj.system.level));
|
||||
rollModifiers.push(skillObj.getRollDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
if (userRollData.customDM && userRollData.customDM !== "") {
|
||||
let s = userRollData.customDM.trim();
|
||||
if (/^[0-9]/.test(s)) rollFormulaParts.push("+");
|
||||
rollFormulaParts.push(s);
|
||||
rollModifiers.push("DM " + s);
|
||||
}
|
||||
|
||||
const rollFormula = rollFormulaParts.join("");
|
||||
const roll = await new Roll(rollFormula, this.actor.getRollData()).roll();
|
||||
|
||||
// Difficulty for First Aid is Average (8)
|
||||
const difficulty = 8;
|
||||
const effect = roll.total - difficulty;
|
||||
const isSuccess = effect >= 0;
|
||||
const healing = isSuccess ? Math.max(1, effect) : 0;
|
||||
|
||||
const cardButtons = isSuccess
|
||||
? [{ label: game.i18n.localize("MGT2.Healing.ApplyHealing"), action: "healing" }]
|
||||
: [];
|
||||
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
formula: roll._formula,
|
||||
tooltip: await roll.getTooltip(),
|
||||
total: Math.round(roll.total * 100) / 100,
|
||||
rollTypeName: game.i18n.localize("MGT2.Healing.FirstAid"),
|
||||
rollObjectName: this.actor.name,
|
||||
rollModifiers: rollModifiers,
|
||||
rollDifficulty: difficulty,
|
||||
rollDifficultyLabel: MGT2Helper.getDifficultyDisplay("Average"),
|
||||
rollEffectStr: isSuccess ? effect.toString() : undefined,
|
||||
healingAmount: isSuccess ? healing : undefined,
|
||||
rollSuccess: isSuccess || undefined,
|
||||
rollFailure: !isSuccess || undefined,
|
||||
showButtons: isSuccess,
|
||||
hasDamage: false,
|
||||
showRollDamage: false,
|
||||
cardButtons: cardButtons,
|
||||
};
|
||||
|
||||
const html = await foundry.applications.handlebars.renderTemplate("systems/mgt2/templates/chat/roll.html", chatData);
|
||||
chatData.content = html;
|
||||
chatData.flags = { mgt2: { healing: { amount: healing } } };
|
||||
|
||||
return roll.toMessage(chatData);
|
||||
}
|
||||
} else if (healType === "surgery") {
|
||||
// Find Medicine skill to pre-select (same as first aid)
|
||||
const medSkill = this.actor.items.find(i => {
|
||||
if (i.type !== "talent" || i.system.subType !== "skill") return false;
|
||||
const normalized = i.name.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
return normalized.includes("medecin") || normalized.includes("medicine");
|
||||
});
|
||||
|
||||
const characteristics = [
|
||||
{ _id: "education", name: game.i18n.localize("MGT2.Characteristics.education.name") }
|
||||
];
|
||||
|
||||
const rollOptions = {
|
||||
rollTypeName: game.i18n.localize("MGT2.Healing.Surgery"),
|
||||
rollObjectName: this.actor.name,
|
||||
characteristics: characteristics,
|
||||
characteristic: "education",
|
||||
skill: medSkill?.id ?? "",
|
||||
skillName: medSkill?.name ?? game.i18n.localize("MGT2.Healing.NoMedicineSkill"),
|
||||
skillLevel: medSkill?.system.level ?? -3,
|
||||
skills: medSkill ? [{ _id: medSkill.id, name: medSkill.name, level: medSkill.system.level }] : [],
|
||||
difficulty: "Average",
|
||||
showHeal: true,
|
||||
healType: MGT2.HealingType.SURGERY,
|
||||
};
|
||||
const userRollData = await RollPromptHelper.roll(rollOptions);
|
||||
if (userRollData) {
|
||||
// Build formula with all DMs — same pattern as standard skill roll
|
||||
const rollFormulaParts = [];
|
||||
const rollModifiers = [];
|
||||
|
||||
if (userRollData.diceModifier) {
|
||||
rollFormulaParts.push("3d6");
|
||||
rollFormulaParts.push(userRollData.diceModifier);
|
||||
} else {
|
||||
rollFormulaParts.push("2d6");
|
||||
}
|
||||
|
||||
if (userRollData.characteristic) {
|
||||
const c = this.actor.system.characteristics[userRollData.characteristic];
|
||||
rollFormulaParts.push(MGT2Helper.getFormulaDM(c.dm));
|
||||
rollModifiers.push(game.i18n.localize(`MGT2.Characteristics.${userRollData.characteristic}.name`) + MGT2Helper.getDisplayDM(c.dm));
|
||||
}
|
||||
|
||||
if (userRollData.skill && userRollData.skill !== "") {
|
||||
if (userRollData.skill === "NP") {
|
||||
rollFormulaParts.push("-3");
|
||||
rollModifiers.push(game.i18n.localize("MGT2.Items.NotProficient"));
|
||||
} else {
|
||||
const skillObj = this.actor.getEmbeddedDocument("Item", userRollData.skill);
|
||||
rollFormulaParts.push(MGT2Helper.getFormulaDM(skillObj.system.level));
|
||||
rollModifiers.push(skillObj.getRollDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
if (userRollData.customDM && userRollData.customDM !== "") {
|
||||
let s = userRollData.customDM.trim();
|
||||
if (/^[0-9]/.test(s)) rollFormulaParts.push("+");
|
||||
rollFormulaParts.push(s);
|
||||
rollModifiers.push("DM " + s);
|
||||
}
|
||||
|
||||
const rollFormula = rollFormulaParts.join("");
|
||||
const roll = await new Roll(rollFormula, this.actor.getRollData()).roll();
|
||||
|
||||
// Difficulty for Surgery is Average (8)
|
||||
const difficulty = 8;
|
||||
const effect = roll.total - difficulty;
|
||||
const isSuccess = effect >= 0;
|
||||
|
||||
// Success: heal Math.max(1, effect); Failure: patient takes 3 + |effect| damage
|
||||
const healing = isSuccess ? Math.max(1, effect) : 0;
|
||||
const surgeryDamage = isSuccess ? 0 : 3 + Math.abs(effect);
|
||||
|
||||
const cardButtons = [];
|
||||
if (isSuccess) {
|
||||
cardButtons.push({ label: game.i18n.localize("MGT2.Healing.ApplyHealing"), action: "healing" });
|
||||
} else {
|
||||
cardButtons.push({ label: game.i18n.localize("MGT2.Healing.ApplySurgeryDamage"), action: "surgeryDamage" });
|
||||
}
|
||||
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
formula: roll._formula,
|
||||
tooltip: await roll.getTooltip(),
|
||||
total: Math.round(roll.total * 100) / 100,
|
||||
rollTypeName: game.i18n.localize("MGT2.Healing.Surgery"),
|
||||
rollObjectName: this.actor.name,
|
||||
rollModifiers: rollModifiers,
|
||||
rollDifficulty: difficulty,
|
||||
rollDifficultyLabel: MGT2Helper.getDifficultyDisplay("Average"),
|
||||
rollEffectStr: effect.toString(),
|
||||
healingAmount: isSuccess ? healing : undefined,
|
||||
surgeryDamageAmount: isSuccess ? undefined : surgeryDamage,
|
||||
rollSuccess: isSuccess || undefined,
|
||||
rollFailure: !isSuccess || undefined,
|
||||
showButtons: true,
|
||||
hasDamage: false,
|
||||
showRollDamage: false,
|
||||
cardButtons: cardButtons,
|
||||
};
|
||||
|
||||
const html = await foundry.applications.handlebars.renderTemplate("systems/mgt2/templates/chat/roll.html", chatData);
|
||||
chatData.content = html;
|
||||
chatData.flags = { mgt2: { surgery: { healing, surgeryDamage } } };
|
||||
|
||||
return roll.toMessage(chatData);
|
||||
}
|
||||
} else if (healType === "medical") {
|
||||
const result = await CharacterPrompts.openHealingDays();
|
||||
if (result) {
|
||||
const endMD = this.actor.system.characteristics.endurance.dm;
|
||||
const medSkill = this.actor.items.find(i =>
|
||||
i.type === "talent" &&
|
||||
i.system.subType === "skill" &&
|
||||
(i.name.toLowerCase().includes("medecin") || i.name.toLowerCase().includes("medicine"))
|
||||
);
|
||||
const skillValue = medSkill ? medSkill.system.level : 0;
|
||||
const days = result.days;
|
||||
const healingPerDay = Math.max(1, 3 + endMD + skillValue);
|
||||
const totalHealing = healingPerDay * days;
|
||||
|
||||
const rollModifiers = [
|
||||
`3 (base)`,
|
||||
`${endMD >= 0 ? "+" : ""}${endMD} END`,
|
||||
`+${skillValue} ${medSkill?.name ?? "Médecine"}`,
|
||||
`× ${days} ${game.i18n.localize("MGT2.RollPrompt.Days").toLowerCase()}`
|
||||
];
|
||||
|
||||
const templateData = {
|
||||
rollObjectName: this.actor.name,
|
||||
rollTypeName: game.i18n.localize("MGT2.Healing.MedicalCare"),
|
||||
rollModifiers,
|
||||
formula: `${healingPerDay} ${game.i18n.localize("MGT2.Items.PerDay")}`,
|
||||
tooltip: "",
|
||||
total: totalHealing,
|
||||
rollSuccess: true,
|
||||
showButtons: true,
|
||||
cardButtons: [
|
||||
{ action: "healing", label: game.i18n.localize("MGT2.Healing.ApplyHealing") }
|
||||
]
|
||||
};
|
||||
|
||||
const content = await renderTemplate(
|
||||
"systems/mgt2/templates/chat/roll.html",
|
||||
templateData
|
||||
);
|
||||
await ChatMessage.create({
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
content,
|
||||
flags: { mgt2: { healing: { amount: totalHealing } } }
|
||||
});
|
||||
}
|
||||
} else if (healType === "natural") {
|
||||
const result = await CharacterPrompts.openHealingDays();
|
||||
if (result) {
|
||||
const endMD = this.actor.system.characteristics.endurance.dm;
|
||||
let totalAmount = 0;
|
||||
const rolls = [];
|
||||
|
||||
for (let i = 0; i < result.days; i++) {
|
||||
const roll = await new Roll("1d6").evaluate();
|
||||
const dayHealing = Math.max(1, roll.total + endMD);
|
||||
rolls.push({ roll, dayHealing });
|
||||
totalAmount += dayHealing;
|
||||
}
|
||||
|
||||
// Build roll details
|
||||
const rollDisplay = rolls.map((r, idx) =>
|
||||
`<div><strong>${game.i18n.localize("MGT2.RollPrompt.Days")} ${idx + 1}:</strong> 1d6 = ${r.roll.total} + ${endMD > 0 ? "+" : ""}${endMD} = <strong>${r.dayHealing}</strong></div>`
|
||||
).join("");
|
||||
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
content: `<div class="mgt2-chat-roll">
|
||||
<div class="mgt2-roll-header">
|
||||
<span class="mgt2-roll-char-name">${this.actor.name}</span>
|
||||
<div class="mgt2-roll-meta">
|
||||
<span class="mgt2-roll-type">${game.i18n.localize("MGT2.Healing.NaturalHealing")}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mgt2-roll-modifier">${result.days} ${game.i18n.localize("MGT2.RollPrompt.Days")}</div>
|
||||
<div style="padding: 8px 0; font-size: 0.9em;">
|
||||
${rollDisplay}
|
||||
</div>
|
||||
<div class="mgt2-effect is-success">
|
||||
${game.i18n.localize("MGT2.Chat.Roll.Effect")} <span class="mgt2-effect-value">${totalAmount}</span>
|
||||
</div>
|
||||
</div>`,
|
||||
flags: { mgt2: { healing: { amount: totalAmount } } }
|
||||
};
|
||||
await ChatMessage.create(chatData);
|
||||
|
||||
// Apply healing immediately
|
||||
await this.actor.applyHealing(totalAmount);
|
||||
ui.notifications.info(
|
||||
game.i18n.format("MGT2.Notifications.HealingApplied",
|
||||
{ name: this.actor.name, amount: totalAmount })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
295
src/module/applications/sheets/creature-sheet.mjs
Normal file
295
src/module/applications/sheets/creature-sheet.mjs
Normal file
@@ -0,0 +1,295 @@
|
||||
import MGT2ActorSheet from "./base-actor-sheet.mjs";
|
||||
import { RollPromptHelper } from "../../roll-prompt.js";
|
||||
import { MGT2Helper } from "../../helper.js";
|
||||
|
||||
const { renderTemplate } = foundry.applications.handlebars;
|
||||
|
||||
/** 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: "combat" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext();
|
||||
const actor = this.document;
|
||||
const enrich = (html) => foundry.applications.ux.TextEditor.implementation.enrichHTML(html ?? "", { async: true });
|
||||
|
||||
context.enrichedBiography = await enrich(actor.system.biography);
|
||||
context.enrichedNotes = await enrich(actor.system.notes);
|
||||
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 Helpers
|
||||
|
||||
static async #postCreatureRoll({ actor, roll, rollLabel, dm, difficulty, difficultyLabel, rollMode, extraTooltip, damageFormula }) {
|
||||
const diffTarget = MGT2Helper.getDifficultyValue(difficulty ?? "Average");
|
||||
const hasDifficulty = !!difficulty;
|
||||
const success = hasDifficulty ? roll.total >= diffTarget : true;
|
||||
const effect = roll.total - diffTarget;
|
||||
const effectStr = (effect >= 0 ? "+" : "") + effect;
|
||||
|
||||
const diceRawTotal = roll.dice.reduce((s, d) => s + d.total, 0);
|
||||
const breakdownParts = [game.i18n.localize("MGT2.Chat.Roll.Dice") + " " + diceRawTotal];
|
||||
if (dm !== 0) breakdownParts.push(`DM ${dm >= 0 ? "+" : ""}${dm}`);
|
||||
if (hasDifficulty) breakdownParts.push(game.i18n.localize("MGT2.Chat.Roll.Effect") + " " + effectStr);
|
||||
if (extraTooltip) breakdownParts.push(extraTooltip);
|
||||
const rollBreakdown = breakdownParts.join(" | ");
|
||||
|
||||
const showRollDamage = success && !!damageFormula;
|
||||
|
||||
const chatData = {
|
||||
creatureName: actor.name,
|
||||
creatureImg: actor.img,
|
||||
rollLabel,
|
||||
formula: roll.formula,
|
||||
total: roll.total,
|
||||
tooltip: await roll.getTooltip(),
|
||||
rollBreakdown,
|
||||
difficulty: hasDifficulty ? diffTarget : null,
|
||||
difficultyLabel: difficultyLabel ?? MGT2Helper.getDifficultyDisplay(difficulty),
|
||||
success: hasDifficulty ? success : null,
|
||||
failure: hasDifficulty ? !success : null,
|
||||
effect: hasDifficulty ? effect : null,
|
||||
effectStr: hasDifficulty ? effectStr : null,
|
||||
modifiers: dm !== 0 ? [`DM ${dm >= 0 ? "+" : ""}${dm}`] : [],
|
||||
showRollDamage,
|
||||
};
|
||||
|
||||
const chatContent = await renderTemplate(
|
||||
"systems/mgt2/templates/chat/creature-roll.html",
|
||||
chatData
|
||||
);
|
||||
|
||||
const flags = showRollDamage ? {
|
||||
mgt2: {
|
||||
damage: {
|
||||
formula: normalizeDice(damageFormula),
|
||||
effect,
|
||||
rollObjectName: actor.name,
|
||||
rollTypeName: rollLabel,
|
||||
}
|
||||
}
|
||||
} : {};
|
||||
|
||||
await ChatMessage.create({
|
||||
content: chatContent,
|
||||
speaker: ChatMessage.getSpeaker({ actor }),
|
||||
rolls: [roll],
|
||||
rollMode: rollMode ?? game.settings.get("core", "rollMode"),
|
||||
flags,
|
||||
});
|
||||
|
||||
return { success, effect, total: roll.total };
|
||||
}
|
||||
|
||||
// ───────────────────────────────────────────────────────── Roll Handlers
|
||||
|
||||
/** Roll a skill check (2d6 + level vs difficulty) — uses unified dialog */
|
||||
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 result = await RollPromptHelper.roll({
|
||||
isCreature: true,
|
||||
showSkillSelector: false,
|
||||
skillName: skill.name,
|
||||
skillLevel: skill.level,
|
||||
difficulty: "Average",
|
||||
title: game.i18n.localize("MGT2.Creature.RollSkill") + " — " + skill.name,
|
||||
});
|
||||
if (!result) return;
|
||||
|
||||
const customDM = parseInt(result.customDM ?? "0", 10) || 0;
|
||||
const skillLevel = parseInt(skill.level ?? 0, 10) || 0;
|
||||
const dm = skillLevel + customDM;
|
||||
const diceModifier = result.diceModifier ?? "";
|
||||
|
||||
// Build formula exactly like character-sheet: parts joined without spaces
|
||||
const parts = [];
|
||||
if (diceModifier) {
|
||||
parts.push("3d6", diceModifier);
|
||||
} else {
|
||||
parts.push("2d6");
|
||||
}
|
||||
if (dm !== 0) parts.push(MGT2Helper.getFormulaDM(dm));
|
||||
const fullFormula = parts.join("");
|
||||
|
||||
const roll = await new Roll(fullFormula).evaluate();
|
||||
const rollLabel = `${skill.name.toUpperCase()} (${skillLevel >= 0 ? "+" : ""}${skillLevel})`;
|
||||
|
||||
const tooltipParts = [`Dés: ${roll.dice.reduce((s, d) => s + d.total, 0)}`];
|
||||
if (skillLevel !== 0) tooltipParts.push(`${skill.name} ${skillLevel >= 0 ? "+" : ""}${skillLevel}`);
|
||||
if (customDM !== 0) tooltipParts.push(`MD perso ${customDM >= 0 ? "+" : ""}${customDM}`);
|
||||
|
||||
await TravellerCreatureSheet.#postCreatureRoll({
|
||||
actor, roll, rollLabel,
|
||||
dm,
|
||||
difficulty: result.difficulty,
|
||||
rollMode: result.rollMode,
|
||||
extraTooltip: tooltipParts.join(" | "),
|
||||
});
|
||||
}
|
||||
|
||||
/** Roll an attack: dialog with skill selector, then roll 2d6+skill+DM vs difficulty; on success roll damage */
|
||||
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 skills = actor.system.skills ?? [];
|
||||
|
||||
const result = await RollPromptHelper.roll({
|
||||
isCreature: true,
|
||||
showSkillSelector: true,
|
||||
creatureSkills: skills,
|
||||
selectedSkillIndex: attack.skill ?? -1,
|
||||
difficulty: "Average",
|
||||
title: game.i18n.localize("MGT2.Creature.RollAttack") + " — " + attack.name,
|
||||
});
|
||||
if (!result) return;
|
||||
|
||||
const skillIndex = parseInt(result.creatureSkillIndex ?? "-1", 10);
|
||||
const chosenSkill = (skillIndex >= 0 && skillIndex < skills.length) ? skills[skillIndex] : null;
|
||||
const skillLevel = parseInt(chosenSkill?.level ?? 0, 10) || 0;
|
||||
const customDM = parseInt(result.customDM ?? "0", 10) || 0;
|
||||
const dm = skillLevel + customDM;
|
||||
const diceModifier = result.diceModifier ?? "";
|
||||
|
||||
// Build formula exactly like character-sheet: parts joined without spaces
|
||||
const parts = [];
|
||||
if (diceModifier) {
|
||||
parts.push("3d6", diceModifier);
|
||||
} else {
|
||||
parts.push("2d6");
|
||||
}
|
||||
if (dm !== 0) parts.push(MGT2Helper.getFormulaDM(dm));
|
||||
const fullFormula = parts.join("");
|
||||
|
||||
const roll = await new Roll(fullFormula).evaluate();
|
||||
const rollLabel = chosenSkill
|
||||
? `${attack.name} — ${chosenSkill.name} (${skillLevel >= 0 ? "+" : ""}${skillLevel})`
|
||||
: attack.name;
|
||||
|
||||
const tooltipParts = [`Dés: ${roll.dice.reduce((s, d) => s + d.total, 0)}`];
|
||||
if (chosenSkill) tooltipParts.push(`${chosenSkill.name} ${skillLevel >= 0 ? "+" : ""}${skillLevel}`);
|
||||
if (customDM !== 0) tooltipParts.push(`MD perso ${customDM >= 0 ? "+" : ""}${customDM}`);
|
||||
|
||||
await TravellerCreatureSheet.#postCreatureRoll({
|
||||
actor, roll, rollLabel,
|
||||
dm,
|
||||
difficulty: result.difficulty,
|
||||
rollMode: result.rollMode,
|
||||
extraTooltip: tooltipParts.join(" | "),
|
||||
damageFormula: attack.damage || null,
|
||||
});
|
||||
}
|
||||
|
||||
// ───────────────────────────────────────────────────────── 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", skill: -1, description: "" };
|
||||
case "traits": return { name: "", value: "", description: "" };
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,8 @@ export default class TravellerItemSheet extends HandlebarsApplicationMixin(found
|
||||
skills.sort(MGT2Helper.compareByName);
|
||||
skills = [{ _id: "NP", name: game.i18n.localize("MGT2.Items.NotProficient") }].concat(skills);
|
||||
|
||||
const enrich = (html) => foundry.applications.ux.TextEditor.implementation.enrichHTML(html ?? "", { async: true });
|
||||
|
||||
return {
|
||||
item: item,
|
||||
document: item,
|
||||
@@ -91,6 +93,10 @@ export default class TravellerItemSheet extends HandlebarsApplicationMixin(found
|
||||
weight: weight,
|
||||
unitlabels: { weight: MGT2Helper.getWeightLabel() },
|
||||
skills: skills,
|
||||
enrichedDescription: await enrich(item.system.description),
|
||||
enrichedDescriptionLong: await enrich(item.system.descriptionLong),
|
||||
enrichedNotes: await enrich(item.system.notes),
|
||||
enrichedLockedDescription: await enrich(item.system.lockedDescription),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -126,6 +132,27 @@ export default class TravellerItemSheet extends HandlebarsApplicationMixin(found
|
||||
bind(".options-delete", TravellerItemSheet.#onOptionDelete);
|
||||
bind(".modifiers-create", TravellerItemSheet.#onModifierCreate);
|
||||
bind(".modifiers-delete", TravellerItemSheet.#onModifierDelete);
|
||||
|
||||
// Activate ProseMirror editors for HTMLField fields
|
||||
for (const btn of html.querySelectorAll(".editor-edit")) {
|
||||
btn.addEventListener("click", async (event) => {
|
||||
event.preventDefault();
|
||||
const editorWrapper = btn.closest(".editor");
|
||||
if (!editorWrapper) return;
|
||||
const editorContent = editorWrapper.querySelector(".editor-content");
|
||||
if (!editorContent || editorContent.classList.contains("ProseMirror")) return;
|
||||
const target = editorContent.dataset.edit;
|
||||
const value = foundry.utils.getProperty(this.document, target) ?? "";
|
||||
btn.remove();
|
||||
editorWrapper.classList.add("prosemirror");
|
||||
await ProseMirrorEditor.create(editorContent, value, {
|
||||
document: this.document,
|
||||
fieldName: target,
|
||||
plugins: {},
|
||||
collaborate: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_activateTabGroups() {
|
||||
|
||||
@@ -21,4 +21,15 @@ export default class TravellerVehiculeSheet extends MGT2ActorSheet {
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "stats" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext();
|
||||
const actor = this.document;
|
||||
const enrich = (html) => foundry.applications.ux.TextEditor.implementation.enrichHTML(html ?? "", { async: true });
|
||||
|
||||
context.enrichedDescription = await enrich(actor.system.description);
|
||||
context.enrichedNotes = await enrich(actor.system.notes);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,45 @@ export class ChatHelper {
|
||||
if (!message || !element) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore disabled state for already-applied buttons
|
||||
const appliedActions = message.flags?.mgt2?.appliedActions ?? [];
|
||||
if (appliedActions.length > 0) {
|
||||
appliedActions.forEach(action => {
|
||||
element.querySelectorAll(`button[data-action="${action}"]`).forEach(btn => {
|
||||
btn.disabled = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Apply buttons are GM-only: hide them for players
|
||||
const GM_ACTIONS = ["damage", "healing", "surgeryDamage"];
|
||||
if (!game.user.isGM) {
|
||||
GM_ACTIONS.forEach(action => {
|
||||
element.querySelectorAll(`button[data-action="${action}"]`).forEach(btn => {
|
||||
btn.style.display = "none";
|
||||
});
|
||||
});
|
||||
// Hide the buttons container if no visible buttons remain
|
||||
element.querySelectorAll(".mgt2-buttons").forEach(container => {
|
||||
const hasVisible = [...container.querySelectorAll("button")]
|
||||
.some(b => b.style.display !== "none");
|
||||
if (!hasVisible) container.style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
element.querySelectorAll('button[data-action="rollDamage"]').forEach(el => {
|
||||
el.addEventListener('click', async event => {
|
||||
await this._processRollDamageButtonEvent(message, event);
|
||||
});
|
||||
});
|
||||
|
||||
element.querySelectorAll('button[data-action="rollRadiation"]').forEach(el => {
|
||||
el.addEventListener('click', async event => {
|
||||
await this._rollRadiationDamage(message, event);
|
||||
});
|
||||
});
|
||||
|
||||
element.querySelectorAll('button[data-action="damage"]').forEach(el => {
|
||||
el.addEventListener('click', async event => {
|
||||
await this._applyChatCardDamage(message, event);
|
||||
@@ -20,11 +53,17 @@ export class ChatHelper {
|
||||
|
||||
element.querySelectorAll('button[data-action="healing"]').forEach(el => {
|
||||
el.addEventListener('click', async event => {
|
||||
ui.notifications.warn("healing");
|
||||
await this._applyChatCardHealing(message, event);
|
||||
});
|
||||
});
|
||||
|
||||
element.querySelectorAll('button[data-index]').forEach(el => {
|
||||
element.querySelectorAll('button[data-action="surgeryDamage"]').forEach(el => {
|
||||
el.addEventListener('click', async event => {
|
||||
await this._applyChatCardSurgeryDamage(message, event);
|
||||
});
|
||||
});
|
||||
|
||||
element.querySelectorAll('button[data-index]:not([data-action])').forEach(el => {
|
||||
el.addEventListener('click', async event => {
|
||||
await this._processRollButtonEvent(message, event);
|
||||
});
|
||||
@@ -57,43 +96,143 @@ export class ChatHelper {
|
||||
static async _processRollDamageButtonEvent(message, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let rollFormula = message.flags.mgt2.damage.formula;
|
||||
|
||||
let roll = await new Roll(rollFormula, {}).roll();
|
||||
|
||||
let speaker;
|
||||
let selectTokens = canvas.tokens.controlled;
|
||||
if (selectTokens.length > 0) {
|
||||
speaker = selectTokens[0].actor;
|
||||
} else {
|
||||
speaker = game.user.character;
|
||||
const damageFlags = message.flags?.mgt2?.damage;
|
||||
if (!damageFlags?.formula) {
|
||||
ui.notifications.warn(game.i18n.localize("MGT2.Errors.InvalidRollFormula"));
|
||||
return;
|
||||
}
|
||||
|
||||
let rollTypeName = message.flags.mgt2.damage.rollTypeName ? message.flags.mgt2.damage.rollTypeName + " DAMAGE" : null;
|
||||
const effect = damageFlags.effect ?? 0;
|
||||
const effectPart = effect > 0 ? `+${effect}` : effect < 0 ? `${effect}` : "";
|
||||
const rollFormula = damageFlags.formula + effectPart;
|
||||
|
||||
let roll;
|
||||
try {
|
||||
roll = await new Roll(rollFormula, {}).roll();
|
||||
} catch (e) {
|
||||
ui.notifications.warn(game.i18n.localize("MGT2.Errors.InvalidRollFormula"));
|
||||
return;
|
||||
}
|
||||
|
||||
const rollTypeName = damageFlags.rollTypeName
|
||||
? damageFlags.rollTypeName + " " + game.i18n.localize("MGT2.Actor.Damage")
|
||||
: null;
|
||||
|
||||
const ap = damageFlags.ap ?? 0;
|
||||
const blast = damageFlags.blast ?? 0;
|
||||
const stun = damageFlags.stun ?? false;
|
||||
const radiation = damageFlags.radiation ?? false;
|
||||
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker({ actor: speaker }),
|
||||
speaker: message.speaker,
|
||||
formula: roll._formula,
|
||||
tooltip: await roll.getTooltip(),
|
||||
total: Math.round(roll.total * 100) / 100,
|
||||
showButtons: true,
|
||||
hasDamage: true,
|
||||
rollTypeName: rollTypeName,
|
||||
rollObjectName: message.flags.mgt2.damage.rollObjectName
|
||||
rollTypeName,
|
||||
rollObjectName: damageFlags.rollObjectName,
|
||||
apValue: ap > 0 ? ap : null,
|
||||
blastRadius: blast > 0 ? blast : null,
|
||||
stunWeapon: stun || null,
|
||||
radiationWeapon: radiation || null,
|
||||
};
|
||||
|
||||
const html = await foundry.applications.handlebars.renderTemplate("systems/mgt2/templates/chat/roll.html", chatData);
|
||||
chatData.content = html;
|
||||
|
||||
// Persist ap, blast, stun, radiation in damage message flags so handlers can read them
|
||||
if (ap > 0 || blast > 0 || stun || radiation) chatData.flags = { mgt2: { damage: { ap, blast, stun, radiation, rollObjectName: damageFlags.rollObjectName } } };
|
||||
|
||||
return roll.toMessage(chatData);
|
||||
}
|
||||
|
||||
static _applyChatCardDamage(message, event) {
|
||||
static async #markButtonApplied(message, btn, action) {
|
||||
const existing = message.flags?.mgt2?.appliedActions ?? [];
|
||||
if (!existing.includes(action)) {
|
||||
await message.setFlag("mgt2", "appliedActions", [...existing, action]);
|
||||
}
|
||||
if (btn) btn.disabled = true;
|
||||
}
|
||||
|
||||
static async _applyChatCardDamage(message, event) {
|
||||
if (game.user.targets.size === 0) {
|
||||
ui.notifications.warn(game.i18n.localize("MGT2.Errors.NoTokenSelected"));
|
||||
return;
|
||||
}
|
||||
const btn = event.currentTarget;
|
||||
const roll = message.rolls[0];
|
||||
return Promise.all(canvas.tokens.controlled.map(t => {
|
||||
const a = t.actor;
|
||||
return a.applyDamage(roll.total);
|
||||
const amount = Math.round(roll.total * 100) / 100;
|
||||
const ap = message.flags?.mgt2?.damage?.ap ?? 0;
|
||||
const stun = message.flags?.mgt2?.damage?.stun ?? false;
|
||||
await Promise.all([...game.user.targets].map(async t => {
|
||||
const result = await t.actor.applyDamage(amount, { ap, stun });
|
||||
if (stun) {
|
||||
const incapRounds = result?.incapRounds ?? 0;
|
||||
if (incapRounds > 0) {
|
||||
ui.notifications.warn(game.i18n.format("MGT2.Notifications.StunIncapacitated", { name: t.actor.name, rounds: incapRounds }));
|
||||
} else {
|
||||
ui.notifications.info(game.i18n.format("MGT2.Notifications.StunDamageApplied", { name: t.actor.name, amount }));
|
||||
}
|
||||
} else {
|
||||
const notifKey = ap > 0 ? "MGT2.Notifications.DamageAppliedAP" : "MGT2.Notifications.DamageApplied";
|
||||
ui.notifications.info(game.i18n.format(notifKey, { name: t.actor.name, amount, ap }));
|
||||
}
|
||||
}));
|
||||
await ChatHelper.#markButtonApplied(message, btn, "damage");
|
||||
}
|
||||
|
||||
static async _applyChatCardHealing(message, event) {
|
||||
if (game.user.targets.size === 0) {
|
||||
ui.notifications.warn(game.i18n.localize("MGT2.Errors.NoTokenSelected"));
|
||||
return;
|
||||
}
|
||||
const btn = event.currentTarget;
|
||||
const amount = message.flags?.mgt2?.healing?.amount
|
||||
?? message.flags?.mgt2?.surgery?.healing
|
||||
?? Math.max(1, message.rolls[0].total);
|
||||
await Promise.all([...game.user.targets].map(async t => {
|
||||
await t.actor.applyHealing(amount);
|
||||
ui.notifications.info(game.i18n.format("MGT2.Notifications.HealingApplied", { name: t.actor.name, amount }));
|
||||
}));
|
||||
await ChatHelper.#markButtonApplied(message, btn, "healing");
|
||||
}
|
||||
|
||||
static async _applyChatCardSurgeryDamage(message, event) {
|
||||
if (game.user.targets.size === 0) {
|
||||
ui.notifications.warn(game.i18n.localize("MGT2.Errors.NoTokenSelected"));
|
||||
return;
|
||||
}
|
||||
const btn = event.currentTarget;
|
||||
const amount = message.flags?.mgt2?.surgery?.surgeryDamage ?? 3;
|
||||
await Promise.all([...game.user.targets].map(async t => {
|
||||
await t.actor.applyDamage(amount, { ignoreArmor: true });
|
||||
ui.notifications.info(game.i18n.format("MGT2.Notifications.DamageApplied", { name: t.actor.name, amount }));
|
||||
}));
|
||||
await ChatHelper.#markButtonApplied(message, btn, "surgeryDamage");
|
||||
}
|
||||
|
||||
static async _rollRadiationDamage(message, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const damageFlags = message.flags?.mgt2?.damage;
|
||||
const rollObjectName = damageFlags?.rollObjectName ?? "";
|
||||
|
||||
// 2D × 20 rads (MGT2 rule: 2d6 × 20)
|
||||
const roll = await new Roll("2d6 * 20", {}).roll();
|
||||
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: message.speaker,
|
||||
formula: roll._formula,
|
||||
tooltip: await roll.getTooltip(),
|
||||
total: Math.round(roll.total),
|
||||
rollObjectName,
|
||||
};
|
||||
|
||||
const html = await foundry.applications.handlebars.renderTemplate("systems/mgt2/templates/chat/radiation.html", chatData);
|
||||
chatData.content = html;
|
||||
return roll.toMessage(chatData);
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ MGT2.SpeedBands = Object.freeze({
|
||||
VerySlow: "MGT2.SpeedBands.VerySlow",
|
||||
Slow: "MGT2.SpeedBands.Slow",
|
||||
Medium: "MGT2.SpeedBands.Medium",
|
||||
High: "MGT2.SpeedBands.High.",
|
||||
High: "MGT2.SpeedBands.High",
|
||||
Fast: "MGT2.SpeedBands.Fast",
|
||||
VeryFast: "MGT2.SpeedBands.VeryFast",
|
||||
Subsonic: "MGT2.SpeedBands.Subsonic",
|
||||
@@ -155,3 +155,33 @@ MGT2.Durations = Object.freeze({
|
||||
Minutes: "MGT2.Durations.Minutes",
|
||||
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"
|
||||
});
|
||||
|
||||
MGT2.HealingType = Object.freeze({
|
||||
FIRST_AID: "MGT2.Healing.FirstAid",
|
||||
SURGERY: "MGT2.Healing.Surgery",
|
||||
MEDICAL_CARE: "MGT2.Healing.MedicalCare",
|
||||
NATURAL_HEALING: "MGT2.Healing.NaturalHealing"
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
CharacterData,
|
||||
VehiculeData,
|
||||
CreatureData,
|
||||
ItemData,
|
||||
EquipmentData,
|
||||
DiseaseData,
|
||||
@@ -17,7 +18,7 @@ import {
|
||||
import { MGT2 } from "./config.js";
|
||||
import { TravellerActor, MGT2Combatant } from "./actors/actor.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 { MGT2Helper } from "./helper.js";
|
||||
import {ChatHelper} from "./chatHelper.js";
|
||||
@@ -73,6 +74,10 @@ Hooks.once("init", async function () {
|
||||
"characteristics.charm.value",
|
||||
"characteristics.psionic.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.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", TravellerCreatureSheet, { types: ["creature"], makeDefault: true, label: "Creature Sheet" });
|
||||
|
||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||
foundry.documents.collections.Items.registerSheet("mgt2", TravellerItemSheet, { makeDefault: true });
|
||||
|
||||
Object.assign(CONFIG.Actor.dataModels, {
|
||||
"character": CharacterData,
|
||||
"vehicule": VehiculeData
|
||||
"vehicule": VehiculeData,
|
||||
"creature": CreatureData
|
||||
});
|
||||
|
||||
Object.assign(CONFIG.Item.dataModels, {
|
||||
|
||||
@@ -109,18 +109,9 @@ export class MGT2Helper {
|
||||
}
|
||||
|
||||
static getDifficultyDisplay(difficulty) {
|
||||
switch(difficulty) {
|
||||
case "Simple": return game.i18n.localize("MGT2.Difficulty.Simple") + " (2+)";
|
||||
case "Easy": return game.i18n.localize("MGT2.Difficulty.Easy") + " (4+)";
|
||||
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;
|
||||
}
|
||||
const key = `MGT2.Difficulty.${difficulty}`;
|
||||
const label = game.i18n.localize(key);
|
||||
return label !== key ? label : null;
|
||||
}
|
||||
|
||||
static getRangeDisplay(range) {
|
||||
|
||||
@@ -47,7 +47,9 @@ export default class CharacterData extends foundry.abstract.TypeDataModel {
|
||||
}),
|
||||
|
||||
health: new fields.SchemaField({
|
||||
radiations: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true })
|
||||
radiations: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
||||
lastFirstAidDate: new fields.StringField({ required: false, blank: true, trim: true }),
|
||||
healingRecoveryMode: new fields.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||
}),
|
||||
study: new fields.SchemaField({
|
||||
skill: new fields.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||
@@ -61,7 +63,7 @@ export default class CharacterData extends foundry.abstract.TypeDataModel {
|
||||
debt: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||
livingCost: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||
monthlyShipPayments: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
|
||||
notes: new fields.StringField({ required: false, blank: true, trim: true, initial: "" })
|
||||
notes: new fields.HTMLField({ required: false, blank: true, trim: true })
|
||||
}),
|
||||
containerView: new fields.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||
containerDropIn: new fields.StringField({ required: false, blank: true, trim: true, initial: "" }),
|
||||
|
||||
97
src/module/models/creature.mjs
Normal file
97
src/module/models/creature.mjs
Normal file
@@ -0,0 +1,97 @@
|
||||
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" }),
|
||||
skill: new fields.NumberField({ required: false, initial: -1, integer: true }),
|
||||
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
|
||||
export { default as CharacterData } from "./character.mjs";
|
||||
export { default as VehiculeData } from "./vehicule.mjs";
|
||||
export { default as CreatureData } from "./creature.mjs";
|
||||
|
||||
// Item DataModels
|
||||
export { default as ItemData } from "./items/item.mjs";
|
||||
|
||||
@@ -13,7 +13,7 @@ export function createCharacteristicField(show = true, showMax = false) {
|
||||
export class ItemBaseData extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
return {
|
||||
description: new fields.StringField({ required: false, blank: true, trim: true, nullable: true }),
|
||||
description: new fields.HTMLField({ required: false, blank: true, trim: true }),
|
||||
subType: new fields.StringField({ required: false, blank: false, nullable: true })
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default class ItemContainerData extends ItemBaseData {
|
||||
schema.weight = new fields.NumberField({ required: false, initial: 0, integer: false });
|
||||
schema.weightless = new fields.BooleanField({ required: false, initial: false });
|
||||
schema.locked = new fields.BooleanField({ required: false, initial: false }); // GM only
|
||||
schema.lockedDescription = new fields.StringField({ required: false, blank: true, trim: true, nullable: true });
|
||||
schema.lockedDescription = new fields.HTMLField({ required: false, blank: true, trim: true });
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ const fields = foundry.data.fields;
|
||||
export default class SpeciesData extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
return {
|
||||
description: new fields.StringField({ required: false, blank: true, trim: true, nullable: true }),
|
||||
description: new fields.HTMLField({ required: false, blank: true, trim: true }),
|
||||
descriptionLong: new fields.HTMLField({ required: false, blank: true, trim: true }),
|
||||
traits: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
|
||||
@@ -13,12 +13,18 @@ export default class WeaponData extends PhysicalItemData {
|
||||
schema.damage = new fields.StringField({ required: false, blank: true, trim: true });
|
||||
schema.magazine = new fields.NumberField({ required: false, initial: 0, min: 0, integer: true });
|
||||
schema.magazineCost = new fields.NumberField({ required: false, initial: 0, min: 0, integer: true });
|
||||
schema.traits = new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({ required: true, blank: true, trim: true }),
|
||||
description: new fields.StringField({ required: false, blank: true, trim: true })
|
||||
})
|
||||
);
|
||||
schema.traits = new fields.SchemaField({
|
||||
ap: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
||||
auto: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
||||
blast: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true }),
|
||||
bulky: new fields.BooleanField({ required: false, initial: false }),
|
||||
veryBulky: new fields.BooleanField({ required: false, initial: false }),
|
||||
stun: new fields.BooleanField({ required: false, initial: false }),
|
||||
smart: new fields.BooleanField({ required: false, initial: false }),
|
||||
radiation: new fields.BooleanField({ required: false, initial: false }),
|
||||
scope: new fields.BooleanField({ required: false, initial: false }),
|
||||
zeroG: new fields.BooleanField({ required: false, initial: false })
|
||||
});
|
||||
schema.options = new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({ required: true, blank: true, trim: true }),
|
||||
@@ -27,4 +33,21 @@ export default class WeaponData extends PhysicalItemData {
|
||||
);
|
||||
return schema;
|
||||
}
|
||||
|
||||
/** Returns a compact display string of active traits (e.g. "AP 2, Auto 3, Blast 5, Bulky") */
|
||||
static getTraitsSummary(traits) {
|
||||
if (!traits) return "";
|
||||
const parts = [];
|
||||
if (traits.ap > 0) parts.push(`AP ${traits.ap}`);
|
||||
if (traits.auto > 0) parts.push(`Auto ${traits.auto}`);
|
||||
if (traits.blast > 0) parts.push(`Blast ${traits.blast}`);
|
||||
if (traits.bulky) parts.push(game.i18n.localize("MGT2.WeaponTraits.Bulky"));
|
||||
if (traits.veryBulky) parts.push(game.i18n.localize("MGT2.WeaponTraits.VeryBulky"));
|
||||
if (traits.stun) parts.push(game.i18n.localize("MGT2.WeaponTraits.Stun"));
|
||||
if (traits.smart) parts.push(game.i18n.localize("MGT2.WeaponTraits.Smart"));
|
||||
if (traits.radiation) parts.push(game.i18n.localize("MGT2.WeaponTraits.Radiation"));
|
||||
if (traits.scope) parts.push(game.i18n.localize("MGT2.WeaponTraits.Scope"));
|
||||
if (traits.zeroG) parts.push(game.i18n.localize("MGT2.WeaponTraits.ZeroG"));
|
||||
return parts.join(", ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ export default class VehiculeData extends foundry.abstract.TypeDataModel {
|
||||
}),
|
||||
skills: new fields.SchemaField({
|
||||
autopilot: new fields.NumberField({ required: true, initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
description: new fields.HTMLField({ required: false, blank: true, trim: true }),
|
||||
notes: new fields.HTMLField({ required: false, blank: true, trim: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,21 +5,49 @@ const { FormDataExtended } = foundry.applications.ux;
|
||||
export class RollPromptHelper {
|
||||
|
||||
static async roll(options) {
|
||||
// Backward compat: allow (actor, options) or just (options)
|
||||
if (options.rollTypeName || options.characteristics || options.skill !== undefined) {
|
||||
// Normal call with options
|
||||
} else {
|
||||
// Called with (actor, options)
|
||||
options = arguments[1] || options;
|
||||
}
|
||||
|
||||
const htmlContent = await renderTemplate('systems/mgt2/templates/roll-prompt.html', {
|
||||
config: CONFIG.MGT2,
|
||||
characteristics: options.characteristics,
|
||||
characteristic: options.characteristic,
|
||||
skills: options.skills,
|
||||
skill: options.skill,
|
||||
fatigue: options.fatigue,
|
||||
encumbrance: options.encumbrance,
|
||||
difficulty: options.difficulty
|
||||
// Character-mode fields
|
||||
characteristics: options.characteristics ?? [],
|
||||
characteristic: options.characteristic ?? "",
|
||||
skills: options.skills ?? [],
|
||||
skill: options.skill ?? "",
|
||||
fatigue: options.fatigue ?? false,
|
||||
encumbrance: options.encumbrance ?? false,
|
||||
difficulty: options.difficulty ?? "Average",
|
||||
timeframe: options.timeframe ?? "Normal",
|
||||
customDM: options.customDM ?? "0",
|
||||
rollMode: options.rollMode ?? "publicroll",
|
||||
// Creature-mode flags
|
||||
isCreature: options.isCreature ?? false,
|
||||
creatureSkills: options.creatureSkills ?? [],
|
||||
selectedSkillIndex: options.selectedSkillIndex ?? -1,
|
||||
showSkillSelector: options.showSkillSelector ?? false,
|
||||
skillName: options.skillName ?? "",
|
||||
skillLevel: options.skillLevel ?? 0,
|
||||
// Healing fields
|
||||
showHeal: options.showHeal ?? false,
|
||||
healType: options.healType ?? null,
|
||||
// Ranged/Melee weapon flags
|
||||
isRanged: options.isRanged ?? false,
|
||||
isMelee: options.isMelee ?? false,
|
||||
isAttack: (options.isRanged ?? false) || (options.isMelee ?? false),
|
||||
autoLevel: options.autoLevel ?? 0,
|
||||
hasScope: options.scope ?? false,
|
||||
hasZeroG: options.zeroG ?? false,
|
||||
});
|
||||
|
||||
const theme = game.settings.get("mgt2", "theme");
|
||||
|
||||
return await DialogV2.wait({
|
||||
window: { title: options.title ?? options.rollTypeName ?? game.i18n.localize("MGT2.RollPrompt.Roll") },
|
||||
classes: ["mgt2-roll-dialog"],
|
||||
content: htmlContent,
|
||||
rejectClose: false,
|
||||
buttons: [
|
||||
|
||||
@@ -19,14 +19,19 @@ export const preloadHandlebarsTemplates = async function() {
|
||||
"systems/mgt2/templates/items/weapon-sheet.html",
|
||||
"systems/mgt2/templates/items/parts/sheet-configuration.html",
|
||||
"systems/mgt2/templates/items/parts/sheet-physical-item.html",
|
||||
"systems/mgt2/templates/items/parts/sheet-physical-item-tab.html",
|
||||
"systems/mgt2/templates/roll-prompt.html",
|
||||
"systems/mgt2/templates/chat/roll.html",
|
||||
//"systems/mgt2/templates/chat/roll-characteristic.html",
|
||||
"systems/mgt2/templates/chat/radiation.html",
|
||||
"systems/mgt2/templates/actors/actor-config-sheet.html",
|
||||
"systems/mgt2/templates/actors/actor-config-characteristic-sheet.html",
|
||||
"systems/mgt2/templates/actors/trait-sheet.html",
|
||||
"systems/mgt2/templates/actors/creature-sheet.html",
|
||||
"systems/mgt2/templates/chat/creature-roll.html",
|
||||
"systems/mgt2/templates/editor-fullview.html"
|
||||
];
|
||||
|
||||
return loadTemplates(templatePaths);
|
||||
const loader = foundry.applications?.handlebars?.loadTemplates ?? loadTemplates;
|
||||
return loader(templatePaths);
|
||||
};
|
||||
@@ -51,6 +51,7 @@
|
||||
font-weight: 600
|
||||
font-style: italic
|
||||
text-align: center
|
||||
color: var(--mgt2-color-form)
|
||||
position: relative
|
||||
& > a
|
||||
&.roll
|
||||
@@ -122,7 +123,7 @@
|
||||
background-color: transparent
|
||||
text-align: center
|
||||
font-size: 1.5rem
|
||||
width: 2rem
|
||||
width: 3rem
|
||||
height: 2rem
|
||||
border: none
|
||||
outline: none
|
||||
@@ -183,13 +184,14 @@ ul
|
||||
float: left
|
||||
margin: 0
|
||||
padding: 0
|
||||
color: var(--mgt2-color-primary-light)
|
||||
color: var(--mgt2-color-form)
|
||||
input
|
||||
display: block
|
||||
border: none
|
||||
font-weight: bold
|
||||
font-family: "Roboto Condensed", sans-serif
|
||||
background-color: #fff
|
||||
color: var(--mgt2-color-form)
|
||||
font-size: 0.8rem
|
||||
border: 1px solid #fff
|
||||
&:hover
|
||||
@@ -203,6 +205,7 @@ ul
|
||||
font-size: 0.7rem
|
||||
text-transform: uppercase
|
||||
text-wrap: nowrap
|
||||
color: var(--mgt2-color-form)
|
||||
i
|
||||
margin-right: 0.25rem
|
||||
.character-body
|
||||
@@ -210,6 +213,7 @@ ul
|
||||
flex-direction: row
|
||||
align-content: flex-start
|
||||
flex-wrap: nowrap
|
||||
min-height: 330px
|
||||
.tab
|
||||
width: 100%
|
||||
|
||||
@@ -236,7 +240,7 @@ ul
|
||||
display: flex
|
||||
margin: 0
|
||||
padding: 0
|
||||
color: #4b4a44
|
||||
color: var(--mgt2-color-form)
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
width: 100%
|
||||
@@ -274,3 +278,15 @@ ul
|
||||
flex-shrink: 0
|
||||
display: flex
|
||||
flex-direction: row
|
||||
|
||||
|
||||
// ── HTMLField editor min-height in notes/biography/finance tabs ──────────────
|
||||
.mgt2.character
|
||||
.tab[data-tab="notes"],
|
||||
.tab[data-tab="biography"],
|
||||
.tab[data-tab="finance"]
|
||||
.editor,
|
||||
.editor-content,
|
||||
prose-mirror
|
||||
min-height: 300px !important
|
||||
height: auto !important
|
||||
|
||||
@@ -1,47 +1,482 @@
|
||||
.chat-sidebar,
|
||||
.mgt2-buttons button
|
||||
background: rgba(0, 0, 0, 0.1)
|
||||
border: 1px solid var(--color-border-light-2)
|
||||
border-radius: 3px
|
||||
box-shadow: 0 0 2px #FFF inset
|
||||
//.chat-message
|
||||
// &.message
|
||||
// color: #0A0405
|
||||
// background-color: #fff
|
||||
// background-image: none
|
||||
.dice-formula,
|
||||
.dice-total
|
||||
background-color: #fff
|
||||
.mgt2-buttons
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
flex-wrap: nowrap
|
||||
// ─── MGT2 Chat Roll Cards ──────────────────────────────────────────────────
|
||||
|
||||
// Light theme for ALL chat messages - matching character sheet
|
||||
li.chat-message
|
||||
background: #ffffff !important
|
||||
border: 1px solid #ccbbbb !important
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.18) !important
|
||||
color: #0A0405
|
||||
margin-top: 5px
|
||||
button
|
||||
i
|
||||
font-size: 1.1rem
|
||||
padding: 0
|
||||
padding: 0 !important
|
||||
|
||||
.message-header
|
||||
background: #0A0405
|
||||
border-bottom: 3px solid #EE4050
|
||||
padding: 4px 10px
|
||||
|
||||
.message-sender
|
||||
color: #EE4050
|
||||
font-family: 'Barlow Condensed', sans-serif
|
||||
font-weight: 700
|
||||
font-size: 0.75rem
|
||||
text-transform: uppercase
|
||||
letter-spacing: 1.5px
|
||||
margin: 0
|
||||
.roll-info
|
||||
|
||||
.message-timestamp
|
||||
color: #888888
|
||||
font-size: 0.68rem
|
||||
|
||||
.message-delete i
|
||||
color: #888888
|
||||
|
||||
&:hover .message-delete i
|
||||
color: #EE4050
|
||||
|
||||
// Plain Foundry roll cards (without .mgt2-chat-roll wrapper)
|
||||
.message-content > .dice-roll
|
||||
background: #fdf8f8
|
||||
padding: 6px 12px
|
||||
|
||||
.dice-formula
|
||||
background: #f5eeee
|
||||
border: 1px solid #ddc8c8
|
||||
border-radius: 3px
|
||||
color: #664444
|
||||
font-size: 0.78rem
|
||||
padding: 2px 10px
|
||||
text-align: center
|
||||
font-family: 'Barlow Condensed', sans-serif
|
||||
display: inline-block
|
||||
margin: 0 auto 4px auto
|
||||
|
||||
.dice-result
|
||||
display: flex
|
||||
flex-direction: column
|
||||
.roll-type-group
|
||||
flex-direction: row
|
||||
flex-wrap: wrap
|
||||
justify-content: space-between
|
||||
display: flex
|
||||
.roll-type-name
|
||||
font-size: 11px
|
||||
text-transform: uppercase
|
||||
color: #515151
|
||||
.roll-object-name
|
||||
font-weight: 400
|
||||
font-size: 1.4rem
|
||||
.roll-success
|
||||
font-size: 1.2rem
|
||||
font-weight: bold
|
||||
text-transform: uppercase
|
||||
margin-top: 1rem
|
||||
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)
|
||||
|
||||
// ── Effect line ──
|
||||
.mgt2-effect
|
||||
text-align: center
|
||||
font-size: 0.72rem
|
||||
font-weight: 600
|
||||
letter-spacing: 1.5px
|
||||
text-transform: uppercase
|
||||
padding: 2px 10px 4px 10px
|
||||
border-bottom: 2px solid transparent
|
||||
|
||||
.mgt2-effect-value
|
||||
font-size: 1rem
|
||||
font-weight: 900
|
||||
margin-left: 4px
|
||||
|
||||
.mgt2-healing-amount
|
||||
font-size: 0.75rem
|
||||
font-weight: 600
|
||||
margin-left: 6px
|
||||
opacity: 0.85
|
||||
|
||||
&.is-success
|
||||
color: #1a8840
|
||||
border-bottom-color: rgba(26,136,64,0.25)
|
||||
|
||||
.mgt2-effect-value
|
||||
color: #1a8840
|
||||
|
||||
&.is-failure
|
||||
color: #EE4050
|
||||
border-bottom-color: rgba(238,64,80,0.25)
|
||||
|
||||
.mgt2-effect-value
|
||||
color: #EE4050
|
||||
|
||||
// ── AP info badge ──
|
||||
.mgt2-ap-info
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
gap: 5px
|
||||
font-size: 0.75rem
|
||||
font-weight: 600
|
||||
color: #6b4e1a
|
||||
background: rgba(180,130,40,0.12)
|
||||
border: 1px solid rgba(180,130,40,0.3)
|
||||
border-radius: 4px
|
||||
padding: 3px 8px
|
||||
margin: 4px 8px 0 8px
|
||||
i
|
||||
color: #b48228
|
||||
|
||||
// ── Auto fire mode info badge ──
|
||||
.mgt2-auto-info
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
gap: 5px
|
||||
font-size: 0.75rem
|
||||
font-weight: 600
|
||||
color: #1a3f6b
|
||||
background: rgba(40,90,180,0.10)
|
||||
border: 1px solid rgba(40,90,180,0.25)
|
||||
border-radius: 4px
|
||||
padding: 3px 8px
|
||||
margin: 4px 8px 0 8px
|
||||
i
|
||||
color: #2855b4
|
||||
|
||||
// ── Blast / explosion area info badge ──
|
||||
.mgt2-blast-info
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
gap: 5px
|
||||
font-size: 0.75rem
|
||||
font-weight: 600
|
||||
color: #7a2a00
|
||||
background: rgba(210,80,20,0.10)
|
||||
border: 1px solid rgba(210,80,20,0.30)
|
||||
border-radius: 4px
|
||||
padding: 3px 8px
|
||||
margin: 4px 8px 0 8px
|
||||
i
|
||||
color: #d24a10
|
||||
|
||||
// ── Stun / incapacitating weapon info badge ──
|
||||
.mgt2-stun-info
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
gap: 5px
|
||||
font-size: 0.75rem
|
||||
font-weight: 600
|
||||
color: #4a1a6b
|
||||
background: rgba(120,40,180,0.10)
|
||||
border: 1px solid rgba(120,40,180,0.28)
|
||||
border-radius: 4px
|
||||
padding: 3px 8px
|
||||
margin: 4px 8px 0 8px
|
||||
i
|
||||
color: #8a28c8
|
||||
|
||||
// ── Radiation weapon info badge ──
|
||||
.mgt2-radiation-info
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
gap: 5px
|
||||
font-size: 0.75rem
|
||||
font-weight: 600
|
||||
color: #1a4a1a
|
||||
background: rgba(40,160,40,0.10)
|
||||
border: 1px solid rgba(40,160,40,0.30)
|
||||
border-radius: 4px
|
||||
padding: 3px 8px
|
||||
margin: 4px 8px 0 8px
|
||||
i
|
||||
color: #28a028
|
||||
|
||||
// ── Radiation roll result card ──
|
||||
.mgt2-radiation-card
|
||||
.mgt2-radiation-label
|
||||
color: #28a028
|
||||
font-weight: 700
|
||||
i
|
||||
margin-right: 4px
|
||||
.mgt2-radiation-rules
|
||||
font-size: 0.72rem
|
||||
color: #555
|
||||
background: rgba(40,160,40,0.07)
|
||||
border: 1px solid rgba(40,160,40,0.20)
|
||||
border-radius: 4px
|
||||
padding: 4px 8px
|
||||
margin: 4px 8px 0 8px
|
||||
display: flex
|
||||
gap: 5px
|
||||
align-items: flex-start
|
||||
i
|
||||
color: #e0a020
|
||||
margin-top: 2px
|
||||
flex-shrink: 0
|
||||
|
||||
// ── 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)
|
||||
|
||||
&:disabled
|
||||
background: #e8e0e0
|
||||
border-color: #c8b8b8
|
||||
color: #a08080
|
||||
cursor: not-allowed
|
||||
box-shadow: none
|
||||
opacity: 0.6
|
||||
225
src/sass/components/_creature.sass
Normal file
225
src/sass/components/_creature.sass
Normal file
@@ -0,0 +1,225 @@
|
||||
// ─────────────────────────────────────────────────
|
||||
// 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: nowrap
|
||||
|
||||
label
|
||||
flex: 0 0 auto
|
||||
font-size: 0.75rem
|
||||
text-transform: uppercase
|
||||
color: var(--mgt2-color-primary)
|
||||
font-weight: 700
|
||||
white-space: nowrap
|
||||
|
||||
.behavior-select
|
||||
flex: 1 1 auto
|
||||
min-width: 0
|
||||
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
|
||||
flex: 0 0 auto
|
||||
color: var(--mgt2-color-form)
|
||||
opacity: 0.5
|
||||
|
||||
.creature-size-badge
|
||||
flex: 0 0 auto
|
||||
white-space: nowrap
|
||||
font-size: 0.75rem
|
||||
font-style: italic
|
||||
color: var(--mgt2-bgcolor-form)
|
||||
background: var(--mgt2-bgcolor-primary)
|
||||
border: 1px solid var(--mgt2-color-primary)
|
||||
border-radius: 3px
|
||||
padding: 1px 6px
|
||||
|
||||
// ── Body / Tabs ────────────────────────────────────
|
||||
// min-height ensures all 4 sidebar tabs are always visible
|
||||
// (4 tabs × 54px each + 8px padding = 224px)
|
||||
.creature-body
|
||||
flex: 1
|
||||
overflow-y: auto
|
||||
padding: 0.5rem 0.75rem
|
||||
min-height: 228px
|
||||
|
||||
.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
|
||||
|
||||
// ── Section headers: use shared .header class (same as character sheet) ──────
|
||||
|
||||
// ── HTMLField editor min-height in info tab ──────────────────────────────────
|
||||
.mgt2.creature
|
||||
// Section headers (skills/attacks/traits) — margin between successive sections
|
||||
.table-container + .header
|
||||
margin-top: 8px
|
||||
|
||||
.tab[data-tab="info"]
|
||||
.editor,
|
||||
.editor-content,
|
||||
prose-mirror
|
||||
min-height: 300px !important
|
||||
height: auto !important
|
||||
@@ -2,3 +2,274 @@
|
||||
.dialog-button
|
||||
color: var(--mgt2-color-primary)
|
||||
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: 8px 14px 6px !important
|
||||
|
||||
// Form group rows
|
||||
.form-group
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
gap: 8px !important
|
||||
margin-bottom: 3px !important
|
||||
padding: 2px 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: 3px 8px !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: 5px 10px !important
|
||||
margin-bottom: 4px !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
|
||||
|
||||
// Read-only state badges
|
||||
.roll-prompt-states
|
||||
display: flex !important
|
||||
gap: 6px !important
|
||||
flex-wrap: wrap !important
|
||||
padding: 2px 0 !important
|
||||
|
||||
.roll-prompt-state-badge
|
||||
display: inline-flex !important
|
||||
align-items: center !important
|
||||
gap: 4px !important
|
||||
padding: 2px 8px !important
|
||||
border-radius: 3px !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.75rem !important
|
||||
font-weight: 600 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 0.8px !important
|
||||
background: #ede8e8 !important
|
||||
border: 1px solid #ccc !important
|
||||
color: #999 !important
|
||||
|
||||
i
|
||||
font-size: 0.7rem !important
|
||||
|
||||
&.is-active
|
||||
background: #fdf0f0 !important
|
||||
border-color: #EE4050 !important
|
||||
color: #EE4050 !important
|
||||
|
||||
strong
|
||||
font-weight: 800 !important
|
||||
|
||||
// Footer buttons
|
||||
.dialog-buttons, .form-footer, footer
|
||||
background: #f5eeee !important
|
||||
border-top: 2px solid #EE4050 !important
|
||||
padding: 7px 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: 5px 12px !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
|
||||
|
||||
// Ranged modifiers fieldset
|
||||
.mgt2-ranged-modifiers
|
||||
margin-top: 4px !important
|
||||
|
||||
.mgt2-ranged-checkboxes, .mgt2-ranged-dodge
|
||||
display: flex !important
|
||||
flex-wrap: wrap !important
|
||||
gap: 6px !important
|
||||
align-items: center !important
|
||||
border-bottom: none !important
|
||||
|
||||
.mgt2-checkbox-tag
|
||||
display: inline-flex !important
|
||||
align-items: center !important
|
||||
gap: 4px !important
|
||||
padding: 2px 7px !important
|
||||
border: 1px solid #ddc8c8 !important
|
||||
border-radius: 3px !important
|
||||
background: #fdf8f8 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.73rem !important
|
||||
font-weight: 600 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 0.8px !important
|
||||
color: #3a2020 !important
|
||||
cursor: pointer !important
|
||||
transition: border-color 0.15s, background 0.15s !important
|
||||
|
||||
em
|
||||
font-style: normal !important
|
||||
color: #999 !important
|
||||
font-weight: 400 !important
|
||||
|
||||
input[type="checkbox"]
|
||||
accent-color: #EE4050 !important
|
||||
width: 13px !important
|
||||
height: 13px !important
|
||||
margin: 0 !important
|
||||
|
||||
&:has(input:checked)
|
||||
border-color: #EE4050 !important
|
||||
background: #fdf0f0 !important
|
||||
color: #EE4050 !important
|
||||
|
||||
em
|
||||
color: #EE4050 !important
|
||||
|
||||
// Auto fire mode selector
|
||||
.mgt2-auto-mode
|
||||
border-bottom: 1px solid #ddc8c8 !important
|
||||
padding-bottom: 4px !important
|
||||
margin-bottom: 2px !important
|
||||
|
||||
.mgt2-auto-hint
|
||||
font-size: 0.72rem !important
|
||||
color: #9a6520 !important
|
||||
margin: 0 0 4px 0 !important
|
||||
font-style: italic !important
|
||||
text-align: center !important
|
||||
|
||||
.mgt2-scope-badge
|
||||
display: inline-flex
|
||||
align-items: center
|
||||
gap: 5px
|
||||
font-size: 0.72rem
|
||||
font-weight: 600
|
||||
color: #1a4060
|
||||
background: rgba(30,100,180,0.10)
|
||||
border: 1px solid rgba(30,100,180,0.28)
|
||||
border-radius: 4px
|
||||
padding: 2px 8px
|
||||
margin-bottom: 4px
|
||||
cursor: help
|
||||
i
|
||||
color: #1a6090
|
||||
|
||||
.mgt2-zerog-badge
|
||||
display: inline-flex
|
||||
align-items: center
|
||||
gap: 5px
|
||||
font-size: 0.72rem
|
||||
font-weight: 600
|
||||
color: #2a3a50
|
||||
background: rgba(60,80,120,0.10)
|
||||
border: 1px solid rgba(60,80,120,0.28)
|
||||
border-radius: 4px
|
||||
padding: 2px 8px
|
||||
margin-bottom: 4px
|
||||
cursor: help
|
||||
i
|
||||
color: #506090
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
font-size: 13px
|
||||
&.field-name
|
||||
background-color: var(--mgt2-input-bgcolor)
|
||||
color: var(--mgt2-color-primary)
|
||||
font-size: 2rem
|
||||
border: none
|
||||
font-weight: 700
|
||||
@@ -58,6 +59,7 @@
|
||||
padding: 0
|
||||
&.field-item-name
|
||||
background-color: var(--mgt2-input-bgcolor)
|
||||
color: var(--mgt2-color-primary)
|
||||
height: auto
|
||||
font-size: 2rem
|
||||
font-weight: 700
|
||||
|
||||
@@ -1,38 +1,459 @@
|
||||
// ─── MGT2 Item Sheets ─────────────────────────────────────────────────────────
|
||||
// New unified layout: type-bar → header (image+name) → stats-bar → full-width tabs
|
||||
|
||||
// ── Outer window ──────────────────────────────────────────────────────────────
|
||||
.itemsheet
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
flex-direction: row
|
||||
.itemsheet-header
|
||||
display: flex
|
||||
background-color: var(--mgt2-bgcolor-primary)
|
||||
color: red
|
||||
padding: 0.5rem
|
||||
align-items: center
|
||||
flex: 0 0 2rem
|
||||
display: flex !important
|
||||
flex-direction: column !important
|
||||
height: 100% !important
|
||||
background: #ffffff !important
|
||||
overflow: hidden !important
|
||||
|
||||
// ── Type bar (replaces vertical sidebar label) ────────────────────────────────
|
||||
.item-type-bar
|
||||
background: #0A0405 !important
|
||||
border-bottom: 3px solid #EE4050 !important
|
||||
padding: 4px 12px !important
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
gap: 8px !important
|
||||
min-height: 0 !important
|
||||
flex-shrink: 0 !important
|
||||
|
||||
.item-type-label
|
||||
color: #EE4050 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.65rem !important
|
||||
font-weight: 700 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 2px !important
|
||||
|
||||
// ── Header: image + name ──────────────────────────────────────────────────────
|
||||
.item-sheet-header
|
||||
background: #0A0405 !important
|
||||
padding: 10px 14px !important
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
gap: 12px !important
|
||||
flex-shrink: 0 !important
|
||||
|
||||
.item-header-img
|
||||
width: 64px !important
|
||||
height: 64px !important
|
||||
object-fit: cover !important
|
||||
border: 2px solid #EE4050 !important
|
||||
border-radius: 4px !important
|
||||
cursor: pointer !important
|
||||
flex-shrink: 0 !important
|
||||
|
||||
.item-header-name
|
||||
flex: 1 !important
|
||||
background: transparent !important
|
||||
border: none !important
|
||||
border-bottom: 1px solid rgba(238,64,80,0.4) !important
|
||||
color: #ffffff !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 1.6rem !important
|
||||
font-weight: 800 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 1px !important
|
||||
padding: 2px 0 !important
|
||||
line-height: 1.1 !important
|
||||
width: 100% !important
|
||||
|
||||
&:focus
|
||||
outline: none !important
|
||||
border-bottom-color: #EE4050 !important
|
||||
|
||||
&::placeholder
|
||||
color: rgba(255,255,255,0.35) !important
|
||||
|
||||
// ── Stats bar (pills) ─────────────────────────────────────────────────────────
|
||||
.item-stats-bar
|
||||
background: #f5eeee !important
|
||||
border-bottom: 1px solid #ddc8c8 !important
|
||||
padding: 6px 14px !important
|
||||
display: flex !important
|
||||
flex-wrap: wrap !important
|
||||
gap: 6px !important
|
||||
flex-shrink: 0 !important
|
||||
|
||||
.item-stat-pill
|
||||
display: flex !important
|
||||
flex-direction: column !important
|
||||
align-items: center !important
|
||||
background: #ffffff !important
|
||||
border: 1px solid #ddc8c8 !important
|
||||
border-radius: 4px !important
|
||||
padding: 3px 10px !important
|
||||
min-width: 56px !important
|
||||
|
||||
.stat-label
|
||||
color: #664444 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.6rem !important
|
||||
font-weight: 700 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 1.5px !important
|
||||
line-height: 1.2 !important
|
||||
|
||||
.stat-value
|
||||
color: #0A0405 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 1rem !important
|
||||
font-weight: 800 !important
|
||||
line-height: 1.1 !important
|
||||
|
||||
input, select
|
||||
color: #0A0405 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 1rem !important
|
||||
font-weight: 800 !important
|
||||
background: transparent !important
|
||||
border: none !important
|
||||
text-align: center !important
|
||||
width: 100% !important
|
||||
padding: 0 !important
|
||||
line-height: 1.1 !important
|
||||
|
||||
&:focus
|
||||
outline: none !important
|
||||
border-bottom: 1px solid #EE4050 !important
|
||||
|
||||
.item-stat-pill-checkbox
|
||||
display: flex !important
|
||||
flex-direction: row !important
|
||||
align-items: center !important
|
||||
gap: 5px !important
|
||||
background: #ffffff !important
|
||||
border: 1px solid #ddc8c8 !important
|
||||
border-radius: 4px !important
|
||||
padding: 4px 10px !important
|
||||
|
||||
input[type="checkbox"]
|
||||
margin: 0 !important
|
||||
width: 14px !important
|
||||
height: 14px !important
|
||||
accent-color: #EE4050 !important
|
||||
|
||||
label
|
||||
writing-mode: tb-rl
|
||||
transform: rotate(-180deg)
|
||||
font-weight: 700
|
||||
font-size: 20px
|
||||
letter-spacing: 5px
|
||||
font-family: "Rubik Mono One", monospace
|
||||
font-style: normal
|
||||
text-transform: uppercase
|
||||
color: #664444 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.65rem !important
|
||||
font-weight: 700 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 1px !important
|
||||
cursor: pointer !important
|
||||
|
||||
// ── Tabs navigation ───────────────────────────────────────────────────────────
|
||||
.itemsheet
|
||||
.horizontal-tabs.tabs
|
||||
background: #f5eeee !important
|
||||
border-bottom: 2px solid #ddc8c8 !important
|
||||
display: flex !important
|
||||
flex-wrap: wrap !important
|
||||
gap: 0 !important
|
||||
padding: 0 10px !important
|
||||
flex-shrink: 0 !important
|
||||
|
||||
.item.tab-select
|
||||
color: #664444 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.72rem !important
|
||||
font-weight: 700 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 1.5px !important
|
||||
padding: 6px 14px !important
|
||||
border: none !important
|
||||
border-bottom: 2px solid transparent !important
|
||||
margin-bottom: -2px !important
|
||||
background: transparent !important
|
||||
cursor: pointer !important
|
||||
transition: color 0.15s, border-color 0.15s !important
|
||||
|
||||
&:hover
|
||||
color: #EE4050 !important
|
||||
|
||||
&.active
|
||||
color: #EE4050 !important
|
||||
border-bottom-color: #EE4050 !important
|
||||
background: transparent !important
|
||||
|
||||
// ── Tab content area ──────────────────────────────────────────────────────────
|
||||
.itemsheet
|
||||
.tab-content-area
|
||||
flex: 1 !important
|
||||
overflow-y: auto !important
|
||||
padding: 10px 14px !important
|
||||
background: #ffffff !important
|
||||
|
||||
.tab[data-group]
|
||||
display: none !important
|
||||
|
||||
&.active
|
||||
display: block !important
|
||||
|
||||
// ── Fields inside item sheets ─────────────────────────────────────────────────
|
||||
.itemsheet
|
||||
.field-group
|
||||
margin-bottom: 8px !important
|
||||
|
||||
label
|
||||
display: block !important
|
||||
color: #664444 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.68rem !important
|
||||
font-weight: 700 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 1px !important
|
||||
margin-bottom: 2px !important
|
||||
|
||||
.field-groups
|
||||
display: flex !important
|
||||
flex-wrap: wrap !important
|
||||
gap: 10px !important
|
||||
align-items: flex-start !important
|
||||
|
||||
.field-group
|
||||
flex: 1 !important
|
||||
min-width: 80px !important
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select,
|
||||
textarea
|
||||
background: #fdf8f8 !important
|
||||
border: 1px solid #ddc8c8 !important
|
||||
border-radius: 3px !important
|
||||
color: #0A0405 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.85rem !important
|
||||
padding: 4px 8px !important
|
||||
width: 100% !important
|
||||
|
||||
&:focus
|
||||
outline: none !important
|
||||
border-color: #EE4050 !important
|
||||
box-shadow: 0 0 0 2px rgba(238,64,80,0.12) !important
|
||||
|
||||
textarea
|
||||
resize: vertical !important
|
||||
min-height: 80px !important
|
||||
|
||||
.mgt2-checkbox
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
gap: 6px !important
|
||||
color: #664444 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.72rem !important
|
||||
font-weight: 700 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 1px !important
|
||||
|
||||
input[type="checkbox"]
|
||||
width: 14px !important
|
||||
height: 14px !important
|
||||
margin: 0 !important
|
||||
accent-color: #EE4050 !important
|
||||
|
||||
// ── Tables inside item sheets ─────────────────────────────────────────────────
|
||||
.itemsheet
|
||||
.table-container
|
||||
border: 1px solid #ddc8c8 !important
|
||||
border-radius: 4px !important
|
||||
overflow: hidden !important
|
||||
margin-top: 8px !important
|
||||
|
||||
.table-row
|
||||
display: flex !important
|
||||
align-items: stretch !important
|
||||
border-bottom: 1px solid #e8dada !important
|
||||
|
||||
&:last-child
|
||||
border-bottom: none !important
|
||||
|
||||
&.heading
|
||||
background: #0A0405 !important
|
||||
color: #EE4050 !important
|
||||
|
||||
.row-item
|
||||
color: #EE4050 !important
|
||||
font-family: 'Barlow Condensed', sans-serif !important
|
||||
font-size: 0.68rem !important
|
||||
font-weight: 700 !important
|
||||
text-transform: uppercase !important
|
||||
letter-spacing: 1px !important
|
||||
padding: 5px 8px !important
|
||||
|
||||
&:not(.heading)
|
||||
background: #ffffff !important
|
||||
|
||||
&:nth-child(even)
|
||||
background: #fdf8f8 !important
|
||||
|
||||
.row-item
|
||||
padding: 4px 6px !important
|
||||
|
||||
input, textarea, select
|
||||
font-size: 0.8rem !important
|
||||
padding: 2px 6px !important
|
||||
|
||||
.row-item
|
||||
flex: 1 !important
|
||||
border-right: 1px solid #e8dada !important
|
||||
|
||||
&:last-child
|
||||
border-right: none !important
|
||||
|
||||
&.row-item-left
|
||||
justify-content: flex-start !important
|
||||
|
||||
&.row-item-right
|
||||
flex: 0 0 auto !important
|
||||
min-width: 36px !important
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
justify-content: center !important
|
||||
|
||||
&.row-item-30
|
||||
flex: 0 0 30% !important
|
||||
|
||||
.item-controls
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
justify-content: center !important
|
||||
gap: 6px !important
|
||||
|
||||
a
|
||||
color: #888888 !important
|
||||
cursor: pointer !important
|
||||
|
||||
&:hover
|
||||
color: #EE4050 !important
|
||||
|
||||
// ── Legacy classes kept for compatibility ─────────────────────────────────────
|
||||
// (old structure hidden, new structure used)
|
||||
.itemsheet-header
|
||||
display: none !important
|
||||
|
||||
.itemsheet-maincol
|
||||
flex: 0 0 130px
|
||||
padding: 0 1rem 0 0
|
||||
display: none !important
|
||||
|
||||
.itemsheet-panel
|
||||
display: contents !important
|
||||
|
||||
|
||||
// ── Details tab: 2-column grid layout ────────────────────────────────────────
|
||||
.itemsheet
|
||||
.item-details-grid
|
||||
display: grid !important
|
||||
grid-template-columns: 1fr 1fr !important
|
||||
gap: 4px 16px !important
|
||||
align-items: start !important
|
||||
|
||||
// Traits table spans full width
|
||||
.table-container
|
||||
grid-column: 1 / -1 !important
|
||||
margin-top: 10px !important
|
||||
|
||||
// ── Field row: label + input on the same line ─────────────────────────────────
|
||||
.itemsheet
|
||||
.field-row
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
gap: 8px !important
|
||||
min-height: 28px !important
|
||||
|
||||
label
|
||||
flex: 0 0 100px !important
|
||||
min-width: 0 !important
|
||||
margin-bottom: 0 !important
|
||||
white-space: nowrap !important
|
||||
overflow: hidden !important
|
||||
text-overflow: ellipsis !important
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select
|
||||
flex: 1 !important
|
||||
width: auto !important
|
||||
height: 24px !important
|
||||
padding: 2px 6px !important
|
||||
|
||||
input.short
|
||||
flex: 0 0 56px !important
|
||||
width: 56px !important
|
||||
|
||||
.range-inputs
|
||||
display: flex !important
|
||||
gap: 4px !important
|
||||
flex: 1 !important
|
||||
|
||||
input
|
||||
flex: 0 0 52px !important
|
||||
width: 52px !important
|
||||
|
||||
select
|
||||
flex: 1 !important
|
||||
|
||||
// Full-width row (e.g. storage)
|
||||
&.full
|
||||
grid-column: 1 / -1 !important
|
||||
|
||||
// Checkbox row variant
|
||||
.field-row--check
|
||||
label
|
||||
flex: unset !important
|
||||
display: flex !important
|
||||
align-items: center !important
|
||||
gap: 6px !important
|
||||
cursor: pointer !important
|
||||
|
||||
// ── Description tab: editor min-height ───────────────────────────────────────
|
||||
.itemsheet
|
||||
.tab[data-tab="tab1"]
|
||||
.editor,
|
||||
.editor-container
|
||||
min-height: 200px !important
|
||||
|
||||
// ── Weapon traits structured grid ────────────────────────────────────────────
|
||||
.mgt2-weapon-traits
|
||||
border: 1px solid var(--color-border-light-tertiary)
|
||||
border-radius: 4px
|
||||
padding: 6px 8px
|
||||
margin-top: 4px
|
||||
|
||||
legend
|
||||
font-size: 0.85em
|
||||
font-weight: bold
|
||||
padding: 0 4px
|
||||
|
||||
.mgt2-weapon-traits-grid
|
||||
display: flex
|
||||
flex: inherit
|
||||
padding: 1rem
|
||||
img
|
||||
&.profile-img
|
||||
width: 100px
|
||||
height: 100px
|
||||
.itemsheet input,
|
||||
.itemsheet select
|
||||
color: var(--mgt2-input-color)
|
||||
background-color: var(--mgt2-input-bgcolor)
|
||||
display: block
|
||||
width: 100%
|
||||
font-size: 13px
|
||||
flex-wrap: wrap
|
||||
gap: 6px 12px
|
||||
align-items: center
|
||||
|
||||
.mgt2-trait-num
|
||||
display: flex
|
||||
align-items: center
|
||||
gap: 4px
|
||||
label
|
||||
font-size: 0.85em
|
||||
white-space: nowrap
|
||||
input[type="number"]
|
||||
width: 44px
|
||||
text-align: center
|
||||
flex: 0 0 44px
|
||||
|
||||
.mgt2-trait-bool
|
||||
display: flex
|
||||
align-items: center
|
||||
gap: 4px
|
||||
label
|
||||
font-size: 0.85em
|
||||
white-space: nowrap
|
||||
cursor: pointer
|
||||
input[type="checkbox"]
|
||||
cursor: pointer
|
||||
|
||||
@@ -1,40 +1,111 @@
|
||||
.mgt2
|
||||
.sheet-sidebar
|
||||
.item
|
||||
margin: 0 1rem
|
||||
// ── Overflow fixes: allow sidebar nav to protrude OUTSIDE the window frame ──
|
||||
// All ancestors of nav.sheet-sidebar need overflow:visible so absolute-positioned
|
||||
// nav (left: 100% of character-body) can extend to the right of the window border.
|
||||
// Layered !important beats Foundry's unlayered overflow:hidden per CSS cascade spec.
|
||||
|
||||
nav[data-group="sidebar"].tabs
|
||||
position: absolute
|
||||
left: 100%
|
||||
top: 172px
|
||||
display: flex
|
||||
.mgt2.character, .mgt2.creature, .mgt2.vehicule
|
||||
overflow: visible !important
|
||||
> .window-content
|
||||
overflow: visible !important
|
||||
.editable, .locked
|
||||
overflow: visible !important
|
||||
|
||||
.mgt2.character .character-body
|
||||
position: relative !important
|
||||
overflow: visible !important
|
||||
|
||||
.mgt2.creature .creature-body
|
||||
position: relative !important
|
||||
overflow: visible !important
|
||||
|
||||
.mgt2.vehicule .vehicule-content
|
||||
position: relative !important
|
||||
overflow: visible !important
|
||||
|
||||
// ── Vertical sidebar tab navigation (outside window, right side) ──
|
||||
.mgt2
|
||||
nav.sheet-sidebar.tabs
|
||||
position: absolute !important
|
||||
left: 100% !important
|
||||
top: 0 !important
|
||||
width: 62px !important
|
||||
flex: none !important
|
||||
display: flex !important
|
||||
flex-direction: column
|
||||
z-index: -1
|
||||
// Rich dark gradient matching MGT2 theme
|
||||
background: linear-gradient(180deg, #1e0507 0%, #110304 40%, #0a0202 100%)
|
||||
border-top: 1px solid rgba(238,64,80,0.35)
|
||||
border-right: 1px solid rgba(238,64,80,0.25)
|
||||
border-bottom: 1px solid rgba(238,64,80,0.2)
|
||||
border-left: 3px solid var(--mgt2-color-primary)
|
||||
border-radius: 0 10px 10px 0
|
||||
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)
|
||||
z-index: 10
|
||||
overflow: hidden !important
|
||||
padding: 2px 0
|
||||
|
||||
& > .item
|
||||
height: 40px
|
||||
position: relative
|
||||
display: flex
|
||||
justify-content: end
|
||||
align-items: center
|
||||
padding-right: 0.75rem
|
||||
background: var(--mgt2-bgcolor-primary)
|
||||
color: var(--mgt2-color-primary)
|
||||
border: 1px solid transparent
|
||||
font-size: 1rem
|
||||
transition: all 250ms ease
|
||||
margin-left: 0
|
||||
&.active
|
||||
text-shadow: none
|
||||
margin: 0
|
||||
border-color: var(--mgt2-color-primary)
|
||||
&::after
|
||||
border-left: none
|
||||
inset: 0.25rem 0.25rem 0.25rem 0
|
||||
&::after
|
||||
content: ""
|
||||
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
|
||||
inset: 0.25rem
|
||||
border: 1px solid var(--mgt2-color-primary)
|
||||
pointer-events: none
|
||||
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
|
||||
margin-left: 0.8rem
|
||||
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)
|
||||
margin-right: 0.4rem
|
||||
i
|
||||
color: black
|
||||
color: var(--mgt2-color-form)
|
||||
a[data-roll]
|
||||
margin-right: 0.5rem
|
||||
.heading
|
||||
|
||||
203
src/sass/components/_vehicule.sass
Normal file
203
src/sass/components/_vehicule.sass
Normal file
@@ -0,0 +1,203 @@
|
||||
// ─────────────────────────────────────────────────
|
||||
// Vehicule Sheet Styles
|
||||
// ─────────────────────────────────────────────────
|
||||
|
||||
.vehicule-sheet
|
||||
|
||||
// ── Header ────────────────────────────────────────
|
||||
.vehicule-header
|
||||
display: flex
|
||||
flex-direction: row
|
||||
align-items: flex-start
|
||||
gap: 0.75rem
|
||||
padding: 0.5rem 0.75rem
|
||||
background: var(--mgt2-bgcolor-form)
|
||||
border-bottom: 2px solid var(--mgt2-color-primary)
|
||||
flex-shrink: 0
|
||||
|
||||
.vehicule-header-img
|
||||
flex: 0 0 90px
|
||||
img.profile
|
||||
width: 90px
|
||||
height: 90px
|
||||
object-fit: cover
|
||||
border: 2px solid var(--mgt2-color-primary)
|
||||
border-radius: 4px
|
||||
cursor: pointer
|
||||
|
||||
.vehicule-header-body
|
||||
flex: 1
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 0.4rem
|
||||
min-width: 0
|
||||
|
||||
.vehicule-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)
|
||||
|
||||
.vehicule-header-stats
|
||||
display: flex
|
||||
flex-direction: row
|
||||
align-items: flex-start
|
||||
gap: 0.75rem
|
||||
flex-wrap: wrap
|
||||
|
||||
// ── Stat boxes (hull, armor) ────────────────────────
|
||||
.vehicule-stat-box
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
background: var(--mgt2-bgcolor-primary)
|
||||
border: 1px solid var(--mgt2-color-primary)
|
||||
border-radius: 4px
|
||||
padding: 3px 8px
|
||||
min-width: 4rem
|
||||
|
||||
label
|
||||
font-family: "Barlow Condensed", sans-serif
|
||||
font-size: 0.65rem
|
||||
font-weight: 700
|
||||
text-transform: uppercase
|
||||
color: var(--mgt2-color-primary)
|
||||
line-height: 1.2
|
||||
white-space: nowrap
|
||||
|
||||
.vehicule-stat-value
|
||||
display: flex
|
||||
align-items: center
|
||||
gap: 2px
|
||||
|
||||
span
|
||||
color: var(--mgt2-color-primary)
|
||||
font-weight: 700
|
||||
|
||||
input[type="number"]
|
||||
width: 2.8rem
|
||||
text-align: center
|
||||
background: transparent
|
||||
border: none
|
||||
color: var(--mgt2-color-form)
|
||||
font-family: "Rubik", monospace
|
||||
font-size: 1rem
|
||||
font-weight: 600
|
||||
padding: 0
|
||||
&:focus
|
||||
outline: none
|
||||
border-bottom: 1px solid var(--mgt2-color-secondary)
|
||||
|
||||
.vehicule-hull
|
||||
min-width: 6rem
|
||||
.vehicule-stat-value input[type="number"]
|
||||
width: 2.5rem
|
||||
|
||||
// ── Armor group ────────────────────────────────────
|
||||
.vehicule-armor-group
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 2px
|
||||
|
||||
.vehicule-armor-label
|
||||
font-family: "Barlow Condensed", sans-serif
|
||||
font-size: 0.65rem
|
||||
font-weight: 700
|
||||
text-transform: uppercase
|
||||
color: var(--mgt2-color-primary)
|
||||
text-align: center
|
||||
|
||||
.vehicule-armor-row
|
||||
display: flex
|
||||
flex-direction: row
|
||||
gap: 4px
|
||||
|
||||
.vehicule-armor-box
|
||||
min-width: 3.5rem
|
||||
|
||||
// ── Body wrapper (contains tabs + sidebar nav) ─────
|
||||
// min-height ensures both tabs in the sidebar are always visible
|
||||
// (2 tabs × 54px each + 8px padding = 116px)
|
||||
.vehicule-content
|
||||
flex: 1
|
||||
display: flex
|
||||
flex-direction: column
|
||||
overflow: hidden
|
||||
min-height: 320px
|
||||
|
||||
// ── Tab panels ─────────────────────────────────────
|
||||
.vehicule-tab
|
||||
flex: 1
|
||||
overflow-y: auto
|
||||
padding: 0.75rem
|
||||
display: none
|
||||
|
||||
&.active
|
||||
display: block
|
||||
|
||||
// ── Stats grid ─────────────────────────────────────
|
||||
.vehicule-stats-grid
|
||||
display: grid
|
||||
grid-template-columns: 1fr 1fr
|
||||
gap: 4px 12px
|
||||
|
||||
.vehicule-field
|
||||
display: flex
|
||||
flex-direction: row
|
||||
align-items: center
|
||||
gap: 8px
|
||||
padding: 3px 0
|
||||
border-bottom: 1px solid rgba(0,0,0,0.08)
|
||||
|
||||
&:last-child
|
||||
border-bottom: none
|
||||
|
||||
label
|
||||
font-family: "Barlow Condensed", sans-serif
|
||||
font-size: 0.72rem
|
||||
font-weight: 700
|
||||
text-transform: uppercase
|
||||
color: var(--mgt2-color-primary)
|
||||
flex: 0 0 120px
|
||||
white-space: nowrap
|
||||
|
||||
input[type="number"],
|
||||
select
|
||||
flex: 1
|
||||
background: transparent
|
||||
border: 1px solid transparent
|
||||
border-radius: 3px
|
||||
color: var(--mgt2-color-form)
|
||||
font-family: "Barlow Condensed", sans-serif
|
||||
font-size: 0.9rem
|
||||
padding: 2px 4px
|
||||
&:focus
|
||||
outline: none
|
||||
border-color: var(--mgt2-color-primary)
|
||||
background: rgba(255,255,255,0.1)
|
||||
|
||||
input[type="number"]
|
||||
text-align: center
|
||||
width: 4rem
|
||||
|
||||
select
|
||||
cursor: pointer
|
||||
|
||||
|
||||
// ── HTMLField editor min-height in description tab ──────────────────────────
|
||||
.mgt2.vehicule
|
||||
.vehicule-tab[data-tab="description"]
|
||||
.editor,
|
||||
.editor-content,
|
||||
prose-mirror
|
||||
min-height: 300px !important
|
||||
height: auto !important
|
||||
@@ -13,3 +13,5 @@
|
||||
@import 'components/_tabs'
|
||||
@import 'components/_tab-sidebar'
|
||||
@import 'components/_tables'
|
||||
@import 'components/_creature'
|
||||
@import 'components/_vehicule'
|
||||
@@ -11,6 +11,7 @@
|
||||
&.sheet
|
||||
.window-content
|
||||
background: var(--mgt2-bgcolor-form)
|
||||
color: var(--mgt2-color-form)
|
||||
padding: 0
|
||||
|
||||
.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
65
system.json
65
system.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "mgt2",
|
||||
"version": "0.1.4",
|
||||
"version": "14.0.0",
|
||||
"title": "MGT2 - Mongoose Traveller (Unofficial)",
|
||||
"description": "An unofficial implementation of Mongoose Publishing Traveller (VO/VF). Traveller is the property of Mongoose Publishing, and can be purchased at https://www.mongoosepublishing.com",
|
||||
"background": "systems/mgt2/assets/screens/rosette-nebula-ngc2239-hoo.webp",
|
||||
@@ -35,9 +35,68 @@
|
||||
"path": "lang/fr.json"
|
||||
}
|
||||
],
|
||||
"documentTypes": {
|
||||
"Actor": {
|
||||
"character": {
|
||||
"htmlFields": [
|
||||
"personal.speciesText.descriptionLong",
|
||||
"biography",
|
||||
"finance.notes",
|
||||
"notes"
|
||||
]
|
||||
},
|
||||
"vehicule": {
|
||||
"htmlFields": [
|
||||
"description",
|
||||
"notes"
|
||||
]
|
||||
},
|
||||
"creature": {
|
||||
"htmlFields": [
|
||||
"biography",
|
||||
"notes"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
"armor": {
|
||||
"htmlFields": [ "description" ]
|
||||
},
|
||||
"career": {
|
||||
"htmlFields": [ "description" ]
|
||||
},
|
||||
"computer": {
|
||||
"htmlFields": [ "description" ]
|
||||
},
|
||||
"contact": {
|
||||
"htmlFields": [ "description", "notes" ]
|
||||
},
|
||||
"container": {
|
||||
"htmlFields": [ "description", "lockedDescription" ]
|
||||
},
|
||||
"disease": {
|
||||
"htmlFields": [ "description" ]
|
||||
},
|
||||
"equipment": {
|
||||
"htmlFields": [ "description" ]
|
||||
},
|
||||
"item": {
|
||||
"htmlFields": [ "description" ]
|
||||
},
|
||||
"species": {
|
||||
"htmlFields": [ "description", "descriptionLong" ]
|
||||
},
|
||||
"talent": {
|
||||
"htmlFields": [ "description" ]
|
||||
},
|
||||
"weapon": {
|
||||
"htmlFields": [ "description" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"compatibility": {
|
||||
"minimum": "11",
|
||||
"verified": "12.324"
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"grid": {
|
||||
"distance": 1.5,
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
"Actor": {
|
||||
"types": [
|
||||
"character",
|
||||
"vehicule"
|
||||
"vehicule",
|
||||
"creature"
|
||||
],
|
||||
"htmlFields": ["notes"],
|
||||
"htmlFields": ["notes", "biography"],
|
||||
"character": {},
|
||||
"vehicule": {}
|
||||
"vehicule": {},
|
||||
"creature": {}
|
||||
},
|
||||
"Item": {
|
||||
"types": [
|
||||
@@ -1,6 +1,6 @@
|
||||
<form class="{{cssClass}} flexcol" autocomplete="off">
|
||||
<div class="form-group">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.config.psionic" data-dtype="Boolean" {{checked system.config.psionic}} />{{ localize 'MGT2.Actor.ShowPsionicTalents' }}</label>
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="psionic" data-dtype="Boolean" {{checked system.config.psionic}} />{{ localize 'MGT2.Actor.ShowPsionicTalents' }}</label>
|
||||
</div>
|
||||
<fieldset>
|
||||
<legend>{{ localize 'MGT2.Actor.Initiative' }}</legend>
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
<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">
|
||||
<div class="character-header-img">
|
||||
<img class="profile" src="{{img}}" data-edit="img" title="{{name}}" height="130" width="100" />
|
||||
@@ -281,6 +272,22 @@
|
||||
<label class="upcase">{{ localize 'MGT2.Actor.Rads' }}</label>
|
||||
<input class="field" name="system.health.radiations" type="text" value="{{system.health.radiations}}" />
|
||||
</div>
|
||||
<!-- HEALING SECTION -->
|
||||
<div class="header upcase">{{ localize 'MGT2.Healing.Title' }}</div>
|
||||
<div class="healing-buttons" style="display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px;">
|
||||
<button type="button" data-action="heal" data-heal-type="firstaid" class="button sm" title="{{ localize 'MGT2.Healing.FirstAid' }}">
|
||||
<i class="fas fa-bandage"></i> {{ localize 'MGT2.Healing.FirstAid' }}
|
||||
</button>
|
||||
<button type="button" data-action="heal" data-heal-type="surgery" class="button sm" title="{{ localize 'MGT2.Healing.Surgery' }}">
|
||||
<i class="fas fa-flask-vial"></i> {{ localize 'MGT2.Healing.Surgery' }}
|
||||
</button>
|
||||
<button type="button" data-action="heal" data-heal-type="medical" class="button sm" title="{{ localize 'MGT2.Healing.MedicalCare' }}">
|
||||
<i class="fas fa-hospital"></i> {{ localize 'MGT2.Healing.MedicalCare' }}
|
||||
</button>
|
||||
<button type="button" data-action="heal" data-heal-type="natural" class="button sm" title="{{ localize 'MGT2.Healing.NaturalHealing' }}">
|
||||
<i class="fas fa-leaf"></i> {{ localize 'MGT2.Healing.NaturalHealing' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<div class="table-row heading color-1">
|
||||
<div class="row-item row-item-30 row-item-left upcase">{{ localize 'MGT2.Actor.Wounds' }}</div>
|
||||
@@ -387,7 +394,7 @@
|
||||
{{#each skills as |skill id|}}
|
||||
<div class="table-row" data-item-id="{{skill._id}}" role="rowgroup">
|
||||
<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 class="row-item row-item-center">{{skill.system.level}}</div>
|
||||
<div class="row-item item-controls">
|
||||
@@ -410,7 +417,7 @@
|
||||
{{#each psionics as |psionic id|}}
|
||||
<div class="table-row" data-item-id="{{psionic._id}}" role="rowgroup">
|
||||
<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 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>
|
||||
@@ -446,13 +453,13 @@
|
||||
{{#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="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 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-2 row-item-right flex-fix">{{weapon.weight}}</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix">
|
||||
<a class="item-control item-equip {{weapon.toggleClass}}" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-equip {{weapon.toggleClass}}" data-action="equipItem" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-storage-in" title="{{ localize 'MGT2.Actor.StoreItem' }}"><i class="fa-solid fa-inbox-in"></i></a>
|
||||
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditWeapon' }}"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteWeapon' }}"><i class="fas fa-trash"></i></a>
|
||||
@@ -471,13 +478,13 @@
|
||||
{{#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="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 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-2 row-item-right flex-fix">{{armor.weight}}</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix">
|
||||
<a class="item-control item-equip {{armor.toggleClass}}" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-equip {{armor.toggleClass}}" data-action="equipItem" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-storage-in" title="{{ localize 'MGT2.Actor.StoreItem' }}"><i class="fa-solid fa-inbox-in"></i></a>
|
||||
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditArmor' }}"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteArmor' }}"><i class="fas fa-trash"></i></a>
|
||||
@@ -496,7 +503,7 @@
|
||||
<div class="row-item row-item-30 row-item-left">{{augment.name}}</div>
|
||||
<div class="row-item row-item-40 row-item-left">{{augment.system.improvement}}</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix">
|
||||
<a class="item-control item-equip {{augment.toggleClass}}" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-equip {{augment.toggleClass}}" data-action="equipItem" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-storage-in" title="{{ localize 'MGT2.Actor.StoreItem' }}"><i class="fa-solid fa-inbox-in"></i></a>
|
||||
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditAugment' }}"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteAugment' }}"><i class="fas fa-trash"></i></a>
|
||||
@@ -514,14 +521,14 @@
|
||||
{{#each computers as |computer id|}}
|
||||
<div class="table-row drop-item-list" data-item-id="{{computer._id}}" role="rowgroup">
|
||||
<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 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}}
|
||||
</div>
|
||||
<div class="row-item row-item-2 row-item-right flex-fix">{{computer.weight}}</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix">
|
||||
<a class="item-control item-equip {{computer.toggleClass}}" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-equip {{computer.toggleClass}}" data-action="equipItem" title="Equip"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-storage-in" title="{{ localize 'MGT2.Actor.StoreItem' }}"><i class="fa-solid fa-inbox-in"></i></a>
|
||||
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditComputer' }}"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteComputer' }}"><i class="fas fa-trash"></i></a>
|
||||
@@ -566,7 +573,7 @@
|
||||
<div class="row-item row-item-2 row-item-center">{{equipment.system.quantity}}</div>
|
||||
<div class="row-item row-item-2 row-item-right flex-fix">{{equipment.weight}}</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix">
|
||||
<a class="item-control item-equip {{equipment.toggleClass}}" title="{{ localize 'MGT2.Actor.EquipUnequip' }}"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-equip {{equipment.toggleClass}}" data-action="equipItem" title="{{ localize 'MGT2.Actor.EquipUnequip' }}"><i class="fa-solid fa-shield-halved"></i></a>
|
||||
<a class="item-control item-storage-in" title="{{ localize 'MGT2.Actor.StoreEquipment' }}"><i class="fa-solid fa-inbox-in"></i></a>
|
||||
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditEquipment' }}"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteEquipment' }}"><i class="fas fa-trash"></i></a>
|
||||
@@ -697,7 +704,7 @@
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<label class="upcase">{{ localize 'MGT2.Actor.Notes' }}</label>
|
||||
<textarea name="system.finance.description" rows="3">{{system.finance.description}}</textarea>
|
||||
{{formInput systemFields.finance.fields.notes enriched=enrichedFinanceNotes value=system.finance.notes name="system.finance.notes" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -729,20 +736,27 @@
|
||||
</div>
|
||||
<div class="tab w100 h100" data-group="sidebar" data-tab="notes">
|
||||
<div class="header upcase">{{ localize 'MGT2.Actor.Notes' }}</div>
|
||||
{{editor system.notes target="system.notes" button=true editable=true}}
|
||||
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
|
||||
</div>
|
||||
<div class="tab w100 h100" data-group="sidebar" data-tab="biography">
|
||||
<div class="header upcase">{{ localize 'MGT2.Actor.Biography' }}</div>
|
||||
{{editor system.biography target="system.biography" button=true editable=true}}
|
||||
{{formInput systemFields.biography enriched=enrichedBiography value=system.biography name="system.biography" toggled=true}}
|
||||
</div>
|
||||
{{#if showTrash}}
|
||||
<!-- <div class="tab" data-group="inventory" data-tab="trash">
|
||||
<p>À FAIRE</p>
|
||||
</div> -->
|
||||
{{/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>
|
||||
<section class="actor-footer">
|
||||
<div><a name="config" title="Config" style="margin-right: 0.5rem;"><i class="fa-solid fa-gear"></i></a></div>
|
||||
</section>
|
||||
</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>
|
||||
273
templates/actors/creature-sheet.html
Normal file
273
templates/actors/creature-sheet.html
Normal file
@@ -0,0 +1,273 @@
|
||||
<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 : COMBAT (compétences + attaques + traits) ── --}}
|
||||
<div class="tab" data-group="primary" data-tab="combat">
|
||||
|
||||
{{!-- Compétences --}}
|
||||
<div class="header upcase">{{ localize 'MGT2.Creature.TabSkills' }}</div>
|
||||
<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 item-controls" style="flex: 0 0 3rem">
|
||||
{{#if isEditable}}<a data-action="addSkill" data-prop="skills" title="{{ localize 'MGT2.Creature.AddSkill' }}"><i class="fas fa-plus"></i></a>{{/if}}
|
||||
</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>
|
||||
|
||||
{{!-- Attaques --}}
|
||||
<div class="header upcase">{{ localize 'MGT2.Creature.TabAttacks' }}</div>
|
||||
<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.Creature.AttackSkill' }}</div>
|
||||
<div class="row-item row-item-left upcase" style="flex: 3">{{ localize 'MGT2.Items.Description' }}</div>
|
||||
<div class="row-item row-item-right item-controls" 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}}
|
||||
<select name="system.attacks.{{i}}.skill">
|
||||
<option value="-1">— {{ localize 'MGT2.RollPrompt.NoSkill' }} —</option>
|
||||
{{#each ../system.skills as |sk si|}}
|
||||
<option value="{{si}}" {{#if (eq si ../skill)}}selected{{/if}}>{{sk.name}} ({{showDM sk.level}})</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
{{else}}
|
||||
{{#if (gte atk.skill 0)}}
|
||||
<span>{{lookup (lookup ../system.skills atk.skill) "name"}}</span>
|
||||
{{else}}
|
||||
<span class="text-muted">—</span>
|
||||
{{/if}}
|
||||
{{/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>
|
||||
|
||||
{{!-- Traits --}}
|
||||
<div class="header upcase">{{ localize 'MGT2.Creature.TabTraits' }}</div>
|
||||
<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 item-controls" 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 combat --}}
|
||||
|
||||
{{!-- ── 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>
|
||||
{{formInput systemFields.biography enriched=enrichedBiography value=system.biography name="system.biography" toggled=true}}
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<label class="upcase">{{ localize 'MGT2.Items.Notes' }}</label>
|
||||
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
|
||||
</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="combat" title="{{ localize 'MGT2.Creature.TabCombat' }}"><i class="fa-solid fa-swords"></i><span class="tab-label">COMBAT</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>
|
||||
@@ -1,16 +1,124 @@
|
||||
<form class="{{cssClass}} flexcol" autocomplete="off" style="align-content: flex-start;align-items: baseline;overflow: hidden;height: 100%;">
|
||||
<div class="{{cssClass}} vehicule-sheet flexcol" style="overflow: hidden; height: 100%;">
|
||||
|
||||
<!-- ── Header ─────────────────────────────────────── -->
|
||||
<section class="vehicule-header">
|
||||
<div class="vehicule-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}}" />
|
||||
</div>
|
||||
<div class="vehicule-header-body">
|
||||
<input class="field-name" name="name" type="text" value="{{name}}" />
|
||||
<ul class="character-summary">
|
||||
<li class="w5-10"><input name="system.personal.title" type="text" value="{{system.personal.title}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderTITLE' }}" /></li>
|
||||
<li class="w2-10"><input name="system.personal.species" type="text" value="{{system.personal.species}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderSPECIES' }}" /></li>
|
||||
<li class="w1-10"><input name="system.personal.age" type="text" value="{{system.personal.age}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderAGE' }}" /></li>
|
||||
<li class="w2-10"><input name="system.personal.wup" type="text" value="{{system.personal.wup}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderUCP' }}" /></li>
|
||||
</ul>
|
||||
<input class="vehicule-name" name="name" type="text" value="{{name}}" />
|
||||
<div class="vehicule-header-stats">
|
||||
<div class="vehicule-stat-box vehicule-hull">
|
||||
<label>{{ localize 'MGT2.Vehicule.Hull' }}</label>
|
||||
<div class="vehicule-stat-value">
|
||||
<input type="number" name="system.life.value" value="{{system.life.value}}" />
|
||||
<span>/</span>
|
||||
<input type="number" name="system.life.max" value="{{system.life.max}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="vehicule-armor-group">
|
||||
<div class="vehicule-armor-label">{{ localize 'MGT2.Vehicule.Armor' }}</div>
|
||||
<div class="vehicule-armor-row">
|
||||
<div class="vehicule-stat-box vehicule-armor-box">
|
||||
<label>{{ localize 'MGT2.Vehicule.ArmorFront' }}</label>
|
||||
<div class="vehicule-stat-value">
|
||||
<input type="number" name="system.armor.front" value="{{system.armor.front}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="vehicule-stat-box vehicule-armor-box">
|
||||
<label>{{ localize 'MGT2.Vehicule.ArmorSides' }}</label>
|
||||
<div class="vehicule-stat-value">
|
||||
<input type="number" name="system.armor.sides" value="{{system.armor.sides}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="vehicule-stat-box vehicule-armor-box">
|
||||
<label>{{ localize 'MGT2.Vehicule.ArmorRear' }}</label>
|
||||
<div class="vehicule-stat-value">
|
||||
<input type="number" name="system.armor.rear" value="{{system.armor.rear}}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
||||
<!-- ── Body: tab content + vertical sidebar nav ──── -->
|
||||
<div class="vehicule-content">
|
||||
|
||||
<!-- Tab: Stats -->
|
||||
<div class="tab vehicule-tab" data-group="primary" data-tab="stats">
|
||||
<div class="vehicule-stats-grid">
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.SpeedCruise' }}</label>
|
||||
<select name="system.speed.cruise">
|
||||
{{selectOptions config.SpeedBands selected=system.speed.cruise localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.SpeedMax' }}</label>
|
||||
<select name="system.speed.maximum">
|
||||
{{selectOptions config.SpeedBands selected=system.speed.maximum localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.Agility' }}</label>
|
||||
<input type="number" name="system.agility" value="{{system.agility}}" />
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.Crew' }}</label>
|
||||
<input type="number" name="system.crew" value="{{system.crew}}" />
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.Passengers' }}</label>
|
||||
<input type="number" name="system.passengers" value="{{system.passengers}}" />
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.Cargo' }}</label>
|
||||
<input type="number" name="system.cargo" value="{{system.cargo}}" />
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.Shipping' }}</label>
|
||||
<input type="number" name="system.shipping" value="{{system.shipping}}" />
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.Cost' }}</label>
|
||||
<input type="number" name="system.cost" value="{{system.cost}}" />
|
||||
</div>
|
||||
|
||||
<div class="vehicule-field">
|
||||
<label>{{ localize 'MGT2.Vehicule.Autopilot' }}</label>
|
||||
<input type="number" name="system.skills.autopilot" value="{{system.skills.autopilot}}" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab: Description -->
|
||||
<div class="tab vehicule-tab" data-group="primary" data-tab="description">
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
|
||||
<!-- Vertical sidebar nav (positioned absolutely right of window) -->
|
||||
<nav class="sheet-sidebar tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="stats" title="{{ localize 'MGT2.Vehicule.TabStats' }}">
|
||||
<i class="fa-solid fa-gauge-high"></i>
|
||||
<span class="tab-label">STATS</span>
|
||||
</a>
|
||||
<a class="item tab-select" data-tab="description" title="{{ localize 'MGT2.Vehicule.TabDescription' }}">
|
||||
<i class="fa-solid fa-circle-info"></i>
|
||||
<span class="tab-label">INFO</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
49
templates/chat/creature-roll.html
Normal file
49
templates/chat/creature-roll.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<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}}" {{#if rollBreakdown}}data-tooltip="{{rollBreakdown}}"{{/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}}
|
||||
|
||||
{{#if effectStr}}
|
||||
<div class="mgt2-effect {{#if success}}is-success{{else}}is-failure{{/if}}">
|
||||
{{ localize 'MGT2.Chat.Roll.Effect' }} <span class="mgt2-effect-value">{{effectStr}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if showRollDamage}}
|
||||
<div class="mgt2-buttons">
|
||||
<button data-action="rollDamage">{{ localize 'MGT2.Chat.Roll.Damages' }}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
24
templates/chat/radiation.html
Normal file
24
templates/chat/radiation.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="mgt2-chat-roll mgt2-radiation-card">
|
||||
<div class="mgt2-roll-header">
|
||||
<span class="mgt2-roll-char-name">{{rollObjectName}}</span>
|
||||
<div class="mgt2-roll-meta">
|
||||
<span class="mgt2-roll-type mgt2-radiation-label">
|
||||
<i class="fa-solid fa-radiation"></i>
|
||||
{{ localize 'MGT2.Chat.Radiation.Title' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dice-roll">
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{formula}}</div>
|
||||
{{{tooltip}}}
|
||||
<h4 class="dice-total">{{total}} {{ localize 'MGT2.Chat.Radiation.Rads' }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mgt2-radiation-rules">
|
||||
<i class="fa-solid fa-triangle-exclamation"></i>
|
||||
{{ localize 'MGT2.Chat.Radiation.Rules' }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,46 +1,103 @@
|
||||
<div class="roll-info">
|
||||
<div class="roll-object-name">{{rollObjectName}}</div>
|
||||
<div class="mgt2-chat-roll">
|
||||
<div class="mgt2-roll-header">
|
||||
<span class="mgt2-roll-char-name">{{rollObjectName}}</span>
|
||||
{{#if rollTypeName}}
|
||||
<div class="mgt2-roll-meta">
|
||||
<span class="mgt2-roll-type">{{rollTypeName}}</span>
|
||||
{{#if rollDifficulty}}
|
||||
<div class="roll-type-group"><div class="roll-type-name">{{rollTypeName}}</div><div class="roll-type-name">{{ localize rollDifficultyLabel }}</div></div>
|
||||
{{else}}
|
||||
<div class="roll-type-name">{{rollTypeName}}</div>
|
||||
<span class="mgt2-roll-sep">•</span>
|
||||
<span class="mgt2-roll-difficulty">{{rollDifficultyLabel}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if rollMessage}}
|
||||
<div>{{rollMessage}}</div>
|
||||
<div class="mgt2-roll-modifier">{{rollMessage}}</div>
|
||||
{{/if}}
|
||||
{{#if rollModifiers}}
|
||||
{{#each rollModifiers as |rollModifier i| }}
|
||||
<div>{{rollModifier}}</div>
|
||||
<div class="mgt2-roll-modifiers">
|
||||
{{#each rollModifiers as |mod i|}}
|
||||
<span class="mgt2-roll-mod-tag">{{mod}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="dice-roll">
|
||||
|
||||
<div class="dice-roll">
|
||||
{{#if flavor}}
|
||||
<div class="dice-flavor">{{flavor}}</div>
|
||||
{{/if}}
|
||||
<div class="dice-result"><div class="dice-formula">{{formula}}</div>{{{tooltip}}}<h4 class="dice-total">{{total}}</h4></div>
|
||||
</div>
|
||||
{{#if rollSuccess}}
|
||||
<div class="roll-success">{{ localize 'MGT2.Chat.Roll.Success' }}</div>
|
||||
{{else if rollFailure}}
|
||||
<div class="roll-success">{{ localize 'MGT2.Chat.Roll.Failure' }}</div>
|
||||
{{/if}}
|
||||
{{#if showButtons}}
|
||||
<div class="mgt2-buttons">
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{formula}}</div>
|
||||
{{{tooltip}}}
|
||||
<h4 class="dice-total {{#if rollSuccess}}success{{else if rollFailure}}failure{{/if}}" {{#if rollBreakdown}}data-tooltip="{{rollBreakdown}}"{{/if}}>{{total}}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if apValue}}
|
||||
<div class="mgt2-ap-info" data-tooltip="{{ localize 'MGT2.Chat.Roll.APIgnoreHint' }}">
|
||||
<i class="fa-solid fa-shield-halved"></i>
|
||||
{{ localize 'MGT2.Chat.Roll.APIgnore' }} {{apValue}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if blastRadius}}
|
||||
<div class="mgt2-blast-info" data-tooltip="{{ localize 'MGT2.Chat.Roll.BlastHint' }}">
|
||||
<i class="fa-solid fa-burst"></i>
|
||||
{{ localize 'MGT2.Chat.Roll.BlastArea' }} {{blastRadius}}m — {{ localize 'MGT2.Chat.Roll.BlastRules' }}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if stunWeapon}}
|
||||
<div class="mgt2-stun-info" data-tooltip="{{ localize 'MGT2.Chat.Roll.StunHint' }}">
|
||||
<i class="fa-solid fa-bolt"></i>
|
||||
{{ localize 'MGT2.Chat.Roll.StunWeapon' }}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if radiationWeapon}}
|
||||
<div class="mgt2-radiation-info" data-tooltip="{{ localize 'MGT2.Chat.Radiation.Hint' }}">
|
||||
<i class="fa-solid fa-radiation"></i>
|
||||
{{ localize 'MGT2.Chat.Radiation.Badge' }}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if autoInfo}}
|
||||
<div class="mgt2-auto-info">
|
||||
<i class="fa-solid fa-gun"></i> {{autoInfo}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#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 rollEffectStr}}
|
||||
<div class="mgt2-effect {{#if rollSuccess}}is-success{{else}}is-failure{{/if}}">
|
||||
{{ localize 'MGT2.Chat.Roll.Effect' }} <span class="mgt2-effect-value">{{rollEffectStr}}</span>
|
||||
{{#if healingAmount}}<span class="mgt2-healing-amount">({{ localize 'MGT2.Healing.Heals' }} {{healingAmount}})</span>{{/if}}
|
||||
{{#if surgeryDamageAmount}}<span class="mgt2-healing-amount">({{ localize 'MGT2.Healing.SurgeryDamage' }} {{surgeryDamageAmount}})</span>{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if showButtons}}
|
||||
<div class="mgt2-buttons">
|
||||
{{#if hasDamage}}
|
||||
<button data-action="damage" title="{{ localize 'MGT2.Chat.Roll.ApplyDamages' }}"><i class="fa-regular fa-heart-circle-minus"></i></button>
|
||||
<!-- <button data-action="healing" data-multiplier="1" title="Apply Healing"><i class="fa-regular fa-heart-circle-plus"></i></button> -->
|
||||
{{/if}}
|
||||
{{#if showRollRequest}}
|
||||
<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>
|
||||
<button data-action="rollDamage">{{ localize 'MGT2.Chat.Roll.Damages' }}</button>
|
||||
{{/if}}
|
||||
{{#each cardButtons as |cardButton i| }}
|
||||
<button data-index="{{i}}" title="{{cardButton.label}}">{{cardButton.label}}</button>
|
||||
{{#if radiationWeapon}}
|
||||
<button data-action="rollRadiation" title="{{ localize 'MGT2.Chat.Radiation.RollButton' }}">
|
||||
<i class="fa-solid fa-radiation"></i> {{ localize 'MGT2.Chat.Radiation.RollButton' }}
|
||||
</button>
|
||||
{{/if}}
|
||||
{{#each cardButtons as |cardButton|}}
|
||||
<button data-action="{{cardButton.action}}" title="{{cardButton.label}}">{{cardButton.label}}</button>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,35 +1,43 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header">
|
||||
<label>{{localize 'MGT2.TYPES.Item.armor'}}</label>
|
||||
<div class="item-type-bar">
|
||||
<span class="item-type-label"><i class="fas fa-shield-halved"></i> {{localize 'MGT2.TYPES.Item.armor'}}</span>
|
||||
</div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item.html }}
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
<div class="w-100">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" />
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
<a class="item tab-select" data-tab="tab3">{{ localize 'MGT2.Items.Configuration' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group w3-10">
|
||||
<div class="item-details-grid">
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item-tab.html }}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Protection' }}</label>
|
||||
<input type="text" name="system.protection" value="{{system.protection}}" data-dtype="String" class="short" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Radiations' }}</label>
|
||||
<input type="number" name="system.radiations" value="{{system.radiations}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.equipped" data-dtype="Boolean" {{checked system.equipped}} />{{ localize 'MGT2.Items.Equipped' }}</label>
|
||||
</div>
|
||||
<div class="field-group w3-10">
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.powered" data-dtype="Boolean" {{checked system.powered}} />{{ localize 'MGT2.Items.Powered' }}</label>
|
||||
</div>
|
||||
{{#if hadContainer}}
|
||||
<div class="field-group w3-10">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Storage' }}</label>
|
||||
<select name="system.container.id">
|
||||
{{selectOptions containers selected=system.container.id valueAttr="_id" labelAttr="name"}}
|
||||
@@ -37,29 +45,19 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Radiations' }}</label>
|
||||
<input type="number" name="system.radiations" value="{{system.radiations}}" data-dtype="Number" />
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Protection' }}</label>
|
||||
<input type="text" name="system.protection" value="{{system.protection}}" data-dtype="String" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-container mt-1">
|
||||
<div class="table-row heading color-2">
|
||||
<div class="row-item row-item-left row-item-30 flex-fix upcase">{{ localize 'MGT2.Items.Options' }}</div>
|
||||
<div class="table-container">
|
||||
<div class="table-row heading">
|
||||
<div class="row-item row-item-left row-item-30">{{ localize 'MGT2.Items.Options' }}</div>
|
||||
<div class="row-item row-item-left">Description</div>
|
||||
<div class="row-item row-item-right row-item-5 flex-fix"><a class="options-create" data-property="options"><i class="fas fa-plus"></i></a></div>
|
||||
<div class="row-item row-item-right"><a class="options-create" data-property="options"><i class="fas fa-plus"></i></a></div>
|
||||
</div>
|
||||
{{#each system.options as |option i| }}
|
||||
<div class="table-row dropitem options-part" data-options-part="{{i}}" data-property="options" role="rowgroup">
|
||||
<div class="row-item row-item-left row-item-30 flex-fix"><input type="text" name="system.options.{{i}}.name" value="{{option.name}}" /></div>
|
||||
<div class="row-item row-item-left row-item-30"><input type="text" name="system.options.{{i}}.name" value="{{option.name}}" /></div>
|
||||
<div class="row-item row-item-left">
|
||||
<textarea name="system.options.{{i}}.description" rows="3">{{option.description}}</textarea>
|
||||
<textarea name="system.options.{{i}}.description" rows="2">{{option.description}}</textarea>
|
||||
</div>
|
||||
<div class="row-item row-item-right row-item-5 flex-fix item-controls">
|
||||
<div class="row-item row-item-right item-controls">
|
||||
<a class="item-control options-delete" title="Delete Option"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,5 +68,4 @@
|
||||
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,44 +1,50 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header"><label class="upcase">{{ localize 'MGT2.Items.Career' }}</label></div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<div class="field-group mt-1">
|
||||
<label class="upcase">{{ localize 'MGT2.Items.Terms' }}</label>
|
||||
<input type="number" name="system.terms" value="{{system.terms}}" data-dtype="Number" />
|
||||
<div class="item-type-bar">
|
||||
<span class="item-type-label"><i class="fas fa-briefcase"></i> {{ localize 'MGT2.Items.Career' }}</span>
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<label class="upcase">{{ localize 'MGT2.Items.Rank' }}</label>
|
||||
<input type="number" name="system.rank" value="{{system.rank}}" data-dtype="Number" />
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" data-dtype="String" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" data-dtype="String" />
|
||||
<div class="field-group mt-1">
|
||||
<label class="upcase">{{ localize 'MGT2.Items.Assignment' }}</label>
|
||||
<input type="text" name="system.assignment" value="{{system.assignment}}" data-dtype="String" />
|
||||
</div>
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
<a class="item tab-select" data-tab="events">{{ localize 'MGT2.Items.EventsMishaps' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Terms' }}</label>
|
||||
<input type="number" name="system.terms" value="{{system.terms}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Rank' }}</label>
|
||||
<input type="number" name="system.rank" value="{{system.rank}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Assignment' }}</label>
|
||||
<input type="text" name="system.assignment" value="{{system.assignment}}" data-dtype="String" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="events">
|
||||
<div class="table-container color-2 mt-1">
|
||||
<div class="table-row heading color-2">
|
||||
<div class="row-item row-item-left upcase">{{ localize 'MGT2.Items.Age' }}</div>
|
||||
<div class="row-item row-item-left upcase">{{ localize 'MGT2.Items.Details' }}</div>
|
||||
<div class="row-item item-controls"><a class="event-create"><i class="fas fa-plus"></i></a></div>
|
||||
<div class="table-container">
|
||||
<div class="table-row heading">
|
||||
<div class="row-item row-item-left">{{ localize 'MGT2.Items.Age' }}</div>
|
||||
<div class="row-item row-item-left">{{ localize 'MGT2.Items.Details' }}</div>
|
||||
<div class="row-item row-item-right item-controls"><a class="event-create"><i class="fas fa-plus"></i></a></div>
|
||||
</div>
|
||||
{{#each system.events as |event i| }}
|
||||
<div class="table-row dropitem events-part" data-events-part="{{i}}" role="rowgroup">
|
||||
<div class="row-item row-item-left"><input type="number" name="system.events.{{i}}.age" value="{{event.age}}" data-dtype="Number" /></div>
|
||||
<div class="row-item row-item-left">
|
||||
<textarea name="system.events.{{i}}.description" rows="3">{{event.description}}</textarea>
|
||||
<textarea name="system.events.{{i}}.description" rows="2">{{event.description}}</textarea>
|
||||
</div>
|
||||
<div class="row-item item-controls">
|
||||
<div class="row-item row-item-right item-controls">
|
||||
<a class="item-control event-delete" title="Delete Event"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,5 +52,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,32 +1,36 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header">
|
||||
<label>{{localize 'MGT2.EquipmentSubType.computer'}}</label>
|
||||
<div class="item-type-bar">
|
||||
<span class="item-type-label"><i class="fas fa-desktop"></i> {{localize 'MGT2.EquipmentSubType.computer'}}</span>
|
||||
</div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item.html }}
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
<div class="w-100">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" />
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
<a class="item tab-select" data-tab="tab3">{{ localize 'MGT2.Items.Configuration' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group">
|
||||
<div class="item-details-grid">
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item-tab.html }}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Processing' }}</label>
|
||||
<input type="number" name="system.processing" value="{{system.processing}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.equipped" data-dtype="Boolean" {{checked system.equipped}} />{{ localize 'MGT2.Items.Equipped' }}</label>
|
||||
</div>
|
||||
{{#if hadContainer}}
|
||||
<div class="field-group">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Storage' }}</label>
|
||||
<select name="system.container.id">
|
||||
{{selectOptions containers selected=system.container.id valueAttr="_id" labelAttr="name"}}
|
||||
@@ -34,21 +38,17 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Processing' }}</label>
|
||||
<input type="number" name="system.processing" value="{{system.processing}}" data-dtype="Number" />
|
||||
</div>
|
||||
<div class="table-container mt-1">
|
||||
<div class="table-row heading color-2">
|
||||
<div class="row-item row-item-left flex-grow-2 upcase">{{ localize 'MGT2.Items.Options' }}</div>
|
||||
<div class="row-item row-item-left flex-grow-3">{{ localize 'MGT2.Items.Description' }}</div>
|
||||
<div class="table-container" style="margin-top:8px;">
|
||||
<div class="table-row heading">
|
||||
<div class="row-item row-item-left">{{ localize 'MGT2.Items.Options' }}</div>
|
||||
<div class="row-item row-item-left">{{ localize 'MGT2.Items.Description' }}</div>
|
||||
<div class="row-item row-item-right"><a class="options-create" data-property="options"><i class="fas fa-plus"></i></a></div>
|
||||
</div>
|
||||
{{#each system.options as |option i| }}
|
||||
<div class="table-row dropitem options-part" data-options-part="{{i}}" data-property="options" role="rowgroup">
|
||||
<div class="row-item row-item-left flex-grow-2"><input type="text" name="system.options.{{i}}.name" value="{{option.name}}" /></div>
|
||||
<div class="row-item row-item-left flex-grow-3">
|
||||
<textarea name="system.options.{{i}}.description" rows="3">{{option.description}}</textarea>
|
||||
<div class="row-item row-item-left"><input type="text" name="system.options.{{i}}.name" value="{{option.name}}" /></div>
|
||||
<div class="row-item row-item-left">
|
||||
<textarea name="system.options.{{i}}.description" rows="2">{{option.description}}</textarea>
|
||||
</div>
|
||||
<div class="row-item row-item-right item-controls">
|
||||
<a class="item-control options-delete" title="Delete Option"><i class="fas fa-trash"></i></a>
|
||||
@@ -61,5 +61,4 @@
|
||||
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,84 +1,80 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header"><label class="upcase">{{ localize 'MGT2.Items.Contact' }}</label></div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Relation' }}</label>
|
||||
<select name="system.relation">
|
||||
{{selectOptions config.ContactRelations selected = system.relation localize = true}}
|
||||
</select>
|
||||
|
||||
<div class="item-type-bar">
|
||||
<span class="item-type-label"><i class="fas fa-address-card"></i> {{ localize 'MGT2.Items.Contact' }}</span>
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Attitude' }}</label>
|
||||
<select name="system.attitude">
|
||||
{{selectOptions config.Attitudes selected = system.attitude localize = true}}
|
||||
</select>
|
||||
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Status' }}</label>
|
||||
<select name="system.status">
|
||||
{{selectOptions config.ContactStatus selected = system.status localize = true}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100 h100 flexcol">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" style="flex-grow: 0;" />
|
||||
<div class="field-groups mt-1" style="flex-grow: 0;">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Species' }}</label>
|
||||
<input type="text" name="system.species" value="{{system.species}}" data-dtype="String" />
|
||||
</div>
|
||||
{{#if settings.useGender}}
|
||||
<div class="field-group" style="margin:0 1rem">
|
||||
<label>{{ localize 'MGT2.Gender' }}</label>
|
||||
<input type="text" name="system.gender" value="{{system.gender}}" data-dtype="String" />
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if settings.usePronouns}}
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Pronouns' }}</label>
|
||||
<input type="text" name="system.pronouns" value="{{system.pronouns}}" data-dtype="String" />
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary" style="flex-grow: 0;">
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Informations' }}</a>
|
||||
<a class="item tab-select" data-tab="description">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="notes">{{ localize 'MGT2.Items.Notes' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Relation' }}</label>
|
||||
<select name="system.relation">
|
||||
{{selectOptions config.ContactRelations selected=system.relation localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Attitude' }}</label>
|
||||
<select name="system.attitude">
|
||||
{{selectOptions config.Attitudes selected=system.attitude localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Status' }}</label>
|
||||
<select name="system.status">
|
||||
{{selectOptions config.ContactStatus selected=system.status localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
{{#if settings.useGender}}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Gender' }}</label>
|
||||
<input type="text" name="system.gender" value="{{system.gender}}" data-dtype="String" />
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Species' }}</label>
|
||||
<input type="text" name="system.species" value="{{system.species}}" data-dtype="String" />
|
||||
</div>
|
||||
{{#if settings.usePronouns}}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Pronouns' }}</label>
|
||||
<input type="text" name="system.pronouns" value="{{system.pronouns}}" data-dtype="String" />
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Title' }}</label>
|
||||
<input type="text" name="system.title" value="{{system.title}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Nickname' }}</label>
|
||||
<input type="text" name="system.nickname" value="{{system.nickname}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group flex-1">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Homeworld' }}</label>
|
||||
<input type="text" name="system.homeworld" value="{{system.homeworld}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-group flex-1">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Location' }}</label>
|
||||
<input type="text" name="system.location" value="{{system.location}}" data-dtype="String" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Occupation' }}</label>
|
||||
<input type="text" name="system.occupation" value="{{system.occupation}}" data-dtype="String" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab w100 h100" data-group="primary" data-tab="description">
|
||||
{{editor system.description.value target="system.description" button=true editable=true}}
|
||||
</div>
|
||||
<div class="tab w100 h100" data-group="primary" data-tab="notes">
|
||||
{{editor system.notes target="system.notes" button=true editable=true}}
|
||||
<div class="tab" data-group="primary" data-tab="description">
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="notes">
|
||||
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,55 +1,59 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header"><label class="upcase">{{ localize 'MGT2.Items.Container' }}</label></div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
{{#if system.locked}}
|
||||
<div class="field-group mt-05">
|
||||
<i class="fa-solid fa-lock"></i><label class="upcase">{{ localize 'MGT2.Items.Locked' }}</label>
|
||||
<div class="item-type-bar">
|
||||
<span class="item-type-label"><i class="fas fa-box"></i> {{ localize 'MGT2.Items.Container' }}</span>
|
||||
{{#if system.locked}}<span class="item-type-label" style="margin-left:8px;"><i class="fa-solid fa-lock"></i></span>{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="field-group mt-05">
|
||||
<label>{{ localize 'MGT2.Items.Weight' }} ({{unitlabels.weight}})</label>
|
||||
<input type="number" value="{{weight}}" readonly />
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" data-dtype="String" />
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: 1">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" data-dtype="String" />
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
{{#if isGM}}
|
||||
<a class="item tab-select" data-tab="tab3">{{ localize 'MGT2.Items.Configuration' }}</a>
|
||||
{{/if}}
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="field-groups mt-05">
|
||||
<div class="field-group flex-1">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.onHand" data-dtype="Boolean" {{checked system.onHand}} />{{ localize 'MGT2.Items.OnHand' }}</label>
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Weight' }} ({{unitlabels.weight}})</label>
|
||||
<input type="number" value="{{weight}}" readonly style="opacity:0.7;" class="short" />
|
||||
</div>
|
||||
{{#if isGM}}
|
||||
<div class="field-group flex-1">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.locked" data-dtype="Boolean" {{checked system.locked}} />{{ localize 'MGT2.Items.Locked' }}</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="field-group flex-1">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Location' }}</label>
|
||||
<input type="text" name="system.location" value="{{system.location}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox">
|
||||
<input type="checkbox" name="system.onHand" id="onhand-{{item.id}}" data-dtype="Boolean" {{checked system.onHand}} />
|
||||
{{ localize 'MGT2.Items.OnHand' }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab3">
|
||||
{{#if isGM}}
|
||||
<div class="field-group mt-05">
|
||||
<label>{{ localize 'MGT2.Items.LockedDescription' }}</label>
|
||||
<textarea name="system.lockedDescription" rows="6">{{system.lockedDescription}}</textarea>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox">
|
||||
<input type="checkbox" name="system.locked" id="locked-{{item.id}}" data-dtype="Boolean" {{checked system.locked}} />
|
||||
{{ localize 'MGT2.Items.Locked' }}
|
||||
</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if isGM}}
|
||||
<div class="tab" data-group="primary" data-tab="tab3">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.LockedDescription' }}</label>
|
||||
{{formInput systemFields.lockedDescription enriched=enrichedLockedDescription value=system.lockedDescription name="system.lockedDescription" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,45 +1,51 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header">
|
||||
<div class="item-type-bar">
|
||||
{{#if (eq system.subType "disease")}}
|
||||
<label>{{localize 'MGT2.DiseaseSubType.disease'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-bacterium"></i> {{localize 'MGT2.DiseaseSubType.disease'}}</span>
|
||||
{{else if (eq system.subType "poison")}}
|
||||
<label>{{localize 'MGT2.DiseaseSubType.poison'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-skull-crossbones"></i> {{localize 'MGT2.DiseaseSubType.poison'}}</span>
|
||||
{{else}}
|
||||
<label>{{localize 'MGT2.DiseaseSubType.wound'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-heart-crack"></i> {{localize 'MGT2.DiseaseSubType.wound'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<div class="field-group mt-1">
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Type' }}</label>
|
||||
<select name="system.subType">
|
||||
{{selectOptions config.DiseaseSubType selected = system.subType localize = true}}
|
||||
{{selectOptions config.DiseaseSubType selected=system.subType localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" />
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group w3-10">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Difficulty' }}</label>
|
||||
<select name="system.difficulty">
|
||||
{{selectOptions config.Difficulty selected = system.difficulty localize = true}}
|
||||
{{selectOptions config.Difficulty selected=system.difficulty localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-group w3-10" style="margin: 0 1rem;">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Damage' }}</label>
|
||||
<input type="text" name="system.damage" value="{{system.damage}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-group w3-10">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Interval' }}</label>
|
||||
<input type="text" name="system.interval" value="{{system.interval}}" data-dtype="String" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-group mt-1 w-100">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,46 +1,46 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header">
|
||||
<div class="item-type-bar">
|
||||
{{#if (eq system.subType "augment")}}
|
||||
<label>{{localize 'MGT2.EquipmentSubType.augment'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-dna"></i> {{localize 'MGT2.EquipmentSubType.augment'}}</span>
|
||||
{{else if (eq system.subType "trinket")}}
|
||||
<label>{{localize 'MGT2.EquipmentSubType.trinket'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-gem"></i> {{localize 'MGT2.EquipmentSubType.trinket'}}</span>
|
||||
{{else if (eq system.subType "clothing")}}
|
||||
<label>{{localize 'MGT2.EquipmentSubType.clothing'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-shirt"></i> {{localize 'MGT2.EquipmentSubType.clothing'}}</span>
|
||||
{{else}}
|
||||
<label>{{localize 'MGT2.EquipmentSubType.equipment'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-toolbox"></i> {{localize 'MGT2.EquipmentSubType.equipment'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Type' }}</label>
|
||||
<select name="system.subType">
|
||||
{{selectOptions config.EquipmentSubType selected = system.subType localize = true}}
|
||||
</select>
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item.html }}
|
||||
</div>
|
||||
<div class="w-100">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" />
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
<a class="item tab-select" data-tab="tab3">{{ localize 'MGT2.Items.Configuration' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.equipped" data-dtype="Boolean" {{checked system.equipped}} />Equipped</label>
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Type' }}</label>
|
||||
<select name="system.subType">
|
||||
{{selectOptions config.EquipmentSubType selected=system.subType localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item-tab.html }}
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.equipped" data-dtype="Boolean" {{checked system.equipped}} />{{ localize 'MGT2.Items.Equipped' }}</label>
|
||||
</div>
|
||||
{{#if hadContainer}}
|
||||
<div class="field-group">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Storage' }}</label>
|
||||
<select name="system.container.id">
|
||||
{{selectOptions containers selected=system.container.id valueAttr="_id" labelAttr="name"}}
|
||||
@@ -53,5 +53,4 @@
|
||||
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,58 +1,57 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header">
|
||||
<div class="item-type-bar">
|
||||
{{#if (eq system.subType "loot")}}
|
||||
<label>{{localize 'MGT2.ItemSubType.loot'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-coins"></i> {{localize 'MGT2.ItemSubType.loot'}}</span>
|
||||
{{else}}
|
||||
<label>{{localize 'MGT2.ItemSubType.software'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-floppy-disk"></i> {{localize 'MGT2.ItemSubType.software'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Type' }}</label>
|
||||
<select name="system.subType">
|
||||
{{selectOptions config.ItemSubType selected = system.subType localize = true}}
|
||||
</select>
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item.html }}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" />
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Type' }}</label>
|
||||
<select name="system.subType">
|
||||
{{selectOptions config.ItemSubType selected=system.subType localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item-tab.html }}
|
||||
{{#if hadContainer}}
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Storage' }}</label>
|
||||
<select name="system.container.id">
|
||||
{{selectOptions containers selected=system.container.id valueAttr="_id" labelAttr="name"}}
|
||||
</select>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if (eq system.subType "software")}}
|
||||
<div class="field-group">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Bandwidth' }}</label>
|
||||
<input type="number" name="system.software.bandwidth" value="{{system.software.bandwidth}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
{{#if hadContainer}}
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Computer' }}</label>
|
||||
<select name="system.software.computerId">
|
||||
{{selectOptions computers selected=system.software.computerId valueAttr="_id" labelAttr="name"}}
|
||||
</select>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Storage' }}</label>
|
||||
<select name="system.container.id">
|
||||
{{selectOptions containers selected=system.container.id valueAttr="_id" labelAttr="name"}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if (eq system.subType "software")}}
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Bandwidth' }}</label>
|
||||
<input type="number" name="system.software.bandwidth" value="{{system.software.bandwidth}}" data-dtype="Number" />
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
24
templates/items/parts/sheet-physical-item-tab.html
Normal file
24
templates/items/parts/sheet-physical-item-tab.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Quantity' }}</label>
|
||||
<input type="number" name="system.quantity" value="{{system.quantity}}" data-dtype="Number" integer="true" positive="true" class="short" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Weight' }} ({{unitlabels.weight}})</label>
|
||||
<input type="number" name="weight" value="{{weight}}" data-dtype="Number" step="0.5" class="short" />
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox">
|
||||
<input type="checkbox" name="system.weightless" data-dtype="Boolean" {{checked system.weightless}} />
|
||||
{{ localize 'MGT2.Items.Weightless' }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Cost' }}</label>
|
||||
<input type="number" name="system.cost" value="{{system.cost}}" data-dtype="Number" step="1" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.TL' }}</label>
|
||||
<select name="system.tl">
|
||||
{{selectOptions config.TL selected=system.tl localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
@@ -1,21 +1,22 @@
|
||||
<div class="field-group mt-05">
|
||||
<label>{{ localize 'MGT2.Items.Quantity' }}</label>
|
||||
<div class="item-stat-pill">
|
||||
<span class="stat-label">{{ localize 'MGT2.Items.Quantity' }}</span>
|
||||
<input type="number" name="system.quantity" value="{{system.quantity}}" data-dtype="Number" integer="true" positive="true" />
|
||||
</div>
|
||||
<div class="field-group mt-05">
|
||||
<label>{{ localize 'MGT2.Items.Weight' }} ({{unitlabels.weight}})</label>
|
||||
<div class="item-stat-pill">
|
||||
<span class="stat-label">{{ localize 'MGT2.Items.Weight' }} ({{unitlabels.weight}})</span>
|
||||
<input type="number" name="weight" value="{{weight}}" data-dtype="Number" step="0.5" />
|
||||
</div>
|
||||
<div class="field-group mt-05">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.weightless" data-dtype="Boolean" {{checked system.weightless}} />{{ localize 'MGT2.Items.Weightless' }}</label>
|
||||
<div class="item-stat-pill-checkbox">
|
||||
<input type="checkbox" name="system.weightless" id="weightless-{{item.id}}" data-dtype="Boolean" {{checked system.weightless}} />
|
||||
<label for="weightless-{{item.id}}">{{ localize 'MGT2.Items.Weightless' }}</label>
|
||||
</div>
|
||||
<div class="field-group mt-05">
|
||||
<label>{{ localize 'MGT2.Items.Cost' }}</label>
|
||||
<div class="item-stat-pill">
|
||||
<span class="stat-label">{{ localize 'MGT2.Items.Cost' }}</span>
|
||||
<input type="number" name="system.cost" value="{{system.cost}}" data-dtype="Number" step="1" />
|
||||
</div>
|
||||
<div class="field-group mt-05">
|
||||
<label>{{ localize 'MGT2.Items.TL' }}</label>
|
||||
<div class="item-stat-pill">
|
||||
<span class="stat-label">{{ localize 'MGT2.Items.TL' }}</span>
|
||||
<select name="system.tl">
|
||||
{{selectOptions config.TL selected = system.tl localize = true}}
|
||||
</select>
|
||||
</select>
|
||||
</div>
|
||||
@@ -1,63 +1,62 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header"><label>{{ localize 'MGT2.Specie' }}</label></div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<div class="item-type-bar">
|
||||
<span class="item-type-label"><i class="fas fa-dna"></i> {{ localize 'MGT2.Specie' }}</span>
|
||||
</div>
|
||||
<div class="w-100" style="display: flex;flex-direction: column;justify-content: flex-start;align-items: stretch;">
|
||||
<input class="field item-name" name="name" type="text" value="{{item.name}}" />
|
||||
<div class="field-group mt-1">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.DetailedDescription' }}</a>
|
||||
<a class="item tab-select" data-tab="tab3">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab w100 h100" data-group="primary" data-tab="tab2">
|
||||
{{editor system.descriptionLong target="system.descriptionLong" button=true editable=true}}
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
{{formInput systemFields.descriptionLong enriched=enrichedDescriptionLong value=system.descriptionLong name="system.descriptionLong" toggled=true}}
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab3">
|
||||
<div class="table-container">
|
||||
<div class="table-row heading color-2">
|
||||
<div class="row-item row-item-left upcase">{{ localize 'MGT2.Items.Characteristics' }}</div>
|
||||
<div class="row-item row-item-center row-item-15 flex-fix">{{ localize 'MGT2.Items.Modifiers' }}</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix"><a class="modifiers-create"><i class="fas fa-plus"></i></a></div>
|
||||
<div class="table-row heading">
|
||||
<div class="row-item row-item-left">{{ localize 'MGT2.Items.Characteristics' }}</div>
|
||||
<div class="row-item row-item-left" style="flex:0 0 120px;">{{ localize 'MGT2.Items.Modifiers' }}</div>
|
||||
<div class="row-item row-item-right item-controls"><a class="modifiers-create"><i class="fas fa-plus"></i></a></div>
|
||||
</div>
|
||||
{{#each system.modifiers as |modifier i| }}
|
||||
<div class="table-row modifiers-part" data-modifiers-part="{{i}}" role="rowgroup">
|
||||
<div class="row-item row-item-left">
|
||||
<select name="system.modifiers.{{i}}.characteristic">
|
||||
{{selectOptions ../config.Characteristics selected=modifier.characteristic localize = true}}
|
||||
{{selectOptions ../config.Characteristics selected=modifier.characteristic localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="row-item row-item-left row-item-15 flex-fix">
|
||||
<div class="row-item row-item-left" style="flex:0 0 120px;">
|
||||
<input type="number" name="system.modifiers.{{i}}.value" value="{{modifier.value}}" />
|
||||
</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix">
|
||||
<div class="row-item row-item-right item-controls">
|
||||
<a class="item-control modifiers-delete" title="Delete Trait"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="table-container mt-1">
|
||||
<div class="table-row heading color-2">
|
||||
<div class="row-item row-item-30 row-item-left upcase">{{ localize 'MGT2.Items.Traits' }}</div>
|
||||
<div class="table-container" style="margin-top:8px;">
|
||||
<div class="table-row heading">
|
||||
<div class="row-item row-item-left" style="flex:0 0 30%;">{{ localize 'MGT2.Items.Traits' }}</div>
|
||||
<div class="row-item row-item-left">{{ localize 'MGT2.Items.Description' }}</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix"><a class="options-create" data-property="traits"><i class="fas fa-plus"></i></a></div>
|
||||
<div class="row-item row-item-right item-controls"><a class="options-create" data-property="traits"><i class="fas fa-plus"></i></a></div>
|
||||
</div>
|
||||
{{#each system.traits as |trait i| }}
|
||||
<div class="table-row options-part" data-options-part="{{i}}" data-property="traits" role="rowgroup">
|
||||
<div class="row-item row-item-30 row-item-left"><input type="text" name="system.traits.{{i}}.name" value="{{trait.name}}" /></div>
|
||||
<div class="row-item row-item-left" style="flex:0 0 30%;"><input type="text" name="system.traits.{{i}}.name" value="{{trait.name}}" /></div>
|
||||
<div class="row-item row-item-left">
|
||||
<textarea name="system.traits.{{i}}.description" rows="3">{{trait.description}}</textarea>
|
||||
<textarea name="system.traits.{{i}}.description" rows="2">{{trait.description}}</textarea>
|
||||
</div>
|
||||
<div class="row-item row-item-15 item-controls flex-fix">
|
||||
<div class="row-item row-item-right item-controls">
|
||||
<a class="item-control options-delete" title="Delete Trait"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,6 +64,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,79 +1,84 @@
|
||||
<div class="{{cssClass}} flexrow itemsheet">
|
||||
<div class="itemsheet-header">
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="item-type-bar">
|
||||
{{#if (eq system.subType "skill")}}
|
||||
<label>{{localize 'MGT2.TalentSubType.skill'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-star"></i> {{localize 'MGT2.TalentSubType.skill'}}</span>
|
||||
{{else if (eq system.subType "psionic")}}
|
||||
<label>{{localize 'MGT2.TalentSubType.psionic'}}</label>
|
||||
<span class="item-type-label"><i class="fas fa-brain"></i> {{localize 'MGT2.TalentSubType.psionic'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<div class="field-group mt-1">
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
<a class="item tab-select" data-tab="tab3">{{ localize 'MGT2.Items.Configuration' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
|
||||
{{!-- Tab 1 : Description --}}
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- Tab 2 : Détails --}}
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Type' }}</label>
|
||||
<select name="system.subType">
|
||||
{{selectOptions config.TalentSubType selected = system.subType localize = true}}
|
||||
{{selectOptions config.TalentSubType selected=system.subType localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Level' }}</label>
|
||||
<input type="number" name="system.level" value="{{system.level}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
<div class="w-100">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" />
|
||||
{{#if (eq system.subType "skill")}}
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Speciality' }}</label>
|
||||
<input type="text" name="system.skill.speciality" value="{{system.skill.speciality}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Level' }}</label>
|
||||
<input type="text" name="system.level" value="{{system.level}}" data-dtype="Number" />
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox">
|
||||
<input type="checkbox" name="system.skill.reduceEncumbrance" data-dtype="Boolean" {{checked system.skill.reduceEncumbrance}} />
|
||||
{{ localize 'MGT2.Items.ReduceEncumbrance' }}
|
||||
</label>
|
||||
</div>
|
||||
{{else if (eq system.subType "psionic")}}
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Level' }}</label>
|
||||
<input type="text" name="system.level" value="{{system.level}}" data-dtype="Number" />
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.PSICost' }}</label>
|
||||
<input type="number" name="system.psionic.cost" value="{{system.psionic.cost}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Reach' }}</label>
|
||||
<select name="system.psionic.reach">
|
||||
<option></option>
|
||||
{{selectOptions config.PsionicReach selected = system.psionic.reach localize = true}}
|
||||
<option value=""></option>
|
||||
{{selectOptions config.PsionicReach selected=system.psionic.reach localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.PSICost' }}</label>
|
||||
<input type="number" name="system.psionic.cost" value="{{system.psionic.cost}}" data-dtype="Number" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Duration' }}</label>
|
||||
<div class="flexrow">
|
||||
<input type="text" name="system.psionic.duration" value="{{system.psionic.duration}}" data-dtype="String" class="flex-basis-50" />
|
||||
<select name="system.psionic.durationUnit" class="flex-basis-50 flex-fix">
|
||||
{{selectOptions config.Durations selected=system.psionic.durationUnit localize = true}}
|
||||
<div class="range-inputs">
|
||||
<input type="text" name="system.psionic.duration" value="{{system.psionic.duration}}" data-dtype="String" />
|
||||
<select name="system.psionic.durationUnit">
|
||||
{{selectOptions config.Durations selected=system.psionic.durationUnit localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="config">{{ localize 'MGT2.Items.Configuration' }}</a>
|
||||
</nav>
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="config">
|
||||
{{#if (eq system.subType "skill")}}
|
||||
<div class="field-group mt-05">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.skill.reduceEncumbrance" data-dtype="Boolean" {{checked system.skill.reduceEncumbrance}} />{{ localize 'MGT2.Items.ReduceEncumbrance' }}</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{!-- Tab 3 : Configuration (jet de dé) --}}
|
||||
<div class="tab" data-group="primary" data-tab="tab3">
|
||||
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,30 +1,76 @@
|
||||
<div class="{{cssClass}} itemsheet">
|
||||
<div class="itemsheet-header"><label class="upcase">{{ localize 'MGT2.Items.Weapon' }}</label></div>
|
||||
<div class="itemsheet-panel">
|
||||
<div class="itemsheet-maincol">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
{{> systems/mgt2/templates/items/parts/sheet-physical-item.html }}
|
||||
<div class="item-type-bar">
|
||||
<span class="item-type-label"><i class="fas fa-gun"></i> {{ localize 'MGT2.Items.Weapon' }}</span>
|
||||
</div>
|
||||
<div class="w-100">
|
||||
<input class="field field-item-name" name="name" type="text" value="{{item.name}}" />
|
||||
<nav class="horizontal-tabs tabs mt-1" data-group="primary">
|
||||
<div class="item-sheet-header">
|
||||
<img class="item-header-img" src="{{item.img}}" data-edit="img" data-tooltip="{{item.name}}" />
|
||||
<input class="item-header-name" name="name" type="text" value="{{item.name}}" />
|
||||
</div>
|
||||
|
||||
<nav class="horizontal-tabs tabs" data-group="primary">
|
||||
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
|
||||
<a class="item tab-select" data-tab="tab2">{{ localize 'MGT2.Items.Details' }}</a>
|
||||
<a class="item tab-select" data-tab="tab3">{{ localize 'MGT2.Items.Configuration' }}</a>
|
||||
</nav>
|
||||
<div class="tab-content-area">
|
||||
<div class="tab" data-group="primary" data-tab="tab1">
|
||||
<div class="field-group mt-1">
|
||||
<div class="field-group">
|
||||
<label>{{ localize 'MGT2.Items.Description' }}</label>
|
||||
<textarea name="system.description" rows="6">{{system.description}}</textarea>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab2">
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group flex-1">
|
||||
<div class="item-details-grid">
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Quantity' }}</label>
|
||||
<input type="number" name="system.quantity" value="{{system.quantity}}" data-dtype="Number" integer="true" positive="true" class="short" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.TL' }}</label>
|
||||
<select name="system.tl">{{selectOptions config.TL selected=system.tl localize=true}}</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Weight' }} ({{unitlabels.weight}})</label>
|
||||
<input type="number" name="weight" value="{{weight}}" data-dtype="Number" step="0.5" class="short" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Cost' }}</label>
|
||||
<input type="number" name="system.cost" value="{{system.cost}}" data-dtype="Number" step="1" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Damage' }}</label>
|
||||
<input type="text" name="system.damage" value="{{system.damage}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Magazine' }}</label>
|
||||
<input type="number" name="system.magazine" value="{{system.magazine}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
{{#unless system.range.isMelee}}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.Range' }}</label>
|
||||
<div class="range-inputs">
|
||||
<input type="text" name="system.range.value" value="{{system.range.value}}" data-dtype="String" />
|
||||
<select name="system.range.unit">
|
||||
{{selectOptions config.MetricRange selected=system.range.unit localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
<div class="field-row">
|
||||
<label>{{ localize 'MGT2.Items.MagazineCost' }}</label>
|
||||
<input type="number" name="system.magazineCost" value="{{system.magazineCost}}" data-dtype="Number" class="short" />
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.weightless" data-dtype="Boolean" {{checked system.weightless}} />{{ localize 'MGT2.Items.Weightless' }}</label>
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.range.isMelee" data-dtype="Boolean" {{checked system.range.isMelee}} />{{ localize 'MGT2.Items.IsMelee' }}</label>
|
||||
</div>
|
||||
<div class="field-row field-row--check">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.equipped" data-dtype="Boolean" {{checked system.equipped}} />{{ localize 'MGT2.Items.Equipped' }}</label>
|
||||
</div>
|
||||
{{#if hadContainer}}
|
||||
<div class="field-group">
|
||||
<div class="field-row full">
|
||||
<label>{{ localize 'MGT2.Items.Storage' }}</label>
|
||||
<select name="system.container.id">
|
||||
{{selectOptions containers selected=system.container.id valueAttr="_id" labelAttr="name"}}
|
||||
@@ -32,58 +78,47 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group w3-10">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="system.range.isMelee" data-dtype="Boolean" {{checked system.range.isMelee}} />{{ localize 'MGT2.Items.IsMelee' }}</label>
|
||||
<fieldset class="mgt2-weapon-traits">
|
||||
<legend>{{ localize 'MGT2.WeaponTraits.SectionTitle' }}</legend>
|
||||
<div class="mgt2-weapon-traits-grid">
|
||||
<div class="mgt2-trait-num" data-tooltip="{{ localize 'MGT2.WeaponTraits.APHint' }}">
|
||||
<label>{{ localize 'MGT2.WeaponTraits.AP' }}</label>
|
||||
<input type="number" name="system.traits.ap" value="{{system.traits.ap}}" data-dtype="Number" min="0" class="short" />
|
||||
</div>
|
||||
{{#unless system.range.isMelee}}
|
||||
<div class="field-group w3-10">
|
||||
<label>{{ localize 'MGT2.Items.Range' }}</label>
|
||||
<div class="flexrow">
|
||||
<input type="text" name="system.range.value" value="{{system.range.value}}" data-dtype="String" />
|
||||
<select name="system.range.unit" class="flex-fix" style="width: 5rem;">
|
||||
{{selectOptions config.MetricRange selected=system.range.unit localize = true}}
|
||||
</select>
|
||||
<div class="mgt2-trait-num" data-tooltip="{{ localize 'MGT2.WeaponTraits.AutoHint' }}">
|
||||
<label>{{ localize 'MGT2.WeaponTraits.Auto' }}</label>
|
||||
<input type="number" name="system.traits.auto" value="{{system.traits.auto}}" data-dtype="Number" min="0" class="short" />
|
||||
</div>
|
||||
<div class="mgt2-trait-num" data-tooltip="{{ localize 'MGT2.WeaponTraits.BlastHint' }}">
|
||||
<label>{{ localize 'MGT2.WeaponTraits.Blast' }}</label>
|
||||
<input type="number" name="system.traits.blast" value="{{system.traits.blast}}" data-dtype="Number" min="0" class="short" />
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
<div class="field-groups mt-1">
|
||||
<div class="field-group w3-10">
|
||||
<label>{{ localize 'MGT2.Items.Damage' }}</label>
|
||||
<input type="text" name="system.damage" value="{{system.damage}}" data-dtype="String" />
|
||||
</div>
|
||||
<div class="field-group w3-10" style="margin: 0 1rem;">
|
||||
<label>{{ localize 'MGT2.Items.Magazine' }}</label>
|
||||
<input type="number" name="system.magazine" value="{{system.magazine}}" data-dtype="Number" />
|
||||
</div>
|
||||
<div class="field-group w3-10">
|
||||
<label>{{ localize 'MGT2.Items.MagazineCost' }}</label>
|
||||
<input type="number" name="system.magazineCost" value="{{system.magazineCost}}" data-dtype="Number" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<div class="table-row heading color-2">
|
||||
<div class="row-item row-item-left upcase">{{ localize 'MGT2.Items.Trait' }}</div>
|
||||
<div class="row-item row-item-left">{{ localize 'MGT2.Items.Description' }}</div>
|
||||
<div class="row-item row-item-right"><a class="options-create" data-property="traits"><i class="fas fa-plus"></i></a></div>
|
||||
</div>
|
||||
{{#each system.traits as |trait i| }}
|
||||
<div class="table-row dropitem options-part" data-options-part="{{i}}" data-property="traits" role="rowgroup">
|
||||
<div class="row-item row-item-left"><input type="text" name="system.traits.{{i}}.name" value="{{trait.name}}" /></div>
|
||||
<div class="row-item row-item-left">
|
||||
<textarea name="system.traits.{{i}}.description" rows="3">{{trait.description}}</textarea>
|
||||
</div>
|
||||
<div class="row-item row-item-right item-controls">
|
||||
<a class="item-control options-delete" title="Delete Trait"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
<label class="mgt2-checkbox mgt2-trait-bool" data-tooltip="{{ localize 'MGT2.WeaponTraits.BulkyHint' }}">
|
||||
<input type="checkbox" name="system.traits.bulky" data-dtype="Boolean" {{checked system.traits.bulky}} />{{ localize 'MGT2.WeaponTraits.Bulky' }}
|
||||
</label>
|
||||
<label class="mgt2-checkbox mgt2-trait-bool" data-tooltip="{{ localize 'MGT2.WeaponTraits.VeryBulkyHint' }}">
|
||||
<input type="checkbox" name="system.traits.veryBulky" data-dtype="Boolean" {{checked system.traits.veryBulky}} />{{ localize 'MGT2.WeaponTraits.VeryBulky' }}
|
||||
</label>
|
||||
<label class="mgt2-checkbox mgt2-trait-bool" data-tooltip="{{ localize 'MGT2.WeaponTraits.StunHint' }}">
|
||||
<input type="checkbox" name="system.traits.stun" data-dtype="Boolean" {{checked system.traits.stun}} />{{ localize 'MGT2.WeaponTraits.Stun' }}
|
||||
</label>
|
||||
<label class="mgt2-checkbox mgt2-trait-bool" data-tooltip="{{ localize 'MGT2.WeaponTraits.SmartHint' }}">
|
||||
<input type="checkbox" name="system.traits.smart" data-dtype="Boolean" {{checked system.traits.smart}} />{{ localize 'MGT2.WeaponTraits.Smart' }}
|
||||
</label>
|
||||
<label class="mgt2-checkbox mgt2-trait-bool" data-tooltip="{{ localize 'MGT2.WeaponTraits.RadiationHint' }}">
|
||||
<input type="checkbox" name="system.traits.radiation" data-dtype="Boolean" {{checked system.traits.radiation}} />{{ localize 'MGT2.WeaponTraits.Radiation' }}
|
||||
</label>
|
||||
<label class="mgt2-checkbox mgt2-trait-bool" data-tooltip="{{ localize 'MGT2.WeaponTraits.ScopeHint' }}">
|
||||
<input type="checkbox" name="system.traits.scope" data-dtype="Boolean" {{checked system.traits.scope}} />{{ localize 'MGT2.WeaponTraits.Scope' }}
|
||||
</label>
|
||||
<label class="mgt2-checkbox mgt2-trait-bool" data-tooltip="{{ localize 'MGT2.WeaponTraits.ZeroGHint' }}">
|
||||
<input type="checkbox" name="system.traits.zeroG" data-dtype="Boolean" {{checked system.traits.zeroG}} />{{ localize 'MGT2.WeaponTraits.ZeroG' }}
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="tab" data-group="primary" data-tab="tab3">
|
||||
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,32 @@
|
||||
<form class="{{cssClass}} flexcol" autocomplete="off" style="padding: 0 6px;">
|
||||
|
||||
{{!-- Hidden fields for healing --}}
|
||||
{{#if showHeal}}
|
||||
<input type="hidden" name="healType" value="{{healType}}" />
|
||||
{{/if}}
|
||||
|
||||
{{!-- ── Mode CRÉATURE : sélecteur de compétence de la créature ── --}}
|
||||
{{#if isCreature}}
|
||||
|
||||
{{#if showSkillSelector}}
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.CreatureSkill' }}</label>
|
||||
<select name="creatureSkillIndex">
|
||||
<option value="-1">— {{ localize 'MGT2.RollPrompt.NoSkill' }} —</option>
|
||||
{{#each creatureSkills}}
|
||||
<option value="{{@index}}" {{#if (eq @index ../selectedSkillIndex)}}selected{{/if}}>{{name}} ({{showDM level}})</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="form-group roll-prompt-info">
|
||||
<span class="roll-prompt-skill-name">{{skillName}}</span>
|
||||
<span class="roll-prompt-skill-level">{{showDM skillLevel}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{!-- ── Mode PERSONNAGE : caractéristique + compétence + états ── --}}
|
||||
{{else}}
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.CharacteristicDM' }}</label>
|
||||
<select name="characteristic">
|
||||
@@ -12,27 +40,166 @@
|
||||
{{selectOptions skills selected=skill valueAttr="_id" labelAttr="name"}}
|
||||
</select>
|
||||
</div>
|
||||
{{#unless isAttack}}
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.Timeframes' }}</label>
|
||||
<select name="timeframes">
|
||||
{{selectOptions config.Timeframes selected = timeframe localize = true}}
|
||||
</select>
|
||||
</div>
|
||||
{{/unless}}
|
||||
<fieldset>
|
||||
<legend>{{ localize 'MGT2.RollPrompt.States' }}</legend>
|
||||
<div class="form-group">
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="encumbrance" data-dtype="Boolean" {{checked encumbrance}} />{{ localize 'MGT2.RollPrompt.EncumbranceDM' }}</label>
|
||||
<label class="mgt2-checkbox"><input type="checkbox" name="fatigue" data-dtype="Boolean" {{checked fatigue}} />{{ localize 'MGT2.RollPrompt.FatigueDM' }}</label>
|
||||
{{!-- Hidden checkboxes preserve form values for the roll calculation --}}
|
||||
<input type="checkbox" name="encumbrance" data-dtype="Boolean" {{checked encumbrance}} style="display:none" />
|
||||
<input type="checkbox" name="fatigue" data-dtype="Boolean" {{checked fatigue}} style="display:none" />
|
||||
{{!-- Read-only state badges --}}
|
||||
<div class="roll-prompt-states">
|
||||
<span class="roll-prompt-state-badge {{#if encumbrance}}is-active{{/if}}">
|
||||
<i class="fa-solid fa-weight-hanging"></i>
|
||||
{{ localize 'MGT2.RollPrompt.EncumbranceDM' }}
|
||||
{{#if encumbrance}}<strong>−2</strong>{{/if}}
|
||||
</span>
|
||||
<span class="roll-prompt-state-badge {{#if fatigue}}is-active{{/if}}">
|
||||
<i class="fa-solid fa-person-dots-from-line"></i>
|
||||
{{ localize 'MGT2.RollPrompt.FatigueDM' }}
|
||||
{{#if fatigue}}<strong>−2</strong>{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
{{#if isRanged}}
|
||||
<fieldset class="mgt2-ranged-modifiers">
|
||||
<legend>{{ localize 'MGT2.RollPrompt.RangedModifiers' }}</legend>
|
||||
{{#if hasScope}}
|
||||
<div class="mgt2-scope-badge" data-tooltip="{{ localize 'MGT2.RollPrompt.ScopeHint' }}">
|
||||
<i class="fa-solid fa-crosshairs"></i>
|
||||
{{ localize 'MGT2.RollPrompt.ScopeActive' }}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if hasZeroG}}
|
||||
<div class="mgt2-zerog-badge" data-tooltip="{{ localize 'MGT2.RollPrompt.ZeroGHint' }}">
|
||||
<i class="fa-solid fa-satellite"></i>
|
||||
{{ localize 'MGT2.RollPrompt.ZeroGActive' }}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if autoLevel}}
|
||||
<div class="form-group mgt2-auto-mode">
|
||||
<label>{{ localize 'MGT2.RollPrompt.FireMode' }}</label>
|
||||
<select name="autoMode">
|
||||
<option value="single">{{ localize 'MGT2.RollPrompt.AutoSingle' }}</option>
|
||||
<option value="burst">{{ localize 'MGT2.RollPrompt.AutoBurst' }} (+{{autoLevel}})</option>
|
||||
<option value="fullAuto">{{ localize 'MGT2.RollPrompt.AutoFull' }} (×{{autoLevel}})</option>
|
||||
</select>
|
||||
</div>
|
||||
<p class="mgt2-auto-hint">⚠ {{ localize 'MGT2.RollPrompt.AutoNoAim' }}</p>
|
||||
{{/if}}
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.Range' }}</label>
|
||||
<select name="rangedRange">
|
||||
<option value="1">{{ localize 'MGT2.RollPrompt.RangeShort' }} (+1)</option>
|
||||
<option value="0" selected>{{ localize 'MGT2.RollPrompt.RangeNormal' }}</option>
|
||||
<option value="-2">{{ localize 'MGT2.RollPrompt.RangeLong' }} (−2)</option>
|
||||
<option value="-4">{{ localize 'MGT2.RollPrompt.RangeExtreme' }} (−4)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.Aim' }}</label>
|
||||
<select name="rangedAim">
|
||||
<option value="0" selected>0</option>
|
||||
<option value="1">+1</option>
|
||||
<option value="2">+2</option>
|
||||
<option value="3">+3</option>
|
||||
<option value="4">+4</option>
|
||||
<option value="5">+5</option>
|
||||
<option value="6">+6</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.FastTarget' }}</label>
|
||||
<select name="rangedFastTarget">
|
||||
<option value="0" selected>0</option>
|
||||
<option value="-1">−1</option>
|
||||
<option value="-2">−2</option>
|
||||
<option value="-3">−3</option>
|
||||
<option value="-4">−4</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mgt2-ranged-checkboxes">
|
||||
<label class="mgt2-checkbox-tag"><input type="checkbox" name="rangedLaserSight" data-dtype="Boolean" />{{ localize 'MGT2.RollPrompt.LaserSight' }} <em>(+1 si Viser)</em></label>
|
||||
<label class="mgt2-checkbox-tag"><input type="checkbox" name="rangedCover" data-dtype="Boolean" />{{ localize 'MGT2.RollPrompt.Cover' }} <em>(−2)</em></label>
|
||||
<label class="mgt2-checkbox-tag"><input type="checkbox" name="rangedProne" data-dtype="Boolean" />{{ localize 'MGT2.RollPrompt.Prone' }} <em>(−1)</em></label>
|
||||
</div>
|
||||
<div class="form-group mgt2-ranged-dodge">
|
||||
<label class="mgt2-checkbox-tag"><input type="checkbox" name="rangedDodge" data-dtype="Boolean" />{{ localize 'MGT2.RollPrompt.Dodge' }}</label>
|
||||
<select name="rangedDodgeDM">
|
||||
<option value="0" selected>MD 0</option>
|
||||
<option value="-1">MD −1</option>
|
||||
<option value="-2">MD −2</option>
|
||||
<option value="-3">MD −3</option>
|
||||
<option value="-4">MD −4</option>
|
||||
<option value="-5">MD −5</option>
|
||||
<option value="-6">MD −6</option>
|
||||
</select>
|
||||
</div>
|
||||
</fieldset>
|
||||
{{/if}}
|
||||
{{#if isMelee}}
|
||||
<fieldset class="mgt2-ranged-modifiers">
|
||||
<legend>{{ localize 'MGT2.RollPrompt.MeleeModifiers' }}</legend>
|
||||
<div class="form-group mgt2-ranged-dodge">
|
||||
<label class="mgt2-checkbox-tag"><input type="checkbox" name="meleeDodge" data-dtype="Boolean" />{{ localize 'MGT2.RollPrompt.Dodge' }}</label>
|
||||
<select name="meleeDodgeDM">
|
||||
<option value="0" selected>MD 0</option>
|
||||
<option value="-1">MD −1</option>
|
||||
<option value="-2">MD −2</option>
|
||||
<option value="-3">MD −3</option>
|
||||
<option value="-4">MD −4</option>
|
||||
<option value="-5">MD −5</option>
|
||||
<option value="-6">MD −6</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mgt2-ranged-dodge">
|
||||
<label class="mgt2-checkbox-tag"><input type="checkbox" name="meleeParry" data-dtype="Boolean" />{{ localize 'MGT2.RollPrompt.Parry' }}</label>
|
||||
<select name="meleeParryDM">
|
||||
<option value="0" selected>MD 0</option>
|
||||
<option value="-1">MD −1</option>
|
||||
<option value="-2">MD −2</option>
|
||||
<option value="-3">MD −3</option>
|
||||
<option value="-4">MD −4</option>
|
||||
<option value="-5">MD −5</option>
|
||||
<option value="-6">MD −6</option>
|
||||
</select>
|
||||
</div>
|
||||
</fieldset>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.CustomDM' }}</label>
|
||||
<input type="text" name="customDM" maxlength="15" />
|
||||
<select name="customDM">
|
||||
<option value="-8">−8</option>
|
||||
<option value="-7">−7</option>
|
||||
<option value="-6">−6</option>
|
||||
<option value="-5">−5</option>
|
||||
<option value="-4">−4</option>
|
||||
<option value="-3">−3</option>
|
||||
<option value="-2">−2</option>
|
||||
<option value="-1">−1</option>
|
||||
<option value="0" selected>0</option>
|
||||
<option value="1">+1</option>
|
||||
<option value="2">+2</option>
|
||||
<option value="3">+3</option>
|
||||
<option value="4">+4</option>
|
||||
<option value="5">+5</option>
|
||||
<option value="6">+6</option>
|
||||
<option value="7">+7</option>
|
||||
<option value="8">+8</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{ localize 'MGT2.RollPrompt.Difficulty' }}</label>
|
||||
<select name="difficulty">
|
||||
<option></option>
|
||||
<option value="">—</option>
|
||||
{{selectOptions config.Difficulty selected = difficulty localize = true}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user