23 Commits
v0.1.0 ... main

Author SHA1 Message Date
74f1b581f7 Ajout des fonctions de gestion des soins 2026-04-21 10:22:39 +02:00
df0a93d715 feat: complete visual redesign of all item sheets + compact chat roll messages
- Rewrote _item.sass with unified layout: type-bar + dark header + stats pills + tabs
 - All 11 item templates converted to new pill-based stats bar
 - Chat roll message font sizes and padding compacted
 - Physical item partial rewritten as stat pills (QTY/WEIGHT/COST/TL)
 - Legacy itemsheet-header and itemsheet-maincol hidden
2026-04-19 21:31:52 +02:00
d62d14c1da Second round de corrections et améliorations 2026-04-19 18:55:34 +02:00
783d4a16e6 Remove assets/regles from remote (keep local) 2026-04-19 10:57:28 +02:00
fa1c02caa6 Migrate to FoundryVTT v13 AppV2 +
│ DataModels
│
│ - Reorganize DataModels into src/module/models/ (one .mjs per type)
│ - Create AppV2 actor/item sheets (HandlebarsApplicationMixin)…
2026-04-19 10:55:44 +02:00
86b2cd5777 Migrate to FoundryVTT v13 AppV2 +
│ DataModels
│
│ - Reorganize DataModels into src/module/models/ (one .mjs per type)
│ - Create AppV2 actor/item sheets (HandlebarsApplicationMixin)…
2026-04-19 10:54:43 +02:00
e3002dd602 Migration FOundry v13/v14 2026-04-19 00:43:33 +02:00
JDR-Ninja
89b3e401a4 Ajouter les sources 2025-06-20 08:43:33 -04:00
JDR-Ninja
f1c4f43c66 Update .gitignore
add src
2025-06-20 08:38:31 -04:00
JDR-Ninja
78ad10918c Merge pull request #4 from cbeach512/#3-Resolve-MGT2-module-deprecation-warnings-for-grid-settings
fix: system.json deprecation warnings
2025-06-20 08:35:53 -04:00
Chad Beach
770e80fd3d updated CHANGELOG.md 2024-08-19 23:42:36 -06:00
Chad Beach
d63526831c change grid to dict 2024-08-19 23:37:08 -06:00
Chad Beach
7f10f617c4 update grid settings calls 2024-08-19 22:51:22 -06:00
JDR-Ninja
5de3533691 Calcul du poids 2024-05-25 08:33:45 -04:00
JDR-Ninja
11a10bbbfc Migration V12 2024-05-24 15:55:48 -04:00
JDR-Ninja
47dd386fe0 Ajustements 2024-05-16 22:06:56 -04:00
JDR-Ninja
c05855fd39 v0.1.2 2024-05-16 21:57:22 -04:00
JDR-Ninja
d0be581d78 Publier la version 0.1.1 2024-05-11 08:38:14 -04:00
JDR-Ninja
e18dd8abfa Correction appel de fonction et enlever mauvaise référence 2024-05-11 08:36:12 -04:00
JDR-Ninja
db54e5213c Ajout de texte 2024-05-07 12:29:20 -04:00
JDR-Ninja
dfb84aca1e Création répertoire web et ajustement texte 2024-05-07 08:03:59 -04:00
JDR-Ninja
cd6fc9fb01 Fix différent texte 2024-05-07 07:55:53 -04:00
JDR-Ninja
2998a62ff9 Traduction et compilation 2024-05-06 19:51:09 -04:00
94 changed files with 14247 additions and 4236 deletions

372
.gitignore vendored
View File

@@ -1,6 +1,3 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
@@ -10,353 +7,8 @@
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
@@ -364,18 +16,6 @@ ASALocalRun/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
@@ -387,12 +27,6 @@ FodyWeavers.xsd
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
mgt2.zip
assets/regles/
.github

34
CHANGELOG.md Normal file
View File

@@ -0,0 +1,34 @@
* `system.json` no longer generates warnings ([#3](https://github.com/JDR-Ninja/foundryvtt-mgt2/issues/3))
## [0.1.4] (2024-05-25)
### Correctifs
* Erreur lors du calcul du poids lors de différent événement (Drop, Delete)
## [0.1.3] (2024-05-24)
### Correctifs
* Localisation
* Ajouter valeur de la difficulté dans le label
### Features
* Support de la v12
## [0.1.2] (2024-05-16)
### Correctifs
* Affichage de la difficulté pour les Talents Psioniques
* Ajout de scrollbar dans la feuille de personnage
* Drag & Drop sur la fiche des Carrières, Maladies, Contacts, Espèces
* Retrait du style sur les messages (le temps d'uniformiser les messages)
* Différents ajustements css
### Features
* Thème Bleu
* Amélioration du modèle Espèce
* Ajout des champs : Description Détaillée, Modificateurs (tableau) et Traits (tableau)
* Lors du Drop d'une Espèce, copie des informations sur la fiche
* Ajout de la Durée pour les Talents Psioniques
* Bouton pour le jet de la Durée des Talents Psionique sur les messages
* Ajout de la difficulté sur la fenêtre des Jets
* Affichage du succès et de l'échec sur les messages

View File

@@ -1 +1,18 @@
# foundryvtt-mgt2
# MGT2 - Mongoose Traveller (Unofficial)
*English version below*
Ce système de jeu pour [Foundry Virtual Tabletop](http://foundryvtt.com) qui fournit une feuille de personnage et un système de jeu
pour Mongoose Publishing Traveller.
Spécialement développé pour la version française traduite par [Modül](https://www.gameontabletop.com/cf3161/traveller-vf.html)
#### Screenshots
![Alt text](https://raw.githubusercontent.com/JDR-Ninja/foundryvtt-mgt2/master/web/foundryvtt/inventory.jpg "Screenshot")
## English
This game system for [Foundry Virtual Tabletop](http://foundryvtt.com) provides character sheet and game system
support for Mongoose Publishing Traveller.
Specially developed for the French version translated by [Modül](https://www.gameontabletop.com/cf3161/traveller-vf.html)

View File

@@ -15,9 +15,19 @@
"TYPES.Actor.vehicule": "Vehicule",
"TYPES.Actor.container": "Container (backpack, chest)",
"MGT2": {
"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"
"Mwamba": "Oppa Mwamba Style",
"Blue": "Blue"
},
"Settings": {
"theme": {
@@ -50,18 +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",
"DeleteCareer":"Delete Career",
"NewSkill":"New Skill",
"DeleteSkill":"Delete Skill",
"EditSkill":"EditSkill",
"PsionicTalents":"Psionic Talents",
"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",
"NewPsionicTalent": "New Psionic Talent",
"AddPsionicTalent": "Add Psionic Talent",
"EditPsionic": "Edit Psionic",
@@ -96,6 +109,7 @@
"EditArmor": "Edit Armor",
"EditAugment": "Edit Augment",
"EditContact": "Edit Contact",
"EditComputer": "Editer Computer",
"EditDisease": "Edit Disease",
"EditItem": "Edit Item",
"EditSoftware": "Edit Software",
@@ -103,6 +117,7 @@
"EditWound": "Edit Wound",
"Encumbrance": "Encumbrance",
"EncumbranceHint": "DM -2 on all physical actions. They will also count as performing heavy labour.",
"EquipUnequip": "Equip/Unequip",
"Fatigue": "Fatigue",
"FatigueHint": "DM -2 to all checks until full rest.",
"Finance": "Finance",
@@ -115,7 +130,9 @@
"NewArmor": "New Armor",
"NewAugment": "New Augment",
"NewContact": "New Contact",
"NewDiseases": "New Diseases",
"NewComputer": "New Computer",
"NewContainer": "New Container",
"NewDisease": "New Diseases",
"NewEquipment": "New Equipment",
"NewItem": "New Item",
"NewWeapon": "New Weapon",
@@ -134,6 +151,7 @@
"ShowMinMax": "Show Min/Max",
"ShowPsionicTalents": "Show Psionic Talents",
"Skills": "Skills",
"TabSkills": "Traits & Compétences",
"States": "States",
"StoreEquipment": "Store Equipment",
"StoreItem": "Store Item",
@@ -241,14 +259,14 @@
},
"Difficulty": {
"NA": "Not Applicable",
"Simple": "Simple",
"Easy": "Easy",
"Routine": "Routine",
"Average": "Average",
"Difficult": "Difficult",
"VeryDifficult": "Very Difficult",
"Formidable": "Formidable",
"Impossible": "Impossible"
"Simple": "Simple (2)",
"Easy": "Easy (4)",
"Routine": "Routine (6)",
"Average": "Average (8)",
"Difficult": "Difficult (10)",
"VeryDifficult": "Very Difficult (12)",
"Formidable": "Formidable (14)",
"Impossible": "Impossible (16)"
},
"PsionicReach": {
"NA": "N/A",
@@ -332,7 +350,10 @@
"EncumbranceDM": "Encumbrance (DM -2)",
"FatigueDM": "Fatigue (DM -2)",
"Boon": "Boon",
"Bane": "Bane"
"Bane": "Bane",
"CreatureSkill": "Skill",
"NoSkill": "No skill",
"Days": "Days"
},
"Timeframes": {
"Normal": "Normal",
@@ -342,10 +363,17 @@
"Chat": {
"Roll": {
"ApplyDamages": "Apply Damages",
"Damages": "Roll damages"
"Damages": "Roll damages",
"Success": "Success",
"Failure": "Failure",
"Effect": "Effect",
"Dice": "Dice",
"Result": "Result",
"DiceModifier": "Dice Modifier"
}
},
"Items": {
"SelectAll": "(all)",
"Age": "Age",
"Armor": "Armor",
"Armors": "Armors",
@@ -365,10 +393,12 @@
"Cost": "Cost",
"Damage": "Damage",
"Description": "Description",
"DetailedDescription": "Detailled Description",
"Details": "Details",
"Disease": "Disease",
"Diseases": "Diseases",
"Difficulty": "Difficulty",
"Duration": "Duration",
"Equipped": "Equipped",
"Equipment": "Equipment",
"Equipments": "Equipments",
@@ -377,7 +407,7 @@
"Informations": "Informations",
"Improvement": "Improvement",
"Interval": "Interval",
"IsMelee": "IsMelee",
"IsMelee": "Melee Weapon",
"Items": "Items",
"Level": "Level",
"Location": "Location",
@@ -385,12 +415,16 @@
"LockedDescription": "Locked Description",
"Magazine": "Magazine",
"MagazineCost": "Magazine Cost",
"Modifier": "Modifier",
"Modifiers": "Modifiers",
"Name": "Name",
"Nickname": "Nickname",
"NotProficient": "Not proficient (-3)",
"Notes": "Notes",
"Occupation": "Occupation",
"OnHand": "On Hand",
"Options": "Options",
"PerDay": "per day",
"PSICost": "PSI Cost",
"Powered": "Powered",
"Processing": "Processing",
@@ -406,6 +440,7 @@
"Relation": "Relation",
"Relations": "Relations",
"Skill": "Skill",
"PsySkill": "Psy Skill",
"Speciality": "Speciality",
"Status": "Status",
"Storage": "Storage",
@@ -415,12 +450,127 @@
"Terms": "Terms",
"Title": "Title",
"Trait": "Trait",
"Traits": "Traits",
"Type": "Type",
"Weapon": "Weapon",
"Weapons": "Weapons",
"Weight": "Weight",
"Weightless": "Weightless",
"Quantity": "Quantity"
},
"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."
},
"Errors": {
"NoTokenSelected": "No token selected. Select a token on the scene before applying.",
"InvalidRollFormula": "Invalid roll formula."
}
}
},
"TYPES.Actor.creature": "Creature"
}

View File

@@ -15,9 +15,19 @@
"TYPES.Actor.vehicule": "Véhicule",
"TYPES.Actor.container": "Contenant (sac, coffre)",
"MGT2": {
"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"
"Mwamba": "Oppa Mwamba Style",
"Blue": "Bleu"
},
"Settings": {
"theme": {
@@ -25,7 +35,7 @@
"hint": "Choisissez un thème"
},
"useWeightMetric": {
"name": "Utiliser le Système Métrique pour le Poid",
"name": "Utiliser le Système Métrique pour le Poids",
"hint": "kilogramme (kg) au lieu de la livre (lbs)"
},
"useDistanceMetric": {
@@ -50,18 +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",
"DeleteCareer":"Supprimer Carrière",
"NewSkill":"Nouvelle Compétence",
"DeleteSkill":"Supprimer Compétence",
"EditSkill":"Éditer Compétence",
"PsionicTalents":"Talents Psionique",
"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",
"NewPsionicTalent": "Nouveau Talent Psionique",
"AddPsionicTalent": "Ajouter Talent Psionique",
"EditPsionic": "Éditer Talent Psionique",
@@ -96,6 +109,7 @@
"EditArmor": "Éditer Armure",
"EditAugment": "Éditer Augmentation",
"EditContact": "Éditer Contact",
"EditComputer": "Éditer Ordinateur",
"EditDisease": "Éditer Maladie",
"EditItem": "Éditer Objet",
"EditSoftware": "Éditer Logiciel",
@@ -103,6 +117,7 @@
"EditWound": "Éditer Blessure",
"Encumbrance": "Encombrement",
"EncumbranceHint": "DM -2 on all physical actions. They will also count as performing heavy labour.",
"EquipUnequip": "Équipper/Déséquipper",
"Fatigue": "Fatigue",
"FatigueHint": "DM -2 to all checks until full rest.",
"Finance": "Finance",
@@ -115,7 +130,9 @@
"NewArmor": "Nouvelle Armure",
"NewAugment": "Nouvelle Augmentation",
"NewContact": "Nouveau Contact",
"NewDiseases": "Nouvelle Maladie",
"NewContainer": "Nouveau Conteneur",
"NewComputer": "Nouvel Ordinateur",
"NewDisease": "Nouvelle Maladie",
"NewEquipment": "Nouvelle Équipement",
"NewItem": "Nouveau Objet",
"NewWeapon": "Nouvel Arme",
@@ -134,6 +151,7 @@
"ShowMinMax": "Afficher le Min/Max",
"ShowPsionicTalents": "Afficher les Talents Psy",
"Skills": "Compétences",
"TabSkills": "Traits & Compétences",
"States": "États",
"StoreEquipment": "Entreposer Équipement",
"StoreItem": "Entreposer Objet",
@@ -143,7 +161,7 @@
"TabOthers": "A",
"TotalWeight": "Poids total",
"UnloadSoftware": "Éjecter le Logiciel",
"UnstoreItem": "Rependre",
"UnstoreItem": "Reprendre l'objet",
"Wounds": "Blessures",
"Show": "Afficher"
},
@@ -241,14 +259,14 @@
},
"Difficulty": {
"NA": "N/A",
"Simple": "Simple",
"Easy": "Facile",
"Routine": "Routine",
"Average": "Moyenne",
"Difficult": "Difficile",
"VeryDifficult": "Très Difficile",
"Formidable": "Formidable",
"Impossible": "Impossible"
"Simple": "Simple (2)",
"Easy": "Facile (4)",
"Routine": "Routine (6)",
"Average": "Moyenne (8)",
"Difficult": "Difficile (10)",
"VeryDifficult": "Très Difficile (12)",
"Formidable": "Formidable (14)",
"Impossible": "Impossible (16)"
},
"PsionicReach": {
"NA": "N/A",
@@ -332,7 +350,10 @@
"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"
},
"Timeframes": {
"Normal": "Normal",
@@ -342,10 +363,17 @@
"Chat": {
"Roll": {
"ApplyDamages": "Appliquer Dégâts",
"Damages": "Lancer les Dégâts"
"Damages": "Lancer les Dégâts",
"Success": "Succès",
"Failure": "Échec",
"Effect": "Effet",
"Dice": "Dés",
"Result": "Résultat",
"DiceModifier": "Modificateur de dés"
}
},
"Items": {
"SelectAll": "(tous)",
"Age": "Âge",
"Armor": "Armure",
"Armors": "Armures",
@@ -365,10 +393,12 @@
"Cost": "Coût",
"Damage": "Dégâts",
"Description": "Description",
"DetailedDescription": "Desc. Détailée",
"Details": "Détails",
"Difficulty": "Difficulté",
"Disease": "Maladie",
"Diseases": "Maladies",
"Duration": "Durée",
"Equipped": "Équipé",
"Equipment": "Équipement",
"Equipments": "Équipements",
@@ -377,7 +407,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",
@@ -385,15 +415,19 @@
"LockedDescription": "Description Verrouillé",
"Magazine": "Chargeur",
"MagazineCost": "Coût du Chargeur",
"Modifier": "Modificateur",
"Modifiers": "Modificateurs",
"Name": "Nom",
"Nickname": "Surnom",
"NotProficient": "Incompétent (-3)",
"Notes": "Notes",
"Occupation": "Profession",
"OnHand": "Sur Soi",
"Options": "Options",
"PerDay": "par jour",
"PSICost": "Coût PSI",
"Powered": "Alimenté",
"Processing": "Traitement",
"Processing": "Capacité de Traitement",
"Protection": "Protection",
"PsionicSkill": "Compétence Psionique",
"Qty": "Qté",
@@ -406,6 +440,7 @@
"Relation": "Relation",
"Relations": "Relations",
"Skill": "Compétence",
"PsySkill": "Comp. Psionique",
"Speciality": "Spécialité",
"Status": "Statut",
"Storage": "Stockage",
@@ -415,12 +450,127 @@
"Terms": "Termes",
"Title": "Titre",
"Trait": "Trait",
"Traits": "Traits",
"Type": "Type",
"Weapon": "Arme",
"Weapons": "Armes",
"Weight": "Poid",
"Weightless": "Aucun Poid",
"Weight": "Poids",
"Weightless": "Aucun Poids",
"Quantity": "Quantité"
},
"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."
},
"Errors": {
"NoTokenSelected": "Aucun token sélectionné. Sélectionnez un token sur la scène avant d'appliquer.",
"InvalidRollFormula": "Formule de jet invalide."
}
}
},
"TYPES.Actor.creature": "Créature"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

8
package.json Normal file
View File

@@ -0,0 +1,8 @@
{
"name": "foundryvtt-mgt2",
"description": "Mongoose Traveller 2nd Edition for FoundryVTT",
"scripts": {
"build": "rollup -c rollup.config.mjs",
"watch": "rollup -c rollup.config.mjs --watch"
}
}

8
rollup.config.mjs Normal file
View File

@@ -0,0 +1,8 @@
export default {
input: 'src/module/core.js',
output: {
file: 'mgt2.bundle.js',
format: 'es',
sourcemap: true,
},
};

114
src/module/actors/actor.js Normal file
View File

@@ -0,0 +1,114 @@
import { ActorCharacter } from "./character.js";
export class MGT2Combatant extends Combatant {
}
export class TravellerActor extends Actor {
prepareDerivedData() {
if (this.type === "character") {
this.system.initiative = ActorCharacter.getInitiative(this);
}
}
async _preCreate(data, options, user) {
if ( (await super._preCreate(data, options, user)) === false ) return false;
if (this.type === "character") {
ActorCharacter.preCreate(this, data, options, user);
}
}
async _onDeleteDescendantDocuments(parent, collection, documents, ids, options, userId) {
await super._onDeleteDescendantDocuments(parent, collection, documents, ids, options, userId);
if (this.type === "character") {
await ActorCharacter.onDeleteDescendantDocuments(this, parent, collection, documents, ids, options, userId);
}
}
async _onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId) {
super._onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId);
//console.log("_onUpdateDescendantDocuments");
if (this.type === "character") {
await ActorCharacter.onUpdateDescendantDocuments(this, parent, collection, documents, changes, options, userId);
}
}
async _preUpdate(changed, options, user) {
if ((await super._preUpdate(changed, options, user)) === false) return false;
if (this.type === "character") {
await ActorCharacter.preUpdate(this, changed, options, user);
}
}
getInitiative($this) {
if (this.type === "character") {
return ActorCharacter.getInitiative(this);
}
}
applyDamage(amount, { ignoreArmor = false } = {}) {
if (this.type === "character") {
return ActorCharacter.applyDamage(this, amount, { ignoreArmor });
} else if (this.type === "creature") {
if (isNaN(amount) || amount === 0) return;
if (amount < 0) amount = Math.abs(amount);
const armorValue = ignoreArmor ? 0 : (this.system.armor ?? 0);
const effective = Math.max(0, amount - armorValue);
if (effective === 0) return;
const newValue = Math.max(0, (this.system.life.value ?? 0) - effective);
return this.update({ "system.life.value": newValue });
}
}
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 });
}
}
}
getContainers() {
if (this.type === "character") {
return ActorCharacter.getContainers(this);
}
return [];
}
getComputers() {
if (this.type === "character") {
return ActorCharacter.getComputers(this);
}
return [];
}
getSkills() {
if (this.type === "character") {
return ActorCharacter.getSkills(this);
}
return [];
}
async recalculateWeight() {
if (this.type === "character") {
return ActorCharacter.recalculateWeight(this);
}
}
}

View File

@@ -0,0 +1,104 @@
const { DialogV2 } = foundry.applications.api;
const { renderTemplate } = foundry.applications.handlebars;
const { FormDataExtended } = foundry.applications.ux;
async function _dialogWithForm(title, templatePath, templateData) {
const htmlContent = await renderTemplate(templatePath, templateData);
const theme = game.settings.get("mgt2", "theme");
return await DialogV2.wait({
window: { title },
content: htmlContent,
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;
}
}
]
});
}
export class CharacterPrompts {
static async openConfig(system) {
return _dialogWithForm(
"Configuration",
"systems/mgt2/templates/actors/actor-config-sheet.html",
{ config: CONFIG.MGT2, system }
);
}
static async openCharacteristic(name, show, showMax, showAll = false) {
return _dialogWithForm(
"Configuration: " + name,
"systems/mgt2/templates/actors/actor-config-characteristic-sheet.html",
{ name, show, showMax, showAll }
);
}
static async openTraitEdit(data) {
const title = data.name ?? game.i18n.localize("MGT2.Actor.EditTrait");
return _dialogWithForm(
title,
"systems/mgt2/templates/actors/trait-sheet.html",
{ config: CONFIG.MGT2, data }
);
}
static async openEditorFullView(title, html) {
const htmlContent = await renderTemplate("systems/mgt2/templates/editor-fullview.html", {
config: CONFIG.MGT2,
html
});
const theme = game.settings.get("mgt2", "theme");
await DialogV2.wait({
window: { title },
content: htmlContent,
rejectClose: false,
buttons: [
{
action: "close",
label: game.i18n.localize("MGT2.Close") || "Fermer",
default: true,
callback: () => null
}
]
});
}
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;
}
}
]
});
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,500 @@
export class ActorCharacter {
static preCreate($this, data, options, user) {
$this.updateSource({ prototypeToken: { actorLink: true } }) // QoL
}
static prepareData(actorData) {
actorData.initiative = this.getInitiative(actorData);
}
static getInitiative($this) {
let c = $this.system.config.initiative;
return $this.system.characteristics[c].dm;
}
static async onDeleteDescendantDocuments($this, parent, collection, documents, ids, options, userId) {
const toDeleteIds = [];
const itemToUpdates = [];
for (let d of documents) {
if (d.type === "container") {
// Delete content
for (let item of $this.items) {
if (item.system.hasOwnProperty("container") && item.system.container.id === d._id)
toDeleteIds.push(item._id);
}
} else if (d.type === "computer") {
// Eject software
for (let item of $this.items) {
if (item.system.hasOwnProperty("software") && item.system.computerId === d._id) {
let clone = foundry.utils.deepClone(item);
clone.system.software.computerId = "";
itemToUpdates.push(clone);
}
}
}
}
if (toDeleteIds.length > 0)
await $this.deleteEmbeddedDocuments("Item", toDeleteIds);
if (itemToUpdates.length > 0)
await $this.updateEmbeddedDocuments('Item', itemToUpdates);
await this.recalculateWeight($this);
}
static async onUpdateDescendantDocuments($this, parent, collection, documents, changes, options, userId) {
await this.calculEncumbranceAndWeight($this, parent, collection, documents, changes, options, userId);
await this.calculComputers($this, parent, collection, documents, changes, options, userId);
}
static async calculComputers($this, parent, collection, documents, changes, options, userId) {
let change;
let i = 0;
let recalculProcessing = false;
for (let d of documents) {
if (changes[i].hasOwnProperty("system")) {
change = changes[i];
if (d.type === "item" && d.system.subType === "software") {
if (change.system.software.hasOwnProperty("bandwidth") || change.system.software.hasOwnProperty("computerId")) {
recalculProcessing = true;
break;
}
}
}
}
if (recalculProcessing) {
let updatedComputers = [];
let computerChanges = {};
let computers = [];
for (let item of $this.items) {
if (item.system.trash === true) continue;
if (item.type === "computer") {
computers.push(item);
computerChanges[item._id] = { processingUsed: 0 };
}
}
for (let item of $this.items) {
if (item.type !== "item" && item.system.subType !== "software") continue;
if (item.system.software.hasOwnProperty("computerId") && item.system.software.computerId !== "") {
computerChanges[item.system.software.computerId].processingUsed += item.system.software.bandwidth;
}
}
for (let computer of computers) {
let newProcessingUsed = computerChanges[computer._id].processingUsed;
if (computer.system.processingUsed !== newProcessingUsed) {
const cloneComputer = foundry.utils.deepClone($this.getEmbeddedDocument("Item", computer._id));
cloneComputer.system.processingUsed = newProcessingUsed;
cloneComputer.system.overload = cloneComputer.system.processingUsed > cloneComputer.system.processing;
updatedComputers.push(cloneComputer);
}
}
if (updatedComputers.length > 0) {
await $this.updateEmbeddedDocuments('Item', updatedComputers);
}
}
}
static async calculEncumbranceAndWeight($this, parent, collection, documents, changes, options, userId) {
let recalculEncumbrance = false;
let recalculWeight = false;
let change;
let i = 0;
for (let d of documents) {
if (changes[i].hasOwnProperty("system")) {
change = changes[i];
if (d.type === "armor" ||
d.type === "computer" ||
d.type === "gear" ||
d.type === "item" ||
d.type === "weapon") {
if (change.system.hasOwnProperty("quantity") ||
change.system.hasOwnProperty("weight") ||
change.system.hasOwnProperty("weightless") ||
change.system.hasOwnProperty("container") ||
change.system.hasOwnProperty("equipped") ||
d.type === "armor") {
recalculWeight = true;
}
} else if (d.type === "talent" && d.system.subType === "skill") {
if (change.system.level || (change.system?.hasOwnProperty("skill") && change.system?.skill.hasOwnProperty("reduceEncumbrance"))) {
recalculEncumbrance = true;
}
} else if (d.type === "container" && (change.system.hasOwnProperty("onHand") || change.system.hasOwnProperty("weightless"))) {
recalculWeight = true;
}
}
i++;
}
if (recalculEncumbrance || recalculWeight) {
const updateData = {};
this.recalculateArmor($this, updateData);
if (recalculEncumbrance) {
const str = $this.system.characteristics.strength.value;
const end = $this.system.characteristics.endurance.value;
let sumSkill = 0;
$this.items.filter(x => x.type === "talent" && x.system.subType === "skill" && x.system.skill.reduceEncumbrance === true).forEach(x => sumSkill += x.system.level);
let normal = str + end + sumSkill;
let heavy = normal * 2;
updateData["system.states.encumbrance"] = $this.system.inventory.weight > normal;
updateData["system.inventory.encumbrance.normal"] = normal;
updateData["system.inventory.encumbrance.heavy"] = heavy;
}
if (recalculWeight)
await this.recalculateWeight($this, updateData);
else if (Object.keys(updateData).length > 0)
await $this.update(updateData);
}
}
static recalculateArmor($this, updateData) {
if (updateData === null || updateData === undefined)
updateData = {};
let armor = 0;
for (let item of $this.items) {
if (item.type === "armor") {
if (item.system.equipped === true && !isNaN(item.system.protection)) {
armor += (+item.system.protection || 0);
}
}
}
updateData["system.inventory.armor"] = armor;
return updateData;
}
static async recalculateWeight($this, updateData) {
if (updateData === null || updateData === undefined)
updateData = {};
let updatedContainers = [];
let containerChanges = {};
let containers = [];
// List all containers
for (let item of $this.items) {
if (item.system.trash === true) continue;
if (item.type === "container") {
containers.push(item);
containerChanges[item._id] = { count: 0, weight: 0 };
}
}
let onHandWeight = 0;
for (let item of $this.items) {
if (item.type === "container") continue;
if (item.system.hasOwnProperty("weightless") && item.system.weightless === true) continue;
let itemWeight = 0;
if (item.system.hasOwnProperty("weight")) {
let itemQty = item.system.quantity;
if (!isNaN(itemQty) && itemQty > 0) {
itemWeight = item.system.weight;
if (itemWeight > 0) {
itemWeight *= itemQty;
}
}
if (item.type === "armor") {
if (item.system.equipped === true) {
if (item.system.powered === true)
itemWeight = 0;
else
itemWeight *= 0.25; // mass of armor that is being worn by 75% OPTIONAL
}
}
if (item.system.container && item.system.container.id && item.system.container.id !== "") {
// bad deleted container id
if (containerChanges.hasOwnProperty(item.system.container.id)) {
containerChanges[item.system.container.id].weight += Math.round(itemWeight * 10) / 10;
containerChanges[item.system.container.id].count += item.system.quantity;
}
} else {
onHandWeight += Math.round(itemWeight * 10) / 10;
}
}
}
// Check containers new weight
for (let container of containers) {
let newWeight = containerChanges[container._id].weight;
let newCount = containerChanges[container._id].count;
if (container.system.weight !== newWeight || container.system.count !== newCount) {
updatedContainers.push({
_id: container._id,
"system.weight": newWeight,
"system.count": newCount,
});
if (container.system.onHand === true &&
(container.system.weight > 0 || container.system.weightless !== true)) {
onHandWeight += container.system.weight;
}
}
}
updateData["system.inventory.weight"] = onHandWeight;
updateData["system.states.encumbrance"] = onHandWeight > $this.system.inventory.encumbrance.normal;
await $this.update(updateData);
if (updatedContainers.length > 0) {
await $this.updateEmbeddedDocuments('Item', updatedContainers);
}
}
static async preUpdate($this, changed, options, user) {
// Calc encumbrance
const newStr = foundry.utils.getProperty(changed, "system.characteristics.strength.value") ?? $this.system.characteristics.strength.value;
const newEnd = foundry.utils.getProperty(changed, "system.characteristics.endurance.value") ?? $this.system.characteristics.endurance.value;
if ((newStr !== $this.system.characteristics.strength.value) || (newEnd !== $this.system.characteristics.endurance.value)) {
let sumSkill = 0;
$this.items.filter(x => x.type === "talent" && x.system.subType === "skill" && x.system.skill.reduceEncumbrance === true).forEach(x => sumSkill += x.system.level);
let normal = newStr + newEnd + sumSkill;
let heavy = normal * 2;
foundry.utils.setProperty(changed, "system.inventory.encumbrance.normal", normal);
foundry.utils.setProperty(changed, "system.inventory.encumbrance.heavy", heavy);
}
//console.log(foundry.utils.getProperty(changed, "system.characteristics.strength.value"));
const characteristicModified = this.computeCharacteristics(changed);
const strengthValue = foundry.utils.getProperty(changed, "system.characteristics.strength.value") ?? $this.system.characteristics.strength.value;
const strengthMax = foundry.utils.getProperty(changed, "system.characteristics.strength.max") ?? $this.system.characteristics.strength.max;
const dexterityValue = foundry.utils.getProperty(changed, "system.characteristics.dexterity.value") ?? $this.system.characteristics.dexterity.value;
const dexterityMax = foundry.utils.getProperty(changed, "system.characteristics.dexterity.max") ?? $this.system.characteristics.dexterity.max;
const enduranceValue = foundry.utils.getProperty(changed, "system.characteristics.endurance.value") ?? $this.system.characteristics.endurance.value;
const enduranceMax = foundry.utils.getProperty(changed, "system.characteristics.endurance.max") ?? $this.system.characteristics.endurance.max;
const lifeValue = strengthValue + dexterityValue + enduranceValue;
const lifeMax = strengthMax + dexterityMax + enduranceMax;
if ($this.system.life.value !== lifeValue)
foundry.utils.setProperty(changed, "system.life.value", lifeValue);
if ($this.system.life.max !== lifeMax)
foundry.utils.setProperty(changed, "system.life.max", lifeMax);
if (characteristicModified && $this.system.personal.ucp === undefined || $this.system.personal.ucp === "") {
// calc
}
//}
// Apply changes in Actor size to Token width/height
// if ( "size" in (this.system.traits || {}) ) {
// const newSize = foundry.utils.getProperty(changed, "system.traits.size");
// if ( newSize && (newSize !== this.system.traits?.size) ) {
// let size = CONFIG.DND5E.tokenSizes[newSize];
// if ( !foundry.utils.hasProperty(changed, "prototypeToken.width") ) {
// changed.prototypeToken ||= {};
// changed.prototypeToken.height = size;
// changed.prototypeToken.width = size;
// }
// }
// }
}
// static applyHealing($this, amount) {
// if (isNaN(amount) || amount === 0) return;
// const strength = $this.system.characteristics.strength;
// const dexterity = $this.system.characteristics.dexterity;
// const endurance = $this.system.characteristics.endurance;
// const data = {
// strength: { value: strength.value },
// dexterity: { value: dexterity.value },
// endurance: { value: endurance.value }
// };
// $this.update({ system: { characteristics: data } });
// }
static applyDamage($this, amount, { ignoreArmor = false } = {}) {
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;
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);
if (!ignoreArmor) {
const armorValue = $this.system.inventory?.armor ?? 0;
amount = Math.max(0, amount - armorValue);
if (amount === 0) return;
}
for (const [key, rank] of Object.entries(data)) {
if (rank.value > 0) {
if (rank.value >= amount) {
rank.value -= amount;
amount = 0;
} else {
amount -= rank.value;
rank.value = 0;
}
rank.dm = this.getModifier(rank.value);
if (amount <= 0) break;
}
}
$this.update({ system: { characteristics: data } });
}
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) {
const containers = [];
for (let item of $this.items) {
if (item.type == "container") {
containers.push(item);
}
}
containers.sort(this.compareByName);
return containers;
}
static getComputers($this) {
const containers = [];
for (let item of $this.items) {
if (item.type == "computer") {
containers.push(item);
}
}
containers.sort(this.compareByName);
return containers;
}
static getSkills($this) {
const skills = [];
for (let item of $this.items) {
if (item.type === "talent" && item.system.subType === "skill") {
skills.push(item);
}
}
skills.sort(this.compareByName);
return skills;
}
static computeCharacteristics(changed) {
let modified = this.computeCharacteristic(changed, "strength");
if (this.computeCharacteristic(changed, "dexterity") && !modified) modified = true;
if (this.computeCharacteristic(changed, "endurance") && !modified) modified = true;
if (this.computeCharacteristic(changed, "intellect") && !modified) modified = true;
if (this.computeCharacteristic(changed, "education") && !modified) modified = true;
if (this.computeCharacteristic(changed, "social") && !modified) modified = true;
if (this.computeCharacteristic(changed, "morale") && !modified) modified = true;
if (this.computeCharacteristic(changed, "luck") && !modified) modified = true;
if (this.computeCharacteristic(changed, "sanity") && !modified) modified = true;
if (this.computeCharacteristic(changed, "charm") && !modified) modified = true;
if (this.computeCharacteristic(changed, "psionic") && !modified) modified = true;
if (this.computeCharacteristic(changed, "other") && !modified) modified = true;
return modified;
}
static computeCharacteristic(changed, name) {
//if (isNaN(c.value) || c.value <= 0) c.value = 0;
//c.dm = this._getModifier(c.value)
const path = `system.characteristics.${name}`;
const newValue = foundry.utils.getProperty(changed, path + ".value");// || this.system.characteristics[name].value;
if (newValue) {
const dm = this.getModifier(newValue);
foundry.utils.setProperty(changed, path + ".dm", dm);
return true;
}
return false;
}
static getModifier(value) {
if (isNaN(value) || value <= 0) return -3;
if (value >= 1 && value <= 2) return -2;
if (value >= 3 && value <= 5) return -1;
if (value >= 6 && value <= 8) return 0;
if (value >= 9 && value <= 11) return 1;
if (value >= 12 && value <= 14) return 2;
return 3;
}
static compareByName(a, b) {
if (!a.hasOwnProperty("name") || !b.hasOwnProperty("name")) {
return 0;
}
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
}
}

View File

@@ -0,0 +1,18 @@
export class VehiculeActorSheet extends ActorSheet {
static get defaultOptions() {
const options = super.defaultOptions;
//if (game.user.isGM || options.editable)
// options.dragDrop.push({ dragSelector: ".drag-item-list", dropSelector: ".drop-item-list" });
return foundry.utils.mergeObject(options, {
classes: ["mgt2", game.settings.get("mgt2", "theme"), "actor", "vehicule", "nopad"],
template: "systems/mgt2/templates/actors/vehicule-sheet.html",
width: 780,
//height: 600,
tabs: [
{ navSelector: ".sheet-sidebar", contentSelector: "form" }
]
});
}
}

View File

@@ -0,0 +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";

View File

@@ -0,0 +1,107 @@
const { HandlebarsApplicationMixin } = foundry.applications.api;
export default class MGT2ActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
constructor(options = {}) {
super(options);
this._sheetMode = this.constructor.SHEET_MODES.PLAY;
}
/** @override */
static DEFAULT_OPTIONS = {
classes: ["mgt2", "sheet", "actor"],
position: {
width: 780,
},
form: {
submitOnChange: true,
closeOnSubmit: false,
},
window: {
resizable: true,
},
dragDrop: [{ dragSelector: ".drag-item-list", dropSelector: ".drop-item-list" }],
actions: {
toggleSheet: MGT2ActorSheet.#onToggleSheet,
},
}
get isPlayMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY;
return this._sheetMode === this.constructor.SHEET_MODES.PLAY;
}
get isEditMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY;
return this._sheetMode === this.constructor.SHEET_MODES.EDIT;
}
tabGroups = { sidebar: "health" }
/** @override */
async _prepareContext() {
const base = await super._prepareContext();
const actor = this.document;
return {
...base,
actor: actor,
// Flat shorthands for template backward-compat (AppV1 style)
name: actor.name,
img: actor.img,
cssClass: this.isEditable ? "editable" : "locked",
system: actor.system,
source: actor.toObject(),
fields: actor.schema.fields,
systemFields: actor.system.schema.fields,
isEditable: this.isEditable,
isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isGM: game.user.isGM,
config: CONFIG.MGT2,
};
}
/** @override */
_onRender(context, options) {
super._onRender(context, options);
// Inject theme class dynamically (can't use game.settings in static DEFAULT_OPTIONS)
const theme = game.settings.get("mgt2", "theme");
if (theme) this.element.classList.add(theme);
this._activateTabGroups();
}
_activateTabGroups() {
for (const [group, activeTab] of Object.entries(this.tabGroups)) {
const nav = this.element.querySelector(`nav[data-group="${group}"]`);
if (!nav) continue;
nav.querySelectorAll('[data-tab]').forEach(link => {
link.classList.toggle('active', link.dataset.tab === activeTab);
link.addEventListener('click', event => {
event.preventDefault();
this.tabGroups[group] = link.dataset.tab;
this.render();
});
});
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(content => {
content.classList.toggle('active', content.dataset.tab === activeTab);
});
}
}
/** @override */
_canDragDrop(selector) {
return this.isEditable;
}
static async #onToggleSheet(event) {
event.preventDefault();
this._sheetMode = this.isPlayMode
? this.constructor.SHEET_MODES.EDIT
: this.constructor.SHEET_MODES.PLAY;
this.render();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,290 @@
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 }) {
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 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}`] : [],
};
const chatContent = await renderTemplate(
"systems/mgt2/templates/chat/creature-roll.html",
chatData
);
await ChatMessage.create({
content: chatContent,
speaker: ChatMessage.getSpeaker({ actor }),
rolls: [roll],
rollMode: rollMode ?? game.settings.get("core", "rollMode"),
});
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}`);
const { success } = await TravellerCreatureSheet.#postCreatureRoll({
actor, roll, rollLabel,
dm,
difficulty: result.difficulty,
rollMode: result.rollMode,
extraTooltip: tooltipParts.join(" | "),
});
// Roll damage only on success
if (success && attack.damage) {
const dmgFormula = normalizeDice(attack.damage);
const dmgRoll = await new Roll(dmgFormula).evaluate();
await dmgRoll.toMessage({
speaker: ChatMessage.getSpeaker({ actor }),
flavor: `<strong>${actor.name}</strong> — ${game.i18n.localize("MGT2.Chat.Weapon.Damage")}: ${attack.name} (${attack.damage})`,
rollMode: result.rollMode ?? game.settings.get("core", "rollMode"),
});
}
}
// ───────────────────────────────────────────────────────── CRUD Handlers
static async #onAddRow(event, target) {
const prop = target.dataset.prop;
if (!prop) return;
const actor = this.document;
const arr = foundry.utils.deepClone(actor.system[prop] ?? []);
arr.push(this._getDefaultRow(prop));
await actor.update({ [`system.${prop}`]: arr });
}
static async #onDeleteRow(event, target) {
const prop = target.dataset.prop;
const index = parseInt(target.dataset.index);
if (!prop || isNaN(index)) return;
const actor = this.document;
const arr = foundry.utils.deepClone(actor.system[prop] ?? []);
arr.splice(index, 1);
await actor.update({ [`system.${prop}`]: arr });
}
_getDefaultRow(prop) {
switch (prop) {
case "skills": return { name: "", level: 0, note: "" };
case "attacks": return { name: "", damage: "1D", skill: -1, description: "" };
case "traits": return { name: "", value: "", description: "" };
default: return {};
}
}
}

View File

@@ -0,0 +1,285 @@
const { HandlebarsApplicationMixin } = foundry.applications.api;
import { MGT2Helper } from "../../helper.js";
export default class TravellerItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["mgt2", "sheet", "item"],
position: { width: 630 },
form: {
submitOnChange: true,
closeOnSubmit: false,
},
window: { resizable: true },
actions: {
careerEventCreate: TravellerItemSheet.#onCareerEventCreate,
careerEventDelete: TravellerItemSheet.#onCareerEventDelete,
optionCreate: TravellerItemSheet.#onOptionCreate,
optionDelete: TravellerItemSheet.#onOptionDelete,
modifierCreate: TravellerItemSheet.#onModifierCreate,
modifierDelete: TravellerItemSheet.#onModifierDelete,
},
}
/** Dynamic PARTS: template resolved per item type */
get PARTS() {
const type = this.document?.type ?? "item";
return {
sheet: {
template: `systems/mgt2/templates/items/${type}-sheet.html`,
},
};
}
/** Resolve template dynamically based on item type */
get template() {
return `systems/mgt2/templates/items/${this.document.type}-sheet.html`;
}
tabGroups = { primary: "tab1" }
/** @override */
async _prepareContext() {
const item = this.document;
const source = item.toObject();
const settings = {
usePronouns: game.settings.get("mgt2", "usePronouns"),
};
let containers = null;
let computers = null;
let hadContainer = false;
if (item.actor !== null) {
hadContainer = true;
containers = [{ name: "", _id: "" }].concat(item.actor.getContainers());
computers = [{ name: "", _id: "" }].concat(item.actor.getComputers());
}
let weight = null;
if (item.system.hasOwnProperty("weight")) {
weight = MGT2Helper.convertWeightForDisplay(item.system.weight);
}
let skills = [];
if (this.actor !== null) {
for (let actorItem of this.actor.items) {
if (actorItem.type === "talent" && actorItem.system.subType === "skill")
skills.push({ _id: actorItem._id, name: actorItem.getRollDisplay() });
}
}
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,
cssClass: this.isEditable ? "editable" : "locked",
system: item.system,
source: source.system,
fields: item.schema.fields,
systemFields: item.system.schema.fields,
isEditable: this.isEditable,
isGM: game.user.isGM,
config: CONFIG.MGT2,
settings: settings,
containers: containers,
computers: computers,
hadContainer: hadContainer,
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),
};
}
/** @override — resolve the per-type template before rendering */
async _renderHTML(context, options) {
const templatePath = `systems/mgt2/templates/items/${this.document.type}-sheet.html`;
const html = await foundry.applications.handlebars.renderTemplate(templatePath, context);
return { sheet: html };
}
/** @override — put rendered HTML into the window content */
_replaceHTML(result, content, options) {
content.innerHTML = result.sheet;
// Inject theme class dynamically (can't use game.settings in static DEFAULT_OPTIONS)
const theme = game.settings.get("mgt2", "theme");
if (theme) this.element.classList.add(theme);
this._activateTabGroups();
this._bindItemEvents();
}
/** Bind CSS class-based events (templates not yet migrated to data-action) */
_bindItemEvents() {
const html = this.element;
if (!this.isEditable) return;
const bind = (sel, handler) => {
for (const el of html.querySelectorAll(sel)) {
el.addEventListener("click", (ev) => handler.call(this, ev, ev.currentTarget));
}
};
bind(".event-create", TravellerItemSheet.#onCareerEventCreate);
bind(".event-delete", TravellerItemSheet.#onCareerEventDelete);
bind(".options-create", TravellerItemSheet.#onOptionCreate);
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() {
for (const [group, activeTab] of Object.entries(this.tabGroups)) {
const nav = this.element.querySelector(`nav[data-group="${group}"], .horizontal-tabs`);
if (!nav) continue;
nav.querySelectorAll('[data-tab]').forEach(link => {
link.classList.toggle('active', link.dataset.tab === activeTab);
link.addEventListener('click', event => {
event.preventDefault();
this.tabGroups[group] = link.dataset.tab;
this.render();
});
});
this.element.querySelectorAll(`.itemsheet-panel [data-tab], [data-group="${group}"][data-tab]`).forEach(content => {
content.classList.toggle('active', content.dataset.tab === activeTab);
});
}
}
/** @override — process form data before submit (weight/qty/cost conversions + container logic) */
_prepareSubmitData(event, form, formData) {
const data = foundry.utils.expandObject(formData.object);
if (data.hasOwnProperty("weight")) {
data.system = data.system || {};
data.system.weight = MGT2Helper.convertWeightFromInput(data.weight);
delete data.weight;
}
if (data.system?.hasOwnProperty("quantity")) {
data.system.quantity = MGT2Helper.getIntegerFromInput(data.system.quantity);
}
if (data.system?.hasOwnProperty("cost")) {
data.system.cost = MGT2Helper.getIntegerFromInput(data.system.cost);
}
// Container/equipped logic
if (data.system?.hasOwnProperty("container") && this.document.system.hasOwnProperty("equipped")) {
const equippedChange = this.document.system.equipped !== data.system.equipped;
const containerChange = this.document.system.container?.id !== data.system.container?.id;
if (equippedChange && data.system.equipped === true) {
data.system.container = { id: "" };
} else if (containerChange && data.system.container?.id !== "" && this.document.system.container?.id === "") {
data.system.equipped = false;
}
}
return foundry.utils.flattenObject(data);
}
// =========================================================
// Actions
// =========================================================
static async #onCareerEventCreate(event) {
event.preventDefault();
const events = this.document.system.events;
let newEvents;
if (!events || events.length === 0) {
newEvents = [{ age: "", description: "" }];
} else {
newEvents = [...events, { age: "", description: "" }];
}
return this.document.update({ system: { events: newEvents } });
}
static async #onCareerEventDelete(event, target) {
event.preventDefault();
const element = target.closest("[data-events-part]");
const index = Number(element.dataset.eventsPart);
const events = foundry.utils.deepClone(this.document.system.events);
const newEvents = Object.entries(events)
.filter(([key]) => Number(key) !== index)
.map(([, val]) => val);
return this.document.update({ system: { events: newEvents } });
}
static async #onOptionCreate(event, target) {
event.preventDefault();
const property = target.dataset.property;
const options = this.document.system[property];
let newOptions;
if (!options || options.length === 0) {
newOptions = [{ name: "", description: "" }];
} else {
newOptions = [...options, { name: "", description: "" }];
}
return this.document.update({ [`system.${property}`]: newOptions });
}
static async #onOptionDelete(event, target) {
event.preventDefault();
const element = target.closest("[data-options-part]");
const property = element.dataset.property;
const index = Number(element.dataset.optionsPart);
const options = foundry.utils.deepClone(this.document.system[property]);
const newOptions = Object.entries(options)
.filter(([key]) => Number(key) !== index)
.map(([, val]) => val);
return this.document.update({ [`system.${property}`]: newOptions });
}
static async #onModifierCreate(event) {
event.preventDefault();
const modifiers = this.document.system.modifiers;
let newModifiers;
if (!modifiers || modifiers.length === 0) {
newModifiers = [{ characteristic: "Endurance", value: null }];
} else {
newModifiers = [...modifiers, { characteristic: "Endurance", value: null }];
}
return this.document.update({ system: { modifiers: newModifiers } });
}
static async #onModifierDelete(event, target) {
event.preventDefault();
const element = target.closest("[data-modifiers-part]");
const index = Number(element.dataset.modifiersPart);
const modifiers = foundry.utils.deepClone(this.document.system.modifiers);
const newModifiers = Object.entries(modifiers)
.filter(([key]) => Number(key) !== index)
.map(([, val]) => val);
return this.document.update({ system: { modifiers: newModifiers } });
}
}

View File

@@ -0,0 +1,35 @@
import MGT2ActorSheet from "./base-actor-sheet.mjs";
export default class TravellerVehiculeSheet extends MGT2ActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "vehicule", "nopad"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "TYPES.Actor.vehicule",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/mgt2/templates/actors/vehicule-sheet.html",
},
}
/** @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;
}
}

136
src/module/chatHelper.js Normal file
View File

@@ -0,0 +1,136 @@
import { MGT2Helper } from "./helper.js";
export class ChatHelper {
static setupCardListeners(message, element, messageData) {
if (!message || !element) {
return;
}
element.querySelectorAll('button[data-action="rollDamage"]').forEach(el => {
el.addEventListener('click', async event => {
await this._processRollDamageButtonEvent(message, event);
});
});
element.querySelectorAll('button[data-action="damage"]').forEach(el => {
el.addEventListener('click', async event => {
await this._applyChatCardDamage(message, event);
});
});
element.querySelectorAll('button[data-action="healing"]').forEach(el => {
el.addEventListener('click', async event => {
await this._applyChatCardHealing(message, event);
});
});
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);
});
});
}
static async _processRollButtonEvent(message, event) {
event.preventDefault();
event.stopPropagation();
let buttons = message.flags.mgt2.buttons;
const index = event.target.dataset.index;
const button = buttons[index];
let roll = await new Roll(button.formula, {}).roll();
const chatData = {
user: game.user.id,
speaker: message.speaker,
formula: roll._formula,
tooltip: await roll.getTooltip(),
total: Math.round(roll.total * 100) / 100,
rollObjectName: button.message.objectName,
rollMessage: MGT2Helper.format(button.message.flavor, Math.round(roll.total * 100) / 100),
};
const html = await foundry.applications.handlebars.renderTemplate("systems/mgt2/templates/chat/roll.html", chatData);
chatData.content = html;
return roll.toMessage(chatData);
}
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;
}
let rollTypeName = message.flags.mgt2.damage.rollTypeName ? message.flags.mgt2.damage.rollTypeName + " " + game.i18n.localize("MGT2.Actor.Damage") : null;
const chatData = {
user: game.user.id,
speaker: ChatMessage.getSpeaker({ actor: 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
};
const html = await foundry.applications.handlebars.renderTemplate("systems/mgt2/templates/chat/roll.html", chatData);
chatData.content = html;
return roll.toMessage(chatData);
}
static _applyChatCardDamage(message, event) {
if (canvas.tokens.controlled.length === 0) {
ui.notifications.warn(game.i18n.localize("MGT2.Errors.NoTokenSelected"));
return;
}
const roll = message.rolls[0];
return Promise.all(canvas.tokens.controlled.map(t => {
const a = t.actor;
return a.applyDamage(roll.total);
}));
}
static _applyChatCardHealing(message, event) {
if (canvas.tokens.controlled.length === 0) {
ui.notifications.warn(game.i18n.localize("MGT2.Errors.NoTokenSelected"));
return;
}
// For First Aid/Surgery healing, use amount from flags; otherwise use roll total
const amount = message.flags?.mgt2?.healing?.amount
?? message.flags?.mgt2?.surgery?.healing
?? Math.max(1, message.rolls[0].total);
return Promise.all(canvas.tokens.controlled.map(t => {
const a = t.actor;
return a.applyHealing(amount);
}));
}
static _applyChatCardSurgeryDamage(message, event) {
if (canvas.tokens.controlled.length === 0) {
ui.notifications.warn(game.i18n.localize("MGT2.Errors.NoTokenSelected"));
return;
}
const amount = message.flags?.mgt2?.surgery?.surgeryDamage ?? 3;
return Promise.all(canvas.tokens.controlled.map(t => {
const a = t.actor;
return a.applyDamage(amount, { ignoreArmor: true });
}));
}
}

187
src/module/config.js Normal file
View File

@@ -0,0 +1,187 @@
export const MGT2 = {};
MGT2.MetricRange = Object.freeze({
meter: "MGT2.MetricRange.meter",
kilometer: "MGT2.MetricRange.kilometer"
});
MGT2.MetricWeight = Object.freeze({
kilogram: "MGT2.MetricWeight.kilogram",
ton: "MGT2.MetricWeight.ton"
});
MGT2.Difficulty = Object.freeze({
NA: "MGT2.Difficulty.NA",
Simple: "MGT2.Difficulty.Simple",
Easy: "MGT2.Difficulty.Easy",
Routine: "MGT2.Difficulty.Routine",
Average: "MGT2.Difficulty.Average",
Difficult: "MGT2.Difficulty.Difficult",
VeryDifficult: "MGT2.Difficulty.VeryDifficult",
Formidable: "MGT2.Difficulty.Formidable",
Impossible: "MGT2.Difficulty.Impossible"
});
MGT2.ItemSubType = Object.freeze({
loot: "MGT2.ItemSubType.loot",
software: "MGT2.ItemSubType.software"
});
MGT2.EquipmentSubType = Object.freeze({
augment: "MGT2.EquipmentSubType.augment",
clothing: "MGT2.EquipmentSubType.clothing",
equipment: "MGT2.EquipmentSubType.equipment",
trinket: "MGT2.EquipmentSubType.trinket",
toolkit: "MGT2.EquipmentSubType.toolkit"
});
MGT2.TalentSubType = Object.freeze({
skill: "MGT2.TalentSubType.skill",
psionic: "MGT2.TalentSubType.psionic"
});
MGT2.DiseaseSubType = Object.freeze({
disease: "MGT2.DiseaseSubType.disease",
poison: "MGT2.DiseaseSubType.poison",
wound: "MGT2.DiseaseSubType.wound"
});
MGT2.PsionicReach = Object.freeze({
NA: "MGT2.PsionicReach.NA",
Personal: "MGT2.PsionicReach.Personal",
Close: "MGT2.PsionicReach.Close",
Short: "MGT2.PsionicReach.Short",
Medium: "MGT2.PsionicReach.Medium",
Long: "MGT2.PsionicReach.Long",
VeryLong: "MGT2.PsionicReach.VeryLong",
Distant: "MGT2.PsionicReach.Distant",
VeryDistant: "MGT2.PsionicReach.VeryDistant",
Continental: "MGT2.PsionicReach.Continental",
Planetary: "MGT2.PsionicReach.Planetary"
});
MGT2.ContactRelations = Object.freeze({
Allie: "MGT2.Contact.Relation.Allie",
Contact: "MGT2.Contact.Relation.Contact",
Rival: "MGT2.Contact.Relation.Rival",
Enemy: "MGT2.Contact.Relation.Enemy"
});
MGT2.ContactStatus = Object.freeze({
Alive: "MGT2.Contact.Status.Alive",
Unknow: "MGT2.Contact.Status.Unknow",
Dead: "MGT2.Contact.Status.Dead"
});
MGT2.Attitudes = Object.freeze({
Unknow: "MGT2.Contact.Attitude.Unknow",
Hostile: "MGT2.Contact.Attitude.Hostile",
Unfriendly: "MGT2.Contact.Attitude.Unfriendly",
Indifferent: "MGT2.Contact.Attitude.Indifferent",
Friendly: "MGT2.Contact.Attitude.Friendly",
Helpful: "MGT2.Contact.Attitude.Helpful",
Complicated: "MGT2.Contact.Attitude.Complicated"
});
MGT2.Characteristics = Object.freeze({
strength: "MGT2.Characteristics.strength.name",
dexterity: "MGT2.Characteristics.dexterity.name",
endurance: "MGT2.Characteristics.endurance.name",
intellect: "MGT2.Characteristics.intellect.name",
education: "MGT2.Characteristics.education.name",
social: "MGT2.Characteristics.social.name",
morale: "MGT2.Characteristics.morale.name",
luck: "MGT2.Characteristics.luck.name",
sanity: "MGT2.Characteristics.sanity.name",
charm: "MGT2.Characteristics.charm.name",
psionic: "MGT2.Characteristics.psionic.name",
other: "MGT2.Characteristics.other.name"
});
MGT2.InitiativeCharacteristics = Object.freeze({
dexterity: "MGT2.Characteristics.dexterity.name",
intellect: "MGT2.Characteristics.intellect.name"
});
MGT2.DamageCharacteristics = Object.freeze({
strength: "MGT2.Characteristics.strength.name",
dexterity: "MGT2.Characteristics.dexterity.name",
endurance: "MGT2.Characteristics.endurance.name"
});
MGT2.TL = Object.freeze({
NA: "MGT2.TL.NA",
Unknow: "MGT2.TL.Unknow",
NotIdentified: "MGT2.TL.NotIdentified",
TL00: "MGT2.TL.L00",
TL01: "MGT2.TL.L01",
TL02: "MGT2.TL.L02",
TL03: "MGT2.TL.L03",
TL04: "MGT2.TL.L04",
TL05: "MGT2.TL.L05",
TL06: "MGT2.TL.L06",
TL07: "MGT2.TL.L07",
TL08: "MGT2.TL.L08",
TL09: "MGT2.TL.L09",
TL10: "MGT2.TL.L10",
TL11: "MGT2.TL.L11",
TL12: "MGT2.TL.L12",
TL13: "MGT2.TL.L13",
TL14: "MGT2.TL.L14",
TL15: "MGT2.TL.L15"
});
MGT2.Timeframes = Object.freeze({
Normal: "MGT2.Timeframes.Normal",
Slower: "MGT2.Timeframes.Slower",
Faster: "MGT2.Timeframes.Faster"
});
MGT2.SpeedBands = Object.freeze({
Stoppped: "MGT2.SpeedBands.Stoppped",
Idle: "MGT2.SpeedBands.Idle",
VerySlow: "MGT2.SpeedBands.VerySlow",
Slow: "MGT2.SpeedBands.Slow",
Medium: "MGT2.SpeedBands.Medium",
High: "MGT2.SpeedBands.High",
Fast: "MGT2.SpeedBands.Fast",
VeryFast: "MGT2.SpeedBands.VeryFast",
Subsonic: "MGT2.SpeedBands.Subsonic",
Hypersonic: "MGT2.SpeedBands.Hypersonic"
});
MGT2.Durations = Object.freeze({
Seconds: "MGT2.Durations.Seconds",
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
src/module/constants.js Normal file
View File

@@ -0,0 +1 @@
export const ATTRIBUTE_TYPES = ["String", "Number", "Boolean", "Formula", "Resource"];

133
src/module/core.js Normal file
View File

@@ -0,0 +1,133 @@
import {
CharacterData,
VehiculeData,
CreatureData,
ItemData,
EquipmentData,
DiseaseData,
CareerData,
TalentData,
ContactData,
ArmorData,
ComputerData,
WeaponData,
ItemContainerData,
SpeciesData
} from "./models/index.mjs";
import { MGT2 } from "./config.js";
import { TravellerActor, MGT2Combatant } from "./actors/actor.js";
import { TravellerItem } from "./item.js";
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";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
import { registerSettings } from "./settings.js";
function registerHandlebarsHelpers() {
Handlebars.registerHelper('showDM', function (dm) {
if (dm === 0) return "0";
if (dm > 0) return `+${dm}`;
if (dm < 0) return `${dm}`;
return "";
});
}
Hooks.once("init", async function () {
CONFIG.MGT2 = MGT2;
CONFIG.Combat.initiative = {
formula: "2d6 + @initiative",
decimals: 2
};
CONFIG.Actor.trackableAttributes = {
character: {
bar: ["life",
"characteristics.strength",
"characteristics.dexterity",
"characteristics.endurance",
"characteristics.intellect",
"characteristics.education",
"characteristics.social",
"characteristics.morale",
"characteristics.luck",
"characteristics.sanity",
"characteristics.charm",
"characteristics.psionic",
"characteristics.other"
],
value: ["life.value",
"health.radiations",
"characteristics.strength.value",
"characteristics.dexterity.value",
"characteristics.endurance.value",
"characteristics.intellect.value",
"characteristics.education.value",
"characteristics.social.value",
"characteristics.morale.value",
"characteristics.luck.value",
"characteristics.sanity.value",
"characteristics.charm.value",
"characteristics.psionic.value",
"characteristics.other.value"]
},
creature: {
bar: ["life"],
value: ["life.value", "life.max", "speed", "armor", "psi"]
}
};
game.mgt2 = {
TravellerActor,
TravellerItem
};
registerHandlebarsHelpers();
registerSettings();
CONFIG.Combatant.documentClass = MGT2Combatant;
CONFIG.Actor.documentClass = TravellerActor;
CONFIG.Item.documentClass = TravellerItem;
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,
"creature": CreatureData
});
Object.assign(CONFIG.Item.dataModels, {
"item": ItemData,
"equipment": EquipmentData,
"disease": DiseaseData,
"career": CareerData,
"talent": TalentData,
"contact": ContactData,
"weapon": WeaponData,
"computer": ComputerData,
"armor": ArmorData,
"container": ItemContainerData,
"species": SpeciesData
});
Hooks.on("renderChatMessageHTML", (message, element, messageData) => {
ChatHelper.setupCardListeners(message, element, messageData);
});
// Preload template partials
await preloadHandlebarsTemplates();
});
export { MGT2 };

221
src/module/helper.js Normal file
View File

@@ -0,0 +1,221 @@
export class MGT2Helper {
static POUNDS_CONVERT = 2.20462262185;
static decimalSeparator;
static badDecimalSeparator;
static {
this.decimalSeparator = Number(1.1).toLocaleString().charAt(1);
this.badDecimalSeparator = (this.decimalSeparator === "." ? "," : ".");
}
static format = function() {
var s = arguments[0];
for (var i = 0; i < arguments.length - 1; i++) {
var reg = new RegExp("\\{" + i + "\\}", "gm");
s = s.replace(reg, arguments[i + 1]);
}
return s;
}
static hasValue(object, property) {
return object !== undefined && object.hasOwnProperty(property) && object[property] !== null && object[property] !== undefined && object[property] !== "";
}
static getItemsWeight(items) {
let weight = 0;
for (let i of items) {
let item = i.hasOwnProperty("system") ? i.system : i;
if (item.hasOwnProperty("weightless") && item.weightless === true) {
continue;
}
if (item.hasOwnProperty("weight")) {
let itemQty = item.quantity
if (!isNaN(itemQty) && itemQty > 0) {
let itemWeight = item.weight;
if (itemWeight > 0) {
weight += itemWeight * itemQty;
}
}
}
}
return weight;
}
static generateUID() {
let result = '';
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 36; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
result += characters.charAt(randomIndex);
if (i === 8 || i === 12 || i === 16 || i === 20)
result += "-";
}
return result;
}
static compareByName(a, b) {
if (!a.hasOwnProperty("name") || !b.hasOwnProperty("name")) {
return 0;
}
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
}
static getDisplayDM(dm) {
if (dm === 0) return " (0)";
if (dm > 0) return ` (+${dm})`;
if (dm < 0) return ` (${dm})`;
return "";
}
static getFormulaDM(dm) {
if (dm === 0) return "+0";
if (dm > 0) return `+${dm}`;
if (dm < 0) return `${dm}`;
return "";
}
static getDiceResults(roll) {
const results = [];
for (const die of roll.dice) {
results.push(die.results);
}
return results.flat(2);
}
static getDiceTotal(roll) {
let total = 0;
for (const die of roll.dice) {
total += die.total;
}
return total;
}
static getDifficultyValue(difficulty) {
switch(difficulty) {
case "Simple": return 2;
case "Easy": return 4;
case "Routine": return 6;
case "Average": return 8;
case "Difficult": return 10;
case "VeryDifficult": return 12;
case "Formidable": return 14;
case "Impossible": return 16;
default:
return 0;
}
}
static getDifficultyDisplay(difficulty) {
const key = `MGT2.Difficulty.${difficulty}`;
const label = game.i18n.localize(key);
return label !== key ? label : null;
}
static getRangeDisplay(range) {
let value = Number(range.value);
if (isNaN(value)) return null;
let label;
//if (game.settings.get("mgt2", "useDistanceMetric") === true) {
if (range.unit !== null && range.unit !== undefined && range.unit !== "")
label = game.i18n.localize(`MGT2.MetricRange.${range.unit}`).toLowerCase();
else
label = "";
//} else {
// TODO
//}
return `${value}${label}`;
}
static getWeightLabel() {
//const label = game.settings.get("mgt2", "useWeightMetric") === true ? "MGT2.MetricSystem.Weight.kg" : "MGT2.ImperialSystem.Weight.lb";
//return game.i18n.localize(label);
return game.i18n.localize("MGT2.MetricSystem.Weight.kg");
}
static getDistanceLabel() {
//const label = game.settings.get("mgt2", "useDistanceMetric") === true ? "MGT2.MetricSystem.Distance.km" : "MGT2.ImperialSystem.Distance.mi";
//return game.i18n.localize(label);
return game.i18n.localize("MGT2.MetricSystem.Distance.km");
}
static getIntegerFromInput(data) {
return Math.trunc(this.getNumberFromInput(data));
}
static getNumberFromInput(data) {
if (data === undefined || data === null) return 0;
if (typeof data === "string") {
let converted = Number(data.replace(/\s+/g, '').replace(this.badDecimalSeparator, this.decimalSeparator).trim());
if (isNaN(converted))
return 0;
return converted;
}
let converted = Number(data);
if (isNaN(converted))
return 0;
return converted;
}
static convertWeightForDisplay(weight) {
//if (game.settings.get("mgt2", "useWeightMetric") === true || weight === 0)
return weight;
// Metric to Imperial
//const pounds = weight * this.POUNDS_CONVERT;
//return Math.round(pounds * 10) / 10;
}
static convertWeightFromInput(weight) {
//if (game.settings.get("mgt2", "useWeightMetric") === true || weight === 0)
return Math.round(weight * 10) / 10;
// Imperial to Metric
//const kg = this.POUNDS_CONVERT / weight;
//return Math.round(kg * 10) / 10;
}
static getDataFromDropEvent(event) {
let data;
try {
return JSON.parse(event.dataTransfer?.getData("text/plain"));
} catch (err) {
return false;
}
//if ( data.type !== "Item" ) return false;
//const item = await Item.implementation.fromDropData(data);
}
static async getItemDataFromDropData(dropData) {
//console.log("getItemDataFromDropData");
let item;
if (game.modules.get("monks-enhanced-journal")?.active && dropData.itemId && dropData.uuid.includes("JournalEntry")) {
const journalEntry = await fromUuid(dropData.uuid);
} else if (dropData.hasOwnProperty("uuid")) {
item = await fromUuid(dropData.uuid);
} else {
let uuid = `${dropData.type}.${dropData.data._id}`;
item = await fromUuid(uuid);
}
if (!item) {
throw new Error(game.i18n.localize("Errors.CouldNotFindItem").replace("_ITEM_ID_", dropData.uuid));
}
if (item.pack) {
const pack = game.packs.get(item.pack);
item = await pack?.getDocument(item._id);
}
return deepClone(item);
}
}

402
src/module/item-sheet.js Normal file
View File

@@ -0,0 +1,402 @@
import { MGT2Helper } from "./helper.js";
/**
* Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
*/
export class TravellerItemSheet extends ItemSheet {
/** @inheritdoc */
static get defaultOptions() {
const options = super.defaultOptions;
return foundry.utils.mergeObject(options, {
classes: ["mgt2", game.settings.get("mgt2", "theme"), "sheet"],
width: 630,
tabs: [{ navSelector: ".horizontal-tabs", contentSelector: ".itemsheet-panel", initial: "tab1" }]
});
}
/* -------------------------------------------- */
get template() {
const path = "systems/mgt2/templates/items";
return `${path}/${this.item.type}-sheet.html`;
}
/** @inheritdoc */
async getData(options) {
const context = await super.getData(options);
//console.log('-=getData=-');
//console.log(context);
const item = context.item;
const source = item.toObject();
context.config = CONFIG.MGT2;
const settings = {};
settings.usePronouns = game.settings.get("mgt2", "usePronouns");
let containers = null;
let computers = null;;
let hadContainer;
if (context.item.actor != null) {
hadContainer = true;
containers = [{ "name": "", "_id": "" }].concat(context.item.actor.getContainers());
computers = [{ "name": "", "_id": "" }].concat(context.item.actor.getComputers());
} else {
hadContainer = false;
}
let weight = null;
if (item.system.hasOwnProperty("weight")) {
weight = MGT2Helper.convertWeightForDisplay(item.system.weight);
}
let unitlabels = {
weight: MGT2Helper.getWeightLabel()
};
let skills = [];
if (this.actor !== null) {
for (let item of this.actor.items) {
if (item.type === "talent") {
if (item.system.subType === "skill")
skills.push({ _id: item._id, name: item.getRollDisplay() });
}
}
}
skills.sort(MGT2Helper.compareByName);
skills = [{ _id: "NP", name: game.i18n.localize("MGT2.Items.NotProficient") }].concat(skills);
foundry.utils.mergeObject(context, {
source: source.system,
system: item.system,
settings: settings,
containers: containers,
computers: computers,
hadContainer: hadContainer,
weight: weight,
unitlabels: unitlabels,
editable: this.isEditable,
isGM: game.user.isGM,
skills: skills,
config: CONFIG
//rollData: this.item.getRollData(),
});
return context;
}
/* -------------------------------------------- */
/** @inheritdoc */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.isEditable) return;
//let handler = ev => this._onDropCustom(ev);
//console.log(html);
// itemsheet-panel
//html.addEventListener("dragstart", this._onDropCustom, false);
html.find('div.itemsheet-panel').each((i, li) => {
// //if (li.classList.contains("inventory-header")) return;
//li.setAttribute("draggable", true);
//li.addEventListener("drop", handler, false);
});
//html.find('div.dropitem').each((i, li) => {
// //if (li.classList.contains("inventory-header")) return;
// li.setAttribute("draggable", true);
// li.addEventListener("dragstart", handler, false);
//});
// if (this.item.type == "weapon") {
// html.find('.trait-create').click(this._onTraitCreate.bind(this));
// html.find('.trait-delete').click(this._onTraitDelete.bind(this));
// }
if (this.item.type == "career") {
html.find('.event-create').click(this._onCareerEventCreate.bind(this));
html.find('.event-delete').click(this._onCareerEventDelete.bind(this));
}
else if (this.item.type == "armor" ||
this.item.type == "computer" ||
this.item.type == "species" ||
this.item.type == "weapon") {
html.find('.options-create').click(this._onOptionCreate.bind(this));
html.find('.options-delete').click(this._onOptionDelete.bind(this));
}
if (this.item.type == "species") {
html.find('.modifiers-create').click(this._onModifierEventCreate.bind(this));
html.find('.modifiers-delete').click(this._onModifierEventDelete.bind(this));
}
}
async _onModifierEventCreate(event) {
event.preventDefault();
await this._onSubmit(event);
let modifiers = this.item.system.modifiers;
let index;
if (modifiers.length === 0) {
modifiers = {};
modifiers["0"] = { characteristic: "Endurance", value: null };
} else {
index = Math.max(...Object.keys(modifiers));
index++;
modifiers[index] = { characteristic: "Endurance", value: null };
}
let update = {
system: {
modifiers: modifiers
}
};
return this.item.update(update);
}
async _onModifierEventDelete(event) {
event.preventDefault();
await this._onSubmit(event);
const element = event.currentTarget.closest(".modifiers-part");
const modifiers = foundry.utils.deepClone(this.item.system.modifiers);
let index = Number(element.dataset.modifiersPart);
const newModifiers = [];
let entries = Object.entries(modifiers);
if (entries.length > 1) {
for (const [key, value] of entries) {
if (key != index)
newModifiers.push(value);
}
}
let update = {
system: {
modifiers: newModifiers
}
};
return this.item.update(update);
}
async _onCareerEventCreate(event) {
event.preventDefault();
await this._onSubmit(event);
let events = this.item.system.events;
let index;
if (events.length === 0) {
events = {};
events["0"] = { age: "", description: "" };
} else {
index = Math.max(...Object.keys(events));
index++;
events[index] = { age: "", description: "" };
}
let update = {
system: {
events: events
}
};
return this.item.update(update);
}
async _onCareerEventDelete(event) {
event.preventDefault();
await this._onSubmit(event);
const element = event.currentTarget.closest(".events-part");
const events = foundry.utils.deepClone(this.item.system.events);
let index = Number(element.dataset.eventsPart);
const newEvents = [];
let entries = Object.entries(events);
if (entries.length > 1) {
for (const [key, value] of entries) {
if (key != index)
newEvents.push(value);
}
}
let update = {
system: {
events: newEvents
}
};
return this.item.update(update);
}
async _onOptionCreate(event) {
event.preventDefault();
await this._onSubmit(event);
//const subType = event.currentTarget.dataset.subType;
const property = event.currentTarget.dataset.property;
//let options = this.item.system[subType][property];
let options = this.item.system[property];
let index;
if (options.length === 0) {
options = {};
options["0"] = { name: "", description: "" };
} else {
index = Math.max(...Object.keys(options));
index++;
options[index] = { name: "", description: "" };
}
let update = {};
//update[`system.${subType}.${property}`] = options;
update[`system.${property}`] = options;
return this.item.update(update);
}
async _onOptionDelete(event) {
event.preventDefault();
await this._onSubmit(event);
const element = event.currentTarget.closest(".options-part");
//const subType = element.dataset.subType;
const property = element.dataset.property;
//const options = foundry.utils.deepClone(this.item.system[subType][property]);
const options = foundry.utils.deepClone(this.item.system[property]);
let index = Number(element.dataset.optionsPart);
const newOptions = [];
let entries = Object.entries(options);
if (entries.length > 1) {
for (const [key, value] of entries) {
if (key != index)
newOptions.push(value);
}
}
let update = {};
//update[`system.${subType}.${property}`] = newOptions;
update[`system.${property}`] = newOptions;
return this.item.update(update);
}
// async _onTraitCreate(event) {
// event.preventDefault();
// await this._onSubmit(event);
// const traits = this.item.system.traits;
// return this.item.update({ "system.traits.parts": traits.parts.concat([["", ""]]) });
// }
// async _onTraitDelete(event) {
// event.preventDefault();
// await this._onSubmit(event);
// const element = event.currentTarget.closest(".traits-part");
// const traits = foundry.utils.deepClone(this.item.system.traits);
// traits.parts.splice(Number(element.dataset.traitsPart), 1);
// return this.item.update({ "system.traits.parts": traits.parts });
// }
_getSubmitData(updateData = {}) {
const formData = foundry.utils.expandObject(super._getSubmitData(updateData));
// Gestion des containers
if (formData.hasOwnProperty("system") && formData.system.hasOwnProperty("container") &&
(this.item.system.hasOwnProperty("equipped"))) {
//*console.log('-=_getSubmitData=-');
//console.log(this.item.system.onHand);
//console.log(formData.system.onHand);
//const onHandChange = this.item.system.onHand !== formData.system.onHand;
const equippedChange = this.item.system.equipped !== formData.system.equipped;
const containerChange = this.item.system.container.id !== formData.system.container.id;
// Maintenant équipé
if (equippedChange) {
if (formData.system.equipped === true) {
//formData.system.onHand = true;
//console.log("clear container");
formData.system.container = {
//inContainer: false,
id: ""
};
}
}
/*else if (onHandChange) {
// Maintenant à portée
if (formData.system.onHand === true) {
//console.log("clear container");
formData.system.container = {
inContainer: false,
id: ""
};
} else {
formData.system.equipped = false;
}
}*/
else if (containerChange) {
// Mise en storage
if (formData.system.container.id !== "" && (this.item.system.container.id === "" || this.item.system.container.id === null)) {
//console.log("put in container");
//formData.system.onHand = false;
formData.system.equipped = false;
//formData.system.container.inContainer = true;
}
}
}
// if (this.item.type == "weapon") {
// const traits = formData.system?.traits;
// if (traits)
// traits.parts = Object.values(traits?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
// }
// else if (this.item.type == "career") {
// const events = formData.system?.events;
// if (events)
// events.parts = Object.values(events?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
// }
// else if (this.item.type == "equipment") {
// if (this.item.system.subType == "armor") {
// // const armor = formData.system?.armor;
// // if (armor)
// // //options.parts = Object.values(options?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
// // console.log(armor.options);
// // armor.options = Object.values(armor?.options || {})
// // .map(d => [d.name || "", d.description || ""]);
// // console.log(armor.options);
// } else if (this.item.system.subType == "computer") {
// const computer = formData.system?.computer;
// if (computer)
// //options.parts = Object.values(options?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
// computer.options = Object.values(computer?.options || {}).map(d => [d[0] || "", d[1] || ""]);
// }
// }
if (formData.hasOwnProperty("weight")) {
formData.system.weight = MGT2Helper.convertWeightFromInput(formData.weight);
delete formData.weight;
}
if (formData.system.hasOwnProperty("quantity")) {
formData.system.quantity = MGT2Helper.getIntegerFromInput(formData.system.quantity);
}
if (formData.system.hasOwnProperty("cost")) {
formData.system.cost = MGT2Helper.getIntegerFromInput(formData.system.cost);
}
//console.log("before flatten");
//console.log(formData);
//console.log("after flatten");
// let x = foundry.utils.flattenObject(formData);;
// console.log(x);
// return x;
return foundry.utils.flattenObject(formData);
}
}

61
src/module/item.js Normal file
View File

@@ -0,0 +1,61 @@
export class TravellerItem extends Item {
/** @inheritdoc */
prepareDerivedData() {
super.prepareDerivedData();
}
async _preUpdate(changed, options, user) {
if ((await super._preUpdate(changed, options, user)) === false) return false;
if (this.type === "computer") {
// Overload
const newProcessing = foundry.utils.getProperty(changed, "system.processing") ?? this.system.processing;
if (newProcessing !== this.system.processing) {
let overload = this.system.processingUsed > newProcessing;
foundry.utils.setProperty(changed, "system.overload", overload);
}
}
// Qty max 1
if (this.type === "computer" || this.type === "container" || (this.type === "item" && this.system.subType === "software")) {
const newQty = foundry.utils.getProperty(changed, "system.quantity") ?? this.system.quantity;
if (newQty !== this.system.quantity && newQty > 1) {
foundry.utils.setProperty(changed, "system.quantity", 1);
}
}
// No Weight
if (this.type === "item" && this.system.subType === "software") {
const newWeight = foundry.utils.getProperty(changed, "system.weight") ?? this.system.weight;
if (newWeight !== this.system.weight && newWeight > 0) {
foundry.utils.setProperty(changed, "system.weight", 0);
}
}
}
getRollDisplay() {
if (this.type === "talent") {
if (this.system.subType === "skill") {
let label;
if (this.system.skill.speciality !== "" && this.system.skill.speciality !== undefined) {
label = `${this.name} (${this.system.skill.speciality})`;
} else {
label = this.name;
}
if (this.system.level > 0)
label += ` (+${this.system.level})`;
else if (this.system.level < 0)
label += ` (${this.system.level})`;
return label;
} else if (this.system.subType === "psionic") {
}
}
return name;
}
}

View File

@@ -0,0 +1,98 @@
import { createCharacteristicField } from "./items/base-item.mjs";
const fields = foundry.data.fields;
export default class CharacterData extends foundry.abstract.TypeDataModel {
static defineSchema() {
return {
name: new fields.StringField({ required: false, blank: false, trim: true }),
life: new fields.SchemaField({
value: new fields.NumberField({ required: false, initial: 0, integer: true }),
max: new fields.NumberField({ required: true, initial: 0, integer: true })
}),
personal: new fields.SchemaField({
title: new fields.StringField({ required: false, blank: true, trim: true }),
species: new fields.StringField({ required: false, blank: true, trim: true }),
speciesText: new fields.SchemaField({
description: new fields.StringField({ required: false, blank: true, trim: true, nullable: true }),
descriptionLong: new fields.HTMLField({ required: false, blank: true, trim: true })
}),
age: new fields.StringField({ required: false, blank: true, trim: true }),
gender: new fields.StringField({ required: false, blank: true, trim: true }),
pronouns: new fields.StringField({ required: false, blank: true, trim: true }),
homeworld: new fields.StringField({ required: false, blank: true, trim: true }),
ucp: 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 }),
description: new fields.StringField({ required: false, blank: true, trim: true })
})
)
}),
biography: new fields.HTMLField({ required: false, blank: true, trim: true }),
characteristics: new fields.SchemaField({
strength: createCharacteristicField(true, true),
dexterity: createCharacteristicField(true, true),
endurance: createCharacteristicField(true, true),
intellect: createCharacteristicField(true, false),
education: createCharacteristicField(true, false),
social: createCharacteristicField(true, false),
morale: createCharacteristicField(true, false),
luck: createCharacteristicField(true, false),
sanity: createCharacteristicField(true, false),
charm: createCharacteristicField(true, false),
psionic: createCharacteristicField(true, false),
other: createCharacteristicField(true, false)
}),
health: new fields.SchemaField({
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: "" }),
total: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true }),
completed: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true })
}),
finance: new fields.SchemaField({
pension: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
credits: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
cashOnHand: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
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.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: "" }),
notes: new fields.HTMLField({ required: false, blank: true, trim: true }),
inventory: new fields.SchemaField({
armor: new fields.NumberField({ required: true, initial: 0, integer: true }),
weight: new fields.NumberField({ required: true, initial: 0, min: 0, integer: false }),
encumbrance: new fields.SchemaField({
normal: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
heavy: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true })
})
}),
states: new fields.SchemaField({
encumbrance: new fields.BooleanField({ required: false, initial: false }),
fatigue: new fields.BooleanField({ required: false, initial: false }),
unconscious: new fields.BooleanField({ required: false, initial: false }),
surgeryRequired: new fields.BooleanField({ required: false, initial: false })
}),
config: new fields.SchemaField({
psionic: new fields.BooleanField({ required: false, initial: true }),
initiative: new fields.StringField({ required: false, blank: true, initial: "dexterity" }),
damages: new fields.SchemaField({
rank1: new fields.StringField({ required: false, blank: true, initial: "strength" }),
rank2: new fields.StringField({ required: false, blank: true, initial: "dexterity" }),
rank3: new fields.StringField({ required: false, blank: true, initial: "endurance" })
})
})
};
}
}

View 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;
}
}
}
}
}
}

View File

@@ -0,0 +1,17 @@
// 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";
export { default as EquipmentData } from "./items/equipment.mjs";
export { default as DiseaseData } from "./items/disease.mjs";
export { default as CareerData } from "./items/career.mjs";
export { default as TalentData } from "./items/talent.mjs";
export { default as ContactData } from "./items/contact.mjs";
export { default as WeaponData } from "./items/weapon.mjs";
export { default as ArmorData } from "./items/armor.mjs";
export { default as ComputerData } from "./items/computer.mjs";
export { default as ItemContainerData } from "./items/container.mjs";
export { default as SpeciesData } from "./items/species.mjs";

View File

@@ -0,0 +1,23 @@
import { PhysicalItemData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class ArmorData extends PhysicalItemData {
static defineSchema() {
const schema = super.defineSchema();
schema.equipped = new fields.BooleanField({ required: false, initial: false });
schema.radiations = new fields.NumberField({ required: false, initial: 0, min: 0, integer: true });
schema.protection = new fields.StringField({ required: false, blank: false, trim: true });
// A Traveller suffers DM-1 to all checks per missing skill level in the required skill.
schema.requireSkill = new fields.StringField({ required: false, blank: false });
schema.requireSkillLevel = new fields.NumberField({ required: false, min: 0, integer: true });
// Powered armour supports its own weight and is effectively weightless for encumbrance.
schema.powered = 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 }),
description: new fields.StringField({ required: false, blank: true, trim: true })
})
);
return schema;
}
}

View File

@@ -0,0 +1,41 @@
const fields = foundry.data.fields;
export function createCharacteristicField(show = true, showMax = false) {
return new fields.SchemaField({
value: new fields.NumberField({ required: true, initial: 0, min: 0, integer: true }),
max: new fields.NumberField({ required: false, initial: 0, min: 0, integer: true }),
dm: new fields.NumberField({ required: false, initial: 0, integer: true }),
show: new fields.BooleanField({ required: false, initial: show }),
showMax: new fields.BooleanField({ required: false, initial: showMax })
});
}
export class ItemBaseData extends foundry.abstract.TypeDataModel {
static defineSchema() {
return {
description: new fields.HTMLField({ required: false, blank: true, trim: true }),
subType: new fields.StringField({ required: false, blank: false, nullable: true })
};
}
}
export class PhysicalItemData extends ItemBaseData {
static defineSchema() {
const schema = super.defineSchema();
schema.quantity = new fields.NumberField({ required: true, initial: 1, min: 0, integer: true });
schema.weight = new fields.NumberField({ required: true, initial: 0, min: 0, integer: false });
schema.weightless = new fields.BooleanField({ required: false, initial: false });
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0, integer: true });
schema.tl = new fields.StringField({ required: true, blank: false, initial: "TL12" });
schema.container = new fields.SchemaField({
id: new fields.StringField({ required: false, blank: true })
});
schema.roll = new fields.SchemaField({
characteristic: new fields.StringField({ required: false, blank: true, trim: true }),
skill: new fields.StringField({ required: false, blank: true, trim: true }),
difficulty: new fields.StringField({ required: false, blank: true, trim: true })
});
schema.trash = new fields.BooleanField({ required: false, initial: false });
return schema;
}
}

View File

@@ -0,0 +1,21 @@
import { ItemBaseData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class CareerData extends ItemBaseData {
static defineSchema() {
const schema = super.defineSchema();
schema.difficulty = new fields.NumberField({ required: true, initial: 0, min: 0, integer: true });
schema.damage = new fields.StringField({ required: false, blank: true });
schema.interval = new fields.StringField({ required: false, blank: true });
schema.assignment = new fields.StringField({ required: false, blank: true });
schema.terms = new fields.NumberField({ required: false, initial: 0, min: 0, integer: true });
schema.rank = new fields.NumberField({ required: false, initial: 0, min: 0, integer: true });
schema.events = new fields.ArrayField(
new fields.SchemaField({
age: new fields.NumberField({ required: false, integer: true }),
description: new fields.StringField({ required: false, blank: true, trim: true })
})
);
return schema;
}
}

View File

@@ -0,0 +1,18 @@
import { PhysicalItemData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class ComputerData extends PhysicalItemData {
static defineSchema() {
const schema = super.defineSchema();
schema.processing = new fields.NumberField({ required: false, initial: 0, min: 0, integer: true });
schema.processingUsed = new fields.NumberField({ required: false, initial: 0, min: 0, integer: true });
schema.overload = 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 }),
description: new fields.StringField({ required: false, blank: true, trim: true })
})
);
return schema;
}
}

View File

@@ -0,0 +1,27 @@
import { ItemBaseData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class ContactData extends ItemBaseData {
static defineSchema() {
const schema = super.defineSchema();
schema.subType.initial = "skill";
schema.cost = new fields.NumberField({ required: true, initial: 1, min: 0, integer: true });
schema.skill = new fields.SchemaField({
speciality: new fields.StringField({ required: false, blank: true, trim: true }),
characteristic: new fields.StringField({ required: false, blank: true, trim: true })
});
schema.status = new fields.StringField({ required: false, blank: true, trim: true, initial: "Alive" });
schema.attitude = new fields.StringField({ required: false, blank: true, trim: true, initial: "Unknow" });
schema.relation = new fields.StringField({ required: false, blank: true, trim: true, initial: "Contact" });
schema.title = new fields.StringField({ required: false, blank: true, trim: true });
schema.nickname = new fields.StringField({ required: false, blank: true, trim: true });
schema.species = new fields.StringField({ required: false, blank: true, trim: true });
schema.gender = new fields.StringField({ required: false, blank: true, trim: true });
schema.pronouns = new fields.StringField({ required: false, blank: true, trim: true });
schema.homeworld = new fields.StringField({ required: false, blank: true, trim: true });
schema.location = new fields.StringField({ required: false, blank: true, trim: true });
schema.occupation = new fields.StringField({ required: false, blank: true, trim: true });
schema.notes = new fields.HTMLField({ required: false, blank: true, trim: true });
return schema;
}
}

View File

@@ -0,0 +1,16 @@
import { ItemBaseData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class ItemContainerData extends ItemBaseData {
static defineSchema() {
const schema = super.defineSchema();
schema.onHand = new fields.BooleanField({ required: false, initial: false });
schema.location = new fields.StringField({ required: false, blank: true, trim: true });
schema.count = new fields.NumberField({ required: false, initial: 0, integer: true });
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.HTMLField({ required: false, blank: true, trim: true });
return schema;
}
}

View File

@@ -0,0 +1,13 @@
import { ItemBaseData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class DiseaseData extends ItemBaseData {
static defineSchema() {
const schema = super.defineSchema();
schema.subType.initial = "disease"; // disease, poison
schema.difficulty = new fields.StringField({ required: true, initial: "Average" });
schema.damage = new fields.StringField({ required: false, blank: true });
schema.interval = new fields.StringField({ required: false, blank: true });
return schema;
}
}

View File

@@ -0,0 +1,14 @@
import { PhysicalItemData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class EquipmentData extends PhysicalItemData {
static defineSchema() {
const schema = super.defineSchema();
schema.equipped = new fields.BooleanField({ required: false, initial: false });
schema.augment = new fields.SchemaField({
improvement: new fields.StringField({ required: false, blank: true, trim: true })
});
schema.subType.initial = "equipment"; // augment, clothing, trinket, toolkit, equipment
return schema;
}
}

View File

@@ -0,0 +1,15 @@
import { PhysicalItemData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class ItemData extends PhysicalItemData {
static defineSchema() {
const schema = super.defineSchema();
schema.subType.initial = "loot";
schema.software = new fields.SchemaField({
bandwidth: new fields.NumberField({ required: false, initial: 0, min: 0, max: 10, integer: true }),
effect: new fields.StringField({ required: false, blank: true, trim: true, initial: "" }),
computerId: new fields.StringField({ required: false, blank: true, initial: "" })
});
return schema;
}
}

View File

@@ -0,0 +1,22 @@
const fields = foundry.data.fields;
export default class SpeciesData extends foundry.abstract.TypeDataModel {
static defineSchema() {
return {
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({
name: new fields.StringField({ required: true, blank: true, trim: true }),
description: new fields.StringField({ required: false, blank: true, trim: true })
})
),
modifiers: new fields.ArrayField(
new fields.SchemaField({
characteristic: new fields.StringField({ required: false, blank: true, trim: true }),
value: new fields.NumberField({ required: false, integer: true, nullable: true })
})
)
};
}
}

View File

@@ -0,0 +1,27 @@
import { ItemBaseData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class TalentData extends ItemBaseData {
static defineSchema() {
const schema = super.defineSchema();
schema.subType.initial = "skill";
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0, integer: true });
schema.level = new fields.NumberField({ required: true, initial: 0, min: 0, integer: true });
schema.skill = new fields.SchemaField({
speciality: new fields.StringField({ required: false, blank: true, trim: true }),
reduceEncumbrance: new fields.BooleanField({ required: false, initial: false })
});
schema.psionic = new fields.SchemaField({
reach: new fields.StringField({ required: false, blank: true, trim: true }),
cost: new fields.NumberField({ required: false, initial: 1, min: 0, integer: true }),
duration: new fields.StringField({ required: false, blank: true, trim: true }),
durationUnit: new fields.StringField({ required: false })
});
schema.roll = new fields.SchemaField({
characteristic: new fields.StringField({ required: false, blank: true, trim: true }),
skill: new fields.StringField({ required: false, blank: true, trim: true }),
difficulty: new fields.StringField({ required: false, blank: true, trim: true })
});
return schema;
}
}

View File

@@ -0,0 +1,30 @@
import { PhysicalItemData } from "./base-item.mjs";
const fields = foundry.data.fields;
export default class WeaponData extends PhysicalItemData {
static defineSchema() {
const schema = super.defineSchema();
schema.equipped = new fields.BooleanField({ required: false, initial: false });
schema.range = new fields.SchemaField({
isMelee: new fields.BooleanField({ required: false, initial: false }),
value: new fields.NumberField({ required: false, integer: true, nullable: true }),
unit: new fields.StringField({ required: false, blank: true, nullable: true })
});
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.options = 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 })
})
);
return schema;
}
}

View File

@@ -0,0 +1,35 @@
const fields = foundry.data.fields;
export default class VehiculeData extends foundry.abstract.TypeDataModel {
static defineSchema() {
return {
name: new fields.StringField({ required: false, blank: false, trim: true }),
skillId: new fields.StringField({ required: false, initial: "", blank: true, trim: true }),
speed: new fields.SchemaField({
cruise: new fields.StringField({ required: false, initial: "Slow", blank: true }),
maximum: new fields.StringField({ required: false, initial: "Medium", blank: true })
}),
agility: new fields.NumberField({ required: false, min: 0, integer: true }),
crew: new fields.NumberField({ required: false, min: 0, integer: true }),
passengers: new fields.NumberField({ required: false, min: 0, integer: true }),
cargo: new fields.NumberField({ required: false, min: 0, integer: false }),
life: new fields.SchemaField({
value: new fields.NumberField({ required: true, initial: 0, integer: true }),
max: new fields.NumberField({ required: true, initial: 0, integer: true })
}),
shipping: new fields.NumberField({ required: false, min: 0, integer: true }),
cost: new fields.NumberField({ required: false, min: 0, integer: true }),
armor: new fields.SchemaField({
front: new fields.NumberField({ required: true, initial: 0, integer: true }),
rear: new fields.NumberField({ required: true, initial: 0, integer: true }),
sides: new fields.NumberField({ required: true, initial: 0, integer: true })
}),
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 })
};
}
}

77
src/module/roll-prompt.js Normal file
View File

@@ -0,0 +1,77 @@
const { DialogV2 } = foundry.applications.api;
const { renderTemplate } = foundry.applications.handlebars;
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,
// 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
});
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: [
{
action: "boon",
label: game.i18n.localize("MGT2.RollPrompt.Boon"),
callback: (event, button, dialog) => {
const formData = new FormDataExtended(dialog.element.querySelector('form')).object;
formData.diceModifier = "dl";
return formData;
}
},
{
action: "submit",
label: game.i18n.localize("MGT2.RollPrompt.Roll"),
icon: '<i class="fa-solid fa-dice"></i>',
default: true,
callback: (event, button, dialog) => {
return new FormDataExtended(dialog.element.querySelector('form')).object;
}
},
{
action: "bane",
label: game.i18n.localize("MGT2.RollPrompt.Bane"),
callback: (event, button, dialog) => {
const formData = new FormDataExtended(dialog.element.querySelector('form')).object;
formData.diceModifier = "dh";
return formData;
}
}
]
});
}
}

86
src/module/settings.js Normal file
View File

@@ -0,0 +1,86 @@
export const registerSettings = function () {
game.settings.register("mgt2", "theme", {
name: "MGT2.Settings.theme.name",
hint: "MGT2.Settings.theme.hint",
scope: "client",
config: true,
default: "black-and-red",
type: String,
choices: {
"black-and-red": "MGT2.Themes.BlackAndRed",
"mwamba": "MGT2.Themes.Mwamba",
"blue": "MGT2.Themes.Blue"
},
requiresReload: true
});
game.settings.register('mgt2', 'usePronouns', {
name: "MGT2.Settings.usePronouns.name",
hint: "MGT2.Settings.usePronouns.hint",
default: false,
scope: 'world',
type: Boolean,
config: true,
requiresReload: false
});
game.settings.register('mgt2', 'useGender', {
name: "MGT2.Settings.useGender.name",
hint: "MGT2.Settings.useGender.hint",
default: false,
scope: 'world',
type: Boolean,
config: true,
requiresReload: false
});
game.settings.register('mgt2', 'showLife', {
name: "MGT2.Settings.showLife.name",
hint: "MGT2.Settings.showLife.hint",
default: false,
scope: 'world',
type: Boolean,
config: true,
requiresReload: false
});
// game.settings.register('mgt2', 'useWeightMetric', {
// name: "MGT2.Settings.useWeightMetric.name",
// hint: "MGT2.Settings.useWeightMetric.hint",
// default: true,
// scope: 'world',
// type: Boolean,
// config: true,
// requiresReload: true
// });
// game.settings.register('mgt2', 'useDistanceMetric', {
// name: "MGT2.Settings.useDistanceMetric.name",
// hint: "MGT2.Settings.useDistanceMetric.hint",
// default: true,
// scope: 'world',
// type: Boolean,
// config: true,
// requiresReload: true
// });
// game.settings.register('mgt2', 'showTrash', {
// name: "Show Trash tab to Player",
// hint: "Player can see the Trash tab and recover item",
// default: false,
// scope: 'world',
// type: Boolean,
// config: true,
// requiresReload: false
// });
/*game.settings.register('mgt2', 'containerDropIn', {
name: "Test",
hint: "Mon hint",
default: true,
scope: 'client',
type: Boolean,
config: true
});*/
};

36
src/module/templates.js Normal file
View File

@@ -0,0 +1,36 @@
/**
* Define a set of template paths to pre-load
* Pre-loaded templates are compiled and cached for fast access when rendering
* @return {Promise}
*/
export const preloadHandlebarsTemplates = async function() {
const templatePaths = [
"systems/mgt2/templates/items/armor-sheet.html",
"systems/mgt2/templates/items/career-sheet.html",
"systems/mgt2/templates/items/computer-sheet.html",
"systems/mgt2/templates/items/contact-sheet.html",
"systems/mgt2/templates/items/container-sheet.html",
"systems/mgt2/templates/items/disease-sheet.html",
"systems/mgt2/templates/items/equipment-sheet.html",
"systems/mgt2/templates/items/item-sheet.html",
"systems/mgt2/templates/items/species-sheet.html",
"systems/mgt2/templates/items/talent-sheet.html",
"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/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"
];
const loader = foundry.applications?.handlebars?.loadTemplates ?? loadTemplates;
return loader(templatePaths);
};

View File

@@ -0,0 +1,292 @@
.characteristics-panel
.tab
padding: 4px
.species
font-size: 13px
margin: 4px 1rem 0 1rem
text-align: justify
a
margin-right: 1rem
.mgt2
.characteristics
flex-basis: 138px
flex-grow: 0
flex-shrink: 0
position: relative
.characteristics-header
color: var(--mgt2-color-primary)
background: var(--mgt2-bgcolor-primary)
font-family: "Rubik", monospace
font-style: normal
font-size: 1rem
line-height: 2rem
text-transform: uppercase
.characteristic-row
display: flex
flex-direction: row
align-items: center
justify-content: center
position: relative
.characteristic-minmax
display: flex
flex-direction: row
align-items: center
justify-content: center
flex-wrap: nowrap
.characteristic-dm
span
&.label
font-size: 0.8rem
font-weight: 600
.characteristic-label
font-family: "Barlow Condensed", sans-serif
font-size: 1.2rem
font-weight: 600
font-style: italic
text-align: center
color: var(--mgt2-color-form)
position: relative
& > a
&.roll
color: black
position: absolute
left: 0
a
&.cfg-characteristic
display: none
font-size: 12px
position: absolute
right: 0
top: 0
&:hover
a
&.cfg-characteristic
display: block
.characteristic-input
color: var(--mgt2-bgcolor-primary)
text-align: center
font-size: 1.5rem
font-weight: 500
width: 2.4rem
height: 2rem
box-sizing: border-box
border: none
outline: none
background: linear-gradient(45deg, #0000 5.66px, #000 0 calc(5.66px + 2px), #0000 0 calc(100% - 5.66px - 2px), #000 0 calc(100% - 5.66px), #0000 0), linear-gradient(-45deg, #0000 5.66px, #000 0 calc(5.66px + 2px), #0000 0 calc(100% - 5.66px - 2px), #000 0 calc(100% - 5.66px), #0000 0), linear-gradient(90deg, #000 4px, #0000 0) -2px 50%/100% calc(100% - 16px) repeat-x, linear-gradient(#000 4px, #0000 0) 50% -2px/calc(100% - 16px) 100% repeat-y
.characteristic-dm
color: var(--mgt2-color-dm)
background-color: transparent
text-align: center
font-size: 1rem
width: 1.5rem
height: 1.4rem
padding: 0
outline: none
border: none
margin: 0
position: absolute
right: 0
background-color: var(--mgt2-bgcolor-dm)
border-radius: 9px
margin-right: 2px
&:focus
outline: none
box-shadow: none
.characteristic-dm-minmax
&:focus
outline: none
box-shadow: none
.minmaxwrapper
display: flex
flex-direction: row
flex-wrap: nowrap
justify-content: center
justify-content: center
align-items: center
margin: 0 0.5rem
box-sizing: border-box
background: linear-gradient(45deg, #0000 7.07px, #000 0 calc(7.07px + 2px), #0000 0 calc(100% - 7.07px - 2px), #000 0 calc(100% - 7.07px), #0000 0), linear-gradient(-45deg, #0000 7.07px, #000 0 calc(7.07px + 2px), #0000 0 calc(100% - 7.07px - 2px), #000 0 calc(100% - 7.07px), #0000 0), linear-gradient(90deg, #000 4px, #0000 0) -2px 50%/100% calc(100% - 20px) repeat-x, linear-gradient(#000 4px, #0000 0) 50% -2px/calc(100% - 20px) 100% repeat-y
input
display: inline-block
color: black
background-color: transparent
text-align: center
font-size: 1.5rem
width: 3rem
height: 2rem
border: none
outline: none
&:focus
outline: none
box-shadow: none
&:first-child
margin-left: 5px
&:last-child
margin-right: 5px
span
font-size: 1.5rem
font-weight: 500
.computer-overload,
.computer-overload i
color: var(--mgt2-color-warning) !important
ul
&.softwares
list-style: none
margin: 0
padding: 0
li
display: inline-block
color: var(--mgt2-color-software)
background-color: var(--mgt2-bgcolor-software)
padding: 3px 7px
border-radius: 8px
a
display: none
&:first-child
margin: 0 0.5rem
&:hover
a
display: inline-block
.character-header
display: flex
margin-top: 8px
margin-right: 8px
flex-direction: row
flex-wrap: nowrap
flex-grow: 0
flex-shrink: 0
justify-content: flex-start
align-items: flex-start
.character-header-img
flex-basis: 138px
flex-grow: 0
flex-shrink: 0
text-align: center
.character-summary
flex: 0 0 100%
margin: 0
padding: 0
list-style: none
border-top: 5px double var(--mgt2-bgcolor-primary)
li
float: left
margin: 0
padding: 0
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
border: 1px solid #111
.character-header-body
display: flex
flex-direction: column
flex-wrap: nowrap
justify-content: flex-start
legend
font-size: 0.7rem
text-transform: uppercase
text-wrap: nowrap
color: var(--mgt2-color-form)
i
margin-right: 0.25rem
.character-body
display: flex
flex-direction: row
align-content: flex-start
flex-wrap: nowrap
min-height: 330px
.tab
width: 100%
.lifes
height: 100%
display: flex
flex-direction: row
justify-content: center
align-items: center
div
font-size: 2rem
.character-states
margin: 0
padding: 0
list-style: none
display: flex
flex-direction: column
justify-content: flex-start
align-items: flex-start
width: 100%
float: right
li
display: flex
margin: 0
padding: 0
color: var(--mgt2-color-form)
justify-content: space-between
align-items: center
width: 100%
font-size: 0.7rem
line-height: 1.1rem
.encumbrance-normal
color: var(--mgt2-encumbrance-normal)!important
.encumbrance-heavy
color: var(--mgt2-encumbrance-heavy)!important
font-weight: bold
.character-body
height: 100%
overflow: hidden
display: flex
flex-direction: row
width: 100%
justify-content: flex-start
align-items: flex-start
border-top: 3px solid black
.actor-footer
bottom: 0
color: var(--mgt2-color-primary)
background-color: var(--mgt2-bgcolor-primary)
width: 100%
margin: 0 -8px
height: 1.5rem
justify-content: space-between
align-items: center
padding: 0 1rem
flex-grow: 0
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

View File

@@ -0,0 +1,366 @@
// 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
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
.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
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
// 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)

View 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

View File

@@ -0,0 +1,150 @@
.mgt2
.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
// 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

View File

@@ -0,0 +1,86 @@
.mgt2
&.sheet
textarea
color: var(--mgt2-input-color)
background-color: var(--mgt2-input-bgcolor)
font-family: "Roboto", sans-serif
font-size: 13px
font-stretch: 100%
input:focus,
textarea:focus,
select:focus
outline: none
box-shadow: none
.checkbox-small
flex: none!important
width: auto!important
height: auto!important
margin: 0!important
.header
color: var(--mgt2-color-primary)
background: var(--mgt2-bgcolor-primary)
font-size: 14px
font-family: "Roboto Condensed", sans-serif
font-weight: bold
padding-left: 5px
margin-bottom: 4px
line-height: 30px
text-transform: uppercase
.field-groups
display: flex
flex-direction: row
flex-wrap: nowrap
align-items: center
justify-content: space-between
.field-group
label
text-transform: uppercase
font-weight: 700
font-size: 14px
font-family: "Roboto Condensed", sans-serif
font-optical-sizing: auto
input
&.field
background-color: var(--mgt2-input-bgcolor)
font-size: 13px
&.field-name
background-color: var(--mgt2-input-bgcolor)
color: var(--mgt2-color-primary)
font-size: 2rem
border: none
font-weight: 700
font-family: "Roboto Condensed", sans-serif
margin-bottom: 0.5rem
padding: 0
&.field-item-name
background-color: var(--mgt2-input-bgcolor)
color: var(--mgt2-color-primary)
height: auto
font-size: 2rem
font-weight: 700
font-family: "Roboto Condensed", sans-serif
.fields
display: flex
.editor
min-height: 3rem
border: 1px solid var(--mgt2-editor-border)
height: 100%
.sheet-body
margin-left: 140px
padding-bottom: 1.5rem
label
&.mgt2-checkbox
display: flex
flex-direction: row
align-items: center
input
margin: 0 0.3rem 0 0

View File

@@ -0,0 +1,418 @@
// MGT2 Item Sheets
// New unified layout: type-bar header (image+name) stats-bar full-width tabs
// Outer window
.itemsheet
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
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
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

View File

@@ -0,0 +1,111 @@
// ── 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.
.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
// 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
position: relative
display: flex !important
flex-direction: column !important
justify-content: center !important
align-items: center !important
gap: 4px !important
min-height: 54px
padding: 8px 4px
color: rgba(238,64,80,0.45)
border-bottom: 1px solid rgba(238,64,80,0.07)
cursor: pointer
transition: background 180ms ease, color 180ms ease, box-shadow 180ms ease
user-select: none
text-decoration: none !important
// Left accent bar
&::before
content: ''
position: absolute
left: -3px
top: 18%
bottom: 18%
width: 3px
background: transparent
border-radius: 0 3px 3px 0
transition: background 180ms ease, top 180ms ease, bottom 180ms ease, box-shadow 180ms ease
&:hover
color: var(--mgt2-color-primary)
background: rgba(238,64,80,0.07)
&::before
background: rgba(238,64,80,0.5)
.tab-label
color: rgba(238,64,80,0.7)
&.active
color: var(--mgt2-color-primary)
background: linear-gradient(90deg, rgba(238,64,80,0.16) 0%, rgba(238,64,80,0.03) 100%)
box-shadow: inset 0 1px 0 rgba(238,64,80,0.12), inset 0 -1px 0 rgba(238,64,80,0.08)
&::before
background: var(--mgt2-color-primary)
top: 10%
bottom: 10%
box-shadow: 0 0 10px rgba(238,64,80,0.7), 0 0 20px rgba(238,64,80,0.3)
i
filter: drop-shadow(0 0 5px rgba(238,64,80,0.55))
.tab-label
color: rgba(238,64,80,0.85)
i
font-size: 1.15rem
pointer-events: none
line-height: 1
.tab-label
font-family: 'Barlow Condensed', sans-serif
font-size: 0.52rem
font-weight: 700
text-transform: uppercase
letter-spacing: 0.8px
color: rgba(238,64,80,0.3)
line-height: 1
pointer-events: none
transition: color 180ms ease

View File

@@ -0,0 +1,172 @@
.container-controls
display: inline-block
margin-left: 1rem
a
&:not(:last-child)
margin-right: 0.5rem
.table-container
display: flex
flex-flow: column nowrap
width: 100%
margin: 0 auto
.table-row
display: flex
flex-flow: row nowrap
width: 100%
position: relative
align-items: flex-start
&.heading
background-color: var(--mgt2-bgcolor-primary)
align-items: center
.row-item
text-transform: uppercase
font-size: 12px
&:first-child
font-weight: bold
font-size: 13px
letter-spacing: 3px
i
margin-right: 0.5rem
&.color-1
.row-item
background-color: var(--mgt2-bgcolor-primary)
color: var(--mgt2-color-primary)
&.color-2
.row-item
background-color: var(--mgt2-bgcolor-form)
color: var(--mgt2-bgcolor-primary)
div
&.row-item
padding-left: 5px
&:last-child
padding-right: 5px
&:hover
&:not(.heading)
background-color: var(--mgt2-row-hover)
.table-row-mb-4
margin-bottom: 4px
.row-item
display: flex
flex-grow: 1
font-size: 14px
line-height: 25px
align-items: center
transition: all 0.15s ease-in-out
overflow: hidden !important
text-overflow: ellipsis
text-wrap: nowrap
&.item-controls
justify-content: right
padding-right: 4px
a
&:not(:last-child)
margin-right: 0.4rem
i
color: var(--mgt2-color-form)
a[data-roll]
margin-right: 0.5rem
.heading
&.color-1
.row-item
i
color: var(--mgt2-color-primary) !important
&.color-2
.row-item
i
color: var(--mgt2-bgcolor-primary) !important
.table-subrow
border-left: 2px var(--mgt2-subrow-color) dashed
color: var(--mgt2-subrow-color)
.row-item
font-size: 0.8em
line-height: 20px
&:first-child
padding-left: 1rem
& > i
margin-right: 4px
.row-item-center
justify-content: center
text-align: center
.row-item-left
justify-content: left
.row-item-right
justify-content: right
.row-item-space-between
justify-content: space-between
.row-item-2
flex-basis: 4rem
.row-item-5
flex-basis: 5%
.row-item-10
flex-basis: 10%
.row-item-12
flex-basis: 4rem
.row-item-15
flex-basis: 5rem
.row-item-20
flex-basis: 20%
.row-item-25
flex-basis: 25%
.row-item-30
flex-basis: 30%
.row-item-35
flex-basis: 35%
.row-item-40
flex-basis: 40%
.row-item-45
flex-basis: 45%
.row-item-50
flex-basis: 50%
.row-item-65
flex-basis: 50%
.row-item-85
flex-basis: 50%
.row-item-storage
flex-wrap: wrap
flex-grow: 0
flex-basis: 20%
font-size: 0.7rem
line-height: 0.8rem
.item-control
&.item-equip
i
color: var(--mgt2-row-inactive-icon)
&.active
i
color: var(--mgt2-color-form)
.row-description
flex-basis: 100%
font-size: 14px
padding: 4px 0
justify-content: left
transition: all 0.15s ease-in-out
.row-sub-container
display: flex
flex-flow: column nowrap
flex: 1
.row-item
padding: 8px 0
border-bottom: 1px solid var(--mgt2-bgcolor-primary)
.table-row:last-child,
.row-sub-container .row-item:last-child
border-bottom: 0
.table-container
&.editable
.table-row
margin-top: 4px
.table-container
&.editable
.table-row:last-child
margin-bottom: 4px
.item-options
position: absolute
top: 0.7rem
font-size: 0.7em
left: 1.6rem
text-transform: uppercase
font-family: "DM Sans", sans-serif
font-optical-sizing: auto
font-weight: 600
font-style: normal
color: var(--mgt2-subrow-color)

View File

@@ -0,0 +1,58 @@
.mgt2
nav
&.horizontal-tabs
color: var(--mgt2-color-primary)
background: var(--mgt2-bgcolor-primary)
font-style: normal
font-weight: 700
font-size: 14px
line-height: 30px
text-transform: uppercase
justify-content: space-around
align-items: center
font-family: "Roboto Condensed", sans-serif
a
&.item
position: relative
flex: 1 1 auto
i
margin-right: 0.5rem
& > a
&.item
&::after
content: ""
position: absolute
inset: 0.25rem 0.25rem 0.25rem 0.25rem
border: 1px solid var( --mgt2-color-primary-active)
pointer-events: none
&.active
&::after
border-bottom: none
border-top: 2px solid var( --mgt2-color-primary-active)
border-left: 2px solid var( --mgt2-color-primary-active)
border-right: 2px solid var( --mgt2-color-primary-active)
inset: 0.25rem 0.25rem 0 0.25rem
.active
color: var(--mgt2-color-primary)
text-decoration: none
text-shadow: none
border-bottom: none
.tab[data-tab].fullsize
height: calc(100% - 3rem)
.subTab
flex-flow: column
height: 100%
display: flex
justify-content: flex-start
align-items: stretch
.tab-scroll
overflow-y: auto
height: 100%
.subTabs
height: 100%
flex-direction: column
&.active
display: flex !important

View 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

17
src/sass/mgt2.sass Normal file
View File

@@ -0,0 +1,17 @@
@import 'utils/typography'
@import 'utils/colors'
@import 'utils/global'
@import 'utils/window'
@import 'utils/flex'
@import 'components/_forms'
@import 'components/_dialog'
@import 'components/_character'
@import 'components/_item'
@import 'components/_chat-sidebar'
@import 'components/_tabs'
@import 'components/_tab-sidebar'
@import 'components/_tables'
@import 'components/_creature'
@import 'components/_vehicule'

View File

@@ -0,0 +1,63 @@
$primary-color: #3498db
$secondary-color: #2ecc71
$background-color: #ecf0f1
$text-color: #34495e
.black-and-red
--mgt2-color-form: #0A0405
--mgt2-bgcolor-form: #fff
--mgt2-color-primary: #EE4050
--mgt2-color-primary-active: #AF2F3C
--mgt2-bgcolor-primary: #0A0405
--mgt2-color-primary-light: #4b4a44
--mgt2-color-warning: #EE4050
--mgt2-color-dm: #fff
--mgt2-bgcolor-dm: #0A0405
--mgt2-color-software: #fff
--mgt2-bgcolor-software: #0A0405
--mgt2-input-color: #0A0405
--mgt2-input-bgcolor: #fff
--mgt2-editor-border: #C6C6C6
--mgt2-row-hover: #F2F2F2
--mgt2-subrow-color: #727272
--mgt2-row-inactive-icon: #b5b3a4
--mgt2-encumbrance-normal: #D94826
--mgt2-encumbrance-heavy: #D82727
.mwamba
--mgt2-color-form: #0A0405
--mgt2-bgcolor-form: #fff
--mgt2-color-primary: #2A9932
--mgt2-color-primary-active: #40ED4E
--mgt2-bgcolor-primary: #0A0405
--mgt2-color-primary-light: #4b4a44
--mgt2-color-warning: #EE4050
--mgt2-color-dm: #fff
--mgt2-bgcolor-dm: #0A0405
--mgt2-color-software: #fff
--mgt2-bgcolor-software: #0A0405
--mgt2-input-color: #0A0405
--mgt2-input-bgcolor: #fff
--mgt2-editor-border: #C6C6C6
--mgt2-row-hover: #F2F2F2
--mgt2-subrow-color: #727272
--mgt2-row-inactive-icon: #b5b3a4
.blue
--mgt2-color-form: #0A0405
--mgt2-bgcolor-form: #fff
--mgt2-color-primary: #91AAC8
--mgt2-color-primary-active: #BCDCFF
--mgt2-bgcolor-primary: #0A0405
--mgt2-color-primary-light: #4b4a44
--mgt2-color-warning: #EE4050
--mgt2-color-dm: #fff
--mgt2-bgcolor-dm: #0A0405
--mgt2-color-software: #fff
--mgt2-bgcolor-software: #0A0405
--mgt2-input-color: #0A0405
--mgt2-input-bgcolor: #fff
--mgt2-editor-border: #C6C6C6
--mgt2-row-hover: #F2F2F2
--mgt2-subrow-color: #727272
--mgt2-row-inactive-icon: #b5b3a4

18
src/sass/utils/_flex.sass Normal file
View File

@@ -0,0 +1,18 @@
.mgt2
.flex-fix
flex-grow: 0 !important
flex-shrink: 0 !important
.flex-basis-10
flex-basis: 10%
.flex-basis-20
flex-basis: 20%
.flex-basis-30
flex-basis: 30%
.flex-basis-40
flex-basis: 40%
.flex-basis-50
flex-basis: 50%
.flex-basis-60
flex-basis: 60%
.flex-basis-70
flex-basis: 70%

View File

@@ -0,0 +1,39 @@
.upcase
text-transform: uppercase
.w1-10
width: calc(100% / 10)
.w2-10
width: calc(100% / 10 * 2)
.w3-10
width: calc(100% / 10 * 3)
.w4-10
width: calc(100% / 10 * 4)
.w5-10
width: calc(100% / 10 * 5)
.h100
height: 100%
.w100
width: 100%
.mgt2
a:hover
text-shadow: none
.w-100
width: 100%
.mb-1
margin-bottom: 8px
.mt-1, .mt-05
margin-top: 8px
.mt-2
margin-top: 14px

View File

@@ -0,0 +1,3 @@
@import url('https://fonts.googleapis.com/css2?family=Barlow+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap')
@import url('https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,300..900;1,300..900&display=swap')
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap')

View File

@@ -0,0 +1,4 @@
$myFont: Helvetica, sans-serif
$myColor: red
$myFontSize: 18px
$myWidth: 680px

View File

@@ -0,0 +1,19 @@
.mgt2
&.sheet
header
&.window-header
color: var(--mgt2-color-primary)
background-color: var(--mgt2-bgcolor-primary)
h4
&.window-title
font-weight: bold
text-transform: uppercase
&.sheet
.window-content
background: var(--mgt2-bgcolor-form)
color: var(--mgt2-color-form)
padding: 0
.nopad
.window-content
padding: 0

11
src/todo.md Normal file
View File

@@ -0,0 +1,11 @@
# BUGS
# Chose à faire
- Enlever les styles inlines
Actors
- NPC
- Creature
- Container

947
styles/mgt2.min.css vendored

File diff suppressed because one or more lines are too long

1
styles/mgt2.min.css.map Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,40 +1,47 @@
{
"id": "mgt2",
"version": "0.1.0",
"title": "MGT2 - Mongoose Traveller (Unofficial)",
"description": "An unofficial implementation of Mongoose Publishing Traveller. 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",
"url": "https://github.com/JDR-Ninja/foundryvtt-mgt2",
"id": "mgt2",
"version": "0.1.4",
"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",
"url": "https://github.com/JDR-Ninja/foundryvtt-mgt2",
"manifest": "https://github.com/JDR-Ninja/foundryvtt-mgt2/releases/latest/download/system.json",
"readme": "https://raw.githubusercontent.com/JDR-Ninja/foundryvtt-mgt2/main/README.md",
"download": "https://github.com/JDR-Ninja/foundryvtt-mgt2/releases/download/v0.1.0/mgt2.zip",
"authors": [
{
"name": "JdR Ninja",
"url": "https://www.jdr.ninja/",
"discord": "jdr.ninja"
}
],
"esmodules": ["mgt2.bundle.js"],
"styles": ["styles/mgt2.min.css"],
"packs": [],
"languages": [
{
"lang": "en",
"name": "English",
"path": "lang/en.json"
},
{
"lang": "fr",
"name": "Français",
"path": "lang/fr.json"
}
],
"compatibility": {
"minimum": "11",
"verified": "11.315"
},
"gridDistance": 1.5,
"gridUnits": "m",
"primaryTokenAttribute": "life"
}
"download": "https://github.com/JDR-Ninja/foundryvtt-mgt2/releases/download/v0.1.4/mgt2.zip",
"changelog": "https://raw.githubusercontent.com/JDR-Ninja/foundryvtt-mgt2/main/CHANGELOG.md",
"authors": [
{
"name": "JdR Ninja",
"url": "https://www.jdr.ninja/",
"discord": "jdr.ninja"
}
],
"esmodules": [
"mgt2.bundle.js"
],
"styles": [
"styles/mgt2.min.css"
],
"packs": [],
"languages": [
{
"lang": "en",
"name": "English",
"path": "lang/en.json"
},
{
"lang": "fr",
"name": "Français",
"path": "lang/fr.json"
}
],
"compatibility": {
"minimum": "11",
"verified": "12.324"
},
"grid": {
"distance": 1.5,
"units": "m"
},
"primaryTokenAttribute": "life"
}

View File

@@ -2,11 +2,13 @@
"Actor": {
"types": [
"character",
"vehicule"
"vehicule",
"creature"
],
"htmlFields": ["notes"],
"htmlFields": ["notes", "biography"],
"character": {},
"vehicule": {}
"vehicule": {},
"creature": {}
},
"Item": {
"types": [

View File

@@ -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>

View File

@@ -0,0 +1,749 @@
<form class="{{cssClass}} flexcol" autocomplete="off" 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" />
</div>
<div class="character-header-body">
<input class="field-name" name="name" type="text" value="{{name}}" />
<ul class="character-summary">
{{#if (and settings.usePronouns settings.useGender)}}
<li class="w1-10"><input name="system.personal.pronouns" type="text" value="{{system.personal.pronouns}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderPRONOUNS' }}" /></li>
<li class="w1-10"><input name="system.personal.gender" type="text" value="{{system.personal.gender}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderGENDER' }}" /></li>
<li class="w4-10"><input name="system.personal.title" type="text" value="{{system.personal.title}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderTITLE' }}" /></li>
{{else if settings.usePronouns}}
<li class="w5-10"><input name="system.personal.pronouns" type="text" value="{{system.personal.pronouns}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderPRONOUNS' }}" /></li>
<li class="w4-10"><input name="system.personal.title" type="text" value="{{system.personal.title}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderTITLE' }}" /></li>
{{else if settings.useGender}}
<li class="w1-10"><input name="system.personal.gender" type="text" value="{{system.personal.gender}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderGENDER' }}" /></li>
<li class="w4-10"><input name="system.personal.title" type="text" value="{{system.personal.title}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderTITLE' }}" /></li>
{{else}}
<li class="w5-10"><input name="system.personal.title" type="text" value="{{system.personal.title}}" placeholder="{{ localize 'MGT2.Actor.PlaceholderTITLE' }}" /></li>
{{/if}}
<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>
<div class="flexrow">
<div class="w4-10">
<!-- FULL REST ICON -->
</div>
<div class="flex-fix">
<fieldset class="lifes">
<legend><a class="roll upcase" data-roll="initiative" tabindex='-1' style="display: inline-flex;"><i class="fa-solid fa-dice"></i>{{ localize 'MGT2.Actor.Initiative' }}</a></legend>
<div>{{showDM initiative}}</div>
</fieldset>
</div>
<div class="flex-fix">
{{#if settings.showLife}}
<fieldset class="lifes">
<legend class="upcase">{{ localize 'MGT2.Actor.Life' }}</legend>
<div>{{system.life.value}}{{#if (gt system.life.max 0) }}/{{system.life.max}}{{/if}}</div>
</fieldset>
{{/if}}
</div>
<div class="flex-fix">
<fieldset class="lifes">
<legend class="upcase">{{ localize 'MGT2.Actor.Armor' }}</legend>
<div>{{system.inventory.armor}}</div>
</fieldset>
</div>
<div class="w4-10">
<fieldset style="margin:0;padding: 0 1rem;">
<legend class="upcase">{{ localize 'MGT2.Actor.States' }}</legend>
<ul class="character-states">
<li><label title="{{ localize 'MGT2.Actor.EncumbranceHint' }}">{{ localize 'MGT2.Actor.Encumbrance' }}</label><input type="checkbox" class="checkbox-small" {{checked system.states.encumbrance}} readonly disabled /></label></li>
<li><label title="{{ localize 'MGT2.Actor.FatigueHint' }}">{{ localize 'MGT2.Actor.Fatigue' }}</label><input type="checkbox" class="checkbox-small" name="system.states.fatigue" data-dtype="Boolean" {{checked system.states.fatigue}} /></label></li>
<li><label title="{{ localize 'MGT2.Actor.SurgeryRequiredHint' }}">{{ localize 'MGT2.Actor.SurgeryRequired' }}</label><input type="checkbox" class="checkbox-small" name="system.states.surgeryRequired" data-dtype="Boolean" {{checked system.states.surgeryRequired}} /></li>
<!-- <li><label>Unconscious</label><input type="checkbox" class="checkbox-small" name="system.states.unconscious" data-dtype="Boolean" {{checked system.states.unconscious}} /></li> -->
</ul>
</fieldset>
</div>
</div>
</div>
</section>
<div style="height: 100%;overflow: hidden;display: flex;flex-direction: row;width: 100%;justify-content: flex-start;align-items: flex-start;">
<div class="characteristics">
<nav class="horizontal-tabs tabs" data-group="characteristics" style="border-right: 7px double #fff;">
<a class="item tab-select" data-tab="core">{{ localize 'MGT2.Actor.TabCore' }}</a>
<a class="item tab-select" data-tab="other">{{ localize 'MGT2.Actor.TabOthers' }}</a>
</nav>
<section class="characteristics-panel">
<div class="tab" data-group="characteristics" data-tab="core">
{{#if system.characteristics.strength.show}}
<div class="characteristic-label"><a class="roll" data-roll="characteristic" data-roll-characteristic="strength" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.strength.name' }}<a class="cfg-characteristic" data-cfg-characteristic="strength" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.strength.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.strength.value" value="{{system.characteristics.strength.value}}" data-dtype="Number" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.strength.max" value="{{system.characteristics.strength.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.strength.dm 0)}}+{{/if}}{{system.characteristics.strength.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.strength.value" value="{{system.characteristics.strength.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.strength.dm 0)}}+{{/if}}{{system.characteristics.strength.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.dexterity.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="dexterity" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.dexterity.name' }}<a class="cfg-characteristic" data-cfg-characteristic="dexterity" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.dexterity.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.dexterity.value" value="{{system.characteristics.dexterity.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.dexterity.max" value="{{system.characteristics.dexterity.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.dexterity.dm 0)}}+{{/if}}{{system.characteristics.dexterity.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.dexterity.value" value="{{system.characteristics.dexterity.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.dexterity.dm 0)}}+{{/if}}{{system.characteristics.dexterity.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.endurance.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="endurance" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.endurance.name' }}<a class="cfg-characteristic" data-cfg-characteristic="endurance" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.endurance.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.endurance.value" value="{{system.characteristics.endurance.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.endurance.max" value="{{system.characteristics.endurance.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.endurance.dm 0)}}+{{/if}}{{system.characteristics.endurance.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.endurance.value" value="{{system.characteristics.endurance.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.endurance.dm 0)}}+{{/if}}{{system.characteristics.endurance.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.intellect.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="intellect" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.intellect.name' }}<a class="cfg-characteristic" data-cfg-characteristic="intellect" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.intellect.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.intellect.value" value="{{system.characteristics.intellect.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.intellect.max" value="{{system.characteristics.intellect.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.intellect.dm 0)}}+{{/if}}{{system.characteristics.intellect.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.intellect.value" value="{{system.characteristics.intellect.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.intellect.dm 0)}}+{{/if}}{{system.characteristics.intellect.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.education.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="education" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.education.name' }}<a class="cfg-characteristic" data-cfg-characteristic="education" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.education.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.education.value" value="{{system.characteristics.education.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.education.max" value="{{system.characteristics.education.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.education.dm 0)}}+{{/if}}{{system.characteristics.education.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.education.value" value="{{system.characteristics.education.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.education.dm 0)}}+{{/if}}{{system.characteristics.education.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.social.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="social" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.social.name' }}<a class="cfg-characteristic" data-cfg-characteristic="social" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.social.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.social.value" value="{{system.characteristics.social.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.social.max" value="{{system.characteristics.social.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.social.dm 0)}}+{{/if}}{{system.characteristics.social.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.social.value" value="{{system.characteristics.social.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.social.dm 0)}}+{{/if}}{{system.characteristics.social.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
</div>
<div class="tab" data-group="characteristics" data-tab="other">
{{#if system.characteristics.morale.show}}
<div class="characteristic-label"><a class="roll" data-roll="characteristic" data-roll-characteristic="morale" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.morale.name' }}<a class="cfg-characteristic" data-cfg-characteristic="morale" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.morale.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.morale.value" value="{{system.characteristics.morale.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.morale.max" value="{{system.characteristics.morale.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.morale.dm 0)}}+{{/if}}{{system.characteristics.morale.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.morale.value" value="{{system.characteristics.morale.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.morale.dm 0)}}+{{/if}}{{system.characteristics.morale.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.luck.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="luck" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.luck.name' }}<a class="cfg-characteristic" data-cfg-characteristic="luck" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.luck.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.luck.value" value="{{system.characteristics.luck.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.luck.max" value="{{system.characteristics.luck.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.luck.dm 0)}}+{{/if}}{{system.characteristics.luck.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.luck.value" value="{{system.characteristics.luck.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.luck.dm 0)}}+{{/if}}{{system.characteristics.luck.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.sanity.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="sanity" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.sanity.name' }}<a class="cfg-characteristic" data-cfg-characteristic="sanity" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.sanity.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.sanity.value" value="{{system.characteristics.sanity.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.sanity.max" value="{{system.characteristics.sanity.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.sanity.dm 0)}}+{{/if}}{{system.characteristics.sanity.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.sanity.value" value="{{system.characteristics.sanity.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.sanity.dm 0)}}+{{/if}}{{system.characteristics.sanity.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.charm.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="charm" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.charm.name' }}<a class="cfg-characteristic" data-cfg-characteristic="charm" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.charm.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.charm.value" value="{{system.characteristics.charm.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.charm.max" value="{{system.characteristics.charm.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.charm.dm 0)}}+{{/if}}{{system.characteristics.charm.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.charm.value" value="{{system.characteristics.charm.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.charm.dm 0)}}+{{/if}}{{system.characteristics.charm.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.psionic.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="psionic" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.psionic.name' }}<a class="cfg-characteristic" data-cfg-characteristic="psionic" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.psionic.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.psionic.value" value="{{system.characteristics.psionic.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.psionic.max" value="{{system.characteristics.psionic.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.psionic.dm 0)}}+{{/if}}{{system.characteristics.psionic.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.psionic.value" value="{{system.characteristics.psionic.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.psionic.dm 0)}}+{{/if}}{{system.characteristics.psionic.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
{{#if system.characteristics.other.show}}
<div class="characteristic-label mt-1"><a class="roll" data-roll="characteristic" data-roll-characteristic="other" tabindex='-1'><i class="fa-solid fa-dice"></i></a>{{ localize 'MGT2.Characteristics.other.name' }}<a class="cfg-characteristic" data-cfg-characteristic="other" title="Configure"><i class="fa-solid fa-gear"></i></a></div>
{{#if system.characteristics.other.showMax}}
<div class="characteristic-minmax">
<div class="minmaxwrapper">
<input type="text" maxlength="2" name="system.characteristics.other.value" value="{{system.characteristics.other.value}}" /><span>|</span><input type="text" maxlength="2" name="system.characteristics.other.max" value="{{system.characteristics.other.max}}" />
</div>
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.other.dm 0)}}+{{/if}}{{system.characteristics.other.dm}}" readonly tabindex='-1' />
</div>
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.other.value" value="{{system.characteristics.other.value}}" />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.other.dm 0)}}+{{/if}}{{system.characteristics.other.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
</div>
</section>
</div>
<div class="tab w100" data-group="sidebar" data-tab="health">
<div class="header upcase">{{ localize 'MGT2.Actor.Health' }}</div>
<div class="field-group mb-1">
<label class="upcase">{{ localize 'MGT2.Actor.Rads' }}</label>
<input class="field" name="system.health.radiations" type="text" value="{{system.health.radiations}}" />
</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>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Difficulty' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Damage' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Interval' }}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="disease" data-subtype="wound" data-create-name="{{ localize 'MGT2.Actor.NewWound' }}" title="{{ localize 'MGT2.Actor.AddWound' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each wounds as |wound id|}}
<div class="table-row item" data-item-id="{{wound._id}}" role="rowgroup">
<div class="row-item row-item-30 row-item-left">{{wound.name}}</div>
<div class="row-item row-item-center">{{wound.system.difficulty}}</div>
<div class="row-item row-item-center">{{wound.system.damage}}</div>
<div class="row-item row-item-center">{{wound.system.interval}}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix">
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditWound' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteWound' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</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.Items.Diseases' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Difficulty' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Damage' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Interval' }}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="disease" data-subtype="disease" data-create-name="{{ localize 'MGT2.Actor.NewDisease' }}" title="{{ localize 'MGT2.Actor.AddDisease' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each diseases as |disease id|}}
<div class="table-row item" data-item-id="{{disease._id}}" role="rowgroup">
<div class="row-item row-item-30 row-item-left"><a data-roll="disease" data-item-id="{{disease._id}}"><i class="fa-solid fa-dice"></i></a>{{disease.name}}</div>
<div class="row-item row-item-center">{{disease.system.difficulty}}</div>
<div class="row-item row-item-center">{{disease.system.damage}}</div>
<div class="row-item row-item-center">{{disease.system.interval}}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix">
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditDisease' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteDisease' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</div>
<div class="tab w100 tab-scroll" data-group="sidebar" data-tab="skills">
<div class="header upcase">{{ localize 'MGT2.Actor.TabSkills' }}</div>
<div class="species"><a title="Description longue"><i class="fa-solid fa-book"></i></a>{{system.personal.speciesText.description}}</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-15 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 row-item-15 item-controls flex-fix"><a class="traits-create"><i class="fas fa-plus"></i></a></div>
</div>
{{#each system.personal.traits as |trait i| }}
<div class="table-row traits-part" data-traits-part="{{i}}" role="rowgroup">
<div class="row-item row-item-15 row-item-left">{{trait.name}}</div>
<div class="row-item row-item-left">{{trait.description}}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix">
<a class="item-control traits-edit" title="{{ localize 'MGT2.Actor.EditTrait' }}"><i class="fas fa-edit"></i></a>
<a class="item-control traits-delete" title="Delete Trait"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
<div class="header upcase">{{ localize 'MGT2.Actor.StudyPeriod' }}</div>
<div class="fields mb-1">
<div class="field-group" style="flex: 2 1 auto;">
<label class="upcase">{{ localize 'MGT2.Actor.TrainingInSkill' }}</label>
<input class="field" name="system.study.skill" type="text" value="{{system.study.skill}}" />
</div>
<div class="field-group" style="flex: 1 1 0%;">
<label>{{ localize 'MGT2.Actor.Completed' }}</label>
<input class="field" name="system.study.completed" type="number" value="{{system.study.completed}}" />
</div>
<div class="field-group" style="flex: 1 1 0%;">
<label class="upcase">{{ localize 'MGT2.Actor.Weeks' }}</label>
<input class="field" name="system.study.total" type="number" value="{{system.study.total}}" />
</div>
</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-30 row-item-left">{{ localize 'MGT2.Items.Careers' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Terms' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Rank' }}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="career" data-create-name="{{ localize 'MGT2.Actor.NewCareer' }}" title="{{ localize 'MGT2.Actor.AddCareer' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each careers as |career id|}}
<div class="table-row item" data-item-id="{{career._id}}" role="rowgroup">
<div class="row-item row-item-30 row-item-left">{{career.name}}</div>
<div class="row-item row-item-center">{{career.system.terms}}</div>
<div class="row-item row-item-center">{{career.system.rank}}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix">
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditCareer' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteCareer' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-30 row-item-left flex-fix">{{ localize 'MGT2.Actor.Skills' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Level' }}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="talent" data-subtype="skill" data-create-name="{{ localize 'MGT2.Actor.NewSkill' }}" title="{{ localize 'MGT2.Actor.AddSkill' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#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}}
</div>
<div class="row-item row-item-center">{{skill.system.level}}</div>
<div class="row-item item-controls">
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditSkill' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteSkill' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
{{#if system.config.psionic}}
<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.PsionicTalents' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Level' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Cost' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Reach' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Difficulty' }}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="talent" data-subtype="psionic" data-create-name="{{ localize 'MGT2.Actor.NewPsionicTalent' }}" title="{{ localize 'MGT2.Actor.AddPsionicTalent' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each psionics as |psionic id|}}
<div class="table-row" data-item-id="{{psionic._id}}" role="rowgroup">
<div class="row-item row-item-30 row-item-left">
<a 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>
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.psionic.reach}}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.psionic.difficulty}}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix">
<a class="item-control item-edit" title="{{ localize 'MGT2.Items.EditPsionic' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Items.DeletePsionic' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
{{/if}}
</div>
<div class="tab w100 subTabs" data-group="sidebar" data-tab="inventory">
<nav class="horizontal-tabs tabs" data-group="inventory">
<a class="item tab-select" data-tab="onhand"><i class="fa-solid fa-person-walking-luggage"></i>{{ localize 'MGT2.Items.OnHand' }}</a>
<a class="item tab-select" data-tab="storage"><i class="fa-solid fa-treasure-chest"></i>{{ localize 'MGT2.Items.Storage' }}</a>
<a class="item tab-select" data-tab="finance"><i class="fa-solid fa-credit-card"></i>{{ localize 'MGT2.Actor.Finance' }}</a>
{{#if showTrash}}
<!-- <a class="item tab-select" data-tab="trash" style="flex-basis: 3rem;flex-grow: 0;" title="Trash"><i class="fa-solid fa-trash" style="margin: 0;"></i></a> -->
{{/if}}
</nav>
<div class="tab w100 tab-scroll" data-group="inventory" data-tab="onhand">
<div class="table-container mt-1">
<div class="table-row heading color-1">
<div class="row-item row-item-30 row-item-left upcase"><i class="fa-solid fa-gun"></i>{{ localize 'MGT2.Items.Weapons' }}</div>
<div class="row-item row-item-2 row-item-center">{{ localize 'MGT2.Items.Range' }}</div>
<div class="row-item row-item-20 row-item-center">{{ localize 'MGT2.Items.Damage' }}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{ localize 'MGT2.Items.Weight' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="weapon" data-create-name="{{ localize 'MGT2.Actor.NewWeapon' }}" title="{{ localize 'MGT2.Actor.AddWeapon' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#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}}
</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-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>
</div>
</div>
{{/each}}
</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-40 row-item-left upcase"><i class="fa-solid fa-shield"></i>{{ localize 'MGT2.Items.Armors' }}</div>
<div class="row-item row-item-10 row-item-center">{{ localize 'MGT2.Items.Rads' }}</div>
<div class="row-item row-item-10 row-item-center">{{ localize 'MGT2.Items.Protection' }}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{ localize 'MGT2.Items.Weight' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="armor" data-create-name="{{ localize 'MGT2.Actor.NewArmor' }}" title="{{ localize 'MGT2.Actor.AddArmor' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#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}}
</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-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>
</div>
</div>
{{/each}}
</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-30 row-item-left upcase"><i class="fa-solid fa-brain-circuit"></i>{{ localize 'MGT2.Actor.Augments' }}</div>
<div class="row-item row-item-40 row-item-left">{{ localize 'MGT2.Items.Improvement' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="equipment" data-subtype="augment" data-create-name="{{ localize 'MGT2.Actor.NewAugment' }}" title="{{ localize 'MGT2.Actor.AddAugment' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each augments as |augment id|}}
<div class="table-row drag-item-list" data-item-id="{{augment._id}}" role="rowgroup">
<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-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>
</div>
</div>
{{/each}}
</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-50 row-item-left upcase"><i class="fa-solid fa-tablet-screen"></i>{{ localize 'MGT2.Items.Computers' }}</div>
<div class="row-item row-item-2 row-item-center"><i class="fa-solid fa-bolt-lightning"></i></div>
<div class="row-item row-item-2 row-item-right flex-fix">{{ localize 'MGT2.Items.Weight' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="computer" data-create-name="{{ localize 'MGT2.Actor.NewComputer' }}" title="{{ localize 'MGT2.Actor.AddComputer' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#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}}
</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-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>
</div>
</div>
{{#each subItems as |subItem|}}
<div class="table-row table-subrow drag-item-list" data-item-id="{{subItem._id}}">
<div class="row-item row-item-50 row-item-left"><i class="fa-brands fa-usb"></i>{{subItem.name}}</div>
<div class="row-item row-item-2 row-item-center">{{subItem.system.bandwidth}}</div>
<div class="row-item row-item-2 row-item-right flex-fix"></div>
<div class="row-item row-item-15 item-controls flex-fix">
<a class="item-control software-eject" title="{{ localize 'MGT2.Actor.UnloadSoftware' }}"><i class="fa-solid fa-eject"></i></i></a>
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditSoftware' }}"><i class="fas fa-edit"></i></a>
</div>
</div>
{{/each}}
{{/each}}
{{#if softwares}}
<fieldset style="padding: 5px;margin: 1rem 0;">
<legend><i class="fa-brands fa-usb"></i> {{ localize 'MGT2.Items.Softwares' }}</legend>
<ul class="softwares">
{{#each softwares as |software id|}}
<li class="drag-item-list" data-item-id="{{software._id}}">{{software.display}}
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditSoftware' }}"><i class="fas fa-edit"></i></a>
<a class="item-delete" title="{{ localize 'MGT2.Actor.DeleteSoftware' }}"><i class="fas fa-trash"></i></a>
</li>
{{/each}}
</ul>
</fieldset>
{{/if}}
</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-85 row-item-left upcase"><i class="fa-solid fa-toolbox"></i>{{ localize 'MGT2.Items.Equipments' }}</div>
<div class="row-item row-item-2 row-item-center">{{ localize 'MGT2.Items.Qty' }}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{ localize 'MGT2.Items.Weight' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="equipment" data-create-name="{{ localize 'MGT2.Actor.Equipment' }}" title="{{ localize 'MGT2.Actor.AddEquipment' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each equipments as |equipment id|}}
<div class="table-row drag-item-list" data-item-id="{{equipment._id}}" role="rowgroup">
<div class="row-item row-item-85 row-item-left">{{equipment.name}}</div>
<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-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>
</div>
</div>
{{/each}}
</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-85 row-item-left upcase"><i class="fa-solid fa-backpack"></i>{{ localize 'MGT2.Items.Items' }}</div>
<div class="row-item row-item-2 row-item-center">{{ localize 'MGT2.Items.Qty' }}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{ localize 'MGT2.Items.Weight' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="item" data-create-name="{{ localize 'MGT2.Actor.NewItem' }}" title="{{ localize 'MGT2.Actor.AddItem' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each items as |item|}}
{{#if (eq item.type "container")}}
<div class="table-row drop-item-list" data-item-id="{{item._id}}">
{{else}}
<div class="table-row drag-item-list" data-item-id="{{item._id}}">
{{/if}}
<div class="row-item row-item-85 row-item-left">{{item.name}}</div>
<div class="row-item row-item-2 row-item-center">{{item.system.quantity}}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{item.weight}}</div>
<div class="row-item row-item-15 item-controls flex-fix">
<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.EditItem' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteItem' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{#if (eq item.type "container")}}
{{#each subItems as |subItem|}}
<div class="table-row table-subrow drag-item-list" data-item-id="{{subItem._id}}">
<div class="row-item row-item-85 row-item-left">{{subItem.name}}</div>
<div class="row-item row-item-2 row-item-center">{{subItem.system.quantity}}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{subItem.weight}}</div>
<div class="row-item row-item-15 item-controls flex-fix">
<a class="item-control item-storage-out" title="{{ localize 'MGT2.Actor.UnstoreItem' }}"><i class="fa-solid fa-inbox-out"></i></a>
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditItem' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteItem' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
{{/if}}
{{/each}}
</div>
<hr />
<div class="table-container">
<div class="table-row">
<div class="row-item row-item-left" style="flex-basis: 48%">{{ localize 'MGT2.Actor.Encumbrance' }} {{encumbranceNormal}} {{settings.weightUnit}} / {{encumbranceHeavy}} {{settings.weightUnit}}</div>
<div class="row-item row-item-right" style="flex-basis: 28%">Total :</div>
<div class="row-item row-item-2 row-item-right {{encumbranceClasses}} flex-fix">{{system.inventory.weight}} {{settings.weightUnit}}</div>
<div class="row-item row-item-15 row-item-left flex-fix {{encumbranceClasses}}"></div>
</div>
</div>
</div>
<div class="tab" data-group="inventory" data-tab="storage">
<div class="mt-1" style="flex-direction: row;display: flex;justify-content: space-between;">
<div>
<label>{{ localize 'MGT2.Items.Containers' }}</label>
<select name="system.containerView">
{{selectOptions containers selected=system.containerView nameAttr="_id" labelAttr="display"}}
</select>
<div class="container-controls">
{{#unless containerShowAll}}<a class="container-edit"><i class="fas fa-edit"></i></a>{{/unless}}
<a class="container-create"><i class="fas fa-plus"></i></a>
{{#unless containerShowAll}}<a class="container-delete"><i class="fas fa-trash"></i></a>{{/unless}}
</div>
</div>
<div>
<label>DropIn</label>
<select name="system.containerDropIn">
{{selectOptions actorContainers selected=system.containerDropIn nameAttr="_id" labelAttr="display"}}
</select>
</div>
</div>
<hr />
{{#if (and containerView.system.locked (not isGM))}}
<i class="fa-solid fa-lock"></i><label class="upcase">{{ localize 'MGT2.Items.Locked' }}</label>
{{else}}
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-30 row-item-left upcase">{{ localize 'MGT2.Items.Items' }}</div>
{{#if containerShowAll}}
<div class="row-item row-item-center row-item-storage">{{ localize 'MGT2.Items.Storage' }}</div>
{{/if}}
<div class="row-item row-item-2 row-item-center flex-fix">{{ localize 'MGT2.Items.Qty' }}</div>
<div class="row-item row-item-2 row-item-center flex-fix">{{ localize 'MGT2.Items.Weight' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"></div>
</div>
{{#each containerItems as |containerItem id|}}
<div class="table-row drag-item-list" data-item-id="{{containerItem._id}}" role="rowgroup">
<div class="row-item row-item-30 row-item-left">{{containerItem.name}}</div>
{{#if ../containerShowAll}}
<div class="row-item row-item-center row-item-storage">{{containerItem.containerName}}</div>
{{/if}}
<div class="row-item row-item-2 row-item-center flex-fix">{{containerItem.system.quantity}}</div>
<div class="row-item row-item-2 row-item-center flex-fix">{{containerItem.weight}}</div>
<div class="row-item row-item-15 item-controls flex-fix">
<a class="item-control item-storage-out" title="{{ localize 'MGT2.Actor.UnstoreItem' }}"><i class="fa-solid fa-inbox-out"></i></a>
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditItem' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteItem' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
<hr />
<div>{{ localize 'MGT2.Actor.TotalWeight' }} : {{containerWeight}} {{settings.weightUnit}}</div>
{{/if}}
</div>
<div class="tab" data-group="inventory" data-tab="finance">
<div class="field-groups mb-1 mt-1">
<div class="field-group">
<label class="upcase">{{ localize 'MGT2.Actor.CashOnHand' }}</label>
<input class="field" name="system.finance.credits" type="text" value="{{system.finance.credits}}" />
</div>
<div class="field-group">
<label class="upcase">{{ localize 'MGT2.Actor.Pension' }}</label>
<input class="field" name="system.finance.pension" type="text" value="{{system.finance.pension}}" />
</div>
<div class="field-group">
<label class="upcase">{{ localize 'MGT2.Actor.LivingCost' }}</label>
<input class="field" name="system.finance.livingCost" type="text" value="{{system.finance.livingCost}}" />
</div>
<div class="field-group">
<label class="upcase">{{ localize 'MGT2.Actor.Debt' }}</label>
<input class="field" name="system.finance.debt" type="text" value="{{system.finance.debt}}" />
</div>
</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>
</div>
</div>
</div>
<div class="tab w100 tab-scroll" data-group="sidebar" data-tab="relations">
<div class="header upcase">{{ localize 'MGT2.Actor.RelationsAndContacts' }}</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item flex-grow-2">{{ localize 'MGT2.Items.Relations' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Relation' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Attitude' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Occupation' }}</div>
<div class="row-item row-item-center">{{ localize 'MGT2.Items.Location' }}</div>
<div class="row-item item-controls"><a class="item-create" data-type-item="contact" data-create-name="{{ localize 'MGT2.Actor.NewContact' }}" title="{{ localize 'MGT2.Actor.AddContact' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each contacts as |contact id|}}
<div class="table-row" data-item-id="{{contact._id}}" role="rowgroup">
<div class="row-item row-item-left flex-grow-2">{{contact.name}}</div>
<div class="row-item row-item-center">{{localize (concat "MGT2.Contact.Relation." contact.system.relation)}}</div>
<div class="row-item row-item-center">{{localize (concat "MGT2.Contact.Attitude." contact.system.attitude)}}</div>
<div class="row-item row-item-center">{{contact.system.occupation}}</div>
<div class="row-item row-item-center">{{contact.system.location}}</div>
<div class="row-item item-controls">
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditContact' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteContact' }}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</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}}
</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}}
</div>
{{#if showTrash}}
<!-- <div class="tab" data-group="inventory" data-tab="trash">
<p>À FAIRE</p>
</div> -->
{{/if}}
</div>
<section class="actor-footer">
<div></div>
<div><a name="config" title="Config" style="margin-right: 0.5rem;"><i class="fa-solid fa-gear"></i></a></div>
</section>
</form>

View File

@@ -1,13 +1,4 @@
<form class="{{cssClass}} flexcol" autocomplete="off" 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.Skills' }}"><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>
<div class="{{cssClass}} flexcol" style="align-content: flex-start;align-items: baseline;overflow: hidden;height: 100%;">
<section class="character-header">
<div class="character-header-img">
<img class="profile" src="{{img}}" data-edit="img" title="{{name}}" height="130" width="100" />
@@ -70,7 +61,7 @@
</div>
</div>
</section>
<div style="height: 100%;overflow: hidden;display: flex;flex-direction: row;width: 100%;justify-content: flex-start;align-items: flex-start;">
<div class="character-body">
<div class="characteristics">
<nav class="horizontal-tabs tabs" data-group="characteristics" style="border-right: 7px double #fff;">
<a class="item tab-select" data-tab="core">{{ localize 'MGT2.Actor.TabCore' }}</a>
@@ -252,7 +243,7 @@
{{else}}
<div class="characteristic-row">
<input class="characteristic-input" type="text" maxlength="2" name="system.characteristics.psionic.value" value="{{system.characteristics.psionic.value}}" />
<input class="characteristic-dm-input" type="text" maxlength="2" value="{{#if (gt system.characteristics.psionic.dm 0)}}+{{/if}}{{system.characteristics.psionic.dm}}" readonly tabindex='-1' />
<input class="characteristic-dm" type="text" maxlength="2" value="{{#if (gt system.characteristics.psionic.dm 0)}}+{{/if}}{{system.characteristics.psionic.dm}}" readonly tabindex='-1' />
</div>
{{/if}}
{{/if}}
@@ -275,12 +266,28 @@
</div>
</section>
</div>
<div class="tab w100" data-group="sidebar" data-tab="health">
<div class="tab w100 tab-scroll" data-group="sidebar" data-tab="health">
<div class="header upcase">{{ localize 'MGT2.Actor.Health' }}</div>
<div class="field-group mb-1">
<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>
@@ -324,7 +331,26 @@
{{/each}}
</div>
</div>
<div class="tab w100" data-group="sidebar" data-tab="skills">
<div class="tab w100 tab-scroll" data-group="sidebar" data-tab="skills">
<div class="header upcase">{{ localize 'MGT2.Actor.TabSkills' }}</div>
<div class="species"><a title="Description détaillé" data-editor="open"><i class="fa-solid fa-book"></i></a>{{system.personal.speciesText.description}}</div>
<div class="table-container">
<div class="table-row heading color-1">
<div class="row-item row-item-15 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 row-item-15 item-controls flex-fix"><a class="traits-create"><i class="fas fa-plus"></i></a></div>
</div>
{{#each system.personal.traits as |trait i| }}
<div class="table-row traits-part" data-traits-part="{{i}}" role="rowgroup">
<div class="row-item row-item-15 row-item-left">{{trait.name}}</div>
<div class="row-item row-item-left">{{trait.description}}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix">
<a class="item-control traits-edit" title="{{ localize 'MGT2.Actor.EditTrait' }}"><i class="fas fa-edit"></i></a>
<a class="item-control traits-delete" title="Delete Trait"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
<div class="header upcase">{{ localize 'MGT2.Actor.StudyPeriod' }}</div>
<div class="fields mb-1">
<div class="field-group" style="flex: 2 1 auto;">
@@ -368,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">
@@ -381,22 +407,22 @@
{{#if system.config.psionic}}
<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.PsionicTalents' }}</div>
<div class="row-item row-item-left upcase">{{ localize 'MGT2.Actor.PsionicTalents' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Level' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Cost' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Reach' }}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{ localize 'MGT2.Items.Difficulty' }}</div>
<div class="row-item row-item-15 row-item-center flex-fix">{{ localize 'MGT2.Items.Difficulty' }}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="talent" data-subtype="psionic" data-create-name="{{ localize 'MGT2.Actor.NewPsionicTalent' }}" title="{{ localize 'MGT2.Actor.AddPsionicTalent' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each psionics as |psionic id|}}
<div class="table-row" data-item-id="{{psionic._id}}" role="rowgroup">
<div class="row-item row-item-30 row-item-left">
<a data-roll="psionic" data-item-id="{{psionic._id}}"><i class="fa-solid fa-dice"></i></a>{{psionic.name}}
<div class="row-item row-item-left">
<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>
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.psionic.reach}}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.system.psionic.difficulty}}</div>
<div class="row-item row-item-10 row-item-center flex-fix">{{psionic.reach}}</div>
<div class="row-item row-item-15 row-item-center flex-fix">{{psionic.difficulty}}</div>
<div class="row-item row-item row-item-15 item-controls flex-fix">
<a class="item-control item-edit" title="{{ localize 'MGT2.Items.EditPsionic' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Items.DeletePsionic' }}"><i class="fas fa-trash"></i></a>
@@ -427,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>
@@ -452,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>
@@ -477,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>
@@ -495,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>
@@ -539,7 +565,7 @@
<div class="row-item row-item-85 row-item-left upcase"><i class="fa-solid fa-toolbox"></i>{{ localize 'MGT2.Items.Equipments' }}</div>
<div class="row-item row-item-2 row-item-center">{{ localize 'MGT2.Items.Qty' }}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{ localize 'MGT2.Items.Weight' }}</div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="equipment" data-create-name="{{ localize 'MGT2.Actor.Equipment' }}" title="{{ localize 'MGT2.Actor.AddEquipment' }}"><i class="fas fa-plus"></i></a></div>
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="equipment" data-create-name="{{ localize 'MGT2.Actor.NewEquipment' }}" title="{{ localize 'MGT2.Actor.AddEquipment' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each equipments as |equipment id|}}
<div class="table-row drag-item-list" data-item-id="{{equipment._id}}" role="rowgroup">
@@ -547,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="Equip/Unequip"><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>
@@ -563,16 +589,16 @@
<div class="row-item row-item-15 item-controls flex-fix"><a class="item-create" data-type-item="item" data-create-name="{{ localize 'MGT2.Actor.NewItem' }}" title="{{ localize 'MGT2.Actor.AddItem' }}"><i class="fas fa-plus"></i></a></div>
</div>
{{#each items as |item|}}
{{#if (eq item.type "container")}}
<div class="table-row drop-item-list" data-item-id="{{item._id}}">
{{#if (eq item.type "container")}}
<div class="table-row drop-item-list" data-item-id="{{item._id}}">
{{else}}
<div class="table-row drag-item-list" data-item-id="{{item._id}}">
{{/if}}
{{/if}}
<div class="row-item row-item-85 row-item-left">{{item.name}}</div>
<div class="row-item row-item-2 row-item-center">{{item.system.quantity}}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{item.weight}}</div>
<div class="row-item row-item-15 item-controls flex-fix">
<a class="item-control item-storage-in" title="Store Item"><i class="fa-solid fa-inbox-in"></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.EditItem' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteItem' }}"><i class="fas fa-trash"></i></a>
</div>
@@ -584,7 +610,7 @@
<div class="row-item row-item-2 row-item-center">{{subItem.system.quantity}}</div>
<div class="row-item row-item-2 row-item-right flex-fix">{{subItem.weight}}</div>
<div class="row-item row-item-15 item-controls flex-fix">
<a class="item-control item-storage-out" title="Unstore Item"><i class="fa-solid fa-inbox-out"></i></a>
<a class="item-control item-storage-out" title="{{ localize 'MGT2.Actor.UnstoreItem' }}"><i class="fa-solid fa-inbox-out"></i></a>
<a class="item-control item-edit" title="{{ localize 'MGT2.Actor.EditItem' }}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{ localize 'MGT2.Actor.DeleteItem' }}"><i class="fas fa-trash"></i></a>
</div>
@@ -608,7 +634,7 @@
<div>
<label>{{ localize 'MGT2.Items.Containers' }}</label>
<select name="system.containerView">
{{selectOptions containers selected=system.containerView nameAttr="_id" labelAttr="display"}}
{{selectOptions containers selected=system.containerView valueAttr="_id" labelAttr="display"}}
</select>
<div class="container-controls">
{{#unless containerShowAll}}<a class="container-edit"><i class="fas fa-edit"></i></a>{{/unless}}
@@ -619,7 +645,7 @@
<div>
<label>DropIn</label>
<select name="system.containerDropIn">
{{selectOptions actorContainers selected=system.containerDropIn nameAttr="_id" labelAttr="display"}}
{{selectOptions actorContainers selected=system.containerDropIn valueAttr="_id" labelAttr="display"}}
</select>
</div>
</div>
@@ -677,8 +703,8 @@
</div>
</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>
<label class="upcase">{{ localize 'MGT2.Actor.Notes' }}</label>
{{formInput systemFields.finance.fields.notes enriched=enrichedFinanceNotes value=system.finance.notes name="system.finance.notes" toggled=true}}
</div>
</div>
</div>
@@ -696,8 +722,8 @@
{{#each contacts as |contact id|}}
<div class="table-row" data-item-id="{{contact._id}}" role="rowgroup">
<div class="row-item row-item-left flex-grow-2">{{contact.name}}</div>
<div class="row-item row-item-center">{{localize (concat "Contact.Relation." contact.system.relation)}}</div>
<div class="row-item row-item-center">{{localize (concat "Contact.Attitude." contact.system.attitude)}}</div>
<div class="row-item row-item-center">{{localize (concat "MGT2.Contact.Relation." contact.system.relation)}}</div>
<div class="row-item row-item-center">{{localize (concat "MGT2.Contact.Attitude." contact.system.attitude)}}</div>
<div class="row-item row-item-center">{{contact.system.occupation}}</div>
<div class="row-item row-item-center">{{contact.system.location}}</div>
<div class="row-item item-controls">
@@ -710,21 +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></div>
<div><a name="config" title="Config" style="margin-right: 0.5rem;"><i class="fa-solid fa-gear"></i></a></div>
</section>
</form>
<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>

View 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>

View 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>

View File

@@ -0,0 +1,12 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<div class="itemsheet-header"><label class="upcase">{{ localize 'MGT2.Items.Trait' }}</label></div>
<div class="itemsheet-panel">
<div class="w-100 h100 flexcol">
<input class="field field-item-name" name="name" type="text" value="{{data.name}}" style="flex-grow: 0;" />
<div class="field-group mt-1">
<label>{{ localize 'MGT2.Items.Description' }}</label>
<textarea name="description" rows="6">{{data.description}}</textarea>
</div>
</div>
</div>
</form>

View File

@@ -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" />
</div>
<div class="vehicule-header-img">
<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>

View File

@@ -0,0 +1,43 @@
<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}}
</div>

View File

@@ -1,35 +1,64 @@
<div class="roll-info">
<div class="roll-object-name">{{rollObjectName}}</div>
{{#if rollTypeName}}
<div class="roll-type-name">{{rollTypeName}}</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}}
<span class="mgt2-roll-sep"></span>
<span class="mgt2-roll-difficulty">{{rollDifficultyLabel}}</span>
{{/if}}
</div>
{{/if}}
</div>
{{#if rollMessage}}
<div class="mgt2-roll-modifier">{{rollMessage}}</div>
{{/if}}
{{#if rollModifiers}}
{{#each rollModifiers as |rollModifier i| }}
<div>{{rollModifier}}</div>
{{/each}}
{{/if}}
</div>
<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 class="mgt2-roll-modifiers">
{{#each rollModifiers as |mod i|}}
<span class="mgt2-roll-mod-tag">{{mod}}</span>
{{/each}}
</div>
</div>
{{#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>
<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 {{#if rollSuccess}}success{{else if rollFailure}}failure{{/if}}" {{#if rollBreakdown}}data-tooltip="{{rollBreakdown}}"{{/if}}>{{total}}</h4>
</div>
</div>
{{#if rollSuccess}}
<div class="mgt2-outcome is-success"><i class="fa-solid fa-check"></i> {{ localize 'MGT2.Chat.Roll.Success' }}</div>
{{else if rollFailure}}
<div class="mgt2-outcome is-failure"><i class="fa-solid fa-xmark"></i> {{ localize 'MGT2.Chat.Roll.Failure' }}</div>
{{/if}}
{{#if showRollDamage}}
<button data-action="rollDamage" title="Roll">{{ localize 'MGT2.Chat.Roll.Damages' }}</button>
{{#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}}
</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>
{{/if}}
{{#if showRollDamage}}
<button data-action="rollDamage">{{ localize 'MGT2.Chat.Roll.Damages' }}</button>
{{/if}}
{{#each cardButtons as |cardButton|}}
<button data-action="{{cardButton.action}}" title="{{cardButton.label}}">{{cardButton.label}}</button>
{{/each}}
</div>
{{/if}}
</div>

View File

@@ -0,0 +1,3 @@
<form class="{{cssClass}}" autocomplete="off" style="padding: 0 0.5rem;">
{{{html}}}
</form>

View File

@@ -1,74 +1,71 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<div class="itemsheet-header">
<label>{{localize 'MGT2.TYPES.Item.armor'}}</label>
<div class="{{cssClass}} itemsheet">
<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>
<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">
<label>{{ localize 'MGT2.Items.Description' }}</label>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</div>
</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">
<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" data-group="primary" data-tab="tab1">
<div class="field-group mt-1">
<label>{{ localize 'MGT2.Items.Description' }}</label>
<textarea name="system.description" rows="6">{{system.description}}</textarea>
<div class="tab" data-group="primary" data-tab="tab2">
<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-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-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}}
</div>
<div class="tab" data-group="primary" data-tab="tab2">
<div class="field-groups mt-1">
<div class="field-group w3-10">
<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">
<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">
<label>{{ localize 'MGT2.Items.Storage' }}</label>
<select name="system.container.id">
{{selectOptions containers selected=system.container.id nameAttr="_id" labelAttr="name"}}
</select>
</div>
{{/if}}
<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"><a class="options-create" data-property="options"><i class="fas fa-plus"></i></a></div>
</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" />
{{#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"><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="field-group">
<label>{{ localize 'MGT2.Items.Protection' }}</label>
<input type="text" name="system.protection" value="{{system.protection}}" data-dtype="String" />
<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>
<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="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>
{{#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">
<textarea name="system.options.{{i}}.description" rows="3">{{option.description}}</textarea>
</div>
<div class="row-item row-item-right row-item-5 flex-fix item-controls">
<a class="item-control options-delete" title="Delete Option"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
<div class="tab" data-group="primary" data-tab="tab3">
</div>
<div class="tab" data-group="primary" data-tab="tab3">
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,50 +1,55 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<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>
<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>
</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">
<a class="item tab-select" data-tab="tab1">{{ localize 'MGT2.Items.Description' }}</a>
<a class="item tab-select" data-tab="events">{{ localize 'MGT2.Items.EventsMishaps' }}</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="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>
{{#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>
</div>
<div class="row-item item-controls">
<a class="item-control event-delete" title="Delete Event"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</div>
</div>
<div class="{{cssClass}} itemsheet">
<div class="item-type-bar">
<span class="item-type-label"><i class="fas fa-briefcase"></i> {{ localize 'MGT2.Items.Career' }}</span>
</div>
<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>
<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">
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</div>
</form>
<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">
<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="2">{{event.description}}</textarea>
</div>
<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>
{{/each}}
</div>
</div>
</div>
</div>

View File

@@ -1,65 +1,64 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<div class="itemsheet-header">
<label>{{localize 'MGT2.EquipmentSubType.computer'}}</label>
<div class="{{cssClass}} itemsheet">
<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>
<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">
<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" data-group="primary" data-tab="tab1">
<div class="field-group mt-1">
<label>{{ localize 'MGT2.Items.Description' }}</label>
<textarea name="system.description" rows="6">{{system.description}}</textarea>
</div>
<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">
<label>{{ localize 'MGT2.Items.Description' }}</label>
{{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="field-groups mt-1">
<div class="field-group">
<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">
<label>{{ localize 'MGT2.Items.Storage' }}</label>
<select name="system.container.id">
{{selectOptions containers selected=system.container.id nameAttr="_id" labelAttr="name"}}
</select>
</div>
{{/if}}
</div>
<div class="field-group mt-1">
</div>
<div class="tab" data-group="primary" data-tab="tab2">
<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" />
<input type="number" name="system.processing" value="{{system.processing}}" data-dtype="Number" class="short" />
</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="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>
<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>
{{/each}}
<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-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}}
</div>
<div class="tab" data-group="primary" data-tab="tab3">
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
<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"><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>
</div>
</div>
{{/each}}
</div>
</div>
<div class="tab" data-group="primary" data-tab="tab3">
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
</div>
</div>
</form>
</div>

View File

@@ -1,84 +1,80 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<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>
<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>
<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 class="{{cssClass}} itemsheet">
<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="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.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="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="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;">
<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" data-group="primary" data-tab="tab1">
<div class="field-group mt-1">
<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">
<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">
<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">
<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">
<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>
<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-row">
<label>{{ localize 'MGT2.Items.Nickname' }}</label>
<input type="text" name="system.nickname" value="{{system.nickname}}" data-dtype="String" />
</div>
<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-row">
<label>{{ localize 'MGT2.Items.Location' }}</label>
<input type="text" name="system.location" value="{{system.location}}" data-dtype="String" />
</div>
<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>
</form>
<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>

View File

@@ -1,55 +1,59 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<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>
{{/if}}
<div class="field-group mt-05">
<label>{{ localize 'MGT2.Items.Weight' }} ({{unitlabels.weight}})</label>
<input type="number" value="{{weight}}" readonly />
<div class="{{cssClass}} itemsheet">
<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>
<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>
<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">
<label>{{ localize 'MGT2.Items.Description' }}</label>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</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">
<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" data-group="primary" data-tab="tab1">
<div class="field-group mt-1">
<label>{{ localize 'MGT2.Items.Description' }}</label>
<textarea name="system.description" rows="6">{{system.description}}</textarea>
<div class="tab" data-group="primary" data-tab="tab2">
<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>
</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>
{{#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>
<div class="tab" data-group="primary" data-tab="tab3">
<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>
{{#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>
</form>
</div>

View File

@@ -1,45 +1,51 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<div class="itemsheet-header">
<div class="{{cssClass}} itemsheet">
<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">
<label>{{ localize 'MGT2.Items.Type' }}</label>
<select name="system.subType">
{{selectOptions config.DiseaseSubType 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>
<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="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">
<label>{{ localize 'MGT2.Items.Difficulty' }}</label>
<select name="system.difficulty">
{{selectOptions config.Difficulty selected = system.difficulty localize = true}}
<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}}
</select>
</div>
<div class="field-group w3-10" style="margin: 0 1rem;">
<div class="field-row">
<label>{{ localize 'MGT2.Items.Difficulty' }}</label>
<select name="system.difficulty">
{{selectOptions config.Difficulty selected=system.difficulty localize=true}}
</select>
</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-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>
</form>
</div>

View File

@@ -1,57 +1,56 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<div class="itemsheet-header">
<div class="{{cssClass}} itemsheet">
<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>
<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">
<label>{{ localize 'MGT2.Items.Description' }}</label>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</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">
<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" data-group="primary" data-tab="tab1">
<div class="field-group mt-1">
<label>{{ localize 'MGT2.Items.Description' }}</label>
<textarea name="system.description" rows="6">{{system.description}}</textarea>
<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.EquipmentSubType selected=system.subType localize=true}}
</select>
</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>
{{#if hadContainer}}
<div class="field-group">
<label>{{ localize 'MGT2.Items.Storage' }}</label>
<select name="system.container.id">
{{selectOptions containers selected=system.container.id nameAttr="_id" labelAttr="name"}}
</select>
</div>
{{/if}}
{{> 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-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}}
</div>
<div class="tab" data-group="primary" data-tab="tab3">
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
</div>
</div>
<div class="tab" data-group="primary" data-tab="tab3">
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
</div>
</div>
</form>
</div>

View File

@@ -1,60 +1,59 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<div class="itemsheet-header">
<div class="{{cssClass}} itemsheet">
<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>
<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>
{{> 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">
<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" data-group="primary" data-tab="tab1">
<div class="field-group mt-1">
<label>{{ localize 'MGT2.Items.Description' }}</label>
<textarea name="system.description" rows="6">{{system.description}}</textarea>
<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>
</div>
<div class="tab" data-group="primary" data-tab="tab2">
{{> systems/mgt2/templates/items/parts/sheet-physical-item-tab.html }}
{{#if hadContainer}}
<div class="field-groups mt-1">
{{#if (eq system.subType "software")}}
<div class="field-group">
<label>{{ localize 'MGT2.Items.Computer' }}</label>
<select name="system.software.computerId">
{{selectOptions computers selected=system.software.computerId nameAttr="_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 nameAttr="_id" labelAttr="name"}}
</select>
</div>
<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 mt-1">
<div class="field-row">
<label>{{ localize 'MGT2.Items.Bandwidth' }}</label>
<input type="number" name="system.software.bandwidth" value="{{system.software.bandwidth}}" data-dtype="Number" />
<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}}
{{/if}}
</div>
</div>
</div>
</form>
</div>

View File

@@ -10,7 +10,7 @@
<label>{{ localize 'MGT2.Items.Skill' }}</label>
<select name="system.roll.skill">
<option></option>
{{selectOptions skills selected=system.roll.skill nameAttr="_id" labelAttr="name"}}
{{selectOptions skills selected=system.roll.skill valueAttr="_id" labelAttr="name"}}
</select>
</div>
<div class="field-group w3-10">

View 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>

View File

@@ -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>

View File

@@ -1,15 +1,67 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<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>
<div class="w-100">
<input class="field item-name" name="name" type="text" value="{{item.name}}" />
<div class="field-group mt-1">
<div class="{{cssClass}} itemsheet">
<div class="item-type-bar">
<span class="item-type-label"><i class="fas fa-dna"></i> {{ localize 'MGT2.Specie' }}</span>
</div>
<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">
<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">
{{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">
<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}}
</select>
</div>
<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-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" 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-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-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="2">{{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}}
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,68 +1,84 @@
<form class="{{cssClass}} flexrow itemsheet" autocomplete="off">
<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="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>
<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.TalentSubType selected = system.subType localize = true}}
</select>
</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}}
</select>
</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">
<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>
{{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>
<div class="field-group">
<label>{{ localize 'MGT2.Items.Reach' }}</label>
<select name="system.psionic.reach">
<option></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>
{{/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}}
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
</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>
{{#if (eq system.subType "skill")}}
<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-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-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-row">
<label>{{ localize 'MGT2.Items.Reach' }}</label>
<select name="system.psionic.reach">
<option value=""></option>
{{selectOptions config.PsionicReach selected=system.psionic.reach localize=true}}
</select>
</div>
<div class="field-row full">
<label>{{ localize 'MGT2.Items.Duration' }}</label>
<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>
{{/if}}
</div>
</div>
</form>
{{!-- 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>

View File

@@ -1,89 +1,104 @@
<form class="{{cssClass}} itemsheet" autocomplete="off">
<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="{{cssClass}} itemsheet">
<div class="item-type-bar">
<span class="item-type-label"><i class="fas fa-gun"></i> {{ localize 'MGT2.Items.Weapon' }}</span>
</div>
<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">
<label>{{ localize 'MGT2.Items.Description' }}</label>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</div>
</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">
<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" data-group="primary" data-tab="tab1">
<div class="field-group mt-1">
<label>{{ localize 'MGT2.Items.Description' }}</label>
<textarea name="system.description" rows="6">{{system.description}}</textarea>
<div class="tab" data-group="primary" data-tab="tab2">
<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>
<div class="tab" data-group="primary" data-tab="tab2">
<div class="field-groups mt-1">
<div class="field-group flex-1">
<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">
<label>{{ localize 'MGT2.Items.Storage' }}</label>
<select name="system.container.id">
{{selectOptions containers selected=system.container.id nameAttr="_id" labelAttr="name"}}
</select>
</div>
{{/if}}
<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-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>
</div>
{{#unless system.range.isMelee}}
<div class="field-group w3-10">
<label>{{ localize 'MGT2.Items.Range' }}</label>
<div class="flexrow">
<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" class="flex-fix" style="width: 5rem;">
{{selectOptions config.MetricRange selected=system.range.unit localize = true}}
<select name="system.range.unit">
{{selectOptions config.MetricRange selected=system.range.unit localize=true}}
</select>
</div>
</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}}
{{/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-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}}
</div>
<div class="tab" data-group="primary" data-tab="tab3">
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
<div class="table-container">
<div class="table-row heading">
<div class="row-item row-item-left">{{ 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="2">{{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}}
</div>
</div>
<div class="tab" data-group="primary" data-tab="tab3">
{{> systems/mgt2/templates/items/parts/sheet-configuration.html }}
</div>
</div>
</form>
</div>

View File

@@ -1,15 +1,43 @@
<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">
{{selectOptions characteristics selected=characteristic nameAttr="_id" labelAttr="name"}}
{{selectOptions characteristics selected=characteristic valueAttr="_id" labelAttr="name"}}
</select>
</div>
<div class="form-group">
<label>{{ localize 'MGT2.RollPrompt.SkillDM' }}</label>
<select name="skill">
<option></option>
{{selectOptions skills selected=skill nameAttr="_id" labelAttr="name"}}
{{selectOptions skills selected=skill valueAttr="_id" labelAttr="name"}}
</select>
</div>
<div class="form-group">
@@ -25,19 +53,37 @@
<label class="mgt2-checkbox"><input type="checkbox" name="fatigue" data-dtype="Boolean" {{checked fatigue}} />{{ localize 'MGT2.RollPrompt.FatigueDM' }}</label>
</div>
</fieldset>
{{/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>
{{#if showDifficulty}}
<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>
{{/if}}
<div class="form-group">
<label>{{ localize 'MGT2.RollPrompt.RollMode' }}</label>
<select name="rollMode">

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB