Migration vers datamodels
This commit is contained in:
46
gulpfile.js
46
gulpfile.js
@@ -1,25 +1,31 @@
|
||||
var gulp = require('gulp');
|
||||
const gulp = require('gulp');
|
||||
const less = require('gulp-less');
|
||||
|
||||
var postcss = require('gulp-postcss');
|
||||
|
||||
var autoprefixer = require('autoprefixer');
|
||||
var cssnext = require('cssnext');
|
||||
var precss = require('precss');
|
||||
|
||||
gulp.task('css', function () {
|
||||
|
||||
var processors = [
|
||||
autoprefixer,
|
||||
cssnext,
|
||||
precss
|
||||
];
|
||||
|
||||
return gulp.src('./postcss/*.css')
|
||||
.pipe(postcss(processors))
|
||||
.pipe(gulp.dest('./styles'));
|
||||
});
|
||||
/* ----------------------------------------- */
|
||||
/* Compile LESS
|
||||
/* ----------------------------------------- */
|
||||
function compileLESS() {
|
||||
return gulp.src("styles/ecryme.less")
|
||||
.pipe(less()).on('error', console.log.bind(console))
|
||||
.pipe(gulp.dest("./css"));
|
||||
}
|
||||
const css = gulp.series(compileLESS);
|
||||
|
||||
/* ----------------------------------------- */
|
||||
/* Watch Updates
|
||||
/* ----------------------------------------- */
|
||||
const LESS_FILES = ["styles/**/*.less"];
|
||||
|
||||
function watchUpdates() {
|
||||
gulp.watch('./postcss/*.css', css);
|
||||
gulp.watch(LESS_FILES, css);
|
||||
}
|
||||
|
||||
/* ----------------------------------------- */
|
||||
/* Export Tasks
|
||||
/* ----------------------------------------- */
|
||||
exports.default = gulp.series(
|
||||
gulp.parallel(css),
|
||||
watchUpdates
|
||||
);
|
||||
exports.css = css;
|
||||
exports.watchUpdates = watchUpdates;
|
||||
|
||||
15
lang/en.json
15
lang/en.json
@@ -112,6 +112,7 @@
|
||||
"applyspleen": "Apply spleen",
|
||||
"skilltranscendence": "Self Transcendence",
|
||||
"confrontation": "Confrontation",
|
||||
"confrontresult": "Confrontation Result",
|
||||
"rollnormal": "Normal (4d6)",
|
||||
"rollspleen": "With Spleen (5d6, worst 4 are kept)",
|
||||
"rollideal": "With Ideal (5d6, best 4 are kept)",
|
||||
@@ -168,7 +169,19 @@
|
||||
"residence": "Residence",
|
||||
"origin": "Origin",
|
||||
"childhood": "Childhood",
|
||||
"bonus": "Bonus"
|
||||
"bonus": "Bonus",
|
||||
"details": "Details",
|
||||
"quantity": "Quantity",
|
||||
"background": "Background",
|
||||
"gmnotes": "GM Notes",
|
||||
"age": "Age",
|
||||
"profession": "Profession",
|
||||
"level": "Level",
|
||||
"create": "Create",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit",
|
||||
"spleen": "Spleen",
|
||||
"ideal": "Ideal"
|
||||
}
|
||||
}
|
||||
}
|
||||
15
lang/fr.json
15
lang/fr.json
@@ -113,6 +113,7 @@
|
||||
"applyspleen": "Utiliser le spleen",
|
||||
"skilltranscendence": "Dépassement de soi",
|
||||
"confrontation": "Confrontation",
|
||||
"confrontresult": "Résultat de Confrontation",
|
||||
"rollnormal": "Normal (4d6)",
|
||||
"rollspleen": "Avec le Spleen (5d6, 4 plus bas conservés)",
|
||||
"rollideal": "Avec l'Idéal (5d6, 4 plus haut conservés)",
|
||||
@@ -169,7 +170,19 @@
|
||||
"residence": "Résidence",
|
||||
"origin": "Origine",
|
||||
"childhood": "Enfance",
|
||||
"bonus": "Bonus"
|
||||
"bonus": "Bonus",
|
||||
"details": "Détails",
|
||||
"quantity": "Quantité",
|
||||
"background": "Background",
|
||||
"gmnotes": "Notes GM",
|
||||
"age": "Âge",
|
||||
"profession": "Profession",
|
||||
"level": "Niveau",
|
||||
"create": "Créer",
|
||||
"delete": "Supprimer",
|
||||
"edit": "Éditer",
|
||||
"spleen": "Spleen",
|
||||
"ideal": "Idéal"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,9 +379,9 @@ export class EcrymeActor extends Actor {
|
||||
rollData.img = this.img
|
||||
rollData.isReroll = false
|
||||
rollData.config = game.system.ecryme.config
|
||||
rollData.traits = foundry.utils.duplicate(this.getRollTraits())
|
||||
rollData.spleen = foundry.utils.duplicate(this.getSpleen() || {})
|
||||
rollData.ideal = foundry.utils.duplicate(this.getIdeal() || {})
|
||||
rollData.traits = this.getRollTraits().map(t => ({ _id: t.id, name: t.name, img: t.img, system: { level: t.system.level, traitype: t.system.traitype } }))
|
||||
rollData.spleen = this.getSpleen() ? foundry.utils.duplicate(this.getSpleen()) : null
|
||||
rollData.ideal = this.getIdeal() ? foundry.utils.duplicate(this.getIdeal()) : null
|
||||
rollData.confrontBonus = this.getBonusList()
|
||||
|
||||
return rollData
|
||||
|
||||
2
modules/actors/sheets/_module.js
Normal file
2
modules/actors/sheets/_module.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as EcrymeActorSheet } from "./pc-npc-sheet.js"
|
||||
export { default as EcrymeAnnencySheet } from "./annency-sheet.js"
|
||||
127
modules/actors/sheets/annency-sheet.js
Normal file
127
modules/actors/sheets/annency-sheet.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import EcrymeBaseActorSheet from "./base-actor-sheet.js"
|
||||
import { EcrymeUtility } from "../../common/ecryme-utility.js"
|
||||
|
||||
/**
|
||||
* Actor sheet for the Annency type using Application V2.
|
||||
*/
|
||||
export default class EcrymeAnnencySheet extends EcrymeBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["annency"],
|
||||
position: { width: 640, height: 600 },
|
||||
actions: {
|
||||
actorEdit: EcrymeAnnencySheet.#onActorEdit,
|
||||
actorDelete: EcrymeAnnencySheet.#onActorDelete,
|
||||
itemEdit: EcrymeAnnencySheet.#onItemEdit,
|
||||
itemDelete: EcrymeAnnencySheet.#onItemDelete,
|
||||
itemCreate: EcrymeAnnencySheet.#onItemCreate,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
annency: { template: "systems/fvtt-ecryme/templates/actors/annency-annency.hbs" },
|
||||
boheme: { template: "systems/fvtt-ecryme/templates/actors/annency-boheme.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "annency" }
|
||||
|
||||
/** Build tabs conditionally based on active modules */
|
||||
_getTabs() {
|
||||
const tabs = {}
|
||||
if (EcrymeUtility.hasCephaly()) {
|
||||
tabs.annency = { id: "annency", group: "primary", label: "ECRY.ui.annency" }
|
||||
}
|
||||
if (EcrymeUtility.hasBoheme()) {
|
||||
tabs.boheme = { id: "boheme", group: "primary", label: "ECRY.ui.boheme" }
|
||||
}
|
||||
// Ensure initial tab is valid
|
||||
if (!tabs[this.tabGroups.primary]) {
|
||||
this.tabGroups.primary = Object.keys(tabs)[0] ?? "annency"
|
||||
}
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
return {
|
||||
actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
type: actor.type,
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
isEditable: this.isEditable,
|
||||
config: game.system.ecryme.config,
|
||||
hasCephaly: EcrymeUtility.hasCephaly(),
|
||||
hasBoheme: EcrymeUtility.hasBoheme(),
|
||||
characters: actor.buildAnnencyActorList(),
|
||||
owner: this.document.isOwner,
|
||||
isGM: game.user.isGM,
|
||||
tabs: this._getTabs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "annency" || partId === "boheme") {
|
||||
context.tab = context.tabs[partId]
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
if (data.type === "Actor") {
|
||||
const actor = await fromUuid(data.uuid)
|
||||
if (actor) {
|
||||
this.actor.addAnnencyActor(actor.id)
|
||||
} else {
|
||||
ui.notifications.warn("Actor not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #region Static Action Handlers
|
||||
|
||||
static #onActorEdit(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
game.actors.get(li?.dataset.actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onActorDelete(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
this.actor.removeAnnencyActor(li?.dataset.actorId)
|
||||
}
|
||||
|
||||
static #onItemEdit(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
const itemId = li?.dataset.itemId ?? target.dataset.itemId
|
||||
this.document.items.get(itemId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onItemDelete(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
EcrymeUtility.confirmDelete(this, $(li)).catch(() => {})
|
||||
}
|
||||
|
||||
static #onItemCreate(event, target) {
|
||||
const dataType = target.dataset.type
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: "NewItem", type: dataType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
81
modules/actors/sheets/base-actor-sheet.js
Normal file
81
modules/actors/sheets/base-actor-sheet.js
Normal file
@@ -0,0 +1,81 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Base actor sheet for Ecryme using Application V2.
|
||||
* Provides common drag-drop, image editing, and shared structure.
|
||||
*/
|
||||
export default class EcrymeBaseActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "sheet", "actor"],
|
||||
position: {
|
||||
width: 860,
|
||||
height: 680,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: ".item-list .item[data-item-id]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: EcrymeBaseActorSheet.#onEditImage,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map((d) => {
|
||||
d.permissions = {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
}
|
||||
|
||||
_canDragStart(selector) { return this.isEditable }
|
||||
_canDragDrop(selector) { return this.isEditable && this.document.isOwner }
|
||||
_onDragStart(event) {}
|
||||
_onDragOver(event) {}
|
||||
async _onDrop(event) {}
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
static async #onEditImage(event, target) {
|
||||
const attr = target.dataset.edit
|
||||
const current = foundry.utils.getProperty(this.document, attr)
|
||||
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||
const fp = new FilePicker({
|
||||
current,
|
||||
type: "image",
|
||||
redirectToRoot: img ? [img] : [],
|
||||
callback: (path) => {
|
||||
this.document.update({ [attr]: path })
|
||||
},
|
||||
top: this.position.top + 40,
|
||||
left: this.position.left + 10,
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
255
modules/actors/sheets/pc-npc-sheet.js
Normal file
255
modules/actors/sheets/pc-npc-sheet.js
Normal file
@@ -0,0 +1,255 @@
|
||||
import EcrymeBaseActorSheet from "./base-actor-sheet.js"
|
||||
import { EcrymeUtility } from "../../common/ecryme-utility.js"
|
||||
|
||||
/**
|
||||
* Actor sheet for PC and NPC types using Application V2.
|
||||
*/
|
||||
export default class EcrymeActorSheet extends EcrymeBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["pc-npc"],
|
||||
position: { width: 860, height: 680 },
|
||||
actions: {
|
||||
openAnnency: EcrymeActorSheet.#onOpenAnnency,
|
||||
itemEdit: EcrymeActorSheet.#onItemEdit,
|
||||
itemDelete: EcrymeActorSheet.#onItemDelete,
|
||||
itemCreate: EcrymeActorSheet.#onItemCreate,
|
||||
subactorEdit: EcrymeActorSheet.#onSubactorEdit,
|
||||
subactorDelete: EcrymeActorSheet.#onSubactorDelete,
|
||||
rollSkill: EcrymeActorSheet.#onRollSkill,
|
||||
rollSpec: EcrymeActorSheet.#onRollSpec,
|
||||
rollSkillConfront: EcrymeActorSheet.#onRollSkillConfront,
|
||||
rollCephaly: EcrymeActorSheet.#onRollCephaly,
|
||||
rollWeaponConfront:EcrymeActorSheet.#onRollWeaponConfront,
|
||||
impactModify: EcrymeActorSheet.#onImpactModify,
|
||||
rollWeapon: EcrymeActorSheet.#onRollWeapon,
|
||||
lockUnlock: EcrymeActorSheet.#onLockUnlock,
|
||||
equipItem: EcrymeActorSheet.#onEquipItem,
|
||||
quantityMinus: EcrymeActorSheet.#onQuantityMinus,
|
||||
quantityPlus: EcrymeActorSheet.#onQuantityPlus,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
skills: { template: "systems/fvtt-ecryme/templates/actors/actor-skills.hbs" },
|
||||
traits: { template: "systems/fvtt-ecryme/templates/actors/actor-traits.hbs" },
|
||||
combat: { template: "systems/fvtt-ecryme/templates/actors/actor-combat.hbs" },
|
||||
cephaly: { template: "systems/fvtt-ecryme/templates/actors/actor-cephaly.hbs" },
|
||||
equipements:{ template: "systems/fvtt-ecryme/templates/actors/actor-equipements.hbs" },
|
||||
biodata: { template: "systems/fvtt-ecryme/templates/actors/actor-biodata.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "skills" }
|
||||
|
||||
/** Build tabs, conditionally adding cephaly if the module is active */
|
||||
_getTabs() {
|
||||
const hasCephaly = EcrymeUtility.hasCephaly()
|
||||
const tabs = {
|
||||
skills: { id: "skills", group: "primary", label: "ECRY.ui.skills" },
|
||||
traits: { id: "traits", group: "primary", label: "ECRY.ui.traits" },
|
||||
combat: { id: "combat", group: "primary", label: "ECRY.ui.healthcombat" },
|
||||
equipements:{ id: "equipements", group: "primary", label: "ECRY.ui.equipment" },
|
||||
biodata: { id: "biodata", group: "primary", label: "ECRY.ui.bionotes" },
|
||||
}
|
||||
if (hasCephaly) {
|
||||
// Insert cephaly after combat, rebuilding the object to preserve insertion order
|
||||
const ordered = {}
|
||||
for (const [k, v] of Object.entries(tabs)) {
|
||||
ordered[k] = v
|
||||
if (k === "combat") ordered.cephaly = { id: "cephaly", group: "primary", label: "ECRY.ui.cephaly" }
|
||||
}
|
||||
for (const tab of Object.values(ordered)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return ordered
|
||||
}
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
return {
|
||||
actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
type: actor.type,
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
isEditable: this.isEditable,
|
||||
config: game.system.ecryme.config,
|
||||
hasCephaly: EcrymeUtility.hasCephaly(),
|
||||
hasBoheme: EcrymeUtility.hasBoheme(),
|
||||
hasAmertume: EcrymeUtility.hasAmertume(),
|
||||
skills: actor.prepareSkills(),
|
||||
traits: actor.getRollTraits(),
|
||||
ideal: actor.getIdeal(),
|
||||
spleen: actor.getSpleen(),
|
||||
weapons: actor.getWeapons(),
|
||||
maneuvers: actor.getManeuvers(),
|
||||
impactsMalus: actor.getImpactsMalus(),
|
||||
equipments: actor.getEquipments(),
|
||||
cephalySkills:actor.getCephalySkills(),
|
||||
confrontations: actor.getConfrontations(),
|
||||
subActors: actor.getSubActors(),
|
||||
annency: actor.getAnnency(),
|
||||
owner: this.document.isOwner,
|
||||
isGM: game.user.isGM,
|
||||
editScore: this.options.editScore ?? true,
|
||||
tabs: this._getTabs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
switch (partId) {
|
||||
case "skills":
|
||||
case "traits":
|
||||
case "combat":
|
||||
case "cephaly":
|
||||
case "equipements":
|
||||
context.tab = context.tabs[partId] ?? { cssClass: "" }
|
||||
break
|
||||
case "biodata":
|
||||
context.tab = context.tabs.biodata
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.biodata.description, { async: true }
|
||||
)
|
||||
context.enrichedGmnotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.biodata.gmnotes, { async: true }
|
||||
)
|
||||
break
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
// #region Drag and Drop
|
||||
|
||||
/** Handle incoming drops: Items from sidebar/compendium, Actors as subactors */
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
if (!data?.type) return
|
||||
|
||||
if (data.type === "Item") {
|
||||
const item = await fromUuid(data.uuid)
|
||||
if (!item) return
|
||||
await this.document.createEmbeddedDocuments("Item", [item.toObject()])
|
||||
} else if (data.type === "Actor") {
|
||||
const actor = fromUuidSync(data.uuid)
|
||||
if (actor) await this.actor.addSubActor(actor.id)
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle outgoing drag from embedded item rows */
|
||||
_onDragStart(event) {
|
||||
const li = event.currentTarget.closest("[data-item-id]")
|
||||
if (!li) return
|
||||
const item = this.document.items.get(li.dataset.itemId)
|
||||
if (!item) return
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(item.toDragData()))
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Static Action Handlers
|
||||
|
||||
static #onOpenAnnency(event, target) {
|
||||
const actorId = target.dataset.annencyId
|
||||
game.actors.get(actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static #onItemEdit(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
const itemId = li?.dataset.itemId ?? target.dataset.itemId
|
||||
this.document.items.get(itemId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onItemDelete(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
EcrymeUtility.confirmDelete(this, $(li)).catch(() => {})
|
||||
}
|
||||
|
||||
static #onItemCreate(event, target) {
|
||||
const dataType = target.dataset.type
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: "NewItem", type: dataType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
static #onSubactorEdit(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
game.actors.get(li?.dataset.actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static #onSubactorDelete(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
this.actor.delSubActor(li?.dataset.actorId)
|
||||
}
|
||||
|
||||
static #onRollSkill(event, target) {
|
||||
this.actor.rollSkill(target.dataset.categoryKey, target.dataset.skillKey)
|
||||
}
|
||||
|
||||
static #onRollSpec(event, target) {
|
||||
this.actor.rollSpec(target.dataset.categoryKey, target.dataset.skillKey, target.dataset.specId)
|
||||
}
|
||||
|
||||
static #onRollSkillConfront(event, target) {
|
||||
this.actor.rollSkillConfront(target.dataset.categoryKey, target.dataset.skillKey)
|
||||
}
|
||||
|
||||
static #onRollCephaly(event, target) {
|
||||
this.actor.rollCephalySkillConfront(target.dataset.skillKey)
|
||||
}
|
||||
|
||||
static #onRollWeaponConfront(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.rollWeaponConfront(li?.dataset.itemId)
|
||||
}
|
||||
|
||||
static #onImpactModify(event, target) {
|
||||
this.actor.modifyImpact(
|
||||
target.dataset.impactType,
|
||||
target.dataset.impactLevel,
|
||||
Number(target.dataset.impactModifier)
|
||||
)
|
||||
}
|
||||
|
||||
static #onRollWeapon(event, target) {
|
||||
this.actor.rollArme(target.dataset.armeId)
|
||||
}
|
||||
|
||||
static #onLockUnlock(event, target) {
|
||||
this.options.editScore = !this.options.editScore
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
static #onEquipItem(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.equipItem(li?.dataset.itemId)
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
static #onQuantityMinus(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.incDecQuantity(li?.dataset.itemId, -1)
|
||||
}
|
||||
|
||||
static #onQuantityPlus(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.incDecQuantity(li?.dataset.itemId, +1)
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
@@ -211,6 +211,8 @@ export class EcrymeUtility {
|
||||
type: "confront-data",
|
||||
rollData1: this.confrontData1,
|
||||
rollData2: this.confrontData2,
|
||||
alias: this.confrontData1.alias,
|
||||
actorImg: this.confrontData1.actorImg,
|
||||
}
|
||||
// Compute margin
|
||||
confront.marginExecution = this.confrontData1.executionTotal - this.confrontData2.preservationTotal
|
||||
@@ -378,6 +380,9 @@ export class EcrymeUtility {
|
||||
'systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs',
|
||||
'systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs',
|
||||
'systems/fvtt-ecryme/templates/actors/partial-impacts.hbs',
|
||||
'systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs',
|
||||
'systems/fvtt-ecryme/templates/items/partials/item-header.hbs',
|
||||
'systems/fvtt-ecryme/templates/items/partials/item-description.hbs',
|
||||
]
|
||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
@@ -1,169 +1,192 @@
|
||||
import { EcrymeUtility } from "../common/ecryme-utility.js";
|
||||
import { EcrymeRollDialog } from "./ecryme-roll-dialog.js";
|
||||
|
||||
export class EcrymeConfrontDialog extends Dialog {
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Main confrontation dialog — Application V2 version.
|
||||
* Features drag-and-drop of dice from the pool to execution/preservation slots.
|
||||
* All event listeners (change + drag-drop) are bound once via _listenersAdded guard.
|
||||
*/
|
||||
export class EcrymeConfrontDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
||||
|
||||
#dragDrop
|
||||
_listenersAdded = false
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, options = {}) {
|
||||
super(options)
|
||||
this.actor = actor
|
||||
this.rollData = rollData
|
||||
this.buttonDisabled = true
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "ecryme-confrontation-dialog"],
|
||||
position: { width: 640 },
|
||||
window: { title: "ECRY.ui.confront" },
|
||||
dragDrop: [{ dragSelector: ".confront-dice-container", dropSelector: null }],
|
||||
actions: {
|
||||
launchConfront: EcrymeConfrontDialog.#onLaunchConfront,
|
||||
cancel: EcrymeConfrontDialog.#onCancel,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
content: { template: "systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
|
||||
let options = foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-ecryme ecryme-confrontation-dialog"],
|
||||
dragDrop: [{ dragSelector: ".confront-dice-container", dropSelector: null }],
|
||||
width: 620, height: 'fit-content', 'z-index': 99999
|
||||
});
|
||||
|
||||
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs', rollData);
|
||||
return new EcrymeConfrontDialog(actor, rollData, html, options);
|
||||
return new EcrymeConfrontDialog(actor, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: game.i18n.localize("ECRY.ui.confront"),
|
||||
content: html,
|
||||
buttons: {
|
||||
launchConfront: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.launchconfront"),
|
||||
callback: () => { this.launchConfront().catch("Error when launching Confrontation") }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.cancel"),
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
async _prepareContext() {
|
||||
return {
|
||||
...this.rollData,
|
||||
config: game.system.ecryme.config,
|
||||
buttonDisabled: this.buttonDisabled,
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
|
||||
// Ensure button is disabled
|
||||
setTimeout(function () { $(".launchConfront").attr("disabled", true) }, 180)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async launchConfront() {
|
||||
let msg = await EcrymeUtility.createChatMessage(this.rollData.alias, "blindroll", {
|
||||
content: await renderTemplate(`systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs`, this.rollData)
|
||||
/** Bind drag-drop and form-change listeners once; re-bind DragDrop on each render. */
|
||||
_onRender(context, options) {
|
||||
// DragDrop must be re-bound each render because the DOM is replaced
|
||||
this.#dragDrop.forEach(d => d.bind(this.element))
|
||||
|
||||
// Form-change listener is bound once (event delegation survives DOM re-renders)
|
||||
if (!this._listenersAdded) {
|
||||
this._listenersAdded = true
|
||||
this.element.addEventListener('change', this.#onFormChange.bind(this))
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
#onFormChange(event) {
|
||||
const target = event.target
|
||||
switch (target.id) {
|
||||
case 'bonusMalusPerso':
|
||||
this.rollData.bonusMalusPerso = Number(target.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-specialization':
|
||||
this.rollData.selectedSpecs = Array.from(target.selectedOptions).map(o => o.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-trait-bonus':
|
||||
this.rollData.traitsBonusSelected = Array.from(target.selectedOptions).map(o => o.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-trait-malus':
|
||||
this.rollData.traitsMalusSelected = Array.from(target.selectedOptions).map(o => o.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-select-transcendence':
|
||||
this.rollData.skillTranscendence = Number(target.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-apply-transcendence':
|
||||
this.rollData.applyTranscendence = target.value
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'annency-bonus':
|
||||
this.rollData.annencyBonus = Number(target.value)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map(d => {
|
||||
d.permissions = {
|
||||
dragstart: () => true,
|
||||
drop: () => true,
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
EcrymeUtility.blindMessageToGM( { rollData: this.rollData, template: "systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs" })
|
||||
console.log("MSG", this.rollData)
|
||||
msg.setFlag("world", "ecryme-rolldata", this.rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async refreshDice() {
|
||||
this.rollData.filter = "execution"
|
||||
let content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData )
|
||||
content += await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData )
|
||||
$("#confront-execution").html(content)
|
||||
|
||||
this.rollData.filter = "preservation"
|
||||
content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData )
|
||||
content += await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData )
|
||||
$("#confront-preservation").html(content)
|
||||
|
||||
this.rollData.filter = "mainpool"
|
||||
content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData )
|
||||
$("#confront-dice-pool").html(content)
|
||||
content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData )
|
||||
$("#confront-bonus-pool").html(content)
|
||||
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async refreshDialog() {
|
||||
const content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs", this.rollData)
|
||||
this.data.content = content
|
||||
this.render(true)
|
||||
|
||||
let button = this.buttonDisabled
|
||||
setTimeout(function () { $(".launchConfront").attr("disabled", button) }, 180)
|
||||
}
|
||||
|
||||
/* ------------------ -------------------------- */
|
||||
_canDragStart(selector) {
|
||||
console.log("CAN DRAG START", selector, super._canDragStart(selector) )
|
||||
return true
|
||||
}
|
||||
_canDragDrop(selector) {
|
||||
console.log("CAN DRAG DROP", selector, super._canDragDrop(selector) )
|
||||
return true
|
||||
}
|
||||
|
||||
/* ------------------ -------------------------- */
|
||||
_onDragStart(event) {
|
||||
console.log("DRAGSTART::::", event)
|
||||
super._onDragStart(event)
|
||||
let dragType = $(event.srcElement).data("drag-type")
|
||||
let diceData = {}
|
||||
console.log("DRAGTYPE", dragType)
|
||||
if (dragType == "dice") {
|
||||
const target = event.target
|
||||
const dragType = target.dataset.dragType
|
||||
let diceData
|
||||
|
||||
if (dragType === "dice") {
|
||||
diceData = {
|
||||
dragType: "dice",
|
||||
diceIndex: $(event.srcElement).data("dice-idx"),
|
||||
diceValue: $(event.srcElement).data("dice-value"),
|
||||
dragType: "dice",
|
||||
diceIndex: target.dataset.diceIdx,
|
||||
diceValue: target.dataset.diceValue,
|
||||
}
|
||||
} else {
|
||||
diceData = {
|
||||
dragType: "bonus",
|
||||
bonusIndex: $(event.srcElement).data("bonus-idx"),
|
||||
bonusValue: 1
|
||||
dragType: "bonus",
|
||||
bonusIndex: target.dataset.bonusIdx,
|
||||
bonusValue: 1,
|
||||
}
|
||||
}
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(diceData));
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(diceData))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_onDragOver(event) {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_onDrop(event) {
|
||||
let dataJSON = event.dataTransfer.getData('text/plain')
|
||||
let data = JSON.parse(dataJSON)
|
||||
if ( data.dragType == "dice") {
|
||||
let idx = Number(data.diceIndex)
|
||||
console.log("DATA", data, event, event.srcElement.className)
|
||||
if (event.srcElement.className.includes("execution") &&
|
||||
this.rollData.availableDices.filter(d => d.location == "execution").length < 2) {
|
||||
let data
|
||||
try { data = JSON.parse(event.dataTransfer.getData("text/plain")) }
|
||||
catch (e) { return }
|
||||
|
||||
// Walk up the DOM to find a meaningful drop area
|
||||
const executionArea = event.target.closest('.confront-execution-area')
|
||||
const preservationArea = event.target.closest('.confront-preservation-area')
|
||||
const diceList = event.target.closest('.confrontation-dice-list')
|
||||
const bonusList = event.target.closest('.confrontation-bonus-list')
|
||||
|
||||
if (data.dragType === "dice") {
|
||||
const idx = Number(data.diceIndex)
|
||||
if (executionArea && this.rollData.availableDices.filter(d => d.location === "execution").length < 2) {
|
||||
this.rollData.availableDices[idx].location = "execution"
|
||||
}
|
||||
if (event.srcElement.className.includes("preservation") &&
|
||||
this.rollData.availableDices.filter(d => d.location == "preservation").length < 2) {
|
||||
} else if (preservationArea && this.rollData.availableDices.filter(d => d.location === "preservation").length < 2) {
|
||||
this.rollData.availableDices[idx].location = "preservation"
|
||||
}
|
||||
if (event.srcElement.className.includes("dice-list")) {
|
||||
} else if (diceList) {
|
||||
this.rollData.availableDices[idx].location = "mainpool"
|
||||
}
|
||||
|
||||
if (this.rollData.availableDices.filter(d => d.location == "execution").length == 2 && this.rollData.availableDices.filter(d => d.location == "preservation").length == 2) {
|
||||
this.buttonDisabled = false
|
||||
} else {
|
||||
this.buttonDisabled = true
|
||||
}
|
||||
} else {
|
||||
let idx = Number(data.bonusIndex)
|
||||
if (event.srcElement.className.includes("execution")) {
|
||||
this.rollData.confrontBonus[idx].location = "execution"
|
||||
}
|
||||
if (event.srcElement.className.includes("preservation")) {
|
||||
this.rollData.confrontBonus[idx].location = "preservation"
|
||||
}
|
||||
if (event.srcElement.className.includes("bonus-list")) {
|
||||
this.rollData.confrontBonus[idx].location = "mainpool"
|
||||
}
|
||||
const execCount = this.rollData.availableDices.filter(d => d.location === "execution").length
|
||||
const presCount = this.rollData.availableDices.filter(d => d.location === "preservation").length
|
||||
this.buttonDisabled = !(execCount === 2 && presCount === 2)
|
||||
|
||||
} else if (data.dragType === "bonus") {
|
||||
const idx = Number(data.bonusIndex)
|
||||
if (executionArea) this.rollData.confrontBonus[idx].location = "execution"
|
||||
else if (preservationArea) this.rollData.confrontBonus[idx].location = "preservation"
|
||||
else if (bonusList) this.rollData.confrontBonus[idx].location = "mainpool"
|
||||
}
|
||||
|
||||
// Manage total values
|
||||
this.computeTotals()
|
||||
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
/* -------------------------------------------- */
|
||||
processTranscendence() {
|
||||
// Apply Transcend if needed
|
||||
if (this.rollData.skillTranscendence > 0) {
|
||||
if (this.rollData.applyTranscendence == "execution") {
|
||||
this.rollData.executionTotal += Number(this.rollData.skillTranscendence)
|
||||
if (this.rollData.applyTranscendence === "execution") {
|
||||
this.rollData.executionTotal += Number(this.rollData.skillTranscendence)
|
||||
} else {
|
||||
this.rollData.preservationTotal += Number(this.rollData.skillTranscendence)
|
||||
}
|
||||
@@ -172,94 +195,78 @@ export class EcrymeConfrontDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
computeTotals() {
|
||||
let rollData = this.rollData
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
const rollData = this.rollData
|
||||
const actor = game.actors.get(rollData.actorId)
|
||||
|
||||
rollData.executionTotal = rollData.availableDices.filter(d => d.location == "execution").reduce((previous, current) => {
|
||||
return previous + current.result
|
||||
}, rollData.skill.value)
|
||||
rollData.executionTotal = rollData.confrontBonus.filter(d => d.location == "execution").reduce((previous, current) => {
|
||||
return previous + 1
|
||||
}, rollData.executionTotal)
|
||||
rollData.executionTotal = rollData.availableDices
|
||||
.filter(d => d.location === "execution")
|
||||
.reduce((acc, d) => acc + d.result, rollData.skill.value)
|
||||
rollData.executionTotal = rollData.confrontBonus
|
||||
.filter(d => d.location === "execution")
|
||||
.reduce((acc) => acc + 1, rollData.executionTotal)
|
||||
|
||||
rollData.preservationTotal = rollData.availableDices.filter(d => d.location == "preservation").reduce((previous, current) => {
|
||||
return previous + current.result
|
||||
}, rollData.skill.value)
|
||||
rollData.preservationTotal = rollData.confrontBonus.filter(d => d.location == "preservation").reduce((previous, current) => {
|
||||
return previous + 1
|
||||
}, rollData.preservationTotal)
|
||||
rollData.preservationTotal = rollData.availableDices
|
||||
.filter(d => d.location === "preservation")
|
||||
.reduce((acc, d) => acc + d.result, rollData.skill.value)
|
||||
rollData.preservationTotal = rollData.confrontBonus
|
||||
.filter(d => d.location === "preservation")
|
||||
.reduce((acc) => acc + 1, rollData.preservationTotal)
|
||||
|
||||
this.processTranscendence()
|
||||
|
||||
if (rollData.selectedSpecs && rollData.selectedSpecs.length > 0) {
|
||||
rollData.spec = foundry.utils.duplicate(actor.getSpecialization(rollData.selectedSpecs[0]))
|
||||
// Specialization
|
||||
if (rollData.selectedSpecs?.length > 0) {
|
||||
rollData.spec = foundry.utils.duplicate(actor.getSpecialization(rollData.selectedSpecs[0]))
|
||||
rollData.specApplied = true
|
||||
rollData.executionTotal += 2
|
||||
rollData.executionTotal += 2
|
||||
rollData.preservationTotal += 2
|
||||
}
|
||||
if ( rollData.specApplied && rollData.selectedSpecs.length == 0) {
|
||||
rollData.spec = undefined
|
||||
if (rollData.specApplied && rollData.selectedSpecs?.length === 0) {
|
||||
rollData.spec = undefined
|
||||
rollData.specApplied = false
|
||||
}
|
||||
|
||||
// Traits bonus/malus
|
||||
rollData.bonusMalusTraits = 0
|
||||
for (let t of rollData.traitsBonus) {
|
||||
t.activated = false
|
||||
for (const t of rollData.traitsBonus) t.activated = false
|
||||
for (const t of rollData.traitsMalus) t.activated = false
|
||||
|
||||
for (const id of (rollData.traitsBonusSelected ?? [])) {
|
||||
const trait = rollData.traitsBonus.find(t => t._id === id)
|
||||
if (trait) { trait.activated = true; rollData.bonusMalusTraits += Number(trait.system.level) }
|
||||
}
|
||||
for (let t of rollData.traitsMalus) {
|
||||
t.activated = false
|
||||
}
|
||||
if (rollData.traitsBonusSelected && rollData.traitsBonusSelected.length > 0) {
|
||||
for (let id of rollData.traitsBonusSelected) {
|
||||
let trait = rollData.traitsBonus.find(t => t._id == id)
|
||||
trait.activated = true
|
||||
rollData.bonusMalusTraits += Number(trait.system.level)
|
||||
}
|
||||
}
|
||||
if (rollData.traitsMalusSelected && rollData.traitsMalusSelected.length > 0) {
|
||||
for (let id of rollData.traitsMalusSelected) {
|
||||
let trait = rollData.traitsMalus.find(t => t._id == id)
|
||||
trait.activated = true
|
||||
rollData.bonusMalusTraits -= Number(trait.system.level)
|
||||
}
|
||||
for (const id of (rollData.traitsMalusSelected ?? [])) {
|
||||
const trait = rollData.traitsMalus.find(t => t._id === id)
|
||||
if (trait) { trait.activated = true; rollData.bonusMalusTraits -= Number(trait.system.level) }
|
||||
}
|
||||
|
||||
rollData.executionTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso)
|
||||
rollData.executionTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso)
|
||||
rollData.preservationTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso)
|
||||
|
||||
this.refreshDialog()
|
||||
this.render()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
async launchConfront() {
|
||||
const msg = await EcrymeUtility.createChatMessage(this.rollData.alias, "blindroll", {
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs`, this.rollData
|
||||
),
|
||||
})
|
||||
EcrymeUtility.blindMessageToGM({
|
||||
rollData: this.rollData,
|
||||
template: "systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs",
|
||||
})
|
||||
msg.setFlag("world", "ecryme-rolldata", this.rollData)
|
||||
}
|
||||
|
||||
html.find('#bonusMalusPerso').change((event) => {
|
||||
this.rollData.bonusMalusPerso = event.currentTarget.value
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-specialization').change((event) => {
|
||||
this.rollData.selectedSpecs = $('#roll-specialization').val()
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-trait-bonus').change((event) => {
|
||||
this.rollData.traitsBonusSelected = $('#roll-trait-bonus').val()
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-trait-malus').change((event) => {
|
||||
this.rollData.traitsMalusSelected = $('#roll-trait-malus').val()
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-select-transcendence').change((event) => {
|
||||
this.rollData.skillTranscendence = Number($('#roll-select-transcendence').val())
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-apply-transcendence').change((event) => {
|
||||
this.rollData.applyTranscendence = $('#roll-apply-transcendence').val()
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#annency-bonus').change((event) => {
|
||||
this.rollData.annencyBonus = Number(event.currentTarget.value)
|
||||
})
|
||||
/* -------------------------------------------- */
|
||||
static async #onLaunchConfront(event, target) {
|
||||
await this.launchConfront()
|
||||
this.close()
|
||||
}
|
||||
|
||||
static #onCancel(event, target) {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
@@ -1,77 +1,80 @@
|
||||
import { EcrymeUtility } from "../common/ecryme-utility.js";
|
||||
import { EcrymeConfrontDialog } from "./ecryme-confront-dialog.js";
|
||||
|
||||
export class EcrymeConfrontStartDialog extends Dialog {
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Confrontation start dialog — Application V2 version.
|
||||
* Player picks which dice formula to roll (normal / spleen / ideal),
|
||||
* the dice are rolled and the main EcrymeConfrontDialog is opened.
|
||||
*/
|
||||
export class EcrymeConfrontStartDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "ecryme-confront-start-dialog"],
|
||||
position: { width: 540 },
|
||||
window: { title: "ECRY.ui.confront" },
|
||||
actions: {
|
||||
rollNormal: EcrymeConfrontStartDialog.#onRollNormal,
|
||||
rollSpleen: EcrymeConfrontStartDialog.#onRollSpleen,
|
||||
rollIdeal: EcrymeConfrontStartDialog.#onRollIdeal,
|
||||
cancel: EcrymeConfrontStartDialog.#onCancel,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
content: { template: "systems/fvtt-ecryme/templates/dialogs/confront-start-dialog.hbs" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, options = {}) {
|
||||
super(options)
|
||||
this.actor = actor?.token?.actor ?? actor
|
||||
this.rollData = rollData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
if (!actor) throw new Error("Ecryme | No actor provided for confront dialog");
|
||||
if (!rollData) throw new Error("Ecryme | No roll data provided for confront dialog");
|
||||
|
||||
if (actor?.token) rollData.tokenId = actor.token.id;
|
||||
let options = { classes: ["fvtt-ecryme ecryme-confront-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 }
|
||||
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/confront-start-dialog.hbs', rollData);
|
||||
return new EcrymeConfrontStartDialog(actor, rollData, html, options);
|
||||
if (!actor) throw new Error("Ecryme | No actor provided for confront dialog")
|
||||
if (!rollData) throw new Error("Ecryme | No roll data provided for confront dialog")
|
||||
if (actor?.token) rollData.tokenId = actor.token.id
|
||||
return new EcrymeConfrontStartDialog(actor, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: game.i18n.localize("ECRY.ui.confront"),
|
||||
content: html,
|
||||
buttons: {
|
||||
rollNormal: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.rollnormal"),
|
||||
callback: () => { this.rollConfront("4d6") }
|
||||
},
|
||||
rollSpleen: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.rollspleen"),
|
||||
callback: () => { this.rollConfront("5d6kl4") }
|
||||
},
|
||||
rollIdeal: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.rollideal"),
|
||||
callback: () => { this.rollConfront("5d6kh4") }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.cancel"),
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
async _prepareContext() {
|
||||
return {
|
||||
...this.rollData,
|
||||
config: game.system.ecryme.config,
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor?.token?.actor || actor;
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollConfront(diceFormula) {
|
||||
// Do the initial roll
|
||||
let myRoll = await new Roll(diceFormula).roll()
|
||||
async #rollConfront(diceFormula) {
|
||||
const myRoll = await new Roll(diceFormula).roll()
|
||||
await EcrymeUtility.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
|
||||
// Fill the available dice table
|
||||
let rollData = this.rollData
|
||||
|
||||
const rollData = this.rollData
|
||||
rollData.roll = foundry.utils.duplicate(myRoll)
|
||||
rollData.availableDices = []
|
||||
for (let result of myRoll.terms[0].results) {
|
||||
for (const result of myRoll.terms[0].results) {
|
||||
if (!result.discarded) {
|
||||
let resultDup = foundry.utils.duplicate(result)
|
||||
resultDup.location = "mainpool"
|
||||
rollData.availableDices.push(resultDup)
|
||||
const dup = foundry.utils.duplicate(result)
|
||||
dup.location = "mainpool"
|
||||
rollData.availableDices.push(dup)
|
||||
}
|
||||
}
|
||||
let confrontDialog = await EcrymeConfrontDialog.create(this.actor, rollData)
|
||||
|
||||
const confrontDialog = await EcrymeConfrontDialog.create(this.actor, rollData)
|
||||
confrontDialog.render(true)
|
||||
this.close()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
}
|
||||
static async #onRollNormal(event, target) { await this.#rollConfront("4d6") }
|
||||
static async #onRollSpleen(event, target) { await this.#rollConfront("5d6kl4") }
|
||||
static async #onRollIdeal(event, target) { await this.#rollConfront("5d6kh4") }
|
||||
static #onCancel(event, target) { this.close() }
|
||||
}
|
||||
@@ -1,86 +1,78 @@
|
||||
import { EcrymeUtility } from "../common/ecryme-utility.js";
|
||||
|
||||
export class EcrymeRollDialog extends Dialog {
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Roll dialog — Application V2 version.
|
||||
* Reads all form values at roll time (no live tracking needed).
|
||||
*/
|
||||
export class EcrymeRollDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "ecryme-roll-dialog"],
|
||||
position: { width: 540 },
|
||||
window: { title: "ECRY.ui.rolltitle" },
|
||||
actions: {
|
||||
roll: EcrymeRollDialog.#onRoll,
|
||||
cancel: EcrymeRollDialog.#onCancel,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
content: { template: "systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, options = {}) {
|
||||
super(options)
|
||||
this.actor = actor
|
||||
this.rollData = rollData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
|
||||
let options = { classes: ["ecryme-roll-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 }
|
||||
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs', rollData);
|
||||
return new EcrymeRollDialog(actor, rollData, html, options);
|
||||
return new EcrymeRollDialog(actor, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: game.i18n.localize("ECRY.ui.rolltitle"),
|
||||
content: html,
|
||||
buttons: {
|
||||
roll: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.roll"),
|
||||
callback: () => { this.roll() }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.cancel"),
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
async _prepareContext() {
|
||||
return {
|
||||
...this.rollData,
|
||||
config: game.system.ecryme.config,
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
roll() {
|
||||
/** Read all form values at roll time, then execute. */
|
||||
static #onRoll(event, target) {
|
||||
const el = this.element
|
||||
|
||||
const bonusEl = el.querySelector('#bonusMalusPerso')
|
||||
const diffEl = el.querySelector('#roll-difficulty')
|
||||
const specEl = el.querySelector('#roll-specialization')
|
||||
const traitBonusEl = el.querySelector('#roll-trait-bonus')
|
||||
const traitMalusEl = el.querySelector('#roll-trait-malus')
|
||||
const transcEl = el.querySelector('#roll-select-transcendence')
|
||||
const spleenEl = el.querySelector('#roll-use-spleen')
|
||||
const idealEl = el.querySelector('#roll-use-ideal')
|
||||
|
||||
if (bonusEl) this.rollData.bonusMalusPerso = Number(bonusEl.value)
|
||||
if (diffEl) this.rollData.difficulty = Number(diffEl.value) || 0
|
||||
if (specEl) this.rollData.selectedSpecs = Array.from(specEl.selectedOptions).map(o => o.value)
|
||||
if (traitBonusEl) this.rollData.traitsBonus = Array.from(traitBonusEl.selectedOptions).map(o => o.value)
|
||||
if (traitMalusEl) this.rollData.traitsMalus = Array.from(traitMalusEl.selectedOptions).map(o => o.value)
|
||||
if (transcEl) this.rollData.skillTranscendence = Number(transcEl.value)
|
||||
if (spleenEl) this.rollData.useSpleen = spleenEl.checked
|
||||
if (idealEl) this.rollData.useIdeal = idealEl.checked
|
||||
|
||||
EcrymeUtility.rollEcryme(this.rollData)
|
||||
this.close()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async refreshDialog() {
|
||||
const content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs", this.rollData)
|
||||
this.data.content = content
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
function onLoad() {
|
||||
}
|
||||
$(function () { onLoad(); });
|
||||
|
||||
html.find('#bonusMalusPerso').change((event) => {
|
||||
console.log("DIFF", event.currentTarget.value)
|
||||
this.rollData.bonusMalusPerso = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#roll-difficulty').change((event) => {
|
||||
this.rollData.difficulty = Number(event.currentTarget.value) || 0
|
||||
})
|
||||
html.find('#roll-specialization').change((event) => {
|
||||
this.rollData.selectedSpecs = $('#roll-specialization').val()
|
||||
})
|
||||
html.find('#roll-trait-bonus').change((event) => {
|
||||
this.rollData.traitsBonus = $('#roll-trait-bonus').val()
|
||||
})
|
||||
html.find('#roll-trait-malus').change((event) => {
|
||||
this.rollData.traitsMalus = $('#roll-trait-malus').val()
|
||||
})
|
||||
html.find('#roll-select-transcendence').change((event) => {
|
||||
this.rollData.skillTranscendence = Number($('#roll-select-transcendence').val())
|
||||
})
|
||||
html.find('#roll-use-spleen').change((event) => {
|
||||
this.rollData.useSpleen = event.currentTarget.checked
|
||||
})
|
||||
html.find('#roll-use-ideal').change((event) => {
|
||||
this.rollData.useIdeal = event.currentTarget.checked
|
||||
})
|
||||
|
||||
static #onCancel(event, target) {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,17 @@ const ECRYME_WELCOME_MESSAGE_URL = "https://www.uberwald.me/gitea/public/fvtt-ec
|
||||
// Import Modules
|
||||
import { EcrymeActor } from "./actors/ecryme-actor.js";
|
||||
import { EcrymeItemSheet } from "./items/ecryme-item-sheet.js";
|
||||
import { EcrymeActorSheet } from "./actors/ecryme-actor-sheet.js";
|
||||
import { EcrymeAnnencySheet } from "./actors/ecryme-annency-sheet.js";
|
||||
import {
|
||||
EcrymeEquipmentSheet,
|
||||
EcrymeWeaponSheet,
|
||||
EcrymeTraitSheet,
|
||||
EcrymeSpecializationSheet,
|
||||
EcrymeManeuverSheet
|
||||
} from "./items/sheets/_module.js";
|
||||
import {
|
||||
EcrymeActorSheet,
|
||||
EcrymeAnnencySheet
|
||||
} from "./actors/sheets/_module.js";
|
||||
import { EcrymeUtility } from "./common/ecryme-utility.js";
|
||||
import { EcrymeCombat } from "./app/ecryme-combat.js";
|
||||
import { EcrymeItem } from "./items/ecryme-item.js";
|
||||
@@ -76,12 +85,16 @@ Hooks.once("init", async function () {
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["pc"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["pc"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["npc"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeAnnencySheet, { types: ["annency"], makeDefault: false });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeAnnencySheet, { types: ["annency"], makeDefault: true });
|
||||
|
||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeItemSheet, { makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeEquipmentSheet, { types: ["equipment"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeWeaponSheet, { types: ["weapon"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeTraitSheet, { types: ["trait"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeSpecializationSheet, { types: ["specialization"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeManeuverSheet, { types: ["maneuver"], makeDefault: true });
|
||||
|
||||
EcrymeUtility.init()
|
||||
|
||||
|
||||
6
modules/items/sheets/_module.js
Normal file
6
modules/items/sheets/_module.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export { default as EcrymeBaseItemSheet } from "./base-item-sheet.js"
|
||||
export { default as EcrymeEquipmentSheet } from "./equipment-sheet.js"
|
||||
export { default as EcrymeWeaponSheet } from "./weapon-sheet.js"
|
||||
export { default as EcrymeTraitSheet } from "./trait-sheet.js"
|
||||
export { default as EcrymeSpecializationSheet } from "./specialization-sheet.js"
|
||||
export { default as EcrymeManeuverSheet } from "./maneuver-sheet.js"
|
||||
131
modules/items/sheets/base-item-sheet.js
Normal file
131
modules/items/sheets/base-item-sheet.js
Normal file
@@ -0,0 +1,131 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Base item sheet for Ecryme using Application V2.
|
||||
* Subclasses must define static PARTS including header, tabs, description, and optionally details.
|
||||
*/
|
||||
export default class EcrymeBaseItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "item"],
|
||||
position: {
|
||||
width: 520,
|
||||
height: "auto",
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: EcrymeBaseItemSheet.#onEditImage,
|
||||
},
|
||||
}
|
||||
|
||||
/** Active tab group tracking */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the tabs definition, adding a "details" tab only if the subclass has a "details" PART.
|
||||
* @returns {Record<string, object>}
|
||||
*/
|
||||
_getTabs() {
|
||||
const tabs = {
|
||||
description: { id: "description", group: "primary", label: "ECRY.ui.description" },
|
||||
}
|
||||
if (this.constructor.PARTS?.details) {
|
||||
tabs.details = { id: "details", group: "primary", label: "ECRY.ui.details" }
|
||||
}
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
item: this.document,
|
||||
system: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
config: game.system.ecryme.config,
|
||||
isEditable: this.isEditable,
|
||||
tabs: this._getTabs(),
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "description") {
|
||||
context.tab = context.tabs.description
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.description, { async: true }
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map((d) => {
|
||||
d.permissions = {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
}
|
||||
|
||||
_canDragStart(selector) { return this.isEditable }
|
||||
_canDragDrop(selector) { return this.isEditable && this.document.isOwner }
|
||||
_onDragStart(event) {}
|
||||
_onDragOver(event) {}
|
||||
async _onDrop(event) {}
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
static async #onEditImage(event, target) {
|
||||
const attr = target.dataset.edit
|
||||
const current = foundry.utils.getProperty(this.document, attr)
|
||||
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||
const fp = new FilePicker({
|
||||
current,
|
||||
type: "image",
|
||||
redirectToRoot: img ? [img] : [],
|
||||
callback: (path) => {
|
||||
this.document.update({ [attr]: path })
|
||||
},
|
||||
top: this.position.top + 40,
|
||||
left: this.position.left + 10,
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
24
modules/items/sheets/equipment-sheet.js
Normal file
24
modules/items/sheets/equipment-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeEquipmentSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["equipment"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-equipment-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/maneuver-sheet.js
Normal file
24
modules/items/sheets/maneuver-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeManeuverSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["maneuver"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-maneuver-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/specialization-sheet.js
Normal file
24
modules/items/sheets/specialization-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeSpecializationSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["specialization"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-specialization-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/trait-sheet.js
Normal file
24
modules/items/sheets/trait-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeTraitSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["trait"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-trait-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/weapon-sheet.js
Normal file
24
modules/items/sheets/weapon-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeWeaponSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["weapon"],
|
||||
position: { width: 540 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-weapon-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
2167
package-lock.json
generated
Normal file
2167
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
package.json
Normal file
22
package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "fvtt-ecryme",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "Ecryme RPG system for Foundry Virtual TableTop",
|
||||
"author": "LeRatierBretonnien",
|
||||
"license": "UNLICENSED",
|
||||
"main": "gulpfile.js",
|
||||
"devDependencies": {
|
||||
"gulp": "^5.0.0",
|
||||
"gulp-less": "^5.0.0",
|
||||
"less": "^4.1.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp css",
|
||||
"watch": "gulp"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://www.uberwald.me/gitea/uberwald/fvtt-ecryme.git"
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000275
|
||||
MANIFEST-000279
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/02/24-18:28:52.374972 7f821e7fc6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.385656 7f821e7fc6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.385721 7f821e7fc6c0 Delete type=3 #273
|
||||
2026/02/25-11:33:37.234178 7f821ffff6c0 Recovering log #277
|
||||
2026/02/25-11:33:37.244778 7f821ffff6c0 Delete type=3 #275
|
||||
2026/02/25-11:33:37.244834 7f821ffff6c0 Delete type=0 #277
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
2026/02/18-11:45:24.449013 7f1e213fc6c0 Recovering log #271
|
||||
2026/02/18-11:45:24.459087 7f1e213fc6c0 Delete type=3 #269
|
||||
2026/02/18-11:45:24.459153 7f1e213fc6c0 Delete type=0 #271
|
||||
2026/02/24-18:28:52.374972 7f821e7fc6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.385656 7f821e7fc6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.385721 7f821e7fc6c0 Delete type=3 #273
|
||||
2026/02/25-09:35:17.826867 7f821d8d46c0 Level-0 table #278: started
|
||||
2026/02/25-09:35:17.826905 7f821d8d46c0 Level-0 table #278: 0 bytes OK
|
||||
2026/02/25-09:35:17.833281 7f821d8d46c0 Delete type=0 #276
|
||||
2026/02/25-09:35:17.840522 7f821d8d46c0 Manual compaction at level-0 from '!folders!1GrTlI1xWvaxdKRI' @ 72057594037927935 : 1 .. '!items!zs7krgXhDRndtqbl' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000212
|
||||
MANIFEST-000216
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/02/24-18:28:52.429828 7f821ffff6c0 Recovering log #211
|
||||
2026/02/24-18:28:52.439806 7f821ffff6c0 Delete type=0 #211
|
||||
2026/02/24-18:28:52.439868 7f821ffff6c0 Delete type=3 #210
|
||||
2026/02/25-11:33:37.286335 7f821effd6c0 Recovering log #214
|
||||
2026/02/25-11:33:37.295774 7f821effd6c0 Delete type=3 #212
|
||||
2026/02/25-11:33:37.295826 7f821effd6c0 Delete type=0 #214
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
2026/02/18-11:45:24.501020 7f1e22bff6c0 Recovering log #208
|
||||
2026/02/18-11:45:24.512291 7f1e22bff6c0 Delete type=3 #206
|
||||
2026/02/18-11:45:24.512365 7f1e22bff6c0 Delete type=0 #208
|
||||
2026/02/24-18:28:52.429828 7f821ffff6c0 Recovering log #211
|
||||
2026/02/24-18:28:52.439806 7f821ffff6c0 Delete type=0 #211
|
||||
2026/02/24-18:28:52.439868 7f821ffff6c0 Delete type=3 #210
|
||||
2026/02/25-09:35:17.846770 7f821d8d46c0 Level-0 table #215: started
|
||||
2026/02/25-09:35:17.846804 7f821d8d46c0 Level-0 table #215: 0 bytes OK
|
||||
2026/02/25-09:35:17.852623 7f821d8d46c0 Delete type=0 #213
|
||||
2026/02/25-09:35:17.869656 7f821d8d46c0 Manual compaction at level-0 from '!journal!wooTFYjEwh83FwgT' @ 72057594037927935 : 1 .. '!journal.pages!wooTFYjEwh83FwgT.xhc7hqoL8kdW6lrD' @ 0 : 0; will stop at (end)
|
||||
2026/02/25-09:35:17.869687 7f821d8d46c0 Manual compaction at level-1 from '!journal!wooTFYjEwh83FwgT' @ 72057594037927935 : 1 .. '!journal.pages!wooTFYjEwh83FwgT.xhc7hqoL8kdW6lrD' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000275
|
||||
MANIFEST-000279
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/02/24-18:28:52.415329 7f821effd6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.426422 7f821effd6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.426510 7f821effd6c0 Delete type=3 #273
|
||||
2026/02/25-11:33:37.273602 7f821f7fe6c0 Recovering log #277
|
||||
2026/02/25-11:33:37.284454 7f821f7fe6c0 Delete type=3 #275
|
||||
2026/02/25-11:33:37.284519 7f821f7fe6c0 Delete type=0 #277
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
2026/02/18-11:45:24.488266 7f1e213fc6c0 Recovering log #271
|
||||
2026/02/18-11:45:24.498651 7f1e213fc6c0 Delete type=3 #269
|
||||
2026/02/18-11:45:24.498723 7f1e213fc6c0 Delete type=0 #271
|
||||
2026/02/24-18:28:52.415329 7f821effd6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.426422 7f821effd6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.426510 7f821effd6c0 Delete type=3 #273
|
||||
2026/02/25-09:35:17.840651 7f821d8d46c0 Level-0 table #278: started
|
||||
2026/02/25-09:35:17.840692 7f821d8d46c0 Level-0 table #278: 0 bytes OK
|
||||
2026/02/25-09:35:17.846652 7f821d8d46c0 Delete type=0 #276
|
||||
2026/02/25-09:35:17.869637 7f821d8d46c0 Manual compaction at level-0 from '!items!13IYF6BPUTivFZzB' @ 72057594037927935 : 1 .. '!items!oSutlbe9wyBZccmf' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000161
|
||||
MANIFEST-000165
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/02/24-18:28:52.402010 7f821ffff6c0 Recovering log #160
|
||||
2026/02/24-18:28:52.411649 7f821ffff6c0 Delete type=0 #160
|
||||
2026/02/24-18:28:52.411699 7f821ffff6c0 Delete type=3 #159
|
||||
2026/02/25-11:33:37.259598 7f821effd6c0 Recovering log #163
|
||||
2026/02/25-11:33:37.270700 7f821effd6c0 Delete type=3 #161
|
||||
2026/02/25-11:33:37.270746 7f821effd6c0 Delete type=0 #163
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
2026/02/18-11:45:24.475762 7f1e22bff6c0 Recovering log #157
|
||||
2026/02/18-11:45:24.485161 7f1e22bff6c0 Delete type=3 #155
|
||||
2026/02/18-11:45:24.485216 7f1e22bff6c0 Delete type=0 #157
|
||||
2026/02/24-18:28:52.402010 7f821ffff6c0 Recovering log #160
|
||||
2026/02/24-18:28:52.411649 7f821ffff6c0 Delete type=0 #160
|
||||
2026/02/24-18:28:52.411699 7f821ffff6c0 Delete type=3 #159
|
||||
2026/02/25-09:35:17.833446 7f821d8d46c0 Level-0 table #164: started
|
||||
2026/02/25-09:35:17.833494 7f821d8d46c0 Level-0 table #164: 0 bytes OK
|
||||
2026/02/25-09:35:17.840352 7f821d8d46c0 Delete type=0 #162
|
||||
2026/02/25-09:35:17.840534 7f821d8d46c0 Manual compaction at level-0 from '!scenes!DDibQQLAvyIq9y09' @ 72057594037927935 : 1 .. '!scenes!zvY1RwBhTfwdZIBa' @ 0 : 0; will stop at (end)
|
||||
2026/02/25-09:35:17.840570 7f821d8d46c0 Manual compaction at level-1 from '!scenes!DDibQQLAvyIq9y09' @ 72057594037927935 : 1 .. '!scenes!zvY1RwBhTfwdZIBa' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000275
|
||||
MANIFEST-000279
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/02/24-18:28:52.362517 7f821ffff6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.372026 7f821ffff6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.372073 7f821ffff6c0 Delete type=3 #273
|
||||
2026/02/25-11:33:37.221392 7f821e7fc6c0 Recovering log #277
|
||||
2026/02/25-11:33:37.232248 7f821e7fc6c0 Delete type=3 #275
|
||||
2026/02/25-11:33:37.232321 7f821e7fc6c0 Delete type=0 #277
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
2026/02/18-11:45:24.436705 7f1e22bff6c0 Recovering log #271
|
||||
2026/02/18-11:45:24.446559 7f1e22bff6c0 Delete type=3 #269
|
||||
2026/02/18-11:45:24.446634 7f1e22bff6c0 Delete type=0 #271
|
||||
2026/02/24-18:28:52.362517 7f821ffff6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.372026 7f821ffff6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.372073 7f821ffff6c0 Delete type=3 #273
|
||||
2026/02/25-09:35:17.814535 7f821d8d46c0 Level-0 table #278: started
|
||||
2026/02/25-09:35:17.814622 7f821d8d46c0 Level-0 table #278: 0 bytes OK
|
||||
2026/02/25-09:35:17.820646 7f821d8d46c0 Delete type=0 #276
|
||||
2026/02/25-09:35:17.840492 7f821d8d46c0 Manual compaction at level-0 from '!folders!00Hn2nNarlL7b0DR' @ 72057594037927935 : 1 .. '!items!yozTUjNuc2rEGjFK' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000275
|
||||
MANIFEST-000279
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/02/24-18:28:52.388644 7f821effd6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.398773 7f821effd6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.398821 7f821effd6c0 Delete type=3 #273
|
||||
2026/02/25-11:33:37.247436 7f821f7fe6c0 Recovering log #277
|
||||
2026/02/25-11:33:37.257397 7f821f7fe6c0 Delete type=3 #275
|
||||
2026/02/25-11:33:37.257468 7f821f7fe6c0 Delete type=0 #277
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
2026/02/18-11:45:24.461683 7f1e223fe6c0 Recovering log #271
|
||||
2026/02/18-11:45:24.472892 7f1e223fe6c0 Delete type=3 #269
|
||||
2026/02/18-11:45:24.472965 7f1e223fe6c0 Delete type=0 #271
|
||||
2026/02/24-18:28:52.388644 7f821effd6c0 Recovering log #274
|
||||
2026/02/24-18:28:52.398773 7f821effd6c0 Delete type=0 #274
|
||||
2026/02/24-18:28:52.398821 7f821effd6c0 Delete type=3 #273
|
||||
2026/02/25-09:35:17.820786 7f821d8d46c0 Level-0 table #278: started
|
||||
2026/02/25-09:35:17.820832 7f821d8d46c0 Level-0 table #278: 0 bytes OK
|
||||
2026/02/25-09:35:17.826739 7f821d8d46c0 Delete type=0 #276
|
||||
2026/02/25-09:35:17.840510 7f821d8d46c0 Manual compaction at level-0 from '!folders!DiwHbtGAkTYxtshX' @ 72057594037927935 : 1 .. '!items!zgNI2haxhBxBDBdl' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
51
styles/_variables.less
Normal file
51
styles/_variables.less
Normal file
@@ -0,0 +1,51 @@
|
||||
// ============================================================
|
||||
// Ecryme LESS Variables
|
||||
// ============================================================
|
||||
|
||||
// Background & images
|
||||
@background-image: url("../images/ui/fond_carnet_01.webp");
|
||||
@logo-image: url("../images/ui/ecryme_logo_small_01.webp");
|
||||
|
||||
// Text colors
|
||||
@color-text-dark: rgba(19, 18, 18, 0.95);
|
||||
@color-text-disabled: #1c2058;
|
||||
|
||||
// Input / select
|
||||
@color-input-bg: white;
|
||||
@color-input-text: #494e6b;
|
||||
|
||||
// Navigation
|
||||
@color-nav-bg: #252525;
|
||||
@color-nav-text: beige;
|
||||
|
||||
// Accent & interaction
|
||||
@color-accent: #ff6600;
|
||||
|
||||
// Dark UI controls
|
||||
@color-control-dark: rgba(30, 25, 20, 1);
|
||||
@color-control-warm: rgba(72, 46, 28, 1);
|
||||
|
||||
// Typography
|
||||
@font-primary: "MailartRubberstamp";
|
||||
|
||||
// ============================================================
|
||||
// Steampunk palette — Ecryme (industrial acid world)
|
||||
// ============================================================
|
||||
@steam-dark: #1A1510; // charbon / fer sombre
|
||||
@steam-metal: #252018; // métal industriel
|
||||
@steam-metal-mid: #352E22; // métal moyen
|
||||
@steam-brass: #B87333; // laiton
|
||||
@steam-brass-light: #D4963A; // laiton clair / reflet
|
||||
@steam-brass-dark: #7A4E1E; // laiton sombre
|
||||
@steam-copper: #C07038; // cuivre
|
||||
@steam-gold: #D4AF37; // or vieilli
|
||||
@steam-rust: #5C2A0A; // rouille
|
||||
@steam-parchment: #EAD9A8; // parchemin / papier vieilli
|
||||
@steam-parchment-dk:#D4BF84; // parchemin sombre
|
||||
@steam-cream: #F2EAD0; // crème
|
||||
@steam-acid: #6B9420; // vert acide industriel (muted)
|
||||
@steam-acid-bright: #9ACD32; // vert acide vif
|
||||
@steam-acid-dark: #3B5412; // vert acide profond
|
||||
@steam-success: #4A7A18; // vert succès
|
||||
@steam-failure: #7B1E1E; // rouge rouille échec
|
||||
@steam-rivet: #8A7055; // couleur rivet
|
||||
430
styles/actor-sheet-steampunk.less
Normal file
430
styles/actor-sheet-steampunk.less
Normal file
@@ -0,0 +1,430 @@
|
||||
// ============================================================
|
||||
// Actor sheets — Steampunk theme
|
||||
// Scoped to .fvtt-ecryme.sheet.actor and .fvtt-ecryme.sheet.annency
|
||||
// Applies visual theming without touching layout or tab structure.
|
||||
// ============================================================
|
||||
|
||||
.fvtt-ecryme.sheet.actor,
|
||||
.fvtt-ecryme.sheet.annency {
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// AppV2 window title bar — brass plate
|
||||
// ----------------------------------------------------------
|
||||
.window-header {
|
||||
.brass-gradient();
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
color: @steam-dark;
|
||||
|
||||
.window-title {
|
||||
font-family: @font-primary;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.header-button,
|
||||
button[data-action="close"] {
|
||||
color: @steam-dark;
|
||||
opacity: 0.75;
|
||||
&:hover { opacity: 1; color: @steam-rust; }
|
||||
}
|
||||
}
|
||||
|
||||
// Window outer frame — rivets
|
||||
border: 2px solid @steam-brass-dark;
|
||||
box-shadow:
|
||||
inset 4px 4px 0 1px @steam-rivet,
|
||||
inset -4px 4px 0 1px @steam-rivet,
|
||||
inset 4px -4px 0 1px @steam-rivet,
|
||||
inset -4px -4px 0 1px @steam-rivet,
|
||||
0 4px 16px rgba(0, 0, 0, 0.55);
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Sheet header — profile image + name area
|
||||
// ----------------------------------------------------------
|
||||
.sheet-header {
|
||||
background: linear-gradient(180deg, @steam-parchment-dk 0%, @steam-parchment 100%);
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
padding: 8px 10px;
|
||||
align-items: stretch;
|
||||
|
||||
// Profile image — fills full header height, square ratio
|
||||
.profile-img {
|
||||
flex: 0 0 auto;
|
||||
align-self: stretch;
|
||||
width: auto;
|
||||
height: auto;
|
||||
aspect-ratio: 1 / 1;
|
||||
border: 3px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.45);
|
||||
background: @steam-parchment-dk;
|
||||
object-fit: cover;
|
||||
object-position: center top;
|
||||
}
|
||||
|
||||
// Character name — large, dark ink
|
||||
h1.charname input {
|
||||
font-family: @font-primary;
|
||||
color: @steam-dark;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid rgba(@steam-brass-dark, 0.4);
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
|
||||
padding-bottom: 2px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-bottom-color: @steam-brass;
|
||||
background: rgba(@steam-cream, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
// Header traits area (spleen/ideal/traits)
|
||||
.actor-header-traits {
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 0.82rem;
|
||||
color: @steam-rust;
|
||||
padding: 1px 0;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.15);
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
|
||||
label { color: @steam-rust; }
|
||||
|
||||
// Trait name as link
|
||||
a[data-action="itemEdit"] {
|
||||
color: @steam-brass-dark;
|
||||
font-weight: bold;
|
||||
&:hover { color: @steam-brass; text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
|
||||
// Annency description textarea
|
||||
textarea {
|
||||
background: @steam-cream;
|
||||
color: @steam-dark;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
font-size: 0.85rem;
|
||||
padding: 3px 5px;
|
||||
resize: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Tab navigation — industrial metal bar
|
||||
// ----------------------------------------------------------
|
||||
nav.sheet-tabs {
|
||||
background: linear-gradient(180deg, @steam-metal 0%, @steam-metal-mid 100%);
|
||||
border-top: 1px solid @steam-brass-dark;
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
padding: 0 8px;
|
||||
gap: 4px;
|
||||
|
||||
a.item {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
color: @steam-parchment-dk;
|
||||
padding: 4px 10px;
|
||||
letter-spacing: 0.04em;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
|
||||
&:hover {
|
||||
color: @steam-brass-light;
|
||||
border-bottom-color: rgba(@steam-brass, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: @steam-brass-light;
|
||||
border-bottom-color: @steam-brass;
|
||||
text-shadow: 0 0 6px rgba(@steam-brass-light, 0.5);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Window content area — parchment background
|
||||
// ----------------------------------------------------------
|
||||
.window-content {
|
||||
background: @steam-parchment;
|
||||
color: @steam-rust;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Sheet body (tab content)
|
||||
// ----------------------------------------------------------
|
||||
.sheet-body {
|
||||
background: transparent;
|
||||
color: @steam-rust;
|
||||
padding: 0 8px;
|
||||
|
||||
// ---- Section title rows ----
|
||||
.items-title-bg {
|
||||
.brass-gradient();
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 3px 6px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
h3, label, .items-title-text {
|
||||
font-family: @font-primary;
|
||||
font-size: 0.92rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
text-shadow: 0 1px 1px rgba(255, 220, 60, 0.4);
|
||||
letter-spacing: 0.04em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// Roll icons in title (NPC category roll)
|
||||
a {
|
||||
color: @steam-dark;
|
||||
opacity: 0.8;
|
||||
&:hover { opacity: 1; }
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Alternating item list ----
|
||||
ul.item-list,
|
||||
ul.stat-list,
|
||||
ul.alternate-list {
|
||||
list-style: none;
|
||||
margin: 2px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li.list-item {
|
||||
background: @steam-parchment;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.18);
|
||||
padding: 3px 4px;
|
||||
color: @steam-rust;
|
||||
font-size: 0.83rem;
|
||||
|
||||
&:nth-child(even) { background: @steam-parchment-dk; }
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
|
||||
// Items with hover effect
|
||||
li.list-item-shadow {
|
||||
transition: background 0.1s;
|
||||
&:hover { background: mix(@steam-parchment, @steam-brass, 88%); }
|
||||
}
|
||||
|
||||
// ---- Labels ----
|
||||
label,
|
||||
.item-name-label-short,
|
||||
.item-name-label-medium,
|
||||
.item-name-label-long,
|
||||
.item-name-label-long2,
|
||||
.item-name-label-free,
|
||||
.item-field-label-short,
|
||||
.item-field-label-medium {
|
||||
color: @steam-rust;
|
||||
}
|
||||
|
||||
// ---- Roll action links (dice icons) ----
|
||||
a[data-action^="roll"],
|
||||
a.roll-skill,
|
||||
a.roll-spec,
|
||||
a.roll-cephaly {
|
||||
color: @steam-brass-dark;
|
||||
&:hover { color: @steam-brass; }
|
||||
i { font-size: 0.85rem; }
|
||||
}
|
||||
|
||||
// ---- Item edit links ----
|
||||
a[data-action="itemEdit"],
|
||||
a.item-edit {
|
||||
color: @steam-brass-dark;
|
||||
&:hover { color: @steam-brass; }
|
||||
}
|
||||
|
||||
// ---- Item control buttons (edit/delete/add) ----
|
||||
.item-controls {
|
||||
a.item-control {
|
||||
color: @steam-rust;
|
||||
opacity: 0.7;
|
||||
padding: 0 3px;
|
||||
&:hover { color: @steam-brass-dark; opacity: 1; }
|
||||
|
||||
&.item-delete:hover { color: @steam-failure; }
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Selects & inputs inside body ----
|
||||
select,
|
||||
input[type="text"],
|
||||
input[type="number"] {
|
||||
background: @steam-cream;
|
||||
color: @steam-dark;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 1px 4px;
|
||||
font-size: 0.83rem;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: @steam-brass;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1),
|
||||
0 0 4px rgba(@steam-brass, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
// Skill level select in header (NPC)
|
||||
.item-field-label-short-header select {
|
||||
background: @steam-parchment-dk;
|
||||
color: @steam-dark;
|
||||
}
|
||||
|
||||
// ---- HR separator — brass wire + gear ----
|
||||
hr {
|
||||
border: none;
|
||||
height: 2px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
@steam-brass-dark 10%,
|
||||
@steam-brass 50%,
|
||||
@steam-brass-dark 90%,
|
||||
transparent 100%
|
||||
);
|
||||
margin: 10px 4px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "⚙";
|
||||
position: absolute;
|
||||
top: -0.6em;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: @steam-brass-dark;
|
||||
font-size: 0.85rem;
|
||||
background: @steam-parchment;
|
||||
padding: 0 4px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Impact boxes (combat tab) ----
|
||||
.impact-box {
|
||||
background: @steam-parchment-dk;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
padding: 6px 8px;
|
||||
margin: 4px;
|
||||
|
||||
.impact-title {
|
||||
.brass-gradient();
|
||||
border-radius: 2px;
|
||||
padding: 3px 6px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
label, .items-title-text {
|
||||
font-family: @font-primary;
|
||||
font-size: 0.88rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
text-shadow: 0 1px 1px rgba(255, 220, 60, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 2px 0;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.18);
|
||||
color: @steam-rust;
|
||||
font-size: 0.83rem;
|
||||
&:last-child { border-bottom: none; }
|
||||
|
||||
// +/- impact buttons
|
||||
a[data-action="impactModify"] {
|
||||
color: @steam-brass-dark;
|
||||
font-size: 1rem;
|
||||
&:hover { color: @steam-brass; }
|
||||
}
|
||||
|
||||
span { font-weight: bold; color: @steam-dark; }
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Sub-list (specializations) ----
|
||||
ul.ul-level1 {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 0 0 16px;
|
||||
|
||||
li {
|
||||
background: transparent;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.1);
|
||||
padding: 2px 4px;
|
||||
font-size: 0.8rem;
|
||||
color: @steam-rust;
|
||||
|
||||
a { color: @steam-brass-dark; &:hover { color: @steam-brass; } }
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Item icon (sheet-competence-img) ----
|
||||
img.sheet-competence-img {
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
background: @steam-parchment-dk;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.form-group.small-editor,
|
||||
.form-group.editor {
|
||||
background: @steam-cream;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 4px;
|
||||
color: @steam-dark;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-group.small-editor textarea,
|
||||
.form-group.editor textarea {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 92px;
|
||||
resize: none;
|
||||
overflow-y: auto;
|
||||
background: @steam-cream;
|
||||
color: @steam-dark;
|
||||
border: none;
|
||||
padding: 4px;
|
||||
font-size: 0.85rem;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// ---- Grid headings (h3/h4 outside of items-title-bg) ----
|
||||
h3, h4 {
|
||||
font-family: @font-primary;
|
||||
color: @steam-brass-dark;
|
||||
margin: 6px 0 3px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
71
styles/actor-sheet-v2.less
Normal file
71
styles/actor-sheet-v2.less
Normal file
@@ -0,0 +1,71 @@
|
||||
// ============================================================
|
||||
// Actor sheet AppV2 styles (.fvtt-ecryme.sheet.actor)
|
||||
// ============================================================
|
||||
|
||||
.fvtt-ecryme.sheet.actor {
|
||||
// Header: compact with profile image
|
||||
.sheet-header {
|
||||
flex: 0 0 auto;
|
||||
min-height: 90px;
|
||||
padding: 4px 6px;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
|
||||
.profile-img {
|
||||
flex: 0 0 80px;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: cover;
|
||||
object-position: 50% 0;
|
||||
border: 1px solid #7a7971;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-fields {
|
||||
flex: 1;
|
||||
|
||||
h1.charname {
|
||||
height: auto;
|
||||
margin: 0 0 4px;
|
||||
border-bottom: 0;
|
||||
|
||||
input {
|
||||
font-family: @font-primary;
|
||||
font-size: 2rem;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actor-header-traits {
|
||||
margin-top: 2px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Tab bar
|
||||
nav.sheet-tabs {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.4rem;
|
||||
|
||||
a.active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
// Sheet body
|
||||
.sheet-body {
|
||||
overflow-y: auto;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:not(.active) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
styles/actor-sheet.less
Normal file
154
styles/actor-sheet.less
Normal file
@@ -0,0 +1,154 @@
|
||||
// ============================================================
|
||||
// Actor sheet scoped styles (.fvtt-ecryme)
|
||||
// ============================================================
|
||||
|
||||
.fvtt-ecryme {
|
||||
.sheet-header {
|
||||
flex: 0 0 210px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.profile-img {
|
||||
flex: 0 0 128px;
|
||||
width: 128px;
|
||||
height: auto;
|
||||
max-height: 128px;
|
||||
margin-top: 0px;
|
||||
margin-right: 10px;
|
||||
object-fit: cover;
|
||||
object-position: 50% 0;
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.header-fields {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
h1.charname {
|
||||
height: 50px;
|
||||
padding: 0px;
|
||||
margin: 5px 0;
|
||||
border-bottom: 0;
|
||||
|
||||
input {
|
||||
font-family: @font-primary;
|
||||
font-size: 3rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sheet-tabs {
|
||||
flex: 0;
|
||||
font-family: @font-primary;
|
||||
font-size: 2.2rem;
|
||||
|
||||
.item {
|
||||
line-height: 40px;
|
||||
font-weight: bold;
|
||||
|
||||
&.active {
|
||||
text-decoration: underline;
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
height: 40px;
|
||||
border-top: 1px solid #AAA;
|
||||
border-bottom: 1px solid #AAA;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.sheet-body,
|
||||
.sheet-body .tab,
|
||||
.sheet-body .tab .editor {
|
||||
height: 100%;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.tox {
|
||||
.tox-editor-container {
|
||||
background: #fff;
|
||||
}
|
||||
.tox-edit-area {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.resource-label {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.items-list {
|
||||
list-style: none;
|
||||
margin: 1px 0;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
|
||||
.item-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item {
|
||||
height: 30px;
|
||||
line-height: 24px;
|
||||
padding: 1px 0;
|
||||
border-bottom: 1px solid #BBB;
|
||||
|
||||
.item-image {
|
||||
flex: 0 0 24px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.item-controls {
|
||||
flex: 0 0 86px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.profile-img-container {
|
||||
margin-right: 0.2rem;
|
||||
max-width: 140px;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
li.folder > .folder-header h3 {
|
||||
color: @color-text-dark;
|
||||
}
|
||||
|
||||
.editor {
|
||||
border: 2;
|
||||
height: 100%;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
.medium-editor {
|
||||
border: 2;
|
||||
height: 240px;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
.small-editor {
|
||||
border: 2;
|
||||
height: 120px;
|
||||
padding: 0 3px;
|
||||
}
|
||||
689
styles/chat-steampunk.less
Normal file
689
styles/chat-steampunk.less
Normal file
@@ -0,0 +1,689 @@
|
||||
// ============================================================
|
||||
// Chat — Steampunk theme for Ecryme
|
||||
// Uses .ecryme-chat-body (custom class) so Foundry CSS never interferes.
|
||||
// Header = brass plate. Body = aged parchment + dark ink.
|
||||
// ============================================================
|
||||
|
||||
// ---- Mixin: rivet ornament (corner box-shadow bolts) ----
|
||||
.riveted-border() {
|
||||
box-shadow:
|
||||
inset 4px 4px 0 1px @steam-rivet,
|
||||
inset -4px 4px 0 1px @steam-rivet,
|
||||
inset 4px -4px 0 1px @steam-rivet,
|
||||
inset -4px -4px 0 1px @steam-rivet,
|
||||
0 3px 10px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
// ---- Mixin: brass gradient ----
|
||||
.brass-gradient() {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
@steam-brass-dark 0%,
|
||||
@steam-brass 30%,
|
||||
@steam-brass-light 50%,
|
||||
@steam-brass 70%,
|
||||
@steam-brass-dark 100%
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Chat message outer frame — brass border + rivets
|
||||
// ============================================================
|
||||
#chat-log .chat-message,
|
||||
.chat-popout .chat-message {
|
||||
border: 2px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
.riveted-border();
|
||||
margin-bottom: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
// Whisper: acid-tinted border
|
||||
&.whisper {
|
||||
border-color: @steam-acid-dark;
|
||||
box-shadow:
|
||||
inset 4px 4px 0 1px @steam-acid-dark,
|
||||
inset -4px 4px 0 1px @steam-acid-dark,
|
||||
inset 4px -4px 0 1px @steam-acid-dark,
|
||||
inset -4px -4px 0 1px @steam-acid-dark,
|
||||
0 3px 10px rgba(0, 0, 0, 0.4);
|
||||
|
||||
.ecryme-chat-body {
|
||||
background: mix(@steam-parchment, @steam-acid, 82%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Message header — brass plate
|
||||
// ============================================================
|
||||
.chat-message-header {
|
||||
.brass-gradient();
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
font-size: 1rem;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
gap: 8px;
|
||||
|
||||
img.actor-icon,
|
||||
.actor-icon {
|
||||
border: 2px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
padding: 1px;
|
||||
background: @steam-parchment-dk;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-actor-name {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
text-shadow: 0 1px 1px rgba(255, 210, 60, 0.5);
|
||||
letter-spacing: 0.04em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.chat-actor-subtitle {
|
||||
font-family: @font-primary;
|
||||
font-size: 0.78rem;
|
||||
font-weight: normal;
|
||||
color: @steam-dark;
|
||||
opacity: 0.75;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Body — aged parchment panel (our class = Foundry never overrides)
|
||||
// ============================================================
|
||||
.ecryme-chat-body {
|
||||
background: @steam-parchment;
|
||||
color: @steam-dark;
|
||||
padding: 6px 8px 8px;
|
||||
font-size: 0.88rem;
|
||||
|
||||
// Skill / ability icon
|
||||
.ecryme-chat-icon-row {
|
||||
overflow: hidden;
|
||||
margin-bottom: 4px;
|
||||
|
||||
img.chat-icon {
|
||||
border: 2px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
|
||||
background: @steam-parchment-dk;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
padding: 2px;
|
||||
float: left;
|
||||
margin: 0 8px 4px 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Brass wire separator
|
||||
hr {
|
||||
border: none;
|
||||
height: 2px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
@steam-brass-dark 10%,
|
||||
@steam-brass 50%,
|
||||
@steam-brass-dark 90%,
|
||||
transparent 100%
|
||||
);
|
||||
margin: 6px 4px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "⚙";
|
||||
position: absolute;
|
||||
top: -0.6em;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: @steam-brass-dark;
|
||||
font-size: 0.8rem;
|
||||
background: @steam-parchment;
|
||||
padding: 0 4px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
// Detail list — dark sepia ink on parchment
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
color: @steam-rust;
|
||||
font-size: 0.87rem;
|
||||
padding: 3px 2px 3px 20px;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.2);
|
||||
position: relative;
|
||||
line-height: 1.4;
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
|
||||
// Brass arrow bullet
|
||||
&::before {
|
||||
content: "▸";
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 4px;
|
||||
color: @steam-brass-dark;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: @steam-brass-dark;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// Result line (success/failure) — no bullet, centered
|
||||
li.ecryme-result-line {
|
||||
padding-left: 4px;
|
||||
text-align: center;
|
||||
border-bottom: none;
|
||||
margin-top: 2px;
|
||||
|
||||
&::before { content: none; }
|
||||
}
|
||||
}
|
||||
|
||||
// GM row with difficulty select
|
||||
.ecryme-chat-gm-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 6px 0 4px;
|
||||
color: @steam-dark;
|
||||
font-size: 0.85rem;
|
||||
|
||||
select {
|
||||
background: @steam-parchment-dk;
|
||||
color: @steam-dark;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 2px 4px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
|
||||
// "Sent to GM" italic note
|
||||
p.ecryme-chat-sent-gm {
|
||||
color: @steam-brass-dark;
|
||||
font-style: italic;
|
||||
font-size: 0.82rem;
|
||||
margin: 4px 0 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Success / Failure labels
|
||||
// ============================================================
|
||||
.chat-result-success {
|
||||
color: @steam-success;
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.chat-result-failure {
|
||||
color: @steam-failure;
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.chat-result-text {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Action buttons — brass mechanical style
|
||||
// ============================================================
|
||||
.chat-card-button,
|
||||
.button-apply-impact,
|
||||
.button-apply-bonus,
|
||||
.button-select-confront,
|
||||
.button-apply-cephaly-difficulty {
|
||||
display: block;
|
||||
width: calc(100% - 8px);
|
||||
margin: 4px 4px 2px;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
font-family: @font-primary;
|
||||
letter-spacing: 0.05em;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
color: @steam-parchment;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
position: relative;
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass, @steam-dark, 50%) 0%,
|
||||
mix(@steam-brass-dark, @steam-dark, 65%) 100%
|
||||
);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 215, 80, 0.2),
|
||||
0 2px 4px rgba(0, 0, 0, 0.35);
|
||||
transition: background 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass-light, @steam-dark, 60%) 0%,
|
||||
mix(@steam-brass, @steam-dark, 50%) 100%
|
||||
);
|
||||
color: @steam-cream;
|
||||
}
|
||||
&:active { top: 1px; }
|
||||
}
|
||||
|
||||
.plus-minus-button {
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass, @steam-dark, 40%) 0%,
|
||||
mix(@steam-brass-dark, @steam-dark, 55%) 100%
|
||||
);
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
color: @steam-parchment;
|
||||
padding: 2px 5px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
|
||||
&:hover { color: @steam-cream; }
|
||||
&:active { position: relative; top: 1px; }
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Dice images
|
||||
// ============================================================
|
||||
.dice-image {
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.dice-image-reroll {
|
||||
border: 2px solid @steam-acid;
|
||||
border-radius: 2px;
|
||||
background-color: rgba(@steam-acid-dark, 0.15);
|
||||
box-shadow: 0 0 5px rgba(@steam-acid, 0.5);
|
||||
}
|
||||
|
||||
|
||||
// ---- Mixin: rivet ornament (corner box-shadow bolts) ----
|
||||
.riveted-border() {
|
||||
box-shadow:
|
||||
inset 4px 4px 0 1px @steam-rivet,
|
||||
inset -4px 4px 0 1px @steam-rivet,
|
||||
inset 4px -4px 0 1px @steam-rivet,
|
||||
inset -4px -4px 0 1px @steam-rivet,
|
||||
0 3px 10px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
// ---- Mixin: brass gradient ----
|
||||
.brass-gradient() {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
@steam-brass-dark 0%,
|
||||
@steam-brass 30%,
|
||||
@steam-brass-light 50%,
|
||||
@steam-brass 70%,
|
||||
@steam-brass-dark 100%
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Chat message container — parchment panel + brass frame
|
||||
// ============================================================
|
||||
#chat-log .chat-message,
|
||||
.chat-popout .chat-message {
|
||||
border: 2px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
.riveted-border();
|
||||
// Parchment background applied at all levels
|
||||
background: @steam-parchment !important;
|
||||
background-color: @steam-parchment !important;
|
||||
color: @steam-dark;
|
||||
margin-bottom: 6px;
|
||||
|
||||
// Cover Foundry's inner wrappers
|
||||
.message-content {
|
||||
background: @steam-parchment !important;
|
||||
background-color: @steam-parchment !important;
|
||||
color: @steam-dark;
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
// All text descendants default to dark ink
|
||||
p, span, div, label, li, ul, h1, h2, h3, h4, h5 {
|
||||
color: @steam-dark;
|
||||
}
|
||||
|
||||
// Whisper: acid-tinted parchment
|
||||
&.whisper {
|
||||
border-color: @steam-acid-dark;
|
||||
background: mix(@steam-parchment, @steam-acid, 85%) !important;
|
||||
background-color: mix(@steam-parchment, @steam-acid, 85%) !important;
|
||||
box-shadow:
|
||||
inset 4px 4px 0 1px @steam-acid-dark,
|
||||
inset -4px 4px 0 1px @steam-acid-dark,
|
||||
inset 4px -4px 0 1px @steam-acid-dark,
|
||||
inset -4px -4px 0 1px @steam-acid-dark,
|
||||
0 3px 10px rgba(0, 0, 0, 0.4);
|
||||
|
||||
.message-content {
|
||||
background: mix(@steam-parchment, @steam-acid, 85%) !important;
|
||||
background-color: mix(@steam-parchment, @steam-acid, 85%) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Message header — brass plate with dark name
|
||||
// ============================================================
|
||||
.chat-message-header {
|
||||
.brass-gradient();
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
border-radius: 2px 2px 0 0;
|
||||
font-size: 1rem;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 6px;
|
||||
gap: 6px;
|
||||
|
||||
// Force brass bg even inside message-content parchment
|
||||
background: linear-gradient(135deg, @steam-brass-dark 0%, @steam-brass 30%, @steam-brass-light 50%, @steam-brass 70%, @steam-brass-dark 100%) !important;
|
||||
background-color: @steam-brass !important;
|
||||
|
||||
img.actor-icon,
|
||||
.actor-icon {
|
||||
border: 2px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 4px rgba(0,0,0,0.4);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 1px;
|
||||
background: @steam-parchment;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-actor-name {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark !important;
|
||||
text-shadow: 0 1px 1px rgba(255, 220, 80, 0.4);
|
||||
letter-spacing: 0.04em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Separator — brass wire with central gear
|
||||
// ============================================================
|
||||
#chat-log .chat-message hr,
|
||||
.chat-popout .chat-message hr {
|
||||
border: none;
|
||||
height: 2px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
@steam-brass-dark 10%,
|
||||
@steam-brass 50%,
|
||||
@steam-brass-dark 90%,
|
||||
transparent 100%
|
||||
);
|
||||
margin: 5px 4px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "⚙";
|
||||
position: absolute;
|
||||
top: -0.6em;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: @steam-brass;
|
||||
font-size: 0.8rem;
|
||||
background: @steam-parchment;
|
||||
padding: 0 4px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Detail list — dark ink on parchment
|
||||
// ============================================================
|
||||
#chat-log .chat-message ul,
|
||||
.chat-popout .chat-message ul {
|
||||
list-style: none;
|
||||
margin: 4px 0;
|
||||
padding: 0 4px;
|
||||
|
||||
li {
|
||||
color: @steam-rust !important; // dark sepia/brown ink — readable on parchment
|
||||
font-size: 0.88rem;
|
||||
padding: 2px 0 2px 18px;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.2);
|
||||
position: relative;
|
||||
line-height: 1.4;
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
|
||||
// Arrow bullet in brass
|
||||
&::before {
|
||||
content: "▸";
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
color: @steam-brass-dark;
|
||||
font-size: 0.75rem;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
strong { color: @steam-brass-dark !important; }
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Skill / ability icon
|
||||
// ============================================================
|
||||
.chat-icon {
|
||||
border: 2px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.3);
|
||||
background: @steam-parchment-dk;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
padding: 2px;
|
||||
margin: 4px 6px 4px 4px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Result labels (success / failure)
|
||||
// ============================================================
|
||||
.chat-result-success {
|
||||
color: @steam-success !important;
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.chat-result-failure {
|
||||
color: @steam-failure !important;
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.chat-result-text {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
color: @steam-dark !important;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Action buttons — brass mechanical style
|
||||
// ============================================================
|
||||
.chat-card-button,
|
||||
.button-apply-impact,
|
||||
.button-apply-bonus,
|
||||
.button-select-confront,
|
||||
.button-apply-cephaly-difficulty {
|
||||
display: block;
|
||||
width: calc(100% - 8px);
|
||||
margin: 4px;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
font-family: @font-primary;
|
||||
letter-spacing: 0.05em;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
color: @steam-parchment !important;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.8);
|
||||
position: relative;
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass, @steam-dark, 50%) 0%,
|
||||
mix(@steam-brass-dark, @steam-dark, 65%) 100%
|
||||
);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 215, 80, 0.2),
|
||||
0 2px 4px rgba(0,0,0,0.4);
|
||||
transition: background 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass-light, @steam-dark, 60%) 0%,
|
||||
mix(@steam-brass, @steam-dark, 50%) 100%
|
||||
);
|
||||
color: @steam-cream !important;
|
||||
}
|
||||
&:active { top: 1px; }
|
||||
}
|
||||
|
||||
.plus-minus-button {
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass, @steam-dark, 40%) 0%,
|
||||
mix(@steam-brass-dark, @steam-dark, 55%) 100%
|
||||
);
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
color: @steam-parchment !important;
|
||||
padding: 2px 5px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
|
||||
&:hover { color: @steam-cream !important; }
|
||||
&:active { position: relative; top: 1px; }
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Dice images — brass frame
|
||||
// ============================================================
|
||||
.dice-image {
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 3px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.dice-image-reroll {
|
||||
border: 2px solid @steam-acid;
|
||||
border-radius: 2px;
|
||||
background-color: rgba(@steam-acid-dark, 0.15);
|
||||
box-shadow: 0 0 5px rgba(@steam-acid, 0.5);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// GM difficulty select
|
||||
// ============================================================
|
||||
#chat-log .chat-message,
|
||||
.chat-popout .chat-message {
|
||||
select[name="cephaly-difficulty"] {
|
||||
background: @steam-parchment-dk;
|
||||
color: @steam-dark;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 2px 4px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// Welcome message — sections & footer
|
||||
// ============================================================
|
||||
.ecryme-chat-body {
|
||||
|
||||
// Title
|
||||
.welcome-message-h3 {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
color: @steam-brass-dark;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||
letter-spacing: 0.06em;
|
||||
margin: 0 0 8px;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.35);
|
||||
}
|
||||
|
||||
// Content sections
|
||||
.welcome-section {
|
||||
color: @steam-dark;
|
||||
font-size: 0.86rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 8px;
|
||||
padding: 5px 6px;
|
||||
background: rgba(@steam-parchment-dk, 0.55);
|
||||
border-left: 3px solid @steam-brass;
|
||||
border-radius: 0 2px 2px 0;
|
||||
|
||||
strong { color: @steam-rust; }
|
||||
|
||||
a {
|
||||
color: @steam-brass-dark;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
&:hover { color: @steam-brass; }
|
||||
}
|
||||
}
|
||||
|
||||
// Footer signature
|
||||
.welcome-footer {
|
||||
font-family: @font-primary;
|
||||
font-size: 0.82rem;
|
||||
color: @steam-rust;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
margin-top: 8px;
|
||||
padding-top: 6px;
|
||||
border-top: 1px solid rgba(@steam-brass-dark, 0.3);
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
}
|
||||
251
styles/chat.less
Normal file
251
styles/chat.less
Normal file
@@ -0,0 +1,251 @@
|
||||
// ============================================================
|
||||
// Chat, dice, roll dialogs, buttons
|
||||
// ============================================================
|
||||
|
||||
.chat-message-header {
|
||||
background: rgba(220, 220, 210, 0.5);
|
||||
font-size: 1.1rem;
|
||||
height: 48px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-chat-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.welcome-message-h3 {
|
||||
font-size: 1.2rem;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem;
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
.chat-message {
|
||||
background: rgba(220, 220, 210, 0.5);
|
||||
font-size: 0.9rem;
|
||||
|
||||
&.whisper {
|
||||
background: rgba(220, 220, 210, 0.75);
|
||||
border: 2px solid #545469;
|
||||
}
|
||||
|
||||
.message-header {
|
||||
.flavor-text,
|
||||
.whisper-to {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-icon {
|
||||
border: 0;
|
||||
padding: 2px 6px 2px 2px;
|
||||
float: left;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-result-text,
|
||||
.chat-actor-name {
|
||||
font-weight: bold;
|
||||
font-family: @font-primary;
|
||||
font-size: 1.2rem;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.chat-result-success { color: darkgreen; }
|
||||
.chat-result-failure { color: darkred; }
|
||||
|
||||
.chat-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
// Roll dialog
|
||||
.roll-dialog-header {
|
||||
height: 52px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.roll-dialog-actor-title {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.3;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ecryme-roll-dialog,
|
||||
.ecryme-confront-start-dialog,
|
||||
.ecryme-confrontation-dialog {
|
||||
.window-header { border-radius: 10px 10px 0% 0%; }
|
||||
.window-content { border-radius: 0% 0% 10px 10px; }
|
||||
|
||||
.sheet-footer {
|
||||
margin-top: 8px;
|
||||
padding: 4px 0;
|
||||
border-top: 1px solid var(--color-border-light-tertiary, #999);
|
||||
gap: 6px;
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ecryme-confront-start-dialog {
|
||||
.sheet-footer {
|
||||
gap: 4px;
|
||||
button { font-size: 0.85rem; }
|
||||
}
|
||||
}
|
||||
|
||||
.skill-roll-dialog div {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
// Actor icon in chat
|
||||
.actor-icon {
|
||||
float: left;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
padding: 2px 6px 2px 2px;
|
||||
}
|
||||
|
||||
// Dice
|
||||
.padding-dice {
|
||||
padding-top: .2rem;
|
||||
padding-bottom: .2rem;
|
||||
}
|
||||
|
||||
.dice-image {
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.dice-image-reroll {
|
||||
background-color: rgba(115, 224, 115, 0.25);
|
||||
border-color: #011d33;
|
||||
box-sizing: border-box;
|
||||
border: 1px;
|
||||
border-radius: 0%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.chat-dice {
|
||||
width: 15%;
|
||||
height: 15%;
|
||||
font-size: 15px;
|
||||
padding: 10px;
|
||||
padding-top: .2rem;
|
||||
padding-bottom: .2rem;
|
||||
}
|
||||
|
||||
.div-center { align-self: center; }
|
||||
|
||||
.ability-icon {
|
||||
border: 0;
|
||||
padding: 2px;
|
||||
max-width: 32px;
|
||||
max-height: 32px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.small-ability-icon {
|
||||
border: 0;
|
||||
padding: 2px;
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.combat-icon {
|
||||
border: 0;
|
||||
padding: 2px;
|
||||
max-width: 24px;
|
||||
max-height: 24px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// Dice cell / formula / total
|
||||
.dice-cell {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dice-formula,
|
||||
.dice-total {
|
||||
height: 54px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
// Buttons
|
||||
.chat-card-button {
|
||||
box-shadow: inset 0px 1px 0px 0px #a6827e;
|
||||
background: linear-gradient(to bottom, rgba(33, 55, 74, 0.98824) 5%, rgba(21, 40, 51, 0.67059) 100%);
|
||||
background-color: rgba(125, 93, 59, 0);
|
||||
border-radius: 3px;
|
||||
border: 2px ridge #846109;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
color: #ffffff;
|
||||
font-size: 0.8rem;
|
||||
padding: 4px 12px 0px 12px;
|
||||
text-decoration: none;
|
||||
text-shadow: 0px 1px 0px #4d3534;
|
||||
position: relative;
|
||||
margin: 2px;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
&:active {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.plus-minus-button {
|
||||
box-shadow: inset 0px 1px 0px 0px #a6827e;
|
||||
background: linear-gradient(to bottom, rgba(33, 55, 74, 0.98824) 5%, rgba(21, 40, 51, 0.67059) 100%);
|
||||
background-color: rgba(125, 93, 59, 0);
|
||||
border-radius: 2px;
|
||||
border: 1px ridge #846109;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
color: #ffffff;
|
||||
padding: 2px;
|
||||
text-decoration: none;
|
||||
text-shadow: 0px 1px 0px #4d3534;
|
||||
position: relative;
|
||||
margin: 0px;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
&:active {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.plus-minus {
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
264
styles/dialog-steampunk.less
Normal file
264
styles/dialog-steampunk.less
Normal file
@@ -0,0 +1,264 @@
|
||||
// ============================================================
|
||||
// Roll & Confrontation dialogs — Steampunk theme
|
||||
// Targets .ecryme-roll-dialog, .ecryme-confront-start-dialog,
|
||||
// .ecryme-confrontation-dialog (AppV2 root classes)
|
||||
// ============================================================
|
||||
|
||||
// Common container mixin
|
||||
.steam-dialog-window() {
|
||||
// Title bar — brass plate
|
||||
.window-header {
|
||||
.brass-gradient();
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
color: @steam-dark;
|
||||
text-shadow: 0 1px 1px rgba(255, 220, 80, 0.4);
|
||||
|
||||
.window-title {
|
||||
font-family: @font-primary;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
// Close button — rivet look
|
||||
.header-button,
|
||||
button[data-action="close"] {
|
||||
color: @steam-dark;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1rem;
|
||||
opacity: 0.7;
|
||||
&:hover { opacity: 1; color: @steam-rust; }
|
||||
}
|
||||
}
|
||||
|
||||
// Content area — aged parchment
|
||||
.window-content {
|
||||
background: @steam-parchment;
|
||||
color: @steam-rust;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Apply to all three dialog app containers
|
||||
// ============================================================
|
||||
.ecryme-roll-dialog,
|
||||
.ecryme-confront-start-dialog,
|
||||
.ecryme-confrontation-dialog {
|
||||
.steam-dialog-window();
|
||||
|
||||
// Outer window frame
|
||||
border: 2px solid @steam-brass-dark;
|
||||
box-shadow:
|
||||
inset 4px 4px 0 1px @steam-rivet,
|
||||
inset -4px 4px 0 1px @steam-rivet,
|
||||
inset 4px -4px 0 1px @steam-rivet,
|
||||
inset -4px -4px 0 1px @steam-rivet,
|
||||
0 4px 14px rgba(0, 0, 0, 0.6);
|
||||
|
||||
// ---- Actor header row ----
|
||||
.roll-dialog-header {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
@steam-parchment-dk 0%,
|
||||
@steam-parchment 60%
|
||||
);
|
||||
border-bottom: 1px solid @steam-brass-dark;
|
||||
border-radius: 0;
|
||||
padding: 6px 8px;
|
||||
margin-bottom: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.actor-icon {
|
||||
border: 2px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.35);
|
||||
background: @steam-parchment-dk;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
padding: 1px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.roll-dialog-actor-title {
|
||||
font-family: @font-primary;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Form labels ----
|
||||
.roll-dialog-label {
|
||||
color: @steam-rust;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// ---- Row separator ----
|
||||
.flexrow {
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.15);
|
||||
padding: 3px 0;
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
|
||||
// ---- Selects & inputs ----
|
||||
select,
|
||||
input[type="text"],
|
||||
input[type="number"] {
|
||||
background: @steam-cream;
|
||||
color: @steam-dark;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 2px 5px;
|
||||
font-size: 0.85rem;
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: @steam-brass;
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12),
|
||||
0 0 4px rgba(@steam-brass, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
select[multiple] {
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
// ---- Headings inside content ----
|
||||
h3, h4 {
|
||||
font-family: @font-primary;
|
||||
color: @steam-brass-dark;
|
||||
font-size: 0.9rem;
|
||||
margin: 6px 0 3px;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.3);
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
// ---- Footer ----
|
||||
.sheet-footer {
|
||||
border-top: 2px solid @steam-brass-dark;
|
||||
background: @steam-parchment-dk;
|
||||
padding: 6px 4px;
|
||||
margin-top: 6px;
|
||||
|
||||
button {
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass, @steam-dark, 50%) 0%,
|
||||
mix(@steam-brass-dark, @steam-dark, 65%) 100%
|
||||
);
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
color: @steam-parchment;
|
||||
font-family: @font-primary;
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 215, 80, 0.2),
|
||||
0 2px 4px rgba(0, 0, 0, 0.35);
|
||||
transition: background 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(180deg,
|
||||
mix(@steam-brass-light, @steam-dark, 60%) 0%,
|
||||
mix(@steam-brass, @steam-dark, 50%) 100%
|
||||
);
|
||||
color: @steam-cream;
|
||||
}
|
||||
&:active { position: relative; top: 1px; }
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
box-shadow: none;
|
||||
&:hover { background: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Confrontation dialog — dice / bonus pool areas
|
||||
// ============================================================
|
||||
.ecryme-confrontation-dialog {
|
||||
|
||||
// Area containers (execution, preservation, pool)
|
||||
.confront-area {
|
||||
background: @steam-parchment-dk;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
min-height: 60px;
|
||||
padding: 4px;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
// Execution area — slight warm tint
|
||||
.confront-execution-area {
|
||||
border-left: 3px solid @steam-brass;
|
||||
}
|
||||
|
||||
// Preservation area — slight cool tint
|
||||
.confront-preservation-area {
|
||||
border-left: 3px solid @steam-copper;
|
||||
}
|
||||
|
||||
// Pool list area
|
||||
.pool-list {
|
||||
border-left: 3px solid @steam-metal-mid;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
// Individual dice container
|
||||
.confront-dice-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
cursor: grab;
|
||||
padding: 3px;
|
||||
border-radius: 2px;
|
||||
transition: background 0.1s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(@steam-brass, 0.18);
|
||||
}
|
||||
|
||||
// Dice image
|
||||
.confront-dice {
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
|
||||
background: @steam-parchment-dk;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
// Dice value label
|
||||
.confront-dice-centered,
|
||||
.confront-bonus-centered {
|
||||
font-family: @font-primary;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
color: @steam-brass-dark;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Bonus spec — acid tint
|
||||
.bonus-spec .confront-dice {
|
||||
border-color: @steam-acid;
|
||||
background-color: mix(@steam-parchment, @steam-acid, 88%);
|
||||
box-shadow: 0 0 4px rgba(@steam-acid, 0.3);
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@
|
||||
|
||||
/* For nav and title */
|
||||
.window-app input,
|
||||
.application input,
|
||||
.fvtt-ecryme .item-form,
|
||||
.sheet header.sheet-header .flex-group-center.flex-compteurs,
|
||||
.sheet header.sheet-header .flex-group-center.flex-fatigue,
|
||||
@@ -76,9 +77,11 @@
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content {
|
||||
.window-app.sheet .window-content,
|
||||
.application.sheet .window-content {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden auto;
|
||||
}
|
||||
|
||||
.strong-text {
|
||||
@@ -396,13 +399,15 @@
|
||||
|
||||
/* ======================================== */
|
||||
/* Sheet */
|
||||
.window-app.sheet .window-content .sheet-header {
|
||||
.window-app.sheet .window-content .sheet-header,
|
||||
.application.sheet .window-content .sheet-header {
|
||||
color: rgba(19, 18, 18, 0.95);
|
||||
background: url("../images/ui/fond_carnet_01.webp");
|
||||
/*background: #494e6b;*/
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select[type="text"] {
|
||||
background: white;
|
||||
color: #494e6b;
|
||||
@@ -420,14 +425,23 @@
|
||||
.window-app.sheet .window-content .sheet-header input[type="number"],
|
||||
.window-app.sheet .window-content .sheet-body input[type="text"],
|
||||
.window-app.sheet .window-content .sheet-body input[type="number"],
|
||||
.window-app.sheet .window-content .sheet-body select[type="text"] {
|
||||
.window-app.sheet .window-content .sheet-body select[type="text"],
|
||||
.application.sheet .window-content .sheet-header select[type="text"],
|
||||
.application.sheet .window-content .sheet-header input[type="text"],
|
||||
.application.sheet .window-content .sheet-header input[type="number"],
|
||||
.application.sheet .window-content .sheet-body input[type="text"],
|
||||
.application.sheet .window-content .sheet-body input[type="number"],
|
||||
.application.sheet .window-content .sheet-body select[type="text"] {
|
||||
color: rgba(19, 18, 18, 0.95);
|
||||
/*color: #494e6b;*/
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content .sheet-header input[type="password"],
|
||||
.window-app.sheet .window-content .sheet-header input[type="date"],
|
||||
.window-app.sheet .window-content .sheet-header input[type="time"] {
|
||||
.window-app.sheet .window-content .sheet-header input[type="time"],
|
||||
.application.sheet .window-content .sheet-header input[type="password"],
|
||||
.application.sheet .window-content .sheet-header input[type="date"],
|
||||
.application.sheet .window-content .sheet-header input[type="time"] {
|
||||
color: rgba(19, 18, 18, 0.95);
|
||||
background: url("../images/ui/fond_carnet_01.webp");
|
||||
border: 1 none;
|
||||
@@ -437,7 +451,10 @@
|
||||
|
||||
.window-app.sheet .window-content .sheet-body input[type="password"],
|
||||
.window-app.sheet .window-content .sheet-body input[type="date"],
|
||||
.window-app.sheet .window-content .sheet-body input[type="time"] {
|
||||
.window-app.sheet .window-content .sheet-body input[type="time"],
|
||||
.application.sheet .window-content .sheet-body input[type="password"],
|
||||
.application.sheet .window-content .sheet-body input[type="date"],
|
||||
.application.sheet .window-content .sheet-body input[type="time"] {
|
||||
color: rgba(19, 18, 18, 0.95);
|
||||
background: url("../images/ui/fond_carnet_01.webp");
|
||||
border: 1 none;
|
||||
@@ -446,7 +463,9 @@
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content .sheet-body select,
|
||||
.window-app.sheet .window-content .sheet-header select {
|
||||
.window-app.sheet .window-content .sheet-header select,
|
||||
.application.sheet .window-content .sheet-body select,
|
||||
.application.sheet .window-content .sheet-header select {
|
||||
color: rgba(19, 18, 18, 0.95);
|
||||
background: #fff;
|
||||
border: 1 none;
|
||||
@@ -455,7 +474,9 @@
|
||||
}
|
||||
|
||||
.window-app .window-content,
|
||||
.window-app.sheet .window-content .sheet-body {
|
||||
.window-app.sheet .window-content .sheet-body,
|
||||
.application .window-content,
|
||||
.application.sheet .window-content .sheet-body {
|
||||
font-size: 0.8rem;
|
||||
/*background: url("../images/ui/pc_sheet_bg.webp") repeat left top;*/
|
||||
background: url("../images/ui/fond_carnet_01.webp");
|
||||
@@ -1566,3 +1587,61 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ==============================
|
||||
Application V2 Item Sheets
|
||||
============================== */
|
||||
|
||||
/* Compact header for item sheets (smaller than actor sheets) */
|
||||
.fvtt-ecryme.item .sheet-header {
|
||||
flex: 0 0 auto;
|
||||
min-height: 70px;
|
||||
padding: 4px 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.fvtt-ecryme.item .sheet-header .item-sheet-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
object-fit: contain;
|
||||
border: 1px solid #7a7971;
|
||||
cursor: pointer;
|
||||
flex: 0 0 64px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.fvtt-ecryme.item .sheet-header .header-fields {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.fvtt-ecryme.item .sheet-header h1.charname {
|
||||
height: auto;
|
||||
margin: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fvtt-ecryme.item .sheet-header h1.charname input {
|
||||
font-family: MailartRubberstamp;
|
||||
font-size: 1.8rem;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Active tab styling for AppV2 (uses <a> without .item class) */
|
||||
.fvtt-ecryme.item nav.sheet-tabs a.active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Details tab content */
|
||||
.fvtt-ecryme.item .sheet-body ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 4px 2px;
|
||||
}
|
||||
|
||||
.fvtt-ecryme.item .sheet-body ul li.flexrow {
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
20
styles/ecryme.less
Normal file
20
styles/ecryme.less
Normal file
@@ -0,0 +1,20 @@
|
||||
// ============================================================
|
||||
// Ecryme — Main LESS entry point
|
||||
// Compiled output: css/ecryme.css
|
||||
// ============================================================
|
||||
|
||||
@import "_variables.less";
|
||||
@import "fonts.less";
|
||||
@import "global.less";
|
||||
@import "sheet.less";
|
||||
@import "actor-sheet.less";
|
||||
@import "actor-sheet-v2.less";
|
||||
@import "item-sheet.less";
|
||||
@import "ui.less";
|
||||
@import "sidebar.less";
|
||||
@import "chat.less";
|
||||
@import "chat-steampunk.less";
|
||||
@import "dialog-steampunk.less";
|
||||
@import "actor-sheet-steampunk.less";
|
||||
@import "item-sheet-steampunk.less";
|
||||
@import "hud.less";
|
||||
8
styles/fonts.less
Normal file
8
styles/fonts.less
Normal file
@@ -0,0 +1,8 @@
|
||||
// ============================================================
|
||||
// Fonts
|
||||
// ============================================================
|
||||
|
||||
@font-face {
|
||||
font-family: "MailartRubberstamp";
|
||||
src: url('../fonts/MailartRubberstamp-Regular.woff') format("woff");
|
||||
}
|
||||
179
styles/global.less
Normal file
179
styles/global.less
Normal file
@@ -0,0 +1,179 @@
|
||||
// ============================================================
|
||||
// Global base styles
|
||||
// ============================================================
|
||||
|
||||
:root {
|
||||
// Actor sheet font styles
|
||||
--window-header-title-font-size: 1.3rem;
|
||||
--window-header-title-font-weight: normal;
|
||||
--window-header-title-color: #f5f5f5;
|
||||
|
||||
--major-button-font-size: 1.05rem;
|
||||
--major-button-font-weight: normal;
|
||||
--major-button-color: #dadada;
|
||||
|
||||
--tab-header-font-size: 1.0rem;
|
||||
--tab-header-font-weight: 700;
|
||||
--tab-header-color: #403f3e;
|
||||
--tab-header-color-active: #4a0404;
|
||||
|
||||
--actor-input-font-size: 0.8rem;
|
||||
--actor-input-font-weight: 500;
|
||||
--actor-input-color: black;
|
||||
|
||||
--actor-label-font-size: 0.8rem;
|
||||
--actor-label-font-weight: 700;
|
||||
--actor-label-color: rgba(70, 67, 49, 0.76863);
|
||||
|
||||
// Debugging highlighters
|
||||
--debug-background-color-red: rgba(255, 0, 0, 0.32941);
|
||||
--debug-background-color-blue: rgba(29, 0, 255, 0.32941);
|
||||
--debug-background-color-green: rgba(84, 255, 0, 0.32941);
|
||||
|
||||
--debug-box-shadow-red: inset 0 0 2px red;
|
||||
--debug-box-shadow-blue: inset 0 0 2px blue;
|
||||
--debug-box-shadow-green: inset 0 0 2px green;
|
||||
}
|
||||
|
||||
.window-app {
|
||||
text-align: justify;
|
||||
font-size: 16px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
// Fonts: title, sidebar, scene nav
|
||||
.sheet header.sheet-header h1 input,
|
||||
.window-app .window-header,
|
||||
#actors .directory-list,
|
||||
#navigation #scene-list .scene.nav-item {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
// Nav and title
|
||||
.sheet nav.sheet-tabs {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
// Inputs, buttons, sidebar, navigation
|
||||
.window-app input,
|
||||
.application input,
|
||||
.fvtt-ecryme .item-form,
|
||||
.sheet header.sheet-header .flex-group-center.flex-compteurs,
|
||||
.sheet header.sheet-header .flex-group-center.flex-fatigue,
|
||||
select,
|
||||
button,
|
||||
.item-checkbox,
|
||||
#sidebar,
|
||||
#players,
|
||||
#navigation #nav-toggle {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.window-header {
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content,
|
||||
.application.sheet .window-content {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden auto;
|
||||
}
|
||||
|
||||
.strong-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tabs .item.active,
|
||||
.blessures-list li ul li:first-child:hover,
|
||||
a:hover {
|
||||
text-shadow: 1px 0px 0px @color-accent;
|
||||
}
|
||||
|
||||
.rollable {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #000;
|
||||
text-shadow: 0 0 10px red;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
&:hover {
|
||||
border-width: 4px;
|
||||
border-color: rgba(37, 124, 37, 0.7);
|
||||
}
|
||||
&:disabled {
|
||||
color: @color-text-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
select:disabled {
|
||||
color: @color-text-disabled;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid #7a7971;
|
||||
}
|
||||
|
||||
// Grid utilities
|
||||
.grid,
|
||||
.grid-2col {
|
||||
display: grid;
|
||||
grid-column: span 2 / span 2;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-gap: 10px;
|
||||
gap: 10px;
|
||||
margin: 10px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.grid-3col { grid-column: span 3 / span 3; grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||
.grid-4col { grid-column: span 4 / span 4; grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
||||
.grid-5col { grid-column: span 5 / span 5; grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
||||
.grid-6col { grid-column: span 5 / span 5; grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
||||
.grid-7col { grid-column: span 7 / span 7; grid-template-columns: repeat(7, minmax(0, 1fr)); }
|
||||
.grid-8col { grid-column: span 8 / span 8; grid-template-columns: repeat(8, minmax(0, 1fr)); }
|
||||
.grid-9col { grid-column: span 9 / span 9; grid-template-columns: repeat(9, minmax(0, 1fr)); }
|
||||
.grid-10col { grid-column: span 10 / span 10; grid-template-columns: repeat(10, minmax(0, 1fr)); }
|
||||
.grid-11col { grid-column: span 11 / span 11; grid-template-columns: repeat(11, minmax(0, 1fr)); }
|
||||
.grid-12col { grid-column: span 12 / span 12; grid-template-columns: repeat(12, minmax(0, 1fr)); }
|
||||
|
||||
// Flex utilities
|
||||
.flex-group-center,
|
||||
.flex-group-left,
|
||||
.flex-group-right {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.flex-group-left {
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.flex-group-right {
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-create-actor {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-shrink {
|
||||
flex: 'flex-shrink';
|
||||
}
|
||||
75
styles/hud.less
Normal file
75
styles/hud.less
Normal file
@@ -0,0 +1,75 @@
|
||||
// ============================================================
|
||||
// HUD, token, pause, logo
|
||||
// ============================================================
|
||||
|
||||
// Token HUD extension
|
||||
.tokenhudext {
|
||||
display: flex;
|
||||
flex: 0 !important;
|
||||
font-weight: 600;
|
||||
|
||||
&.left {
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 2.75rem;
|
||||
right: 4rem;
|
||||
}
|
||||
|
||||
&.right {
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 2.75rem;
|
||||
left: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.control-icon.tokenhudicon {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
min-width: 6rem;
|
||||
flex-basis: auto;
|
||||
padding: 0;
|
||||
line-height: 1rem;
|
||||
margin: 0.25rem;
|
||||
|
||||
&.right {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
#token-hud .status-effects.active {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.token-sheet .window-content .flexcol .sheet-tabs {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
// Pause screen
|
||||
#pause {
|
||||
font-size: 2rem;
|
||||
|
||||
> h3 { color: #CCC; }
|
||||
|
||||
> img {
|
||||
content: @logo-image;
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
top: -200px;
|
||||
left: calc(50% - 132px);
|
||||
}
|
||||
}
|
||||
|
||||
// Logo
|
||||
#logo {
|
||||
content: @logo-image;
|
||||
width: 100px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
// Confront dice
|
||||
.confront-dice {
|
||||
border-width: 0px;
|
||||
}
|
||||
258
styles/item-sheet-steampunk.less
Normal file
258
styles/item-sheet-steampunk.less
Normal file
@@ -0,0 +1,258 @@
|
||||
// ============================================================
|
||||
// Item sheets — Steampunk theme
|
||||
// Scoped to .fvtt-ecryme.item
|
||||
// Same visual language as actor-sheet-steampunk.less
|
||||
// ============================================================
|
||||
|
||||
.fvtt-ecryme.item {
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// AppV2 window title bar — brass plate
|
||||
// ----------------------------------------------------------
|
||||
.window-header {
|
||||
.brass-gradient();
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
color: @steam-dark;
|
||||
|
||||
.window-title {
|
||||
font-family: @font-primary;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.header-button,
|
||||
button[data-action="close"] {
|
||||
color: @steam-dark;
|
||||
opacity: 0.75;
|
||||
&:hover { opacity: 1; color: @steam-rust; }
|
||||
}
|
||||
}
|
||||
|
||||
// Window outer frame — rivets
|
||||
border: 2px solid @steam-brass-dark;
|
||||
box-shadow:
|
||||
inset 4px 4px 0 1px @steam-rivet,
|
||||
inset -4px 4px 0 1px @steam-rivet,
|
||||
inset 4px -4px 0 1px @steam-rivet,
|
||||
inset -4px -4px 0 1px @steam-rivet,
|
||||
0 4px 16px rgba(0, 0, 0, 0.55);
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Window content area — parchment background
|
||||
// ----------------------------------------------------------
|
||||
.window-content {
|
||||
background: @steam-parchment;
|
||||
color: @steam-rust;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Sheet header — item image + name
|
||||
// ----------------------------------------------------------
|
||||
.sheet-header {
|
||||
background: linear-gradient(180deg, @steam-parchment-dk 0%, @steam-parchment 100%);
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
padding: 8px 10px;
|
||||
align-items: center;
|
||||
|
||||
.item-sheet-img {
|
||||
border: 3px solid @steam-brass-dark;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.45);
|
||||
background: @steam-parchment-dk;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
h1.charname input {
|
||||
font-family: @font-primary;
|
||||
color: @steam-dark;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid rgba(@steam-brass-dark, 0.4);
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
|
||||
padding-bottom: 2px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-bottom-color: @steam-brass;
|
||||
background: rgba(@steam-cream, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Tab navigation — industrial metal bar
|
||||
// ----------------------------------------------------------
|
||||
nav.sheet-tabs {
|
||||
background: linear-gradient(180deg, @steam-metal 0%, @steam-metal-mid 100%);
|
||||
border-top: 1px solid @steam-brass-dark;
|
||||
border-bottom: 2px solid @steam-brass-dark;
|
||||
padding: 0 8px;
|
||||
gap: 4px;
|
||||
|
||||
a {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.1rem;
|
||||
color: @steam-parchment-dk;
|
||||
padding: 4px 10px;
|
||||
letter-spacing: 0.04em;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: @steam-brass-light;
|
||||
border-bottom-color: rgba(@steam-brass, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: @steam-brass-light;
|
||||
border-bottom-color: @steam-brass;
|
||||
text-shadow: 0 0 6px rgba(@steam-brass-light, 0.5);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Sheet body (tab content)
|
||||
// ----------------------------------------------------------
|
||||
.sheet-body {
|
||||
background: transparent;
|
||||
color: @steam-rust;
|
||||
padding: 0 8px;
|
||||
|
||||
// ---- Field rows ----
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 4px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul li.flexrow {
|
||||
align-items: center;
|
||||
padding: 4px 2px;
|
||||
border-bottom: 1px solid rgba(@steam-brass-dark, 0.18);
|
||||
color: @steam-rust;
|
||||
font-size: 0.85rem;
|
||||
gap: 6px;
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
|
||||
// ---- Labels ----
|
||||
label,
|
||||
.item-name-label-short,
|
||||
.item-name-label-medium,
|
||||
.item-name-label-long,
|
||||
.item-name-label-long2,
|
||||
.item-name-label-free,
|
||||
.item-field-label-short,
|
||||
.item-field-label-medium {
|
||||
color: @steam-rust;
|
||||
}
|
||||
|
||||
// ---- Selects & inputs ----
|
||||
select,
|
||||
input[type="text"],
|
||||
input[type="number"] {
|
||||
background: @steam-cream;
|
||||
color: @steam-dark;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 2px 5px;
|
||||
font-size: 0.85rem;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: @steam-brass;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1),
|
||||
0 0 4px rgba(@steam-brass, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Description editor area ----
|
||||
.tab.description {
|
||||
.editor,
|
||||
.editor-content,
|
||||
.prosemirror,
|
||||
[data-edit] {
|
||||
background: @steam-cream;
|
||||
color: @steam-dark;
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 6px 8px;
|
||||
font-size: 0.86rem;
|
||||
min-height: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Section title rows ----
|
||||
.items-title-bg {
|
||||
.brass-gradient();
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
padding: 3px 6px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
h3, label, .items-title-text {
|
||||
font-family: @font-primary;
|
||||
font-size: 0.92rem;
|
||||
font-weight: bold;
|
||||
color: @steam-dark;
|
||||
text-shadow: 0 1px 1px rgba(255, 220, 60, 0.4);
|
||||
letter-spacing: 0.04em;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- h3/h4 outside section titles ----
|
||||
h3, h4 {
|
||||
font-family: @font-primary;
|
||||
color: @steam-brass-dark;
|
||||
margin: 6px 0 3px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
// ---- HR separator — brass wire + gear ----
|
||||
hr {
|
||||
border: none;
|
||||
height: 2px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
@steam-brass-dark 10%,
|
||||
@steam-brass 50%,
|
||||
@steam-brass-dark 90%,
|
||||
transparent 100%
|
||||
);
|
||||
margin: 10px 4px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "⚙";
|
||||
position: absolute;
|
||||
top: -0.6em;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: @steam-brass-dark;
|
||||
font-size: 0.85rem;
|
||||
background: @steam-parchment;
|
||||
padding: 0 4px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Item icon (competence img) ----
|
||||
img.sheet-competence-img {
|
||||
border: 1px solid @steam-brass-dark;
|
||||
border-radius: 2px;
|
||||
background: @steam-parchment-dk;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
styles/item-sheet.less
Normal file
59
styles/item-sheet.less
Normal file
@@ -0,0 +1,59 @@
|
||||
// ============================================================
|
||||
// AppV2 Item Sheet styles (.fvtt-ecryme.item)
|
||||
// ============================================================
|
||||
|
||||
.fvtt-ecryme.item {
|
||||
.sheet-header {
|
||||
flex: 0 0 auto;
|
||||
min-height: 70px;
|
||||
padding: 4px 6px;
|
||||
align-items: center;
|
||||
|
||||
.item-sheet-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
object-fit: contain;
|
||||
border: 1px solid #7a7971;
|
||||
cursor: pointer;
|
||||
flex: 0 0 64px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.header-fields {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
h1.charname {
|
||||
height: auto;
|
||||
margin: 0;
|
||||
border-bottom: 0;
|
||||
|
||||
input {
|
||||
font-family: @font-primary;
|
||||
font-size: 1.8rem;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Active tab styling (AppV2 uses <a> without .item class)
|
||||
nav.sheet-tabs a.active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.sheet-body {
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 4px 2px;
|
||||
}
|
||||
|
||||
ul li.flexrow {
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
189
styles/sheet.less
Normal file
189
styles/sheet.less
Normal file
@@ -0,0 +1,189 @@
|
||||
// ============================================================
|
||||
// Sheet styles (actor + item, AppV1 + AppV2)
|
||||
// ============================================================
|
||||
|
||||
// Sheet header background
|
||||
.window-app.sheet .window-content .sheet-header,
|
||||
.application.sheet .window-content .sheet-header {
|
||||
color: @color-text-dark;
|
||||
background: @background-image;
|
||||
}
|
||||
|
||||
// Input / select base (light background)
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select[type="text"] {
|
||||
background: @color-input-bg;
|
||||
color: @color-input-text;
|
||||
}
|
||||
|
||||
select {
|
||||
background: @color-input-bg;
|
||||
color: @color-input-text;
|
||||
}
|
||||
|
||||
// Sheet content inputs & selects — dark text
|
||||
.window-app.sheet .window-content,
|
||||
.application.sheet .window-content {
|
||||
.sheet-header,
|
||||
.sheet-body {
|
||||
select[type="text"],
|
||||
input[type="text"],
|
||||
input[type="number"] {
|
||||
color: @color-text-dark;
|
||||
}
|
||||
|
||||
input[type="password"],
|
||||
input[type="date"],
|
||||
input[type="time"] {
|
||||
color: @color-text-dark;
|
||||
background: @background-image;
|
||||
border: 1 none;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
select {
|
||||
color: @color-text-dark;
|
||||
background: #fff;
|
||||
border: 1 none;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sheet body + window-content background
|
||||
.window-app .window-content,
|
||||
.window-app.sheet .window-content .sheet-body,
|
||||
.application .window-content,
|
||||
.application.sheet .window-content .sheet-body {
|
||||
font-size: 0.8rem;
|
||||
background: @background-image;
|
||||
color: @color-text-dark;
|
||||
}
|
||||
|
||||
section.sheet-body {
|
||||
padding: 0.25rem 0.5rem;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
.sheet {
|
||||
header.sheet-header {
|
||||
.profile-img {
|
||||
object-fit: cover;
|
||||
object-position: 50% 0;
|
||||
margin: 0.5rem 0 0.5rem 0.5rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.flex-compteurs {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.resource-content {
|
||||
width: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
nav.sheet-tabs {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
height: 3rem;
|
||||
flex: 0 0 3rem;
|
||||
margin: 0;
|
||||
padding: 0 0 0 0.25rem;
|
||||
text-align: center;
|
||||
line-height: 1.5rem;
|
||||
border-top: 0 none;
|
||||
border-bottom: 0 none;
|
||||
background-color: @color-nav-bg;
|
||||
color: @color-nav-text;
|
||||
}
|
||||
|
||||
.tab[data-tab] {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 0.010rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
nav.sheet-tabs {
|
||||
a,
|
||||
.item {
|
||||
position: relative;
|
||||
padding: 0 0.25rem;
|
||||
color: @color-nav-text;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 2rem;
|
||||
width: 1px;
|
||||
border-right: 1px dashed rgba(52, 52, 52, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
.window-app.sheet .window-content {
|
||||
.tooltip:hover .tooltiptext {
|
||||
top: 2rem;
|
||||
left: 2rem;
|
||||
margin: 0;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.carac-value,
|
||||
.competence-xp {
|
||||
margin: 0.05rem;
|
||||
flex-basis: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip widget
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.tooltiptext {
|
||||
text-align: left;
|
||||
background: rgba(231, 229, 226, 0.9);
|
||||
width: 150px;
|
||||
padding: 3px 0;
|
||||
font-size: 0.9rem;
|
||||
top: 1px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
&:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-nobottom {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
// Select diff helper
|
||||
.select-diff {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
width: 50px;
|
||||
}
|
||||
156
styles/sidebar.less
Normal file
156
styles/sidebar.less
Normal file
@@ -0,0 +1,156 @@
|
||||
// ============================================================
|
||||
// Sidebar, controls, hotbar, navigation
|
||||
// ============================================================
|
||||
|
||||
#sidebar {
|
||||
font-size: 1rem;
|
||||
background-color: #f5f5f5;
|
||||
background-position: 0px 35px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: @background-image;
|
||||
color: @color-text-dark;
|
||||
|
||||
&.collapsed {
|
||||
height: 470px !important;
|
||||
}
|
||||
|
||||
#sidebar-tabs i {
|
||||
display: inline-block;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar-tabs {
|
||||
flex: 0 0 32px;
|
||||
box-sizing: border-box;
|
||||
margin: 0 0 5px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0);
|
||||
box-shadow: inset 0 0 2rem rgba(0, 0, 0, 0.5);
|
||||
|
||||
> .collapsed,
|
||||
~ .chat-control-icon {
|
||||
color: @color-text-dark;
|
||||
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
> .item.active {
|
||||
border: 1px solid rgba(114, 98, 72, 1);
|
||||
background: rgba(30, 25, 20, 0.75);
|
||||
box-shadow: 0 0 6px inset rgba(114, 98, 72, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar tabs chat control icon
|
||||
#sidebar-tabs > .collapsed,
|
||||
#chat-controls .chat-control-icon {
|
||||
color: @color-text-dark;
|
||||
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
.sidebar-tab .directory-list .entity {
|
||||
border-top: 1px dashed rgba(0, 0, 0, 0.25);
|
||||
border-bottom: 0 none;
|
||||
padding: 0.25rem 0;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
// Controls & tools
|
||||
#controls {
|
||||
.scene-control,
|
||||
.control-tool {
|
||||
box-shadow: 0 0 3px #000;
|
||||
margin: 0 0 8px;
|
||||
border-radius: 0;
|
||||
background: @color-control-dark;
|
||||
background-origin: padding-box;
|
||||
-o-border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
}
|
||||
|
||||
.scene-control.active,
|
||||
.control-tool.active,
|
||||
.scene-control:hover,
|
||||
.control-tool:hover {
|
||||
background: @color-control-warm;
|
||||
background-origin: padding-box;
|
||||
-o-border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
box-shadow: 0 0 3px #ff6400;
|
||||
}
|
||||
}
|
||||
|
||||
// Hotbar
|
||||
#hotbar {
|
||||
#action-bar #macro-list {
|
||||
border: 1px solid @color-control-warm;
|
||||
box-shadow: 2px 2px 5px #000000;
|
||||
}
|
||||
|
||||
#action-bar .macro {
|
||||
-o-border-image: url(img/ui/bg_control.jpg) 21 repeat;
|
||||
border-image: url(img/ui/bg_control.jpg) 21 repeat;
|
||||
border-image-slice: 6 6 6 6 fill;
|
||||
border-image-width: 6px 6px 6px 6px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.bar-controls {
|
||||
background: @color-control-dark;
|
||||
border: 1px solid @color-control-warm;
|
||||
}
|
||||
}
|
||||
|
||||
// Players & navigation
|
||||
#players {
|
||||
-o-border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
background: @color-control-dark;
|
||||
}
|
||||
|
||||
#navigation #scene-list {
|
||||
.scene.nav-item {
|
||||
background: @color-control-dark;
|
||||
background-origin: padding-box;
|
||||
-o-border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
|
||||
&.active {
|
||||
background: @color-control-warm;
|
||||
}
|
||||
}
|
||||
|
||||
.scene.view,
|
||||
.scene.context {
|
||||
background: @color-control-warm;
|
||||
background-origin: padding-box;
|
||||
-o-border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
box-shadow: 0 0 3px #ff6400;
|
||||
}
|
||||
}
|
||||
|
||||
#navigation #nav-toggle {
|
||||
background: @color-control-dark;
|
||||
background-origin: padding-box;
|
||||
-o-border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
}
|
||||
359
styles/ui.less
Normal file
359
styles/ui.less
Normal file
@@ -0,0 +1,359 @@
|
||||
// ============================================================
|
||||
// Generic UI utilities and layout helpers
|
||||
// ============================================================
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul, li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.header-fields li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Alternate list rows
|
||||
.alterne-list {
|
||||
> .list-item:hover {
|
||||
background: rgba(100, 100, 50, 0.25);
|
||||
}
|
||||
> .list-item:nth-child(even) {
|
||||
background: rgba(80, 60, 0, 0.10);
|
||||
}
|
||||
> .list-item:nth-child(odd) {
|
||||
background: rgb(160, 130, 100, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.specialisation-label {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.carac-label,
|
||||
.attr-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
flex: 1 1 5rem;
|
||||
display: flex !important;
|
||||
color: @color-text-dark;
|
||||
}
|
||||
|
||||
.list-item-shadow {
|
||||
background: rgba(87, 60, 32, 0.35);
|
||||
flex-grow: 0;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.list-item-shadow2 {
|
||||
background: rgba(87, 60, 32, 0.25);
|
||||
flex-grow: 0;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.item-display-show { display: block; }
|
||||
.item-display-hide { display: none; }
|
||||
|
||||
.item-quantite {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.list-item-margin1 { margin-left: 1rem; }
|
||||
.list-item-margin2 { margin-left: 2rem; }
|
||||
.list-item-margin3 { margin-left: 3rem; }
|
||||
.list-item-margin4 { margin-left: 4rem; }
|
||||
|
||||
.sheet-competence-img {
|
||||
width: 24px;
|
||||
max-width: 24px;
|
||||
height: 24px;
|
||||
max-height: 24px;
|
||||
flex-grow: 0;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.competence-column {
|
||||
flex-direction: column;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
flex-grow: 0;
|
||||
flex-basis: 1;
|
||||
}
|
||||
|
||||
.competence-header {
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
font-weight: bold;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.description-label {
|
||||
flex-grow: 2;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.status-header-label { margin-left: 2px; }
|
||||
.roll-dialog-label { margin: 4px 0; min-width: 96px; }
|
||||
|
||||
// Select[multiple] in roll dialogs needs explicit height so options are visible
|
||||
.skill-roll-dialog,
|
||||
.confrontation-roll-dialog,
|
||||
.confrontation-start-dialog {
|
||||
select[multiple] {
|
||||
min-height: 60px;
|
||||
height: auto;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.short-label { flex-grow: 1; }
|
||||
.keyword-label { font-size: 0.85rem; }
|
||||
.item-sheet-label { flex-grow: 1; }
|
||||
.item-text-long-line { flex-grow: 3; }
|
||||
|
||||
.score-label {
|
||||
flex-grow: 2;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.attribut-value,
|
||||
.carac-value {
|
||||
flex-grow: 0;
|
||||
flex-basis: 64px;
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.sante-value,
|
||||
.competence-value {
|
||||
flex-grow: 0;
|
||||
flex-basis: 2rem;
|
||||
margin-right: 0.25rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.description-value {
|
||||
flex-grow: 0;
|
||||
flex-basis: 4rem;
|
||||
margin-right: 0.25rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.small-label { margin-top: 5px; }
|
||||
.padd-right { margin-right: 8px; }
|
||||
.padd-left { margin-left: 8px; }
|
||||
|
||||
.stack-left {
|
||||
align-items: center;
|
||||
flex-shrink: 1;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.packed-left {
|
||||
white-space: nowrap;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.input-numeric-short {
|
||||
width: 40px;
|
||||
max-width: 40px;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
flex-basis: 40px;
|
||||
margin-right: 0.25rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.abilities-table {
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
// Image helpers
|
||||
.button-img {
|
||||
vertical-align: baseline;
|
||||
width: 8%;
|
||||
height: 8%;
|
||||
max-height: 48px;
|
||||
border-width: 0px;
|
||||
border: 1px solid rgba(0, 0, 0, 0);
|
||||
|
||||
&:hover {
|
||||
color: rgba(255, 255, 128, 0.7);
|
||||
border: 1px solid rgba(255, 128, 0, 0.8);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.button-effect-img {
|
||||
vertical-align: baseline;
|
||||
width: 16px;
|
||||
max-height: 16px;
|
||||
height: 16;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.small-button-container {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border: 0;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.item-checkbox {
|
||||
height: 25px;
|
||||
border: 1px solid rgba(115, 105, 83, 0.65098);
|
||||
border-left: none;
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
color: black;
|
||||
padding-top: 5px;
|
||||
margin-right: 0px;
|
||||
width: 45px;
|
||||
position: relative;
|
||||
left: 0px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.skill-label { font-size: 0.7rem; }
|
||||
.skill-good-checkbox { max-height: 10px; max-width: 10px; }
|
||||
|
||||
.flex-actions-bar { flex-grow: 2; }
|
||||
|
||||
// Item name / field labels
|
||||
.item-sheet-img {
|
||||
width: 64px;
|
||||
height: auto;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.item-name-img { flex-grow: 1; max-width: 2rem; min-width: 2rem; }
|
||||
.item-name-label-header { flex-grow: 2; max-width: 12rem; min-width: 12rem; }
|
||||
.item-name-label-header-long { flex-grow: 2; max-width: 14rem; min-width: 14rem; }
|
||||
.item-name-label-header-long2 { flex-grow: 2; max-width: 24rem; min-width: 24rem; }
|
||||
.item-name-label { flex-grow: 2; max-width: 10rem; min-width: 10rem; }
|
||||
.item-name-label-long { margin-top: 4px; flex-grow: 2; max-width: 12rem; min-width: 12rem; }
|
||||
.item-name-label-short { margin-top: 4px; flex-grow: 1; max-width: 4rem; min-width: 4rem; }
|
||||
.item-name-label-medium { margin-top: 4px; flex-grow: 2; max-width: 6rem; min-width: 6rem; }
|
||||
.item-name-label-medium2 { margin-top: 4px; flex-grow: 0; max-width: 10rem; min-width: 10rem; }
|
||||
.item-name-label-free { margin-top: 4px; align-self: flex-start; }
|
||||
.item-name-label-long2 { margin-top: 4px; flex-grow: 2; max-width: 22rem; min-width: 22rem; }
|
||||
.item-name-label-level2 { flex-grow: 2; max-width: 9rem; min-width: 9rem; }
|
||||
|
||||
.item-field-label-short { margin-top: 4px; flex-grow: 1; max-width: 4rem; min-width: 4rem; }
|
||||
.item-field-label-short-header { margin-top: 4px; flex-grow: 1; max-width: 2.2rem; min-width: 2.2rem; }
|
||||
.item-field-label-medium { flex-grow: 1; max-width: 6rem; min-width: 6rem; }
|
||||
.item-field-skill { flex-grow: 1; max-width: 6.8rem; min-width: 6.8rem; }
|
||||
.item-field-label-long { flex-grow: 1; max-width: 10rem; min-width: 10rem; }
|
||||
|
||||
.item-control-end { align-self: flex-end; }
|
||||
.alternate-list { margin-top: 4px; flex-wrap: nowrap; }
|
||||
.item-filler { flex-grow: 6; flex-shrink: 7; }
|
||||
.item-controls-fixed { min-width: 2rem; max-width: 2rem; }
|
||||
.item-controls-fixed-full { min-width: 3rem; max-width: 3rem; }
|
||||
.attribute-label { font-weight: bold; }
|
||||
.flexrow-no-expand { flex-grow: 0; }
|
||||
.flexrow-start { justify-content: flex-start; align-content: flex-start; align-self: flex-start; }
|
||||
.item-input-small { max-width: 16px; max-height: 12px; }
|
||||
.character-summary-rollable { text-decoration: underline; }
|
||||
.ul-level1 { padding-left: 2rem; }
|
||||
|
||||
// Impact / confrontation
|
||||
.impact-box {
|
||||
border-width: 2px;
|
||||
border-color: #000000;
|
||||
border-radius: 6px;
|
||||
border: 2px ridge #443307;
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.impact-title {
|
||||
font-size: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.items-title-bg {
|
||||
margin-top: 6px;
|
||||
color: @color-text-dark;
|
||||
}
|
||||
|
||||
.items-title-text {
|
||||
text-align: center;
|
||||
font-family: @font-primary;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.lock-icon { width: 16px; height: 16px; }
|
||||
.img-no-border { max-width: 48px; max-height: 48px; border: 0px; }
|
||||
.no-grow { flex-grow: 1; max-width: 32px; }
|
||||
.status-col-name { max-width: 72px; }
|
||||
.status-small-label { font-size: 0.65rem; }
|
||||
|
||||
.confront-bonus-container {
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.confront-bonus-centered {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
font-size: 1.6rem;
|
||||
color: darkgreen;
|
||||
font-family: @font-primary;
|
||||
transform: translate(-50%, -55%);
|
||||
}
|
||||
|
||||
.dice-spec { max-width: 64px; }
|
||||
.bonus-spec { max-width: 48px; }
|
||||
|
||||
.confront-dice-container {
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.confront-dice-centered {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
font-size: 2rem;
|
||||
color: darkgreen;
|
||||
font-family: @font-primary;
|
||||
transform: translate(-50%, -55%);
|
||||
}
|
||||
|
||||
.confront-area {
|
||||
margin: 2px;
|
||||
padding: 4px;
|
||||
min-height: 64px;
|
||||
border-width: 2px;
|
||||
border-color: #000000;
|
||||
border-radius: 6px;
|
||||
border: 2px ridge #443307;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pool-list {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -108,7 +108,7 @@
|
||||
"secondaryTokenAttribute": "secondary.delirium",
|
||||
"socket": true,
|
||||
"styles": [
|
||||
"styles/ecryme.css"
|
||||
"css/ecryme.css"
|
||||
],
|
||||
"relationships": {
|
||||
"requires": [
|
||||
|
||||
57
templates/actors/actor-biodata.hbs
Normal file
57
templates/actors/actor-biodata.hbs
Normal file
@@ -0,0 +1,57 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="biodata" data-group="primary">
|
||||
|
||||
<div class="grid grid-2col">
|
||||
<div>
|
||||
<ul class="item-list alternate-list">
|
||||
<li class="item flexrow">
|
||||
<label class="item-name-label-medium">{{localize "ECRY.ui.bornplace"}}</label>
|
||||
<input type="text" name="system.biodata.lieunaissance" value="{{system.biodata.lieunaissance}}" />
|
||||
</li>
|
||||
<li class="item flexrow">
|
||||
<label class="item-name-label-medium">{{localize "ECRY.ui.age"}}</label>
|
||||
<input type="text" name="system.biodata.age" value="{{system.biodata.age}}" />
|
||||
</li>
|
||||
<li class="item flexrow">
|
||||
<label class="item-name-label-medium">{{localize "ECRY.ui.profession"}}</label>
|
||||
<input type="text" name="system.biodata.profession" value="{{system.biodata.profession}}" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li class="item flexrow">
|
||||
<label class="item-name-label-medium">{{localize "ECRY.ui.residence"}}</label>
|
||||
<input type="text" name="system.biodata.residence" value="{{system.biodata.residence}}" />
|
||||
</li>
|
||||
<li class="item flexrow">
|
||||
<label class="item-name-label-medium">{{localize "ECRY.ui.origin"}}</label>
|
||||
<input type="text" name="system.biodata.nationalite" value="{{system.biodata.nationalite}}" />
|
||||
</li>
|
||||
<li class="item flexrow">
|
||||
<label class="item-name-label-medium">{{localize "ECRY.ui.childhood"}}</label>
|
||||
<input type="text" name="system.biodata.enfance" value="{{system.biodata.enfance}}" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<span class="item-name-label-header items-title-bg">
|
||||
<h3><label class="items-title-text">{{localize "ECRY.ui.background"}}</label></h3>
|
||||
</span>
|
||||
<div class="form-group editor">
|
||||
{{formInput systemFields.biodata.fields.description enriched=enrichedDescription
|
||||
value=system.biodata.description name="system.biodata.description" toggled=true}}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<span class="item-name-label-header items-title-bg">
|
||||
<h3><label class="items-title-text">{{localize "ECRY.ui.gmnotes"}}</label></h3>
|
||||
</span>
|
||||
<div class="form-group editor">
|
||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enrichedGmnotes
|
||||
value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
</section>
|
||||
42
templates/actors/actor-cephaly.hbs
Normal file
42
templates/actors/actor-cephaly.hbs
Normal file
@@ -0,0 +1,42 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="cephaly" data-group="primary">
|
||||
|
||||
<div class="grid grid-2col">
|
||||
|
||||
<div>
|
||||
<h3>{{localize "ECRY.ui.cephaly"}}</h3>
|
||||
<ul class="stat-list alternate-list item-list">
|
||||
{{#each cephalySkills as |skill skillkey|}}
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-long">
|
||||
<a data-action="rollCephaly" data-skill-key="{{skillkey}}">
|
||||
<i class="fa-solid fa-dice-d6"></i>
|
||||
{{localize skill.name}}
|
||||
</a>
|
||||
</span>
|
||||
<select class="item-field-label-short"
|
||||
name="system.cephaly.skilllist.{{skillkey}}.value">
|
||||
{{selectOptions @root.config.skillLevel selected=skill.value}}
|
||||
</select>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{#if annency.id}}
|
||||
<h3>{{localize "ECRY.ui.annency"}} :
|
||||
<a data-action="openAnnency" data-annency-id="{{annency.id}}">
|
||||
{{annency.name}}<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
</h3>
|
||||
<ul class="stat-list alternate-list item-list">
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-long">{{annency.system.base.description}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
68
templates/actors/actor-combat.hbs
Normal file
68
templates/actors/actor-combat.hbs
Normal file
@@ -0,0 +1,68 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="combat" data-group="primary">
|
||||
|
||||
{{!-- Impacts --}}
|
||||
<div class="flexrow">
|
||||
{{> systems/fvtt-ecryme/templates/actors/partial-impacts.hbs
|
||||
impacts=system.impacts.physical impacttype="physical" impactMalus=impactsMalus.physical}}
|
||||
{{> systems/fvtt-ecryme/templates/actors/partial-impacts.hbs
|
||||
impacts=system.impacts.mental impacttype="mental" impactMalus=impactsMalus.mental}}
|
||||
{{> systems/fvtt-ecryme/templates/actors/partial-impacts.hbs
|
||||
impacts=system.impacts.social impacttype="social" impactMalus=impactsMalus.social}}
|
||||
</div>
|
||||
|
||||
{{!-- Weapons --}}
|
||||
<ul class="item-list alternate-list">
|
||||
<li class="item flexrow list-item items-title-bg">
|
||||
<span class="item-name-label-header-long2">
|
||||
<h3><label class="item-name-label-header-long2">{{localize "ECRY.ui.weapons"}}</label></h3>
|
||||
</span>
|
||||
<span class="item-field-label-medium">
|
||||
<label>{{localize "ECRY.ui.type"}}</label>
|
||||
</span>
|
||||
<span class="item-field-label-medium">
|
||||
<label>{{localize "ECRY.ui.effect"}}</label>
|
||||
</span>
|
||||
</li>
|
||||
{{#each weapons as |weapon key|}}
|
||||
<li class="item flexrow list-item list-item-shadow" data-item-id="{{weapon._id}}">
|
||||
<a data-action="itemEdit" data-item-id="{{weapon._id}}" class="item-name-img" title="{{localize 'ECRY.ui.edit'}}">
|
||||
<img class="sheet-competence-img" src="{{weapon.img}}" />
|
||||
</a>
|
||||
<span class="item-name-label-long2">
|
||||
<a data-action="rollWeaponConfront" data-item-id="{{weapon._id}}">
|
||||
<i class="fa-regular fa-swords"></i>
|
||||
{{weapon.name}}
|
||||
</a>
|
||||
</span>
|
||||
<span class="item-field-label-medium">{{localize (concat "ECRY.ui." weapon.system.weapontype)}}</span>
|
||||
<span class="item-field-label-medium">{{weapon.system.effect}}</span>
|
||||
<div class="item-filler"> </div>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemDelete" data-item-id="{{weapon._id}}" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
{{!-- Maneuvers --}}
|
||||
<ul class="item-list alternate-list">
|
||||
<li class="item flexrow list-item items-title-bg">
|
||||
<span class="item-name-label-header-long2">
|
||||
<h3><label class="item-name-label-header-long2">{{localize "ECRY.ui.maneuvers"}}</label></h3>
|
||||
</span>
|
||||
</li>
|
||||
{{#each maneuvers as |maneuver key|}}
|
||||
<li class="item flexrow list-item list-item-shadow" data-item-id="{{maneuver._id}}">
|
||||
<a data-action="itemEdit" data-item-id="{{maneuver._id}}" class="item-name-img" title="{{localize 'ECRY.ui.edit'}}">
|
||||
<img class="sheet-competence-img" src="{{maneuver.img}}" />
|
||||
</a>
|
||||
<span class="item-name-label-long2">{{maneuver.name}}</span>
|
||||
<div class="item-filler"> </div>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemDelete" data-item-id="{{maneuver._id}}" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
40
templates/actors/actor-equipements.hbs
Normal file
40
templates/actors/actor-equipements.hbs
Normal file
@@ -0,0 +1,40 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="equipements" data-group="primary">
|
||||
|
||||
{{!-- Free equipment (plain text area) --}}
|
||||
<span class="item-name-label-header items-title-bg">
|
||||
<h3><label class="items-title-text">{{localize "ECRY.ui.equipmentfree"}}</label></h3>
|
||||
</span>
|
||||
<div class="form-group small-editor">
|
||||
<textarea name="system.equipmentfree" rows="4">{{system.equipmentfree}}</textarea>
|
||||
</div>
|
||||
|
||||
{{!-- Equipment list --}}
|
||||
<ul class="item-list alternate-list">
|
||||
<li class="item flexrow list-item items-title-bg">
|
||||
<span class="item-name-label-header">
|
||||
<h3><label class="items-title-text">{{localize "ECRY.ui.equipment"}}s</label></h3>
|
||||
</span>
|
||||
<span class="item-field-label-medium">
|
||||
<label>{{localize "ECRY.ui.weight"}}</label>
|
||||
</span>
|
||||
<div class="item-filler"> </div>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemCreate" data-type="equipment" title="{{localize 'ECRY.ui.create'}}"><i class="fas fa-plus"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{#each equipments as |equip key|}}
|
||||
<li class="item list-item flexrow list-item-shadow" data-item-id="{{equip._id}}">
|
||||
<a data-action="itemEdit" data-item-id="{{equip._id}}" class="item-name-img" title="{{localize 'ECRY.ui.edit'}}">
|
||||
<img class="sheet-competence-img" src="{{equip.img}}" />
|
||||
</a>
|
||||
<span class="item-name-label">{{equip.name}}</span>
|
||||
<span class="item-field-label-medium">{{equip.system.weight}}</span>
|
||||
<div class="item-filler"> </div>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemDelete" data-item-id="{{equip._id}}" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
70
templates/actors/actor-skills.hbs
Normal file
70
templates/actors/actor-skills.hbs
Normal file
@@ -0,0 +1,70 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="skills" data-group="primary">
|
||||
|
||||
<div class="grid grid-3col">
|
||||
|
||||
{{#each skills as |category categkey|}}
|
||||
<div>
|
||||
<ul class="stat-list alternate-list item-list">
|
||||
<li class="item flexrow list-item items-title-bg">
|
||||
<span class="item-name-label-header impact-title">
|
||||
<h3>
|
||||
{{#if (eq @root.type "npc")}}
|
||||
<a data-action="rollSkillConfront" data-category-key="{{categkey}}" data-skill-key="rawnpc">
|
||||
<i class="fa-regular fa-swords"></i>
|
||||
</a>
|
||||
<a data-action="rollSkill" data-category-key="{{categkey}}" data-skill-key="rawnpc">
|
||||
<i class="fa-solid fa-dice-d6"></i>
|
||||
{{/if}}
|
||||
<label class="items-title-text">{{localize category.name}} ({{valueAtIndex @root.impactsMalus categkey}})</label>
|
||||
{{#if (eq @root.type "npc")}}
|
||||
</a>
|
||||
<select class="item-field-label-short-header"
|
||||
name="system.skills.{{categkey}}.pnjvalue">
|
||||
{{selectOptions @root.config.skillLevel selected=category.pnjvalue}}
|
||||
</select>
|
||||
{{/if}}
|
||||
</h3>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
{{#each category.skilllist as |skill skillkey|}}
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-long">
|
||||
<a data-action="rollSkillConfront" data-category-key="{{categkey}}" data-skill-key="{{skillkey}}">
|
||||
<i class="fa-regular fa-swords"></i>
|
||||
</a>
|
||||
<a data-action="rollSkill" data-category-key="{{categkey}}" data-skill-key="{{skillkey}}">
|
||||
<i class="fa-solid fa-dice-d6"></i>
|
||||
{{localize skill.name}}
|
||||
</a>
|
||||
</span>
|
||||
<select class="item-field-label-short"
|
||||
name="system.skills.{{categkey}}.skilllist.{{skillkey}}.value">
|
||||
{{selectOptions @root.config.skillLevel selected=skill.value}}
|
||||
</select>
|
||||
</li>
|
||||
<li class="item flexrow list-item">
|
||||
<ul class="ul-level1">
|
||||
{{#each skill.spec as |spec idx|}}
|
||||
<li class="item flexrow list-item" data-item-id="{{spec._id}}" data-item-type="specialization">
|
||||
<a data-action="rollSpec" data-category-key="{{categkey}}" data-skill-key="{{skillkey}}" data-spec-id="{{spec._id}}">
|
||||
<i class="fa-solid fa-dice-d6"></i>
|
||||
{{spec.name}}
|
||||
</a>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemEdit" data-item-id="{{spec._id}}" title="{{localize 'ECRY.ui.edit'}}"><i class="fas fa-edit"></i></a>
|
||||
<a data-action="itemDelete" data-item-id="{{spec._id}}" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</li>
|
||||
{{/each}}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
30
templates/actors/actor-traits.hbs
Normal file
30
templates/actors/actor-traits.hbs
Normal file
@@ -0,0 +1,30 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="traits" data-group="primary">
|
||||
|
||||
<ul class="item-list alternate-list">
|
||||
<li class="item flexrow list-item items-title-bg">
|
||||
<span class="item-name-label-header-long2">
|
||||
<h3><label class="item-name-label-header-long2">{{localize "ECRY.ui.traits"}}</label></h3>
|
||||
</span>
|
||||
<span class="item-field-label-short">
|
||||
<label>{{localize "ECRY.ui.level"}}</label>
|
||||
</span>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemCreate" data-type="trait" title="{{localize 'ECRY.ui.create'}}"><i class="fas fa-plus"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{#each traits as |trait key|}}
|
||||
<li class="item flexrow list-item list-item-shadow" data-item-id="{{trait._id}}">
|
||||
<a data-action="itemEdit" data-item-id="{{trait._id}}" class="item-name-img" title="{{localize 'ECRY.ui.edit'}}">
|
||||
<img class="sheet-competence-img" src="{{trait.img}}" />
|
||||
</a>
|
||||
<span class="item-name-label-long2">{{trait.name}}</span>
|
||||
<span class="item-field-label-short"><label>{{trait.system.level}}</label></span>
|
||||
<div class="item-filler"> </div>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemDelete" data-item-id="{{trait._id}}" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
50
templates/actors/annency-annency.hbs
Normal file
50
templates/actors/annency-annency.hbs
Normal file
@@ -0,0 +1,50 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="annency" data-group="primary">
|
||||
|
||||
<div class="grid grid-2col">
|
||||
|
||||
<div>
|
||||
<h3>{{localize "ECRY.ui.annency"}}</h3>
|
||||
<ul class="stat-list alternate-list item-list">
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-short">{{localize "ECRY.ui.iscollective"}}</span>
|
||||
<input type="checkbox" name="system.base.iscollective" {{checked system.base.iscollective}} />
|
||||
<span class="item-name-label-short">{{localize "ECRY.ui.ismultiple"}}</span>
|
||||
<input type="checkbox" name="system.base.ismultiple" {{checked system.base.ismultiple}} />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>{{localize "ECRY.ui.characters"}}</h3>
|
||||
<ul class="stat-list alternate-list item-list">
|
||||
{{#each characters as |character id|}}
|
||||
<li class="item flexrow" data-actor-id="{{character.id}}">
|
||||
<img class="item-name-img" src="{{character.img}}" />
|
||||
<span class="item-name-label">{{character.name}}</span>
|
||||
<div class="item-filler"> </div>
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="actorEdit" title="{{localize 'ECRY.ui.edit'}}"><i class="fas fa-edit"></i></a>
|
||||
<a data-action="actorDelete" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>{{localize "ECRY.ui.location"}}</h3>
|
||||
<ul class="stat-list alternate-list item-list">
|
||||
{{#each system.base.location as |location index|}}
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-medium">{{localize "ECRY.ui.location"}} {{index}}</span>
|
||||
<textarea rows="3" name="system.base.location.{{index}}">{{location}}</textarea>
|
||||
</li>
|
||||
{{/each}}
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-medium">{{localize "ECRY.ui.enhancements"}}</span>
|
||||
<textarea rows="3" name="system.base.enhancements">{{system.base.enhancements}}</textarea>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
23
templates/actors/annency-boheme.hbs
Normal file
23
templates/actors/annency-boheme.hbs
Normal file
@@ -0,0 +1,23 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="boheme" data-group="primary">
|
||||
|
||||
<h3>{{localize "ECRY.ui.oniricform"}}</h3>
|
||||
<ul class="stat-list alternate-list item-list">
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-medium">{{localize "ECRY.ui.name"}}</span>
|
||||
<input type="text" name="system.boheme.name" value="{{system.boheme.name}}" />
|
||||
</li>
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-medium">{{localize "ECRY.ui.ideals"}}</span>
|
||||
<input type="text" name="system.boheme.ideals" value="{{system.boheme.ideals}}" />
|
||||
</li>
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-medium">{{localize "ECRY.ui.politic"}}</span>
|
||||
<input type="text" name="system.boheme.politic" value="{{system.boheme.politic}}" />
|
||||
</li>
|
||||
<li class="item flexrow list-item">
|
||||
<span class="item-name-label-medium">{{localize "ECRY.ui.description"}}</span>
|
||||
<textarea rows="3" name="system.boheme.description">{{system.boheme.description}}</textarea>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
@@ -8,9 +8,9 @@
|
||||
{{#each impacts as |value key|}}
|
||||
<li class="flexrow" data-impact-type="{{../impacttype}}">
|
||||
<span class="item-field-label-medium"><label>{{localize (concat "ECRY.ui." key)}}</label></span>
|
||||
<a class="impact-modify" data-impact-modifier="+1" data-impact-type="{{../impacttype}}" data-impact-level="{{key}}"><i class="fas fa-plus-square"></i></a>
|
||||
<a data-action="impactModify" data-impact-modifier="+1" data-impact-type="{{../impacttype}}" data-impact-level="{{key}}"><i class="fas fa-plus-square"></i></a>
|
||||
<span class="">{{value}}</span>
|
||||
<a class="impact-modify" data-impact-modifier="-1" data-impact-type="{{../impacttype}}" data-impact-level="{{key}}"><i class="fas fa-minus-square"></i></a>
|
||||
<a data-action="impactModify" data-impact-modifier="-1" data-impact-type="{{../impacttype}}" data-impact-level="{{key}}"><i class="fas fa-minus-square"></i></a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
51
templates/actors/partials/actor-header.hbs
Normal file
51
templates/actors/partials/actor-header.hbs
Normal file
@@ -0,0 +1,51 @@
|
||||
<header class="sheet-header flexrow">
|
||||
<img class="profile-img" src="{{img}}" data-action="editImage" data-edit="img" title="{{name}}" />
|
||||
<div class="header-fields flexcol">
|
||||
<h1 class="charname">
|
||||
<input name="name" type="text" value="{{name}}" placeholder="Name" />
|
||||
</h1>
|
||||
{{#if (eq type "annency")}}
|
||||
{{!-- Annency header: description --}}
|
||||
<div class="flexrow">
|
||||
<label class="item-name-label-medium">{{localize "ECRY.ui.description"}} :</label>
|
||||
<textarea rows="3" name="system.base.description">{{system.base.description}}</textarea>
|
||||
</div>
|
||||
{{else}}
|
||||
{{!-- PC/NPC header: spleen, ideal, traits (rows always visible, controls conditional on item existence) --}}
|
||||
<div class="flexrow actor-header-traits">
|
||||
<ul>
|
||||
<li class="flexrow item" data-item-id="{{spleen._id}}">
|
||||
<label class="item-field-label-short">{{localize "ECRY.ui.spleen"}} :</label>
|
||||
<label class="item-name-label-long">{{spleen.name}}</label>
|
||||
<div class="item-filler"> </div>
|
||||
{{#if spleen}}
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemEdit" data-item-id="{{spleen._id}}" title="{{localize 'ECRY.ui.edit'}}"><i class="fas fa-edit"></i></a>
|
||||
<a data-action="itemDelete" data-item-id="{{spleen._id}}" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</li>
|
||||
<li class="item flexrow" data-item-id="{{ideal._id}}">
|
||||
<label class="item-field-label-short">{{localize "ECRY.ui.ideal"}} :</label>
|
||||
<label class="item-name-label-long">{{ideal.name}}</label>
|
||||
<div class="item-filler"> </div>
|
||||
{{#if ideal}}
|
||||
<div class="item-controls item-controls-fixed">
|
||||
<a data-action="itemEdit" data-item-id="{{ideal._id}}" title="{{localize 'ECRY.ui.edit'}}"><i class="fas fa-edit"></i></a>
|
||||
<a data-action="itemDelete" data-item-id="{{ideal._id}}" title="{{localize 'ECRY.ui.delete'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</li>
|
||||
<li class="item flexrow flexrow-no-expand flexrow-start">
|
||||
<label class="item-name-label-short">{{localize "ECRY.ui.traits"}} :</label>
|
||||
{{#each traits as |trait key|}}
|
||||
<label class="item-name-label-free">
|
||||
<a data-action="itemEdit" data-item-id="{{trait._id}}">{{trait.name}}</a>{{#unless @last}}, {{/unless}}
|
||||
</label>
|
||||
{{/each}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</header>
|
||||
@@ -5,33 +5,30 @@
|
||||
<h4 class="chat-actor-name">{{alias}}</h4>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="ecryme-chat-body">
|
||||
|
||||
{{#if img}}
|
||||
<div>
|
||||
<img class="chat-icon" src="{{img}}" alt="{{alias}}" />
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if img}}
|
||||
<div class="ecryme-chat-icon-row">
|
||||
<img class="chat-icon" src="{{img}}" alt="{{alias}}" />
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<ul>
|
||||
<li>{{localize "ECRY.ui.cephaly"}} : {{localize skill.name}}</li>
|
||||
<li>{{localize "ECRY.ui.cephaly"}} : <strong>{{localize skill.name}}</strong></li>
|
||||
|
||||
{{#if annency}}
|
||||
<li>{{localize "ECRY.ui.annencybonus"}} {{annency.name}}: {{annencyBonus}}</li>
|
||||
<li>{{localize "ECRY.ui.annencybonus"}} {{annency.name}}: <strong>{{annencyBonus}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt marginExecution 0)}}
|
||||
<li>{{localize "ECRY.ui.execution"}} {{executionTotal}} vs {{difficulty}} : {{marginExecution}}</li>
|
||||
<li>{{localize cephalySuccess}}</li>
|
||||
<li>{{localize "ECRY.ui.execution"}} {{executionTotal}} vs {{difficulty}} : <strong>{{marginExecution}}</strong></li>
|
||||
<li class="ecryme-result-line"><label class="chat-result-text chat-result-success">{{localize cephalySuccess}}</label></li>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt marginPreservation 0)}}
|
||||
<li>{{localize "ECRY.ui.preservation"}} {{preservationTotal}} vs {{difficulty}} : {{marginPreservation}}</li>
|
||||
<li>{{localize cephalyFailure}}</li>
|
||||
<li>{{localize "ECRY.ui.preservation"}} {{preservationTotal}} vs {{difficulty}} : <strong>{{marginPreservation}}</strong></li>
|
||||
<li class="ecryme-result-line"><label class="chat-result-text chat-result-failure">{{localize cephalyFailure}}</label></li>
|
||||
{{/if}}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -5,52 +5,50 @@
|
||||
<h4 class="chat-actor-name">{{alias}}</h4>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="ecryme-chat-body">
|
||||
|
||||
{{#if img}}
|
||||
<div>
|
||||
<img class="chat-icon" src="{{img}}" alt="{{alias}}" />
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if img}}
|
||||
<div class="ecryme-chat-icon-row">
|
||||
<img class="chat-icon" src="{{img}}" alt="{{alias}}" />
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<ul>
|
||||
{{#if (eq mode "cephaly")}}
|
||||
<li>{{localize "ECRY.ui.cephaly"}} : {{localize skill.name}} </li>
|
||||
<li>{{localize "ECRY.ui.cephaly"}} : <strong>{{localize skill.name}}</strong></li>
|
||||
{{else}}
|
||||
<li>Confrontation : {{alias}} </li>
|
||||
<li>Confrontation : <strong>{{alias}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
<li>{{localize skill.name}}: {{skill.value}} </li>
|
||||
<li>{{localize skill.name}}: <strong>{{skill.value}}</strong></li>
|
||||
{{#if spec}}
|
||||
<li>{{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}}) </li>
|
||||
<li>{{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}})</li>
|
||||
{{/if}}
|
||||
|
||||
{{#each traitsBonus as |trait idx|}}
|
||||
{{#if trait.activated}}
|
||||
<li>{{localize "ECRY.chat.traitbonus"}}: {{trait.name}} ({{trait.system.level}}) </li>
|
||||
<li>{{localize "ECRY.chat.traitbonus"}}: <strong>{{trait.name}}</strong> ({{trait.system.level}})</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#each traitsMalus as |trait idx|}}
|
||||
{{#if trait.activated}}
|
||||
<li>{{localize "ECRY.chat.traitmalus"}}: {{trait.name}} ({{trait.system.level}}) </li>
|
||||
<li>{{localize "ECRY.chat.traitmalus"}}: <strong>{{trait.name}}</strong> ({{trait.system.level}})</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#if bonusMalusTraits}}
|
||||
<li>{{localize "ECRY.chat.bonusmalustraits"}}: {{bonusMalusTraits}} </li>
|
||||
<li>{{localize "ECRY.chat.bonusmalustraits"}}: <strong>{{bonusMalusTraits}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
{{#if (isGM)}}
|
||||
{{else}}
|
||||
<li>{{localize "ECRY.ui.execution"}} : {{executionTotal}}</li>
|
||||
<li>{{localize "ECRY.ui.preservation"}} : {{preservationTotal}}</li>
|
||||
<li>{{localize "ECRY.ui.execution"}} : <strong>{{executionTotal}}</strong></li>
|
||||
<li>{{localize "ECRY.ui.preservation"}} : <strong>{{preservationTotal}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
</ul>
|
||||
|
||||
{{#if (isGM)}}
|
||||
{{#if (eq mode "cephaly")}}
|
||||
<div>
|
||||
<div class="ecryme-chat-gm-row">
|
||||
<span>{{localize "ECRY.chat.difficulty"}}</span>
|
||||
<select id="{{rollId}}-cephaly-difficulty" name="cephaly-difficulty">
|
||||
{{#for 1 20 1}}
|
||||
@@ -58,15 +56,12 @@
|
||||
{{/for}}
|
||||
</select>
|
||||
</div>
|
||||
<button class="button-apply-cephaly-difficulty">{{localize "ECRY.ui.cephalydifficulty"}}</button>
|
||||
<button class="chat-card-button button-apply-cephaly-difficulty">{{localize "ECRY.ui.cephalydifficulty"}}</button>
|
||||
{{else}}
|
||||
<button class="button-select-confront">{{localize "ECRY.ui.selectconfront"}}</button>
|
||||
<button class="chat-card-button button-select-confront">{{localize "ECRY.ui.selectconfront"}}</button>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div>
|
||||
{{localize "ECRY.chat.sentogm"}}
|
||||
</div>
|
||||
<p class="ecryme-chat-sent-gm">{{localize "ECRY.chat.sentogm"}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -2,53 +2,60 @@
|
||||
{{#if actorImg}}
|
||||
<img class="actor-icon" src="{{actorImg}}" alt="{{alias}}" />
|
||||
{{/if}}
|
||||
<h4 class="chat-actor-name">{{alias}}</h4>
|
||||
<div class="flexcol">
|
||||
<h4 class="chat-actor-name">{{alias}}</h4>
|
||||
<span class="chat-actor-subtitle">{{localize "ECRY.ui.confrontresult"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="ecryme-chat-body">
|
||||
|
||||
{{#if img}}
|
||||
<div>
|
||||
<img class="chat-icon" src="{{img}}" alt="{{alias}}" />
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<ul>
|
||||
<li><strong>Confrontation</strong> : {{rollData1.alias}} vs {{rollData2.alias}}</li>
|
||||
<li>{{localize rollData1.skill.name}} ({{rollData1.skill.value}}) vs {{localize rollData2.skill.name}} ({{rollData2.skill.value}}) </li>
|
||||
<li>{{rollData1.executionTotal}} vs {{rollData2.preservationTotal}} : {{marginExecution}}</li>
|
||||
<li>{{rollData1.preservationTotal}} vs {{rollData2.executionTotal}} : {{marginPreservation}}</li>
|
||||
<li>{{localize rollData1.skill.name}} ({{rollData1.skill.value}}) vs {{localize rollData2.skill.name}} ({{rollData2.skill.value}})</li>
|
||||
<li>{{localize "ECRY.ui.execution"}} : {{rollData1.executionTotal}} vs {{rollData2.preservationTotal}} → <strong>{{marginExecution}}</strong></li>
|
||||
<li>{{localize "ECRY.ui.preservation"}} : {{rollData1.preservationTotal}} vs {{rollData2.executionTotal}} → <strong>{{marginPreservation}}</strong></li>
|
||||
|
||||
{{#if rollData1.weapon}}
|
||||
<li>{{rollData1.alias}} {{rollData1.weapon.name}} ({{rollData1.weapon.system.effect}})
|
||||
</li>
|
||||
<li>{{rollData1.alias}} — {{rollData1.weapon.name}} ({{rollData1.weapon.system.effect}})</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if rollData2.weapon}}
|
||||
<li>{{rollData2.alias}} {{rollData2.weapon.name}} ({{rollData2.weapon.system.effect}})</li>
|
||||
<li>{{rollData2.alias}} — {{rollData2.weapon.name}} ({{rollData2.weapon.system.effect}})</li>
|
||||
{{/if}}
|
||||
|
||||
<li>{{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.execution"}} : {{effectExecution}}</li>
|
||||
<li>{{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.execution"}} : <strong>{{effectExecution}}</strong></li>
|
||||
{{#if impactExecution}}
|
||||
<li>Impact {{rollData2.alias}} : 1 {{localize (concat "ECRY.ui." impactExecution)}}</li>
|
||||
<button class="button-apply-impact" data-token-id="{{rollData2.tokenId}}" data-actor-id="{{rollData2.actorId}}" data-impact-type={{rollData1.skill.categKey}} data-impact="{{impactExecution}}">{{localize "ECRY.ui.applyimpact"}}</button>
|
||||
<button class="chat-card-button button-apply-impact"
|
||||
data-token-id="{{rollData2.tokenId}}"
|
||||
data-actor-id="{{rollData2.actorId}}"
|
||||
data-impact-type={{rollData1.skill.categKey}}
|
||||
data-impact="{{impactExecution}}">{{localize "ECRY.ui.applyimpact"}}</button>
|
||||
{{/if}}
|
||||
{{#if bonus2}}
|
||||
<li>Bonus {{rollData2.alias}} : {{bonus2}}</li>
|
||||
<button class="button-apply-bonus" data-token-id="{{rollData2.tokenId}}" data-actor-id="{{rollData2.actorId}}" data-bonus="{{bonus2}}">{{localize "ECRY.ui.applybonus"}}</button>
|
||||
<li>Bonus {{rollData2.alias}} : <strong>{{bonus2}}</strong></li>
|
||||
<button class="chat-card-button button-apply-bonus"
|
||||
data-token-id="{{rollData2.tokenId}}"
|
||||
data-actor-id="{{rollData2.actorId}}"
|
||||
data-bonus="{{bonus2}}">{{localize "ECRY.ui.applybonus"}}</button>
|
||||
{{/if}}
|
||||
|
||||
<li>{{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.preservation"}} : {{effectPreservation}}</li>
|
||||
<li>{{localize "ECRY.ui.effect"}} {{localize "ECRY.ui.preservation"}} : <strong>{{effectPreservation}}</strong></li>
|
||||
{{#if impactPreservation}}
|
||||
<li>Impact {{rollData1.alias}} : 1 {{localize (concat "ECRY.ui." impactPreservation)}}</li>
|
||||
<button class="button-apply-impact" data-token-id="{{rollData1.tokenId}}" data-actor-id="{{rollData1.actorId}}" data-impact-type={{rollData1.skill.categKey}} data-impact="{{impactPreservation}}">{{localize "ECRY.ui.applyimpact"}}</button>
|
||||
<button class="chat-card-button button-apply-impact"
|
||||
data-token-id="{{rollData1.tokenId}}"
|
||||
data-actor-id="{{rollData1.actorId}}"
|
||||
data-impact-type={{rollData1.skill.categKey}}
|
||||
data-impact="{{impactPreservation}}">{{localize "ECRY.ui.applyimpact"}}</button>
|
||||
{{/if}}
|
||||
{{#if bonus1}}
|
||||
<li>Bonus {{rollData1.alias}} : {{bonus1}}</li>
|
||||
<button class="button-apply-bonus" data-token-id="{{rollData1.tokenId}}" data-actor-id="{{rollData1.actorId}}" data-bonus="{{bonus1}}">{{localize "ECRY.ui.applybonus"}}</button>
|
||||
<li>Bonus {{rollData1.alias}} : <strong>{{bonus1}}</strong></li>
|
||||
<button class="chat-card-button button-apply-bonus"
|
||||
data-token-id="{{rollData1.tokenId}}"
|
||||
data-actor-id="{{rollData1.actorId}}"
|
||||
data-bonus="{{bonus1}}">{{localize "ECRY.ui.applybonus"}}</button>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -5,61 +5,55 @@
|
||||
<h4 class="chat-actor-name">{{alias}}</h4>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="ecryme-chat-body">
|
||||
|
||||
{{#if img}}
|
||||
<div >
|
||||
<div class="ecryme-chat-icon-row">
|
||||
<img class="chat-icon" src="{{img}}" alt="{{name}}" />
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="flexcol">
|
||||
</div>
|
||||
<ul>
|
||||
{{#if skill}}
|
||||
<li>{{localize skill.name}}: <strong>{{skill.value}}</strong></li>
|
||||
{{#if spec}}
|
||||
<li>{{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}})</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<ul>
|
||||
{{#if skill}}
|
||||
<li>{{localize skill.name}}: {{skill.value}} </li>
|
||||
{{#if spec}}
|
||||
<li>{{localize "ECRY.chat.specialization"}} {{spec.name}} (+{{spec.system.bonus}}) </li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if impactMalus}}
|
||||
<li>{{localize "ECRY.ui.impactmalus"}}: <strong>{{impactMalus}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
{{#if impactMalus}}
|
||||
<li>{{localize "ECRY.ui.impactmalus"}}: {{impactMalus}} </li>
|
||||
{{/if}}
|
||||
{{#if skillTranscendence}}
|
||||
<li>{{localize "ECRY.ui.skilltranscendence"}}: <strong>{{skillTranscendence}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
{{#if skillTranscendence}}
|
||||
<li>{{localize "ECRY.ui.skilltranscendence"}}: {{skillTranscendence}} </li>
|
||||
{{/if}}
|
||||
{{#if traitsBonusList}}
|
||||
{{#each traitsBonusList as |trait idx|}}
|
||||
<li>{{localize "ECRY.chat.traitbonus"}}: <strong>{{trait.name}}</strong> ({{trait.system.level}})</li>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if traitsMalusList}}
|
||||
{{#each traitsMalusList as |trait idx|}}
|
||||
<li>{{localize "ECRY.chat.traitmalus"}}: <strong>{{trait.name}}</strong> ({{trait.system.level}})</li>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if bonusMalusTraits}}
|
||||
<li>{{localize "ECRY.chat.bonusmalustraits"}}: <strong>{{bonusMalusTraits}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
{{#if traitsBonusList}}
|
||||
{{#each traitsBonusList as |trait idx|}}
|
||||
<li>{{localize "ECRY.chat.traitbonus"}}: {{trait.name}} ({{trait.system.level}}) </li>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if traitsMalusList}}
|
||||
{{#each traitsMalusList as |trait idx|}}
|
||||
<li>{{localize "ECRY.chat.traitmalus"}}: {{trait.name}} ({{trait.system.level}}) </li>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if bonusMalusTraits}}
|
||||
<li>{{localize "ECRY.chat.bonusmalustraits"}}: {{bonusMalusTraits}} </li>
|
||||
{{/if}}
|
||||
<li>{{localize "ECRY.chat.formula"}}: <strong>{{diceFormula}}</strong></li>
|
||||
<li>{{localize "ECRY.chat.dicesum"}}: <strong>{{diceSum}}</strong></li>
|
||||
<li>{{localize "ECRY.chat.result"}}: <strong>{{total}}</strong></li>
|
||||
{{#if difficulty}}
|
||||
<li>{{localize "ECRY.chat.difficulty"}}: {{difficulty}} — {{localize "ECRY.chat.margin"}}: <strong>{{margin}}</strong></li>
|
||||
{{#if isSuccess}}
|
||||
<li class="ecryme-result-line"><label class="chat-result-text chat-result-success">{{localize "ECRY.chat.success"}}</label></li>
|
||||
{{else}}
|
||||
<li class="ecryme-result-line"><label class="chat-result-text chat-result-failure">{{localize "ECRY.chat.failure"}}</label></li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
<li>{{localize "ECRY.chat.formula"}}: {{diceFormula}} </li>
|
||||
<li>{{localize "ECRY.chat.dicesum"}}: {{diceSum}} </li>
|
||||
<li>{{localize "ECRY.chat.result"}}: {{total}} </li>
|
||||
{{#if difficulty}}
|
||||
<li>{{localize "ECRY.chat.difficulty"}}: {{difficulty}} - {{localize "ECRY.chat.margin"}}: {{margin}} </li>
|
||||
{{#if isSuccess}}
|
||||
<li><label class="chat-result-text chat-result-success ">{{localize "ECRY.chat.success"}}</label></li>
|
||||
{{else}}
|
||||
<li><label class="chat-result-text chat-result-failure">{{localize "ECRY.chat.failure"}}</label></li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<form class="confrontation-roll-dialog">
|
||||
<div class="confrontation-roll-dialog">
|
||||
<header class="roll-dialog-header">
|
||||
{{#if img}}
|
||||
<img class="actor-icon" src="{{img}}" data-edit="img" title="{{name}}" />
|
||||
<img class="actor-icon" src="{{img}}" title="{{name}}" />
|
||||
{{/if}}
|
||||
<h1 class="dialog-roll-title roll-dialog-header">{{title}} ({{skill.value}})</h1>
|
||||
</header>
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="flexrow">
|
||||
|
||||
<div>
|
||||
<h3>{{localize "ECRY.ui.execution"}} : <span id="execution-total">{{executionTotal}}</span> </h3>
|
||||
<h3>{{localize "ECRY.ui.execution"}} : <span id="execution-total">{{executionTotal}}</span></h3>
|
||||
<div id="confront-execution" class="flexrow confront-area confront-execution-area">
|
||||
{{> systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs filter="execution"}}
|
||||
{{> systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs filter="execution"}}
|
||||
@@ -54,13 +54,13 @@
|
||||
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">{{localize "ECRY.ui.skilltranscendence"}} : </span>
|
||||
<select class="" id="roll-select-transcendence" data-type="Number">
|
||||
<select id="roll-select-transcendence" data-type="Number">
|
||||
{{selectOptions config.skillLevel selected=skillTranscendence}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">{{localize "ECRY.ui.transcendapply"}} : </span>
|
||||
<select class="" id="roll-apply-transcendence" data-type="String">
|
||||
<select id="roll-apply-transcendence" data-type="String">
|
||||
{{selectOptions config.transcendanceOptions selected=applyTranscendence localize=true}}
|
||||
</select>
|
||||
</div>
|
||||
@@ -68,9 +68,9 @@
|
||||
{{#if skill.spec}}
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">{{localize "ECRY.ui.spec"}} : </span>
|
||||
<select class="" id="roll-specialization" data-type="String" multiple>
|
||||
<select id="roll-specialization" data-type="String" multiple>
|
||||
{{#each skill.spec as |spec idx|}}
|
||||
<option value="{{spec.id}}" {{#if (eq spec.name @root.spec.name)}}selected{{/if}}>{{spec.name}}</option>
|
||||
<option value="{{spec.id}}" {{#if (eq spec.name @root.spec.name)}}selected{{/if}}>{{spec.name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">{{localize "ECRY.ui.traitbonus"}} : </span>
|
||||
<select class="" id="roll-trait-bonus" data-type="String" multiple>
|
||||
<select id="roll-trait-bonus" data-type="String" multiple>
|
||||
{{#each traitsBonus as |trait idx|}}
|
||||
<option value="{{trait._id}}" {{#if trait.activated}}selected{{/if}}>{{trait.name}} ({{trait.system.level}})</option>
|
||||
{{/each}}
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">{{localize "ECRY.ui.traitmalus"}} : </span>
|
||||
<select class="" id="roll-trait-malus" data-type="String" multiple>
|
||||
<select id="roll-trait-malus" data-type="String" multiple>
|
||||
{{#each traitsMalus as |trait idx|}}
|
||||
<option value="{{trait._id}}" {{#if trait.activated}}selected{{/if}}>{{trait.name}} ({{trait.system.level}})</option>
|
||||
{{/each}}
|
||||
@@ -101,25 +101,32 @@
|
||||
</div>
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">{{localize "ECRY.ui.annencybonus"}}</span>
|
||||
<select class="" id="annency-bonus" name="annencyBonus" data-type="String">
|
||||
<option value="0">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>
|
||||
<select id="annency-bonus" name="annencyBonus" data-type="String">
|
||||
<option value="0">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>
|
||||
</select>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">Bonus/Malus : </span>
|
||||
<select id="bonusMalusPerso" name="bonusMalusPerso" type="text" data-dtype="String">
|
||||
<select id="bonusMalusPerso" name="bonusMalusPerso" data-dtype="String">
|
||||
{{selectOptions config.bonusMalusPersoOptions selected=bonusMalusPerso labelAttr="label"}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<footer class="sheet-footer flexrow">
|
||||
<button type="button" data-action="launchConfront" {{#if buttonDisabled}}disabled{{/if}}>
|
||||
<i class="fas fa-check"></i> {{localize "ECRY.ui.launchconfront"}}
|
||||
</button>
|
||||
<button type="button" data-action="cancel">
|
||||
<i class="fas fa-times"></i> {{localize "ECRY.ui.cancel"}}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
<form class="confrontation-roll-dialog">
|
||||
<header class="roll-dialog-header">
|
||||
<div class="confrontation-start-dialog">
|
||||
<div class="flexrow roll-dialog-header">
|
||||
{{#if img}}
|
||||
<img class="actor-icon" src="{{img}}" data-edit="img" title="{{name}}" />
|
||||
<img class="actor-icon" src="{{img}}" title="{{name}}" />
|
||||
{{/if}}
|
||||
<h1 class="dialog-roll-title roll-dialog-header">{{title}}</h1>
|
||||
</header>
|
||||
|
||||
<div class="flexcol">
|
||||
|
||||
<span class="roll-dialog-actor-title">{{title}}</span>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<footer class="sheet-footer flexcol">
|
||||
<button type="button" data-action="rollNormal">
|
||||
<i class="fas fa-check"></i> {{localize "ECRY.ui.rollnormal"}}
|
||||
</button>
|
||||
<button type="button" data-action="rollSpleen">
|
||||
<i class="fas fa-check"></i> {{localize "ECRY.ui.rollspleen"}}
|
||||
</button>
|
||||
<button type="button" data-action="rollIdeal">
|
||||
<i class="fas fa-check"></i> {{localize "ECRY.ui.rollideal"}}
|
||||
</button>
|
||||
<button type="button" data-action="cancel">
|
||||
<i class="fas fa-times"></i> {{localize "ECRY.ui.cancel"}}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<form class="skill-roll-dialog">
|
||||
<div class="skill-roll-dialog">
|
||||
<header class="roll-dialog-header">
|
||||
{{#if img}}
|
||||
<img class="actor-icon" src="{{img}}" data-edit="img" title="{{name}}" />
|
||||
<img class="actor-icon" src="{{img}}" title="{{name}}" />
|
||||
{{/if}}
|
||||
<h1 class="dialog-roll-title roll-dialog-header">{{title}}</h1>
|
||||
<span class="roll-dialog-actor-title">{{title}}</span>
|
||||
</header>
|
||||
|
||||
<div class="flexcol">
|
||||
@@ -11,12 +11,20 @@
|
||||
{{> systems/fvtt-ecryme/templates/dialogs/partial-common-roll-dialog.hbs}}
|
||||
|
||||
<div class="flexrow">
|
||||
<span class="roll-dialog-label">Difficulté : </span>
|
||||
<select class="" type="text" id="roll-difficulty" data-dtype="String">
|
||||
<span class="roll-dialog-label">{{localize "ECRY.ui.difficulty"}} : </span>
|
||||
<select id="roll-difficulty" data-dtype="String">
|
||||
{{selectOptions config.difficulty selected=difficulty localize=true labelAttr="difficulty"}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<footer class="sheet-footer flexrow">
|
||||
<button type="button" data-action="roll">
|
||||
<i class="fas fa-check"></i> {{localize "ECRY.ui.roll"}}
|
||||
</button>
|
||||
<button type="button" data-action="cancel">
|
||||
<i class="fas fa-times"></i> {{localize "ECRY.ui.cancel"}}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
19
templates/items/item-equipment-details.hbs
Normal file
19
templates/items/item-equipment-details.hbs
Normal file
@@ -0,0 +1,19 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="details" data-group="primary">
|
||||
<ul>
|
||||
<li class="flexrow">
|
||||
<label class="item-field-label-long">{{localize "ECRY.ui.quantity"}}</label>
|
||||
<input type="number" class="item-field-label-short" name="system.quantity" value="{{system.quantity}}" />
|
||||
</li>
|
||||
<li class="flexrow">
|
||||
<label class="item-field-label-long">{{localize "ECRY.ui.weight"}}</label>
|
||||
<input type="number" class="item-field-label-short" name="system.weight" value="{{system.weight}}" />
|
||||
</li>
|
||||
<li class="flexrow">
|
||||
<label class="item-field-label-long">{{localize "ECRY.ui.cost"}}</label>
|
||||
<input type="number" class="item-field-label-short" name="system.cost" value="{{system.cost}}" />
|
||||
<select name="system.costunit">
|
||||
{{selectOptions config.costUnits selected=system.costunit localize=true labelAttr="name"}}
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
5
templates/items/item-maneuver-details.hbs
Normal file
5
templates/items/item-maneuver-details.hbs
Normal file
@@ -0,0 +1,5 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="details" data-group="primary">
|
||||
<ul>
|
||||
{{!-- Maneuver has no additional details --}}
|
||||
</ul>
|
||||
</section>
|
||||
14
templates/items/item-specialization-details.hbs
Normal file
14
templates/items/item-specialization-details.hbs
Normal file
@@ -0,0 +1,14 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="details" data-group="primary">
|
||||
<ul>
|
||||
<li class="flexrow">
|
||||
<label class="item-name-label-long">{{localize "ECRY.ui.skill"}}</label>
|
||||
<select name="system.skillkey">
|
||||
{{selectOptions config.skills selected=system.skillkey localize=true valueAttr="key" labelAttr="name"}}
|
||||
</select>
|
||||
</li>
|
||||
<li class="flexrow">
|
||||
<label class="item-name-label-long">{{localize "ECRY.ui.bonus"}}</label>
|
||||
<input type="number" class="item-field-label-short" name="system.bonus" value="{{system.bonus}}" />
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
16
templates/items/item-trait-details.hbs
Normal file
16
templates/items/item-trait-details.hbs
Normal file
@@ -0,0 +1,16 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="details" data-group="primary">
|
||||
<ul>
|
||||
<li class="flexrow">
|
||||
<label class="item-name-label-long">{{localize "ECRY.ui.traitType"}}</label>
|
||||
<select name="system.traitype">
|
||||
{{selectOptions config.traitTypes selected=system.traitype}}
|
||||
</select>
|
||||
</li>
|
||||
<li class="flexrow">
|
||||
<label class="item-name-label-long">{{localize "ECRY.ui.niveauTrait"}}</label>
|
||||
<select name="system.level">
|
||||
{{selectOptions config.traitLevel selected=system.level labelAttr="text"}}
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
25
templates/items/item-weapon-details.hbs
Normal file
25
templates/items/item-weapon-details.hbs
Normal file
@@ -0,0 +1,25 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="details" data-group="primary">
|
||||
<ul>
|
||||
<li class="flexrow">
|
||||
<label class="item-name-label-long">{{localize "ECRY.ui.weapontype"}}</label>
|
||||
<select name="system.weapontype">
|
||||
{{selectOptions config.weaponTypes selected=system.weapontype localize=true}}
|
||||
</select>
|
||||
</li>
|
||||
<li class="flexrow">
|
||||
<label class="item-name-label-long">{{localize "ECRY.ui.effect"}}</label>
|
||||
<input type="number" class="item-field-label-short" name="system.effect" value="{{system.effect}}" />
|
||||
</li>
|
||||
<li class="flexrow">
|
||||
<label class="item-field-label-long">{{localize "ECRY.ui.weight"}}</label>
|
||||
<input type="number" class="item-field-label-short" name="system.weight" value="{{system.weight}}" />
|
||||
</li>
|
||||
<li class="flexrow">
|
||||
<label class="item-field-label-long">{{localize "ECRY.ui.cost"}}</label>
|
||||
<input type="number" class="item-field-label-short" name="system.cost" value="{{system.cost}}" />
|
||||
<select name="system.costunit">
|
||||
{{selectOptions config.costUnits selected=system.costunit localize=true labelAttr="name"}}
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
5
templates/items/partials/item-description.hbs
Normal file
5
templates/items/partials/item-description.hbs
Normal file
@@ -0,0 +1,5 @@
|
||||
<section class="tab sheet-body {{tab.cssClass}}" data-tab="description" data-group="primary">
|
||||
<div class="editor">
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
</div>
|
||||
</section>
|
||||
6
templates/items/partials/item-header.hbs
Normal file
6
templates/items/partials/item-header.hbs
Normal file
@@ -0,0 +1,6 @@
|
||||
<header class="sheet-header flexrow">
|
||||
<img class="item-sheet-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
|
||||
<div class="header-fields">
|
||||
<h1 class="charname">{{formInput fields.name value=source.name}}</h1>
|
||||
</div>
|
||||
</header>
|
||||
@@ -1,42 +1,47 @@
|
||||
<h3 class="welcome-message-h3">Bonjour à tous !</h3>
|
||||
|
||||
<div class="message-chat-center">
|
||||
👋 Juste un petit message pour vous informer que :
|
||||
<br />
|
||||
<strong
|
||||
>⚠️ Le nouveau financement participatif pour la prochaine extension
|
||||
d'Écryme, LES SECRETS DE L'ÉCRYME ouvre le 21 octobre !</strong
|
||||
>
|
||||
<div class="chat-message-header">
|
||||
<img class="actor-icon" src="systems/fvtt-ecryme/images/icons/logo-ecryme.webp" alt="Écryme" />
|
||||
<h4 class="chat-actor-name">Écryme RPG</h4>
|
||||
</div>
|
||||
|
||||
<div class="message-chat-center">
|
||||
⚠️ Suivez la page de pré-lancement ici pour être sûr de ne pas manquer le
|
||||
lancement : <br /><a href="https://shorturl.at/qDjg7"
|
||||
>https://shorturl.at/qDjg7</a
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="message-chat-center">
|
||||
Nous avons aussi un nouveau Discord pour ceux ou celles qui souhaiteraient
|
||||
participer plus activement à la communauté des jeux d'Open Sesame Games, avec
|
||||
un espace dédié aux écrymiens ! <br />
|
||||
Nouveaux joueurs comme vétérans sont les bienvenus, n'hésitez pas à passer
|
||||
pour papoter, profiter de nos ressources, ou suivre les nouvelles d'OSG plus
|
||||
directement. Cliquez ici :<br />
|
||||
<a href="https://discord.gg/dUPhNfJdaD">https://discord.gg/dUPhNfJdaD</a
|
||||
><br />
|
||||
</div>
|
||||
|
||||
<div class="message-chat-center">
|
||||
Ce système vous est proposé par Open Sesame Games.<br />
|
||||
Vous trouverez de l'aide dans
|
||||
@UUID[Compendium.fvtt-ecryme.help.JournalEntry.wooTFYjEwh83FwgT]{Aide pour
|
||||
Ecryme}<br />
|
||||
ainsi que sur le Discord de Foundry FR :<br>
|
||||
<a href="https://discord.gg/pPSDNJk">https://discord.gg/pPSDNJk</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
Merci pour votre attention et à très bientôt pour la suite ! L'équipe Open
|
||||
Sesame Games
|
||||
<div class="ecryme-chat-body">
|
||||
|
||||
<h3 class="welcome-message-h3">⚙ Bonjour à tous !</h3>
|
||||
|
||||
<div class="welcome-section">
|
||||
👋 Juste un petit message pour vous informer que :
|
||||
<br />
|
||||
<strong>⚠️ Le nouveau financement participatif pour la prochaine extension
|
||||
d'Écryme, LES SECRETS DE L'ÉCRYME ouvre le 21 octobre !</strong>
|
||||
</div>
|
||||
|
||||
<div class="welcome-section">
|
||||
⚠️ Suivez la page de pré-lancement ici pour être sûr de ne pas manquer le
|
||||
lancement :<br />
|
||||
<a href="https://shorturl.at/qDjg7">https://shorturl.at/qDjg7</a>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="welcome-section">
|
||||
Nous avons aussi un nouveau Discord pour ceux ou celles qui souhaiteraient
|
||||
participer plus activement à la communauté des jeux d'Open Sesame Games, avec
|
||||
un espace dédié aux écrymiens !<br />
|
||||
Nouveaux joueurs comme vétérans sont les bienvenus, n'hésitez pas à passer
|
||||
pour papoter, profiter de nos ressources, ou suivre les nouvelles d'OSG plus
|
||||
directement.<br />
|
||||
<a href="https://discord.gg/dUPhNfJdaD">Discord Open Sesame Games</a>
|
||||
</div>
|
||||
|
||||
<div class="welcome-section">
|
||||
Ce système vous est proposé par <strong>Open Sesame Games</strong>.<br />
|
||||
Vous trouverez de l'aide dans
|
||||
@UUID[Compendium.fvtt-ecryme.help.JournalEntry.wooTFYjEwh83FwgT]{Aide pour Écryme}<br />
|
||||
ainsi que sur le Discord de Foundry FR :<br />
|
||||
<a href="https://discord.gg/pPSDNJk">Discord Foundry FR</a>
|
||||
</div>
|
||||
|
||||
<div class="welcome-footer">
|
||||
⚙ Merci pour votre attention et à très bientôt ! — L'équipe Open Sesame Games
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user