Compare commits

...

52 Commits

Author SHA1 Message Date
adc912e6cd Ajout/upgrade des arts obscurs 2025-08-11 22:53:23 +02:00
51a457ebf6 Foundry v13 migration 2025-05-02 08:34:22 +02:00
2e9c558027 Ajout arts obscurs 2024-11-17 22:46:52 +01:00
bcd0758328 Ajout arts obscurs 2024-11-17 22:45:48 +01:00
2b680a203f Fix jet avec prestance 2024-08-11 14:40:41 +02:00
e3d7874dce Fix masque/demaque + pouvoir passif avec point 2024-07-30 13:45:50 +02:00
ab6a5832c0 Various v12 fixes 2024-07-13 12:13:06 +02:00
d83a999974 Various v12 fixes 2024-07-13 12:12:38 +02:00
b83890a764 Add v12 support 2024-05-23 15:38:50 +02:00
5ad3c165e5 Add v12 support 2024-05-23 11:25:51 +02:00
2b3e774cbb Correction sur les pouvoirs des fiches de PNJ 2024-04-25 10:30:15 +02:00
96f8d2bceb Fix roll pouvoir + pouvoirs passifs 2024-04-11 12:36:50 +02:00
e288c90ee4 Bouton d'ajout d'items dans la fiche PNJ 2024-04-01 17:27:20 +02:00
8916de8613 Bouton d'ajout d'items dans la fiche 2024-03-31 17:53:56 +02:00
8598df5a57 Ajout de la gestion des Points d'usage 2024-03-23 11:37:15 +01:00
8781462c8d Correction sur competences à 0 + diverses ameliorations 2024-03-06 19:00:01 +01:00
8c38aead3e Correction sur competences à 0 + diverses ameliorations 2024-03-06 18:46:53 +01:00
67bf71e6c0 Fix competences 2024-03-01 13:39:32 +01:00
63d15e82bb Enhance stats 2024-02-08 12:56:25 +01:00
62c3787cea Affichage des specialisations 2023-12-19 22:13:26 +01:00
df61abac19 Gestion des heritages 2023-12-19 21:35:20 +01:00
a7d1a14c52 Fix css for compendiums 2023-05-29 17:00:57 +02:00
b0dc6f36e4 Fix css for compendiums 2023-05-29 16:33:08 +02:00
5109d2aa91 Modification CSS pour compendiums 2023-05-29 13:22:43 +02:00
51c162ecbb v10/v11 compat 2023-05-25 15:43:55 +02:00
44d02b0cd1 Fix sur pouvoirs, heritage et 2 pts de tricherie 2023-05-01 18:48:34 +02:00
9b1600304a Fix sur pouvoirs, heritage et 2 pts de tricherie 2023-04-30 20:08:29 +02:00
2dff59c829 Fix pv value pour PNJ 2023-04-24 15:59:07 +02:00
55a2a8e3c3 Fix malus 2023-04-23 23:13:31 +02:00
2da1f56a91 Ajout XP + rework fees 2023-04-23 17:13:08 +02:00
66bd9dd2c8 Ajout XP + rework fees 2023-04-23 17:12:43 +02:00
15427f3747 Gestion des attaques ciblées 2023-04-11 13:29:04 +02:00
577eccbbd3 Gestion des attaques ciblées 2023-04-11 13:26:51 +02:00
05026d454b Add attaque dos+plusieurs 2023-04-10 14:11:47 +02:00
6497369d7f Gestion assommer/charge 2023-04-09 21:45:46 +02:00
5e5ddd1c3b Rework combat 2023-04-08 20:21:09 +02:00
a72108db5b Rework combat 2023-04-08 18:50:30 +02:00
6a46faadc2 Rework combat 2023-04-08 18:49:54 +02:00
e95f7de0c5 Fix divers 2023-04-08 09:55:08 +02:00
9d3ef8cbeb CSS journal fix 2023-04-07 16:56:37 +02:00
c6ec1b74a2 Petits fixes 2023-03-13 20:39:38 +01:00
1b12dc44c9 Fiches de PNJ 2023-03-13 09:00:49 +01:00
f26cd7670c Various fixes 2023-03-11 12:11:27 +01:00
02f8207fb7 Tri alpha + ajout contacts 2023-03-10 13:21:06 +01:00
439797e71e Fix predilection 2023-03-10 09:30:43 +01:00
1d82a6aa60 Fix predilection 2023-03-10 09:08:10 +01:00
11b0f22aa7 Diverses ameliorations 2023-03-09 13:16:19 +01:00
b0a3cb08cb Fix sur armes et affichage 2023-03-09 00:26:52 +01:00
2f3a8e91bd Fix sur armes et affichage 2023-03-09 00:04:23 +01:00
f00825ea91 Fix sur armes et affichage 2023-03-08 23:44:59 +01:00
3fa80b6e57 Fix sur armes et affichage 2023-03-08 23:44:19 +01:00
fac6618b74 Divers ajouts 2023-03-08 16:58:11 +01:00
131 changed files with 6159 additions and 2548 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.history/

View File

@@ -1,8 +1,8 @@
# Système Foundry pour Hawkmoon (French RPG, Titam France/Sombres Projets)
# Système Foundry pour Les Héritiers (French RPG, Titam France/Sombres Projets)
## EN
Unofficial system for Hawkmoon (French version from Titam France).
Unofficial system for Les Heritiers (from Titam France).
This system has been approved by Département des Sombres Projets ( http://www.titam-france.fr/ ), thanks !
@@ -10,7 +10,7 @@ Books are mandatory to play and are available at : http://www.titam-france.fr
## FR
Système non-officiel pour le JDR Hawkmoon (Titam France/Sombres Projets).
Système non-officiel pour le JDR Les Héritiers (Titam France/Sombres Projets).
Ce système a été autorisé par le Département des Sombres Projets ( http://www.titam-france.fr/ ), merci à eux !
@@ -18,7 +18,7 @@ Les livres du jeu sont nécessaires pour jouer, et sont disponibles ici : http:/
# Credits
Hawkmoon, le jeu de rôle du Troisième Millénaire, is a property of Titam France/Sombres Projets.
Les Héritiers, is a property of Titam France/Sombres Projets.
# Developmement
@@ -26,4 +26,4 @@ LeRatierBretonnien
# Tests, icones et saisie des données
Prêtre, Blondin, Zechrub/Chris, Kyllian, Lightbringer
Prêtre, Carter

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
assets/icons/erudit.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
assets/icons/gentleman.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
assets/icons/profil.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
assets/icons/roublard.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
assets/icons/sort.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View File

@@ -1,31 +1,24 @@
{
"ACTOR": {
"TypePersonnage": "Personnage",
"TypeCellule": "Cellule",
"TypeCreature": "Créature"
},
"ITEM": {
"TypeArtefact": "Artefact",
"TypeArme": "Arme",
"TypeTalent": "Talent",
"TypeHistorique": "Historique",
"TypeProfil": "Profil",
"TypeCompetence": "Compétence",
"TypeProtection": "Protection",
"TypeMonnaie": "Monnaie",
"TypeEquipement": "Equipement",
"TypeRessource": "Ressource",
"TypeContact": "Contact"
},
"HAWKMOON": {
"ui": {
"editContact": "Modifier le contact",
"deleteContact": "Supprimer le contact",
"editTrait": "Modifier le trait",
"deleteTrait": "Supprimer le trait"
"TYPES": {
"Actor": {
"personnage": "Personnage",
"pnj": "PNJ"
},
"Item": {
"accessoire": "Accessoire",
"arme": "Arme",
"atoutfeerique": "Atout féerique",
"avantage": "Avantage",
"capacitenaturelle": "Capacité naturelle",
"competence": "Compétence",
"contact": "Contact",
"desavantage": "Désavantage",
"equipement": "Equipement",
"fee": "Fée",
"pouvoir": "Pouvoir",
"profil": "Profil",
"protection": "Protection",
"sort": "Sort"
}
}
}

View File

@@ -3,23 +3,24 @@
* @extends {ActorSheet}
*/
import { HeritiersActorSheet } from "./heritiers-actor-sheet.js";
import { HeritiersActorSheet } from "./heritiers-actor-sheet.js";
import { HeritiersUtility } from "./heritiers-utility.js";
/* -------------------------------------------- */
export class HeritiersCreatureSheet extends HeritiersActorSheet {
export class HeritiersActorPNJSheet extends HeritiersActorSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-les-heritiers", "sheet", "actor"],
template: "systems/fvtt-les-heritiers/templates/creature-sheet.html",
width: 640,
height: 720,
template: "systems/fvtt-les-heritiers/templates/actor-pnj-sheet.html",
width: 780,
height: 840,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: false
})
}
}

View File

@@ -6,16 +6,16 @@
import { HeritiersUtility } from "./heritiers-utility.js";
/* -------------------------------------------- */
export class HeritiersActorSheet extends ActorSheet {
export class HeritiersActorSheet extends foundry.appv1.sheets.ActorSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-les-heritiers", "sheet", "actor"],
template: "systems/fvtt-les-heritiers/templates/actor-sheet.html",
width: 640,
height: 720,
width: 780,
height: 840,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: false
@@ -24,7 +24,7 @@ export class HeritiersActorSheet extends ActorSheet {
/* -------------------------------------------- */
async getData() {
const objectData = duplicate(this.object)
const objectData = foundry.utils.duplicate(this.object)
let formData = {
title: this.title,
@@ -38,26 +38,39 @@ export class HeritiersActorSheet extends ActorSheet {
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
skills: this.actor.getSkills(),
utileSkills :this.actor.organizeUtileSkills(),
futileSkills :this.actor.organizeFutileSkills(),
armes: duplicate(this.actor.getWeapons()),
monnaies: duplicate(this.actor.getMonnaies()),
fee: duplicate(this.actor.getFee() || {} ),
protections: duplicate(this.actor.getArmors()),
combat: this.actor.getCombatValues(),
equipements: duplicate(this.actor.getEquipments()),
avantages: duplicate(this.actor.getAvantages()),
atouts: duplicate(this.actor.getAtouts()),
capacites: duplicate(this.actor.getCapacites()),
desavantages: duplicate(this.actor.getDesavantages()),
pvMalus: this.actor.getPvMalus(),
utileSkillsMental: this.actor.organizeUtileSkills("mental"),
utileSkillsPhysical: this.actor.organizeUtileSkills("physical"),
competencesMagie: HeritiersUtility.getCompetencesMagie(),
futileSkills: this.actor.organizeFutileSkills(),
contacts: this.actor.organizeContacts(),
armes: foundry.utils.duplicate(this.actor.getWeapons()),
monnaies: foundry.utils.duplicate(this.actor.getMonnaies()),
pouvoirs: foundry.utils.duplicate(this.actor.getPouvoirs()),
fee: foundry.utils.duplicate(this.actor.getFee() || {}),
protections: foundry.utils.duplicate(this.actor.getArmors()),
combat: this.actor.getCombatValues(),
equipements: foundry.utils.duplicate(this.actor.getEquipments()),
avantages: foundry.utils.duplicate(this.actor.getAvantages()),
atouts: foundry.utils.duplicate(this.actor.getAtouts()),
capacites: foundry.utils.duplicate(this.actor.getCapacites()),
desavantages: foundry.utils.duplicate(this.actor.getDesavantages()),
profils: foundry.utils.duplicate(this.actor.getProfils()),
pvMalus: this.actor.getPvMalus(),
heritage: game.settings.get("fvtt-les-heritiers", "heritiers-heritage"),
initiative: this.actor.getFlag("world", "last-initiative") || -1,
description: await TextEditor.enrichHTML(this.object.system.biodata.description, {async: true}),
habitat: await TextEditor.enrichHTML(this.object.system.biodata.habitat, {async: true}),
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.description, { async: true }),
revesetranges: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.revesetranges, { async: true }),
secretsdecouverts: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.secretsdecouverts, { async: true }),
questions: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.questions, { async: true }),
habitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.habitat, { async: true }),
playernotes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.playernotes, { async: true }),
magieList: this.actor.prepareMagie(),
options: this.options,
owner: this.document.isOwner,
editScore: this.options.editScore,
isGM: game.user.isGM
config: game.system.lesheritiers.config,
isGM: game.user.isGM,
isPNJ: (this.actor.type == "pnj")
}
this.formData = formData;
@@ -66,19 +79,42 @@ export class HeritiersActorSheet extends ActorSheet {
}
/* -------------------------------------------- */
getCelluleTalents( ) {
let talents = []
for(let cellule of game.actors) {
if (cellule.type == "cellule") {
let found = cellule.system.members.find( it => it.id == this.actor.id)
if (found) {
talents = talents.concat( cellule.getTalents() )
dialogRecupUsage() {
new Dialog({
title: "Récupération des Points d'Usage",
content: "<p>Combien de Points d'Usage souhaitez-vous récupérer ?</p>",
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "1 Point",
callback: () => {
this.actor.recupUsage(1)
}
},
two: {
icon: '<i class="fas fa-check"></i>',
label: "2 Points",
callback: () => {
this.actor.recupUsage(2)
}
},
four: {
icon: '<i class="fas fa-check"></i>',
label: "4 Points",
callback: () => {
this.actor.recupUsage(4)
}
},
all: {
icon: '<i class="fas fa-check"></i>',
label: "Tous les Points",
callback: () => {
this.actor.recupUsage(100)
}
}
}
}
return talents
}).render(true)
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
@@ -86,14 +122,14 @@ export class HeritiersActorSheet extends ActorSheet {
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item")
let itemId = li.data("item-id")
const item = this.actor.items.get( itemId )
const item = this.actor.items.get(itemId)
item.sheet.render(true)
})
})
// Delete Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
@@ -101,8 +137,8 @@ export class HeritiersActorSheet extends ActorSheet {
})
html.find('.edit-item-data').change(ev => {
const li = $(ev.currentTarget).parents(".item")
let itemId = li.data("item-id")
let itemType = li.data("item-type")
let itemId = li.data("item-id")
let itemType = li.data("item-type")
let itemField = $(ev.currentTarget).data("item-field")
let dataType = $(ev.currentTarget).data("dtype")
let value = ev.currentTarget.value
@@ -115,44 +151,94 @@ export class HeritiersActorSheet extends ActorSheet {
let value = Number($(event.currentTarget).data("adversite-value"))
this.actor.incDecAdversite(adv, value)
})
html.find('.quantity-modify').click(event => {
const li = $(event.currentTarget).parents(".item")
const value = Number($(event.currentTarget).data("quantite-value"))
this.actor.incDecQuantity( li.data("item-id"), value );
this.actor.incDecQuantity(li.data("item-id"), value);
})
html.find('.roll-initiative').click((event) => {
this.actor.rollInitiative()
})
html.find('.roll-carac').click((event) => {
const key = $(event.currentTarget).data("key")
this.actor.rollCarac(key, false)
})
html.find('.roll-rang').click((event) => {
const key = $(event.currentTarget).data("rang-key")
this.actor.rollRang(key, false)
})
html.find('.roll-root-competence').click((event) => {
const compKey = $(event.currentTarget).data("attr-key")
this.actor.rollRootCompetence(compKey)
})
html.find('.roll-competence').click((event) => {
const li = $(event.currentTarget).parents(".item")
let compId = li.data("item-id")
let compId = li.data("item-id")
this.actor.rollCompetence(compId)
})
html.find('.roll-sort').click((event) => {
const li = $(event.currentTarget).parents(".item")
let sortId = li.data("item-id")
this.actor.rollSort(sortId)
})
html.find('.roll-attaque-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAttaqueArme(armeId)
})
html.find('.roll-attaque-brutale-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAttaqueBrutaleArme(armeId)
})
html.find('.roll-attaque-charge-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAttaqueChargeArme(armeId)
})
html.find('.roll-assomer-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAssomerArme(armeId)
})
html.find('.roll-pouvoir').click((event) => {
const li = $(event.currentTarget).parents(".item")
let pouvoirId = li.data("item-id")
this.actor.rollPouvoir(pouvoirId)
})
html.find('.dialog-recup-usage').click((event) => {
this.dialogRecupUsage()
})
html.find('.item-add').click((event) => {
const itemType = $(event.currentTarget).data("type")
if (itemType == "sort") {
// Get data-sort-competence
let sortCompetence = $(event.currentTarget).data("sort-competence");
if (sortCompetence) {
this.actor.createEmbeddedDocuments('Item', [{ name: `Nouveau ${itemType} de ${sortCompetence}`, type: itemType, system: { competence: sortCompetence } }], { renderSheet: true })
return
}
}
this.actor.createEmbeddedDocuments('Item', [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
})
html.find('.lock-unlock-sheet').click((event) => {
this.options.editScore = !this.options.editScore;
this.render(true);
});
});
html.find('.item-equip').click(ev => {
const li = $(ev.currentTarget).parents(".item");
this.actor.equipItem( li.data("item-id") );
this.render(true);
this.actor.equipItem(li.data("item-id"));
this.render(true);
});
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {

View File

@@ -17,8 +17,8 @@ export class HeritiersActor extends Actor {
/**
* Override the create() function to provide additional SoS functionality.
*
* This overrided create() function adds initial items
* Namely: Basic skills, money,
* This overrided create() function adds initial items
* Namely: Basic skills, money,
*
* @param {Object} data Barebones actor data which this function adds onto.
* @param {Object} options (Unused) Additional options which customize the creation workflow.
@@ -39,13 +39,14 @@ export class HeritiersActor extends Actor {
if (data.type == 'personnage') {
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.competences")
data.items = skills.map(i => i.toObject())
data.items = []
for (let skill of skills) {
if (skill.system.categorie == "utile" && skill.system.profil != "magie") {
data.items.push(skill.toObject())
}
}
}
if (data.type == 'creature') {
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.skills-creatures")
data.items = skills.map(i => i.toObject())
data.items.push({ name: "Arme naturelle 1", type: 'arme', img: "systems/fvtt-les-heritiers/assets/icons/melee.webp", system: { typearme: "contact", bonusmaniementoff: 0, seuildefense: 0, degats: "0" } })
data.items.push({ name: "Arme naturelle 2", type: 'arme', img: "systems/fvtt-les-heritiers/assets/icons/melee.webp", system: { typearme: "contact", bonusmaniementoff: 0, seuildefense: 0, degats: "0" } })
if (data.type == 'pnj') {
}
return super.create(data, options);
@@ -53,26 +54,8 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
prepareArme(arme) {
arme = duplicate(arme)
let combat = this.getCombatValues()
if (arme.system.typearme == "contact" || arme.system.typearme == "contactjet") {
let bonusDefense = 0
arme.system.competence = duplicate(this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée"))
arme.system.attrKey = "pui"
arme.system.totalDegats = arme.system.degats + "+" + combat.bonusDegatsTotal
arme.system.totalOffensif = this.system.attributs.pui.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.seuildefense + bonusDefense
arme.system.isdefense = true
}
if (arme.system.typearme == "jet" || arme.system.typearme == "tir") {
arme.system.competence = duplicate(this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "armes à distance"))
arme.system.attrKey = "adr"
arme.system.totalOffensif = this.system.attributs.adr.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff
arme.system.totalDegats = arme.system.degats
if (arme.system.isdefense) {
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.seuildefense
}
}
arme = foundry.utils.duplicate(arme)
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
return arme
}
@@ -87,13 +70,23 @@ export class HeritiersActor extends Actor {
return armes
}
/* -------------------------------------------- */
getOtherMeleeWeapons(excludeArme) {
let armes = []
for (let arme of this.items) {
if (HeritiersUtility.isArmeMelee(arme) && arme.id != excludeArme._id) {
armes.push(this.prepareArme(arme))
}
}
return armes
}
/* -------------------------------------------- */
getMonnaies() {
return this.items.filter(it => it.type == "monnaie")
}
/* ----------------------- --------------------- */
addMember(actorId) {
let members = duplicate(this.system.members)
let members = foundry.utils.duplicate(this.system.members)
members.push({ id: actorId })
this.update({ 'system.members': members })
}
@@ -103,41 +96,94 @@ export class HeritiersActor extends Actor {
}
/* ----------------------- --------------------- */
getItemSorted(types) {
let items = this.items.filter(item => types.includes(item.type)) || []
HeritiersUtility.sortArrayObjectsByName(items)
return items
}
getEquipments() {
return this.items.filter(item => item.type == "equipement")
return this.getItemSorted(["equipement", "accessoire"])
}
getAvantages() {
return this.items.filter(item => item.type == "avantage")
return this.getItemSorted(["avantage"])
}
getDesavantages() {
return this.items.filter(item => item.type == "desavantage")
return this.getItemSorted(["desavantage"])
}
getMonnaies() {
return this.items.filter(item => item.type == "monnaie")
return this.getItemSorted(["monnaie"])
}
getArmors() {
return this.items.filter(item => item.type == "protection")
return this.getItemSorted(["protection"])
}
getTalents() {
return this.items.filter(item => item.type == "talent")
return this.getItemSorted(["talent"])
}
getContacts() {
return this.items.filter(item => item.type == "contact")
return this.getItemSorted(["contact"])
}
getAtouts() {
return this.items.filter(item => item.type == "atoutfeerique")
return this.getItemSorted(["atoutfeerique"])
}
getCapacites() {
return this.items.filter(item => item.type == "capacitenaturelle")
return this.getItemSorted(["capacitenaturelle"])
}
getFee() {
return this.items.find(item => item.type == "fee")
}
getProfils() {
return this.getItemSorted(["profil"])
}
getPouvoirs() {
let pouvoirs = []
for (let item of this.items) {
if (item.type == "pouvoir") {
let itemObj = foundry.utils.duplicate(item)
itemObj.maxUsage = this.getPouvoirUsageMax(item)
pouvoirs.push(itemObj)
}
}
HeritiersUtility.sortArrayObjectsByName(pouvoirs)
return pouvoirs
}
getSorts() {
return this.getItemSorted(["sort"])
}
getCompetencesMagie() {
let comp = []
for (let item of this.items) {
if (item.type == "competence" && item.system.profil == "magie") {
let itemObj = foundry.utils.duplicate(item)
comp.push(itemObj)
}
}
HeritiersUtility.sortArrayObjectsByName(comp)
return comp
}
prepareMagie() {
let magieList = []
for (let item of this.items) {
if (item.type == "competence" && item.system.profil == "magie") {
let magie = {}
magie.name = item.name
magie.competence = foundry.utils.duplicate(item)
magie.sorts = []
for (let sort of this.items) {
if (sort.type == "sort" && sort.system.competence == item.name) {
magie.sorts.push(sort)
}
}
magieList.push(magie)
}
}
return magieList
}
/* -------------------------------------------- */
getSkills() {
let comp = []
for (let item of this.items) {
item = duplicate(item)
item = foundry.utils.duplicate(item)
if (item.type == "competence") {
comp.push(item)
}
@@ -146,19 +192,75 @@ export class HeritiersActor extends Actor {
}
/* -------------------------------------------- */
organizeUtileSkills() {
prepareUtileSkill(item) {
let specList = []
if (item?.system?.categorie == "utile") {
for (let spec of item.system.specialites) {
specList.push(spec.name)
}
}
item.nbSpec = specList.length
item.specList = specList.toString()
}
/* -------------------------------------------- */
organizeMagicSkills() {
let comp = {}
for (let key in game.system.lesheritiers.config.competenceProfil) {
comp[key] = []
if (game.system.lesheritiers.config.competenceProfil[key].kind == "magical")
comp[key] = { skills: [], niveau: 0 }
}
for (let item of this.items) {
if (item.type == "competence") {
if (item.system.categorie == "utile") {
comp[item.system.profil].push(item)
if (item.system.categorie == "utile" && comp[item.system.profil]) {
this.prepareUtileSkill(item)
comp[item.system.profil].skills.push(item)
}
}
}
return comp
for (let key in comp) {
HeritiersUtility.sortArrayObjectsByName(comp[key].skills)
}
return Object.fromEntries(Object.entries(comp).sort())
}
/* -------------------------------------------- */
organizeUtileSkills(kind = "mental") {
let comp = {}
for (let key in game.system.lesheritiers.config.competenceProfil) {
if (game.system.lesheritiers.config.competenceProfil[key].kind == kind)
comp[key] = { skills: [], niveau: this.system.competences[key].niveau }
}
for (let item of this.items) {
if (item.type == "competence") {
if (item.system.categorie == "utile" && comp[item.system.profil]) {
this.prepareUtileSkill(item)
comp[item.system.profil].skills.push(item)
}
}
}
for (let key in comp) {
HeritiersUtility.sortArrayObjectsByName(comp[key].skills)
}
return Object.fromEntries(Object.entries(comp).sort())
}
/* -------------------------------------------- */
organizeContacts() {
let contactList = {}
for (let item of this.items) {
if (item.type == "contact") {
let c = contactList[item.system.contacttype] || { label: game.system.lesheritiers.config.contactType[item.system.contacttype], list: [] }
c.list.push(item)
contactList[item.system.contacttype] = c
}
}
for (let key in contactList) {
HeritiersUtility.sortArrayObjectsByName(contactList[key].list)
}
return contactList
}
/* -------------------------------------------- */
@@ -171,6 +273,7 @@ export class HeritiersActor extends Actor {
}
}
}
HeritiersUtility.sortArrayObjectsByName(comp)
return HeritiersUtility.sortByName(comp)
}
@@ -210,9 +313,39 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async prepareData() {
let pvMax = (this.system.caracteristiques.con.rang * 3) + 9 + this.system.pv.mod
if (this.system.pv.max != pvMax) {
this.update({ 'system.pv.max': pvMax })
}
if (this.system.biodata.magie || this.type == "pnj") {
let pointsAmes = this.system.caracteristiques.esp.rang + this.system.caracteristiques.san.rang + this.getMaxRangMagie()
if (this.system.magie.pointsame.max != pointsAmes) {
this.update({ 'system.magie.pointsame.max': pointsAmes })
}
}
super.prepareData();
}
/* -------------------------------------------- */
getMaxRangMagie() {
let niv = 0
let bestMagie
for (let comp of this.items) {
if (comp.type == "competence" && comp.system.profil == "magie") {
if (comp.system.niveau > niv) {
bestMagie = comp
niv = comp.system.niveau
}
}
}
if (bestMagie) {
return Math.round(bestMagie.system.niveau / 2)
}
return 0
}
/* -------------------------------------------- */
prepareDerivedData() {
@@ -232,7 +365,7 @@ export class HeritiersActor extends Actor {
getItemById(id) {
let item = this.items.find(item => item.id == id);
if (item) {
item = duplicate(item)
item = foundry.utils.duplicate(item)
}
return item;
}
@@ -240,7 +373,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async equipItem(itemId) {
let item = this.items.find(item => item.id == itemId)
if (item && item.system) {
if (item?.system) {
let update = { _id: item.id, "system.equipped": !item.system.equipped }
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
}
@@ -251,10 +384,12 @@ export class HeritiersActor extends Actor {
let item = this.items.find(item => item.id == itemId)
if (item) {
console.log("Item ", item, itemField, dataType, value)
if (dataType.toLowerCase() == "number") {
value = Number(value)
} else {
value = String(value)
if (dataType) {
if (dataType.toLowerCase() == "number") {
value = Number(value)
} else {
value = String(value)
}
}
let update = { _id: item.id, [`system.${itemField}`]: value };
this.updateEmbeddedDocuments("Item", [update])
@@ -264,15 +399,15 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
getPvMalus() {
if (this.system.pv.value > 0) {
if (this.system.pv.value < this.system.pv.max / 2) {
return -1
}
if (this.system.pv.value < 5) {
return -2
return { name: "Santé", value: -2 }
}
return 0
if (this.system.pv.value < this.system.pv.max / 2) {
return { name: "Santé", value: -1 }
}
return { name: "Santé", value: 0 }
}
return "Moribond(e)"
return { name: "Moribond(e)", value: -50 }
}
/* -------------------------------------------- */
@@ -288,7 +423,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
getCarac(attrKey) {
return duplicate(this.system.caracteristiques)
return foundry.utils.duplicate(this.system.caracteristiques)
}
/* -------------------------------------------- */
@@ -299,7 +434,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async equipGear(equipmentId) {
let item = this.items.find(item => item.id == equipmentId);
if (item && item.system.data) {
if (item?.system) {
let update = { _id: item.id, "system.equipped": !item.system.equipped };
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
}
@@ -309,13 +444,13 @@ export class HeritiersActor extends Actor {
getSubActors() {
let subActors = [];
for (let id of this.system.subactors) {
subActors.push(duplicate(game.actors.get(id)));
subActors.push(foundry.utils.duplicate(game.actors.get(id)));
}
return subActors;
}
/* -------------------------------------------- */
async addSubActor(subActorId) {
let subActors = duplicate(this.system.subactors);
let subActors = foundry.utils.duplicate(this.system.subactors);
subActors.push(subActorId);
await this.update({ 'system.subactors': subActors });
}
@@ -337,7 +472,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async incDecAdversite(adv, incDec = 0) {
let adversite = duplicate(this.system.adversite)
let adversite = foundry.utils.duplicate(this.system.adversite)
adversite[adv] += Number(incDec)
adversite[adv] = Math.max(adversite[adv], 0)
this.update({ 'system.adversite': adversite })
@@ -384,7 +519,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async setPredilectionUsed(compId, predIdx) {
let comp = this.items.get(compId)
let pred = duplicate(comp.system.predilections)
let pred = foundry.utils.duplicate(comp.system.predilections)
pred[predIdx].used = true
await this.updateEmbeddedDocuments('Item', [{ _id: compId, 'system.predilections': pred }])
}
@@ -406,7 +541,7 @@ export class HeritiersActor extends Actor {
}
if (arme.system.totalDefensif > maxDef) {
maxDef = arme.system.totalDefensif
bestArme = duplicate(arme)
bestArme = foundry.utils.duplicate(arme)
}
}
return bestArme
@@ -421,7 +556,7 @@ export class HeritiersActor extends Actor {
for (let auto of talent.system.automations) {
if (auto.eventtype === "prepare-roll") {
if (auto.competence.toLowerCase() == competence.name.toLowerCase()) {
talent = duplicate(talent)
talent = foundry.utils.duplicate(talent)
talent.system.bonus = auto.bonus
talent.system.baCost = auto.baCost
talents.push(talent)
@@ -432,7 +567,23 @@ export class HeritiersActor extends Actor {
}
return talents
}
/* -------------------------------------------- */
getCurrentParade() {
if (this.system.statutmasque == "masque") {
return this.system.combat.parade.masquee
}
return this.system.combat.parade.demasquee
}
/* -------------------------------------------- */
getCurrentEsquive() {
if (this.system.statutmasque == "masque") {
return this.system.combat.esquive.masquee
}
return this.system.combat.esquive.demasquee
}
getCurrentResistancePhysique() {
return this.system.combat.resistancephysique.value
}
/* -------------------------------------------- */
getTricherie() {
return this.system.rang.tricherie.value
@@ -445,9 +596,27 @@ export class HeritiersActor extends Actor {
incDecTricherie(value) {
let tricherie = this.system.rang.tricherie
tricherie.value += value
if (tricherie.value < 0 || tricherie.value > tricherie.max) {
ui.notifications.warn("Pas assez de points de Tricherie !")
return false
}
tricherie.value = Math.max(tricherie.value, 0)
tricherie.value = Math.min(tricherie.value, tricherie.max)
this.update({ 'system.rang.tricherie': tricherie })
return true
}
/* -------------------------------------------- */
getPireCompetence(compName1, compName2) {
let comp1 = this.items.find(it => it.name == compName1)
let comp2 = this.items.find(it => it.name == compName2)
if (comp1 && comp2) {
if (comp1.system.niveau > comp2.system.niveau) {
return comp1
} else {
return comp2
}
}
return undefined
}
/* -------------------------------------------- */
@@ -463,23 +632,33 @@ export class HeritiersActor extends Actor {
rollData.tricherie = this.getTricherie()
rollData.heritage = this.getHeritages()
rollData.useTricherie = false
rollData.useSpecialite = false
rollData.useHeritage = false
rollData.pvMalus = this.getPvMalus()
rollData.pouvoirPointsUsage = 1
rollData.rulesMalus.push(this.getPvMalus())
if (compId) {
rollData.competence = duplicate(this.items.get(compId) || {})
rollData.competence = foundry.utils.duplicate(this.items.get(compId) || {})
this.prepareUtileSkill(rollData.competence)
rollData.actionImg = rollData.competence?.img
}
if (compName) {
rollData.competence = duplicate(this.items.find(item => item.name.toLowerCase() == compName.toLowerCase()) || {})
rollData.actionImg = rollData.competence?.img
rollData.competence = foundry.utils.duplicate(this.items.find(item => item.name.toLowerCase() == compName.toLowerCase()) || {})
if (rollData.competence?.name) {
this.prepareUtileSkill(rollData.competence)
rollData.actionImg = rollData.competence?.img
} else {
rollData.competence = undefined
}
}
HeritiersUtility.updateWithTarget(rollData)
return rollData
}
/* -------------------------------------------- */
async rollInitiative() {
let rollData = this.getCommonRollData(undefined, "Art de la guerre")
rollData.mode = "init"
rollData.mode = "init"
if (this.system.caracteristiques["san"].value > this.system.caracteristiques["per"].value) {
rollData.caracKey = "san"
} else {
@@ -489,17 +668,36 @@ export class HeritiersActor extends Actor {
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
/* -------------------------------------------- */
async rollCarac(key, isInit = false) {
let rollData = this.getCommonRollData()
rollData.mode = "carac"
rollData.mode = "carac"
rollData.carac = this.system.caracteristiques[key]
rollData.caracKey = key
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
/* -------------------------------------------- */
async rollRang(key, isInit = false) {
let rollData = this.getCommonRollData()
rollData.mode = "rang"
rollData.rang = this.system.rang[key]
rollData.rangKey = key
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
/* -------------------------------------------- */
async rollRootCompetence(compKey) {
let rollData = this.getCommonRollData()
rollData.mode = "competence"
rollData.competence = { name: this.system.competences[compKey].label, system: { niveau: this.system.competences[compKey].niveau } }
console.log("RollDatra", rollData)
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
/* -------------------------------------------- */
async rollCompetence(compId) {
let rollData = this.getCommonRollData(compId)
@@ -510,45 +708,246 @@ export class HeritiersActor extends Actor {
}
/* -------------------------------------------- */
async rollArmeOffensif(armeId) {
let arme = this.items.get(armeId)
if (arme.type == "arme") {
arme = this.prepareArme(arme)
async rollSort(sortId) {
let sort = this.items.get(sortId)
let comp = this.items.find(it => it.type == "competence" && it.name.toLowerCase() == sort.system.competence.toLowerCase())
if (!comp) {
ui.notifications.warn("Compétence de magie associée non trouvée !")
return
}
let rollData = this.getCommonRollData(arme.system.attrKey, arme.system.competence._id)
rollData.arme = arme
HeritiersUtility.updateWithTarget(rollData)
console.log("ARME!", rollData)
let rollData = this.getCommonRollData(comp.id)
rollData.mode = "sort"
rollData.sort = foundry.utils.duplicate(sort)
rollData.sdValue = HeritiersUtility.getSDSortValue(sort.system.niveau)
rollData.sortPointsAme = sort.system.niveau
if (sort.system.carac2 != "none") {
// get the best carac between carac1 and carac2
if (this.system.caracteristiques[sort.system.carac1].value > this.system.caracteristiques[sort.system.carac2].value) {
rollData.caracKey = sort.system.carac1
} else {
rollData.caracKey = sort.system.carac2
}
rollData.caracMessage = "Ce sort peut être lancé avec " + game.system.lesheritiers.config.caracList[sort.system.carac1] + " ou " + game.system.lesheritiers.config.caracList[sort.system.carac2] + ". La meilleure caractéristique a été selectionnée."
}
console.log("RollData", rollData)
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
/* -------------------------------------------- */
async rollArmeDegats(armeId, targetVigueur = undefined) {
async rollAttaqueArme(armeId) {
let arme = this.items.get(armeId)
if (arme.type == "arme") {
arme = this.prepareArme(arme)
if (arme) {
arme = foundry.utils.duplicate(arme)
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
let competenceName = "Tir"
let key = "prec"
if (arme.system.isMelee) {
competenceName = "Mêlée"
key = "agi"
}
let rollData = this.getCommonRollData(undefined, competenceName)
rollData.carac = this.system.caracteristiques[key]
rollData.caracKey = key
rollData.arme = arme
rollData.mode = "arme"
rollData.armes = this.getOtherMeleeWeapons(arme)
if (rollData.defenderTokenId && arme.system.isMelee) {
rollData.cacheDifficulte = true
}
console.log(">>>> ARME", rollData)
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
console.log("DEGATS", arme)
let roll = new Roll("1d10+" + arme.system.totalDegats).roll({ async: false })
await HeritiersUtility.showDiceSoNice(roll, game.settings.get("core", "rollMode"));
let nbEtatPerdus = 0
if (targetVigueur) {
nbEtatPerdus = Math.floor(roll.total / targetVigueur)
}
/* -------------------------------------------- */
async rollAttaqueBrutaleArme(armeId) {
let arme = this.items.get(armeId)
if (arme) {
let key = "for"
let competenceName = "Mêlée"
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
let rollData = this.getCommonRollData(undefined, competenceName)
rollData.carac = this.system.caracteristiques[key]
rollData.caracKey = key
rollData.arme = foundry.utils.duplicate(arme)
rollData.mode = "attaquebrutale"
rollData.armes = this.getOtherMeleeWeapons(arme)
rollData.rulesMalus.push({ name: "Attaque brutale", value: -2 })
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
let rollData = {
arme: arme,
finalResult: roll.total,
alias: this.name,
actorImg: this.img,
actorId: this.id,
actionImg: arme.img,
targetVigueur: targetVigueur,
nbEtatPerdus: nbEtatPerdus
}
/* -------------------------------------------- */
async rollAttaqueChargeArme(armeId) {
let arme = this.items.get(armeId)
if (arme) {
let key = "agi"
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
let pireCompetence = this.getPireCompetence("Mêlée", "Mouvement")
let rollData = this.getCommonRollData(undefined, pireCompetence.name)
rollData.carac = this.system.caracteristiques[key]
rollData.caracKey = key
rollData.arme = foundry.utils.duplicate(arme)
rollData.armes = this.getOtherMeleeWeapons(arme)
rollData.mode = "attaquecharge"
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
}
/* -------------------------------------------- */
async rollAssomerArme(armeId) {
let arme = this.items.get(armeId)
if (arme) {
let competenceName = "Mêlée"
//arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
let rollData = this.getCommonRollData(undefined, competenceName)
rollData.carac = this.system.caracteristiques["agi"]
rollData.caracKey = "agi"
rollData.arme = foundry.utils.duplicate(arme)
rollData.mode = "assommer"
if (rollData.defenderTokenId) {
rollData.cacheDifficulte = true
}
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
}
/* -------------------------------------------- */
pouvoirPassifDialog(pouvoir) {
let rollData = this.getCommonRollData()
rollData.pouvoir = pouvoir
rollData.mode = "pouvoirpassif"
rollData.pouvoirPointsUsage = 0
rollData.noRoll = true
let d = new Dialog({
title: "Activer le pouvoir passif " + pouvoir.name,
content: "<p>Choisissez le nombre de Points d'Usage</p>",
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "1 Point d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 1;
HeritiersUtility.rollHeritiers(rollData);
}
},
two: {
icon: '<i class="fas fa-check"></i>',
label: "2 Points d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 2;
HeritiersUtility.rollHeritiers(rollData);
}
},
three: {
icon: '<i class="fas fa-check"></i>',
label: "3 Points d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 3;
HeritiersUtility.rollHeritiers(rollData);
}
},
four: {
icon: '<i class="fas fa-check"></i>',
label: "4 Points d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 4;
HeritiersUtility.rollHeritiers(rollData);
}
},
close: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => {
}
}
},
default: "one",
render: html => console.log("Pouvoir passif"),
close: html => console.log("No option")
});
d.render(true);
}
/* -------------------------------------------- */
async rollPouvoir(pouvoirId) {
let pouvoir = this.items.get(pouvoirId)
if (pouvoir) {
if (pouvoir.system.pouvoirtype == "passif") {
this.pouvoirPassifDialog(pouvoir)
return
}
let rollData = this.getCommonRollData(undefined, undefined)
rollData.pouvoirMaxUsage = this.getPouvoirUsageMax(pouvoir)
rollData.pouvoir = foundry.utils.duplicate(pouvoir)
rollData.mode = "pouvoir"
if (pouvoir.system.feeriemasque != "autre") {
rollData.pouvoirBase = foundry.utils.duplicate(this.system.rang[pouvoir.system.feeriemasque.toLowerCase()])
rollData.pouvoirBase.label = "Féerie"
if (pouvoir.system.istest && !pouvoir.system.carac) {
ui.notifications.warn("Le pouvoir actif " + pouvoir.name + " n'a pas de caractéristique associée")
}
if (pouvoir.system.istest) {
rollData.carac = foundry.utils.duplicate(this.system.caracteristiques[pouvoir.system.carac])
rollData.caracKey = pouvoir.system.carac
} else {
rollData.noRoll = true
HeritiersUtility.rollHeritiers(rollData);
return;
//this.incDecPointsUsage(pouvoir.id, -rollData.pouvoirPointsUsage)
//ui.notifications.warn("Le pouvoir actif " + pouvoir.name + " a été utilisé, dépense de " + pouvoirPointsUsage + " points d'usage")
}
}
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
}
HeritiersUtility.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-les-heritiers/templates/chat-degats-result.html`, rollData)
})
}
/* -------------------------------------------- */
incDecPointsUsage(pouvoirId, value) {
let pouvoir = this.items.get(pouvoirId)
let newValue = pouvoir.system.pointsusagecourant + value
newValue = Math.max(newValue, 0)
newValue = Math.min(newValue, this.getPouvoirUsageMax(pouvoir))
this.updateEmbeddedDocuments('Item', [{ _id: pouvoirId, 'system.pointsusagecourant': newValue }])
}
/* -------------------------------------------- */
getPouvoirUsage(pouvoirId) {
let pouvoir = this.items.get(pouvoirId)
return pouvoir.system.pointsusagecourant
}
/* -------------------------------------------- */
getPouvoirUsageMax(pouvoir) {
if (pouvoir.system.masquetype == "masque") {
return this.system.rang.masque.value
}
return this.system.rang.feerie.value
}
/* -------------------------------------------- */
recupUsage(value) {
let updates = []
for (let pouvoir of this.items) {
if (pouvoir.type == "pouvoir") {
let newValue = pouvoir.system.pointsusagecourant + value
newValue = Math.max(newValue, 0)
newValue = Math.min(newValue, this.getPouvoirUsageMax(pouvoir))
updates.push({ _id: pouvoir.id, 'system.pointsusagecourant': newValue })
}
}
if (updates.length > 0) {
this.updateEmbeddedDocuments('Item', updates)
}
}
}

View File

@@ -8,7 +8,7 @@ export const HERITIERS_CONFIG = {
"prec": "Précision",
"esp": "Esprit",
"per": "Perception",
"pres": "Présence",
"pres": "Prestance",
"san": "Sang-Froid"
},
@@ -16,18 +16,26 @@ export const HERITIERS_CONFIG = {
"utile": "Utile",
"futile": "Futile"
},
contactType: {
contact: "Contact",
allie: "Allié",
ennemi: "Ennemi",
interet: "Personne d'interêt"
},
competenceProfil : {
"aventurier": "Aventurier",
"roublard": "Roublard",
"combattant": "Combattant",
"erudit": "Erudit",
"savant": "Savant",
"gentleman": "Gentleman"
"aventurier": {kind: "physical", name: "Aventurier"},
"roublard": {kind: "physical",name: "Roublard"},
"combattant": {kind: "physical",name:"Combattant"},
"erudit": {kind: "mental",name:"Erudit"},
"savant": {kind: "mental",name:"Savant"},
"gentleman": {kind: "mental",name:"Gentleman"},
"magie": {kind: "magical", name: "Magie"},
},
baseTestPouvoir: {
"feerie": "Féerie",
"Masque": "Masque",
"masque": "Masque",
"autre": "Autre"
},
resistancePouvoir: {
@@ -43,6 +51,10 @@ export const HERITIERS_CONFIG = {
"passif": "Passif",
"metamorphose": "Métamorphose"
},
statutMasque: {
"masque": "Masqué",
"demasque":"Démasqué"
},
niveauPouvoir: {
"normal": "Normal",
"profond": "Profond",
@@ -53,23 +65,42 @@ export const HERITIERS_CONFIG = {
"demasque": "Démasqué"
},
seuilsDifficulte: {
"0": "Aucun/Non applicable",
"5": "Enfantine",
"6": "Triviale",
"8": "Aisée",
"10": "Normale",
"12": "Compliquée",
"14": "Difficile",
"16": "Très Difficile",
"18": "Critique",
"20": "Insurmontable",
"22": "Surhumaine",
"24": "Epique",
"26": "Légendaire",
"28": "Mythique",
"30": "Divine"
"-1": "Aucun/Non applicable",
"5": "Enfantine (5)",
"6": "Triviale (6)",
"7": "Moins Triviale (7)",
"8": "Aisée (8)",
"9": "Moins Aisée (9)",
"10": "Normale (10)",
"11": "Moins Normale (11)",
"12": "Compliquée (12)",
"13": "Plus Compliquée (13)",
"14": "Difficile (14)",
"15": "Plus Difficile (15)",
"16": "Très Difficile (16)",
"17": "Très Très Difficile (17)",
"18": "Critique (18)",
"19": "Plus Critique (19)",
"20": "Insurmontable (20)",
"21": "Très Insurmontable (21)",
"22": "Surhumaine (22)",
"23": "Très Surhumaine (23)",
"24": "Epique (24)",
"25": "Plus Epique (25)",
"26": "Légendaire (26)",
"27": "Très Légendaire (27)",
"28": "Mythique (28)",
"29": "Plus Mythique (29)",
"30": "Divine (30)"
},
attaqueCible: {
"none": "Aucune",
"membre": "Membre",
"main": "Main",
"tete": "Tête/Coeur"
},
categorieArme : {
"trait": "Arme de trait",
"poing": "Arme de poing",
@@ -115,7 +146,72 @@ export const HERITIERS_CONFIG = {
"traditionnelle": "Traditionnelle",
"moderne": "Moderne",
"orientale": "Orientale"
}
},
typeContact: {
"contact": "Contact",
"allie": "Allié",
"ennemi": "Ennemi",
"interet": "Personne d'interêt"
},
niveauContact: {
"1": "1",
"2": "2",
"3": "3",
},
pointsUsageList: {
"1": "1",
"2": "2",
"3": "3",
"4": "4",
},
attaquePlusieursList : {
"0": "0",
"1": "+1",
"2": "+2",
},
attaque2ArmesListe: [
{value: "0", label: "Aucun"},
{value: "-4", label: "Deux armes à 1 main"},
{value: "-2", label: "Deux armes naturelles"},
{value: "-2", label: "Avec spécialisation \"Mauvaise Main\""}
],
typeProfil: {
"mineur": "Mineur",
"majeur": "Majeur",
},
bonusMalusContext: [
{value: "-6", label: "-6"},
{value: "-5", label: "-5"},
{value: "-4", label: "-4"},
{value: "-3", label: "-3"},
{value: "-2", label: "-2"},
{value: "-1", label: "-1"},
{value: "0", label: "0"},
{value: "1", label: "+1"},
{value: "2", label: "+2"},
{value: "3", label: "+3"},
{value: "4", label: "+4"},
{value: "5", label: "+5"},
{value: "6", label: "+6"}
],
listNiveauSort: {
"1" : "1",
"2" : "2",
"3" : "3",
"4" : "4"
},
listNiveau: {
"0": "0",
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7",
"8": "8",
"9": "9",
"10": "10"
},
}

View File

@@ -4,12 +4,12 @@ import { HeritiersUtility } from "./heritiers-utility.js";
* Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
*/
export class HeritiersItemSheet extends ItemSheet {
export class HeritiersItemSheet extends foundry.appv1.sheets.ItemSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-les-heritiers", "sheet", "item"],
template: "systems/fvtt-les-heritiers/templates/item-sheet.html",
dragDrop: [{ dragSelector: null, dropSelector: null }],
@@ -48,7 +48,7 @@ export class HeritiersItemSheet extends ItemSheet {
/* -------------------------------------------- */
async getData() {
const objectData = duplicate(this.object)
const objectData = foundry.utils.duplicate(this.object)
let formData = {
title: this.title,
id: this.id,
@@ -62,11 +62,25 @@ export class HeritiersItemSheet extends ItemSheet {
options: this.options,
owner: this.document.isOwner,
config: game.system.lesheritiers.config,
description: await TextEditor.enrichHTML(this.object.system.description, {async: true}),
isArmeMelee: HeritiersUtility.isArmeMelee(this.object),
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.description, {async: true}),
mr: (this.object.type == 'specialisation'),
isGM: game.user.isGM
isGM: game.user.isGM,
usageMax: -1
}
// Items specific data
if (this.object.type == 'pouvoir' && this.document.isOwner && this.actor) {
formData.usageMax = this.actor.getPouvoirUsageMax(this.object)
if (this.object.system.pointsusagecourant == -1) {
this.object.system.pointsusagecourant = formData.usageMax
}
}
if (this.object.type == 'sort' ) {
formData.competencesMagie = HeritiersUtility.getCompetencesMagie()
}
//this.options.editable = !(this.object.origin == "embeddedItem");
console.log("ITEM DATA", formData, this);
return formData;
@@ -86,7 +100,7 @@ export class HeritiersItemSheet extends ItemSheet {
/* -------------------------------------------- */
postItem() {
let chatData = duplicate(HeritiersUtility.data(this.item));
let chatData = foundry.utils.duplicate(HeritiersUtility.data(this.item));
if (this.actor) {
chatData.actor = { id: this.actor.id };
}
@@ -128,55 +142,55 @@ export class HeritiersItemSheet extends ItemSheet {
})
html.find('#add-specialite').click(ev => {
let spec = duplicate(this.object.system.specialites)
spec.push( { name: "Nouvelle Spécialité", id: randomID(16), used: false })
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec.push( { name: "Nouvelle Spécialité", id: foundry.utils.randomID(16), used: false })
this.object.update( { 'system.specialites': spec })
})
html.find('.delete-specialite').click(ev => {
const li = $(ev.currentTarget).parents(".specialite-item")
let index = li.data("specialite-index")
let spec = duplicate(this.object.system.specialites)
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec.splice(index,1)
this.object.update( { 'system.specialites': spec })
})
html.find('.edit-specialite').change(ev => {
const li = $(ev.currentTarget).parents(".specialite-item")
let index = li.data("specialite-index")
let spec = duplicate(this.object.system.specialites)
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec[index].name = ev.currentTarget.value
spec[index].id = spec[index].id || randomID(16)
spec[index].id = spec[index].id || foundry.utils.randomID(16)
this.object.update( { 'system.specialites': spec })
})
html.find('.edit-specialite-description').change(ev => {
const li = $(ev.currentTarget).parents(".specialite-item")
let index = li.data("specialite-index")
let spec = duplicate(this.object.system.specialites)
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec[index].description = ev.currentTarget.value
spec[index].id = spec[index].id || randomID(16)
spec[index].id = spec[index].id || foundry.utils.randomID(16)
this.object.update( { 'system.specialites': spec })
})
})
html.find('#add-automation').click(ev => {
let autom = duplicate(this.object.system.automations)
autom.push( { eventtype: "on-drop", name: "Automatisation 1", competence: "", minLevel: 0, id: randomID(16) })
let autom = foundry.utils.duplicate(this.object.system.automations)
autom.push( { eventtype: "on-drop", name: "Automatisation 1", competence: "", minLevel: 0, id: foundry.utils.randomID(16) })
this.object.update( { 'system.automations': autom })
})
html.find('.delete-automation').click(ev => {
const li = $(ev.currentTarget).parents(".automation-item")
let index = li.data("automation-index")
let autom = duplicate(this.object.system.automations)
let autom = foundry.utils.duplicate(this.object.system.automations)
autom.splice(index,1)
this.object.update( { 'system.automations': autom })
})
html.find('.automation-edit-field').change(ev => {
let index = $(ev.currentTarget).data("automation-index")
let field = $(ev.currentTarget).data("automation-field")
let auto = duplicate(this.object.system.automations)
let auto = foundry.utils.duplicate(this.object.system.automations)
auto[index][field] = ev.currentTarget.value
auto[index].id = auto[index].id || randomID(16)
auto[index].id = auto[index].id || foundry.utils.randomID(16)
this.object.update( { 'system.automations': auto })
})
})
// Update Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");

View File

@@ -15,8 +15,10 @@ export const defaultItemImg = {
arme: "systems/fvtt-les-heritiers/assets/icons/weapon.webp",
accessoire: "systems/fvtt-les-heritiers/assets/icons/item.webp",
protection: "systems/fvtt-les-heritiers/assets/icons/armor.webp",
fee: "systems/fvtt-les-heritiers/assets/icons/faery_type.webp"
fee: "systems/fvtt-les-heritiers/assets/icons/faery_type.webp",
profil: "systems/fvtt-les-heritiers/assets/icons/profil.webp",
equipement: "systems/fvtt-les-heritiers/assets/icons/equipement.webp",
sort: "systems/fvtt-les-heritiers/assets/icons/sort.webp",
}
/**

View File

@@ -11,7 +11,7 @@
import { HeritiersActor } from "./heritiers-actor.js";
import { HeritiersItemSheet } from "./heritiers-item-sheet.js";
import { HeritiersActorSheet } from "./heritiers-actor-sheet.js";
import { HeritiersCreatureSheet } from "./heritiers-creature-sheet.js";
import { HeritiersActorPNJSheet } from "./heritiers-actor-pnj-sheet.js";
import { HeritiersUtility } from "./heritiers-utility.js";
import { HeritiersCombat } from "./heritiers-combat.js";
import { HeritiersItem } from "./heritiers-item.js";
@@ -30,7 +30,7 @@ Hooks.once("init", async function () {
HeritiersUtility.preloadHandlebarsTemplates()
/* -------------------------------------------- */
// Set an initiative formula for the system
// Set an initiative formula for the system
CONFIG.Combat.initiative = {
formula: "1d10",
decimals: 1
@@ -46,6 +46,8 @@ Hooks.once("init", async function () {
CONFIG.Combat.documentClass = HeritiersCombat
CONFIG.Actor.documentClass = HeritiersActor
CONFIG.Item.documentClass = HeritiersItem
// Create an object of bonus/malus from -6 to +6 signed
HERITIERS_CONFIG.bonusMalus = Array.from({ length: 7 }, (v, k) => toString(k - 6))
game.system.lesheritiers = {
HeritiersUtility,
config: HERITIERS_CONFIG
@@ -53,12 +55,12 @@ Hooks.once("init", async function () {
/* -------------------------------------------- */
// Register sheet application classes
Actors.unregisterSheet("core", ActorSheet);
Actors.registerSheet("fvtt-les-heritiers", HeritiersActorSheet, { types: ["personnage"], makeDefault: true })
Actors.registerSheet("fvtt-les-heritiers", HeritiersCreatureSheet, { types: ["creature"], makeDefault: true })
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", HeritiersActorSheet, { types: ["personnage"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", HeritiersActorPNJSheet, { types: ["pnj"], makeDefault: true })
Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("fvtt-les-heritiers", HeritiersItemSheet, { makeDefault: true })
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", HeritiersItemSheet, { makeDefault: true })
HeritiersUtility.init()
@@ -78,31 +80,17 @@ function welcomeMessage() {
}
/* -------------------------------------------- */
// Register world usage statistics
function registerUsageCount(registerKey) {
if (game.user.isGM) {
game.settings.register(registerKey, "world-key", {
name: "Unique world key",
scope: "world",
config: false,
default: "",
type: String
});
let worldKey = game.settings.get(registerKey, "world-key")
if (worldKey == undefined || worldKey == "") {
worldKey = randomID(32)
game.settings.set(registerKey, "world-key", worldKey)
}
// Simple API counter
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
//$.ajaxSetup({
//headers: { 'Access-Control-Allow-Origin': '*' }
//})
$.ajax(regURL)
async function importDefaultScene() {
let exists = game.scenes.find(j => j.name == "Accueil");
if (!exists) {
const scenes = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.scenes")
let newDocuments = scenes.filter(i => i.name == "Accueil");
await game.scenes.documentClass.create(newDocuments);
game.scenes.find(i => i.name == "Accueil").activate();
}
}
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -119,14 +107,15 @@ Hooks.once("ready", function () {
});
}
registerUsageCount('fvtt-les-heritiers')
welcomeMessage()
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
console.log("ClassCounter loaded", moduleCounter)
moduleCounter.ClassCounter.registerUsageCount()
}).catch(err =>
console.log("No stats available, giving up.")
)
welcomeMessage();
importDefaultScene();
// CSS patch for v9
if (game.version) {
let sidebar = document.getElementById("sidebar");
sidebar.style.width = "min-content";
}
});
/* -------------------------------------------- */
@@ -136,10 +125,9 @@ Hooks.on("chatMessage", (html, content, msg) => {
if (content[0] == '/') {
let regExp = /(\S+)/g;
let commands = content.match(regExp);
if (game.system.mournblade.commands.processChatCommand(commands, content, msg)) {
if (game.system.lesheritiers.commands.processChatCommand(commands, content, msg)) {
return false;
}
}
return true;
});

View File

@@ -5,43 +5,70 @@ export class HeritiersRollDialog extends Dialog {
/* -------------------------------------------- */
static async create(actor, rollData) {
let options = { classes: ["HeritiersDialog"], width: 320, height: 'fit-content', 'z-index': 99999 };
let html = await renderTemplate('systems/fvtt-les-heritiers/templates/roll-dialog-generic.html', rollData);
let options = { classes: ["HeritiersDialog"], width: 420, height: 'fit-content', 'z-index': 99999 };
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-les-heritiers/templates/roll-dialog-generic.html', rollData);
return new HeritiersRollDialog(actor, rollData, html, options);
}
/* -------------------------------------------- */
constructor(actor, rollData, html, options, close = undefined) {
let buttons = {
rolld8: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d8",
callback: () => { this.roll("d8") }
}
}
let enableD10 = false
let enableD12 = false
if (rollData.mode == "pouvoir" || rollData.competence?.system.niveau > 0) {
enableD10 = true
}
if (rollData.mode == "pouvoir" || rollData.competence?.system.niveau > 1) {
enableD12 = true
}
if (enableD10) {
buttons.rolld10 = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("d10") }
}
}
if (enableD12) {
buttons.rolld12 = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d12",
callback: () => { this.roll("d12") }
}
}
if (rollData.tricherie) {
buttons["rollTricherie"] = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer avec 1 Point de Tricherie",
callback: () => { this.roll("tricherie") }
}
}
if (rollData.heritage) {
buttons["rollHeritage"] = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer avec 1 Point d'Héritage",
callback: () => { this.roll("heritage") }
}
}
buttons["Cancel"] = {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
}
let conf = {
title: "Test de Capacité",
content: html,
buttons:
{
rolld8: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d8",
callback: () => { this.roll("d8") }
},
rolld10: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("d10") }
},
rolld12: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d12",
callback: () => { this.roll("d12") }
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
}
},
buttons: buttons,
close: close
}
// Overwrite in case of carac only -> 1d10
// Overwrite in case of carac only -> 1d8
if (rollData.mode == "carac") {
conf.buttons = {
rolld8: {
@@ -64,7 +91,16 @@ export class HeritiersRollDialog extends Dialog {
/* -------------------------------------------- */
roll(dice) {
this.rollData.mainDice = dice
if (dice == "heritage") {
this.rollData.useHeritage = true
}
else {
if (dice == "tricherie") {
this.rollData.useTricherie = true
} else {
this.rollData.mainDice = dice
}
}
HeritiersUtility.rollHeritiers(this.rollData)
}
@@ -73,7 +109,6 @@ export class HeritiersRollDialog extends Dialog {
activateListeners(html) {
super.activateListeners(html);
var dialog = this;
function onLoad() {
}
$(function () { onLoad(); });
@@ -82,16 +117,30 @@ export class HeritiersRollDialog extends Dialog {
this.rollData.sdValue = Number(event.currentTarget.value)
})
html.find('#caracKey').change(async (event) => {
//console.log("caracKey", event.currentTarget.value)
this.rollData.caracKey = String(event.currentTarget.value)
})
html.find('#bonus-malus-context').change((event) => {
this.rollData.bonusMalusContext = Number(event.currentTarget.value)
})
html.find('#useTricherie').change((event) => {
this.rollData.useTricherie = event.currentTarget.checked
html.find('#bonus-attaque-plusieurs').change((event) => {
this.rollData.bonusAttaquePlusieurs = Number(event.currentTarget.value)
})
html.find('#useHeritage').change((event) => {
this.rollData.useHeritage = event.currentTarget.checked
html.find('#useSpecialite').change((event) => {
this.rollData.useSpecialite = event.currentTarget.checked
})
html.find('#pouvoirPointsUsage').change((event) => {
this.rollData.pouvoirPointsUsage = Number(event.currentTarget.value)
})
html.find('#attaqueDos').change((event) => {
this.rollData.attaqueDos = event.currentTarget.checked
})
html.find('#bonus-attaque-seconde-arme').change((event) => {
this.rollData.secondeArme = String(event.currentTarget.value)
})
html.find('#attaque-cible').change((event) => {
this.rollData.attaqueCible = String(event.currentTarget.value)
})
}
}

View File

@@ -2,6 +2,45 @@
import { HeritiersCombat } from "./heritiers-combat.js";
import { HeritiersCommands } from "./heritiers-commands.js";
const __facesAdjacentes = {
"d8": {
1: [4, 8, 6],
2: [7, 5, 3],
3: [2, 8, 6],
4: [1, 5, 7],
5: [2, 4, 8],
6: [1, 7, 3],
7: [2, 4, 6],
8: [1, 3, 5]
},
"d10": {
1: [4, 6, 9, 7],
2: [6, 8, 5, 9],
3: [7, 5, 8, 10],
4: [10, 6, 7, 1],
5: [3, 9, 2, 8],
6: [1, 4, 2, 9],
7: [1, 3, 4, 10],
8: [2, 10, 5, 3],
9: [1, 5, 6, 2],
10: [8, 4, 3, 7]
},
"d12": {
1: [2, 3, 4, 5, 6],
2: [1, 6, 8, 12, 3],
3: [1, 4, 11, 12, 2],
4: [1, 5, 10, 11, 3],
5: [1, 6, 9, 10, 4],
6: [1, 2, 8, 9, 5],
7: [8, 9, 10, 11, 12],
8: [2, 6, 9, 7, 12],
9: [5, 10, 7, 8, 6],
10: [4, 11, 7, 9, 5],
11: [7, 10, 4, 3, 12],
12: [2, 8, 7, 11, 3]
}
}
/* -------------------------------------------- */
export class HeritiersUtility {
@@ -9,7 +48,7 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static async init() {
Hooks.on('renderChatLog', (log, html, data) => HeritiersUtility.chatListeners(html))
Hooks.on("getChatLogEntryContext", (html, options) => HeritiersUtility.chatRollMenu(html, options))
/* Unused for Heitiers : Hooks.on("getChatMessageContextOptions", (html, options) => HeritiersUtility.chatRollMenu(html, options))*/
this.rollDataStore = {}
this.defenderStore = {}
@@ -42,17 +81,16 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static sortByName(table) {
static sortByName(table) {
return table.sort(function (a, b) {
let fa = a.name.toLowerCase(),
fb = b.name.toLowerCase();
if (fa < fb) {
return -1;
}
if (fa > fb) {
return 1;
}
return 0;
return a.name.localeCompare(b.name);
})
}
/* -------------------------------------------- */
static sortArrayObjectsByName(myArray) {
myArray.sort((a, b) => {
return a.name.localeCompare(b.name);
})
}
@@ -66,6 +104,29 @@ export class HeritiersUtility {
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.competences")
this.skills = skills.map(i => i.toObject())
this.competencesMagie = this.skills.filter(s => s.system.profil == "magie")
game.settings.register("fvtt-les-heritiers", "heritiers-heritage", {
name: "Points d'héritage",
hint: "Points d'héritage du groupe",
scope: "world",
config: true,
default: 0,
type: Number
})
}
/* -------------------------------------------- */
static getSDSortValue(niveau) {
if (niveau <= 2) return 12;
if (niveau <= 4) return 14;
if (niveau <= 6) return 16;
return 18;
}
/* -------------------------------------------- */
static getCompetencesMagie() {
return this.competencesMagie
}
/* -------------------------------------------- */
@@ -87,18 +148,29 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static async chatListeners(html) {
html.on("click", '.predilection-reroll', async event => {
$(html).on("click", '.predilection-reroll', async event => {
let predIdx = $(event.currentTarget).data("predilection-index")
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
await actor.setPredilectionUsed(rollData.competence._id, predIdx)
rollData.competence = duplicate(actor.getCompetence(rollData.competence._id))
rollData.competence = foundry.utils.duplicate(actor.getCompetence(rollData.competence._id))
HeritiersUtility.rollHeritiers(rollData)
})
html.on("click", '.roll-chat-degat', async event => {
$(html).on("click", '.roll-tricherie-2', async event => {
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
if (await actor.incDecTricherie(-2)) {
rollData.forcedValue = Number($(event.currentTarget).data("dice-value"))
HeritiersUtility.rollHeritiers(rollData)
}
})
$(html).on("click", '.roll-chat-degat', async event => {
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "heritiers-roll")
@@ -115,9 +187,9 @@ export class HeritiersUtility {
'systems/fvtt-les-heritiers/templates/partial-item-header.html',
'systems/fvtt-les-heritiers/templates/partial-item-description.html',
'systems/fvtt-les-heritiers/templates/partial-item-nav.html',
'systems/fvtt-les-heritiers/templates/partial-list-niveau.html'
'systems/fvtt-les-heritiers/templates/partial-utile-skills.html'
]
return loadTemplates(templatePaths);
return foundry.applications.handlebars.loadTemplates(templatePaths);
}
/* -------------------------------------------- */
@@ -194,14 +266,14 @@ export class HeritiersUtility {
let id = rollData.rollId;
let oldRollData = this.rollDataStore[id] || {};
let newRollData = mergeObject(oldRollData, rollData);
let newRollData = foundry.utils.mergeObject(oldRollData, rollData);
this.rollDataStore[id] = newRollData;
}
/* -------------------------------------------- */
static saveRollData(rollData) {
game.socket.emit("system.fvtt-les-heritiers", {
name: "msg_update_roll", data: rollData
}); // Notify all other clients of the roll
}); // Notify all other clients of the roll
this.updateRollData(rollData);
}
@@ -212,7 +284,6 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static onSocketMesssage(msg) {
//console.log("SOCKET MESSAGE", msg.name, game.user.character.id, msg.data.defenderId);
if (msg.name == "msg_update_defense_state") {
this.updateDefenseState(msg.data.defenderId, msg.data.rollId);
}
@@ -269,123 +340,274 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static computeMonnaieDetails(valueSC) {
let po = Math.floor(valueSC / 400)
let pa = Math.floor((valueSC - (po*400)) / 20)
let sc = valueSC - (po*400) - (pa*20)
let pa = Math.floor((valueSC - (po * 400)) / 20)
let sc = valueSC - (po * 400) - (pa * 20)
return {
po: po, pa: pa, sc: sc, valueSC: valueSC
po: po, pa: pa, sc: sc, valueSC: valueSC
}
}
/* -------------------------------------------- */
static incDecHeritage() {
}
/* -------------------------------------------- */
static computeResult(actor, rollData) {
rollData.diceResult = -1
let resTab = []
for ( let res of rollData.roll.terms[0].results) {
rollData.diceResult = Math.max(res.result, rollData.diceResult)
resTab.push(res.result)
}
let isFailure = false
if (rollData.mainDice.includes("d10")) {
if ( rollData.diceResult == 1) {
rollData.finalResult -= 3
isFailure = true
}
}
if (rollData.mainDice.includes("d12")) {
if ( rollData.diceResult == 1 || rollData.diceResult == 2) {
rollData.finalResult -= 5
isFailure = true
}
}
// Heritage/Tricherie management
let isTricherieHeritage = rollData.useHeritage || rollData.useTricherie
rollData.marge = 0
if (!isFailure && (rollData.useHeritage || rollData.useTricherie)) {
if (isTricherieHeritage) {
let resTab = [rollData.roll.terms[0].results[0].result, rollData.roll.terms[0].results[1].result, rollData.roll.terms[0].results[2].result]
rollData.diceResult = resTab[0] + "," + resTab[1] + "," + resTab[2]
let foundryTotal = resTab[0] + resTab[1] + resTab[2]
if (resTab[1] == 1) { resTab[1] -= 4 }
if (resTab[2] == 1) { resTab[2] -= 6 }
if (resTab[2] == 2) { resTab[2] -= 7 }
rollData.diceValue = Math.max(Math.max(resTab[0], resTab[1]), resTab[2])
rollData.finalResult = rollData.roll.total - foundryTotal + rollData.diceValue
// Gestion des résultats spéciaux
resTab = resTab.sort()
if ( (resTab[0] == resTab[1]) && (resTab[1] == resTab[2])) {
if ((resTab[0] == resTab[1]) && (resTab[1] == resTab[2])) {
rollData.marge = 7
rollData.isSuccess = true
rollData.isCriticalSuccess = true
rollData.isCriticalSuccess = true
rollData.isBrelan = true
}
if ((resTab[0]+1 == resTab[1]) && (resTab[1]+1 == resTab[2]) ) {
if ((resTab[0] + 1 == resTab[1]) && (resTab[1] + 1 == resTab[2])) {
rollData.marge = 7
rollData.isSuccess = true
rollData.isCriticalSuccess = true
}
if ( rollData.useTricherie) {
rollData.isCriticalSuccess = true
rollData.isSuite = true
}
if (rollData.useTricherie) {
actor.incDecTricherie(-1)
}
if ( rollData.useHeritage) {
if (rollData.useHeritage) {
this.incDecHeritage()
}
}
//rollData.finalResult = Math.max(rollData.finalResult, 0)
//console.log("Result : ", rollData)
if (rollData.marge == 0 && rollData.sdValue > 0 ) {
rollData.marge = rollData.finalResult - rollData.sdValue
rollData.isSuccess = (rollData.finalResult >= rollData.sdValue)
rollData.isCriticalSuccess = ((rollData.finalResult - rollData.sdValue) >= 7)
rollData.isCriticalFailure = ((rollData.finalResult - rollData.sdValue) <= -7)
} else {
rollData.finalResult = rollData.roll.total
let rollValue = rollData.forcedValue || rollData.roll.terms[0].results[0].result
rollData.diceResult = rollValue
rollData.diceValue = rollValue
if (rollData.mainDice.includes("d10")) {
if (rollValue == 1) {
rollData.finalResult -= 3 + rollValue // substract 3 and the 1 value that has been added
}
}
if (rollData.mainDice.includes("d12")) {
if (rollValue == 1 || rollValue == 2) {
rollData.finalResult -= 5 + rollValue // Remove also the dice result has it has been added already
}
}
if (!rollData.forcedValue) {
rollData.adjacentFaces = foundry.utils.duplicate(__facesAdjacentes[rollData.mainDice][rollData.diceValue])
}
}
}
/* -------------------------------------------- */
static computeArmeDegats(rollData, actor) {
rollData.degatsArme = rollData.arme.system.degats + rollData.marge
if (rollData.attaqueDeuxArmes != 0 && rollData.secondeArme) {
let secondeArme = actor.items.get(secondeArme)
if (secondeArme) {
rollData.degatsArme += secondeArme.system.degats
rollData.degatsArme += actor.system.caracteristiques.for.value
}
} else {
if (rollData.arme.system.categorie == "lourde") {
rollData.degatsArme += actor.system.caracteristiques.for.value
}
if (rollData.arme.system.categorie == "blanche" || rollData.arme.system.categorie == "improvise") {
rollData.degatsArme += Math.max(0, actor.system.caracteristiques.for.value - 2)
}
if (rollData.mode == "attaquecharge") {
rollData.degatsArme += 3
}
}
if (rollData.attaqueCible == "membre") {
rollData.degatsArme -= 2
}
if (rollData.attaqueCible == "main") {
rollData.degatsArme -= 3
}
if (rollData.attaqueCible == "tete") {
rollData.degatsArme *= 3
}
}
/* -------------------------------------------- */
static computeMarge(rollData, seuil) {
if (rollData.marge == 0 && seuil >= 0) {
rollData.marge = rollData.finalResult - seuil
rollData.isSuccess = (rollData.finalResult >= seuil)
rollData.isCriticalSuccess = ((rollData.finalResult - seuil) >= 7)
rollData.isCriticalFailure = ((rollData.finalResult - seuil) <= -7)
// Si compétence > 0 et d8 -> echec critique impossible
if (rollData?.competence?.system.niveau > 0 && rollData?.mainDice == "d8") {
rollData.isCriticalFailure = false
}
}
}
/* -------------------------------------------- */
static async displayUneDefense(rollData, actor, nomDefense, valeurDefense) {
rollData.defenderMode = nomDefense
rollData.defenderValue = valeurDefense
rollData.marge = 0
this.computeMarge(rollData, valeurDefense)
if (rollData.isSuccess) {
this.computeArmeDegats(rollData, actor)
}
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-cc-result.html`, rollData)
}, rollData, "selfroll")
}
/* -------------------------------------------- */
static async displayAsssomer(rollData, actor, nomAttaque, etatAssomer, valeurDefense) {
rollData.defenderMode = nomAttaque
rollData.etatAssommer = etatAssomer
rollData.defenderValue = valeurDefense
rollData.marge = 0
this.computeMarge(rollData, valeurDefense)
rollData.dureeAssommer = (rollData.marge) ? rollData.marge * 2 : 1
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-assommer-result.html`, rollData)
}, rollData, "selfroll")
}
/* -------------------------------------------- */
static async rollHeritiers(rollData) {
let actor = this.getActorFromRollData(rollData)
if (rollData.mode == "pouvoir" && actor.getPouvoirUsage(rollData.pouvoir._id) < rollData.pouvoirPointsUsage) {
ui.notifications.warn("Pas assez de points d'usage pour ce pouvoir.")
return
}
//rollData.actionImg = "systems/fvtt-les-heritiers/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
rollData.carac = duplicate(actor.system.caracteristiques[rollData.caracKey])
if (rollData.caracKey == "pre") rollData.caracKey = "pres"; // Patch tomanage wrong carac key
rollData.carac = foundry.utils.duplicate(actor.system.caracteristiques[rollData.caracKey])
rollData.nbDice = (rollData.useTricherie || rollData.useHeritage) ? 3 : 1
rollData.diceFormula = rollData.nbDice + rollData.mainDice + "kh1"
//console.log("BEFORE COMP", rollData)
if (rollData.competence) {
let compmod = (rollData.competence.system.niveau == 0) ? -3 : 0
rollData.diceFormula += `+${rollData.carac.value}+${rollData.competence.system.niveau}+${rollData.bonusMalusContext}+${compmod}`
if (rollData.forcedValue) {
rollData.diceFormula = rollData.forcedValue
} else {
rollData.diceFormula += `+${rollData.carac.value}+${rollData.bonusMalusContext}`
}
rollData.diceFormula += `+${rollData.pvMalus}`
if (rollData.arme && rollData.arme.type == "arme") {
rollData.diceFormula += `+${rollData.arme.system.bonusmaniementoff}`
if (rollData.useTricherie || rollData.useHeritage) {
rollData.diceFormula = "{1d8, 1d10, 1d12}"
} else {
rollData.diceFormula = "1" + rollData.mainDice + "kh1"
}
}
let myRoll = new Roll(rollData.diceFormula).roll({ async: false })
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
rollData.roll = myRoll
console.log(">>>> ", myRoll)
let rangValue = 0
if (rollData.rang) {
rangValue = rollData.rang.value
}
if (rollData.competence) {
let compmod = 0 // Bonus de compétence à 0 dans Les Heritiers
let specBonus = (rollData.useSpecialite) ? 1 : 0
rollData.diceFormula += `+${rollData.carac.value}+${rangValue}+${rollData.competence.system.niveau}+${specBonus}+${rollData.bonusMalusContext}+${compmod}`
} else if (rollData.pouvoirBase) {
rollData.diceFormula += `+${rollData.carac.value}+${rollData.pouvoirBase.value}+${rangValue}+${rollData.bonusMalusContext}`
} else {
rollData.diceFormula += `+${rollData.carac.value}+${rangValue}+${rollData.bonusMalusContext}`
}
let ruleMalus = 0
for (let malus of rollData.rulesMalus) {
ruleMalus += malus.value
}
rollData.diceFormula += `+${ruleMalus}`
// Gestion bonus attaque à plusieurs
let bonusAttaque = rollData.bonusAttaquePlusieurs
if (rollData.attaqueDos) {
bonusAttaque = 2
if (rollData.bonusAttaquePlusieurs) {
bonusAttaque = 3 // Valeur max, cf règle page 197
}
}
rollData.diceFormula += `+${bonusAttaque}`
// Gestion attaque avec 2 armes
if (rollData.attaqueDeuxArmes != 0) {
rollData.diceFormula += `+${rollData.attaqueDeuxArmes}`
}
// Gestion des attaques ciblées
if (rollData.attaqueCible != "none") {
if (rollData.attaqueCible == "membre") {
rollData.diceFormula += `-2`
}
if (rollData.attaqueCible == "main") {
rollData.diceFormula += `-3`
}
if (rollData.attaqueCible == "tete") {
rollData.diceFormula += `-6`
}
}
if (!rollData.noRoll) {
let myRoll = await new Roll(rollData.diceFormula).roll()
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
rollData.roll = foundry.utils.duplicate(myRoll)
console.log(">>>> ", myRoll)
this.computeResult(actor, rollData)
this.computeMarge(rollData, rollData.sdValue) // Calcul de la marge si seuil présent
}
rollData.finalResult = myRoll.total
this.computeResult(actor, rollData)
if (rollData.mode == "init") {
actor.setFlag("world", "last-initiative", rollData.finalResult)
}
// Gestion pouvoir et points d'usage
if (rollData.mode == "pouvoir" || rollData.mode == "pouvoirpassif") {
actor.incDecPointsUsage(rollData.pouvoir._id, -rollData.pouvoirPointsUsage)
}
this.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
}, rollData)
// Gestion attaque standard
if ((rollData.mode == "arme" || rollData.mode == "attaquebrutale" || rollData.mode == "attaquecharge") &&
rollData.defenderTokenId && rollData.arme) {
if (rollData.arme.system.categorie != "trait" && rollData.arme.system.categorie != "poing" && rollData.arme.system.categorie != "epaule") {
await this.displayUneDefense(rollData, actor, "Parade", rollData.defenderParade)
await this.displayUneDefense(rollData, actor, "Esquive", rollData.defenderEsquive)
} else if (rollData.sdValue) {
this.displayUneDefense(rollData, actor, "A Distance", rollData.sdValue)
} else {
ui.notifications.warn("Pas de difficulté positionnée pour l'attaque à distance.")
}
}
// Gestion assomer
if (rollData.mode == "assommer" && rollData.defenderTokenId && rollData.arme) {
await this.displayAsssomer(rollData, actor, "Assommer", "Surprise", rollData.defenderResistancePhysique)
await this.displayAsssomer(rollData, actor, "Assommer", "Conscient, Résistance+6", rollData.defenderResistancePhysique + 6)
await this.displayAsssomer(rollData, actor, "Assommer", "Conscient, Parade", rollData.defenderParade)
await this.displayAsssomer(rollData, actor, "Assommer", "Conscient, Esquive", rollData.defenderEsquive + 6)
}
}
/* -------------------------------------------- */
static async bonusRollHeritiers(rollData) {
rollData.bonusFormula = rollData.addedBonus
let bonusRoll = new Roll(rollData.bonusFormula).roll({ async: false })
let bonusRoll = await new Roll(rollData.bonusFormula).roll()
await this.showDiceSoNice(bonusRoll, game.settings.get("core", "rollMode"));
rollData.bonusRoll = bonusRoll
rollData.bonusRoll = foundry.utils.duplicate(bonusRoll)
rollData.finalResult += rollData.bonusRoll.total
this.computeResult(rollData)
this.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
}, rollData)
}
@@ -395,6 +617,10 @@ export class HeritiersUtility {
return game.users.filter(filter).map(user => user._id);
}
/* -------------------------------------------- */
static isArmeMelee(arme) {
return (arme.type == "arme" && (arme.system.categorie == "lourde" || arme.system.categorie == "blanche" || arme.system.categorie == "improvise"))
}
/* -------------------------------------------- */
static getWhisperRecipients(rollMode, name) {
switch (rollMode) {
@@ -412,7 +638,7 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static blindMessageToGM(chatOptions) {
let chatGM = duplicate(chatOptions);
let chatGM = foundry.utils.duplicate(chatOptions);
chatGM.whisper = this.getUsers(user => user.isGM);
chatGM.content = "Blinde message of " + game.user.name + "<br>" + chatOptions.content;
console.log("blindMessageToGM", chatGM);
@@ -476,11 +702,17 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static getBasicRollData() {
let rollData = {
rollId: randomID(16),
rollId: foundry.utils.randomID(16),
rollMode: game.settings.get("core", "rollMode"),
sdList: game.system.lesheritiers.config.seuilsDifficulte,
sdValue: 0,
bonusMalusContext: 0
sdValue: -1,
bonusAttaquePlusieurs: 0,
attaqueDeuxArmes: 0,
attaqueDos: false,
bonusMalusContext: 0,
attaqueCible: "none",
config: game.system.lesheritiers.config,
rulesMalus: []
}
return rollData
}
@@ -491,18 +723,18 @@ export class HeritiersUtility {
if (target) {
rollData.defenderTokenId = target.id
let defender = game.canvas.tokens.get(rollData.defenderTokenId).actor
rollData.armeDefense = defender.getBestDefenseValue()
rollData.targetVigueur = defender.getVigueur()
if (rollData.armeDefense) {
rollData.difficulte = rollData.armeDefense.system.totalDefensif
} else {
ui.notifications.warn("Aucune arme de défense équipée, difficulté manuelle à positionner.")
}
rollData.defenderName = defender.name
rollData.defenderParade = defender.getCurrentParade()
rollData.defenderEsquive = defender.getCurrentEsquive()
rollData.defenderResistancePhysique = defender.getCurrentResistancePhysique()
}
}
/* -------------------------------------------- */
static createChatWithRollMode(name, chatOptions, rollData = undefined) {
static createChatWithRollMode(name, chatOptions, rollData = undefined, rollMode = undefined) {
if (rollMode == undefined) {
rollMode = game.settings.get("core", "rollMode")
}
this.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions, rollData)
}
@@ -548,13 +780,13 @@ export class HeritiersUtility {
static chatRollMenu(html, options) {
let canApply = li => canvas.tokens.controlled.length && li.find(".heritiers-roll").length
let canApplyBA = function (li) {
let message = game.messages.get(li.attr("data-message-id"))
let message = game.messages.get($(li).attr("data-message-id"))
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
return (!rollData.isReroll && actor.getBonneAventure() > 0)
}
let canApplyPE = function (li) {
let message = game.messages.get(li.attr("data-message-id"))
let message = game.messages.get($(li).attr("data-message-id"))
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
return (!rollData.isReroll && actor.getEclat() > 0)
@@ -589,11 +821,11 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
let itemId = li.data("item-id");
let msgTxt = "<p>Are you sure to remove this Item ?";
let msgTxt = "<p>Certain de supprimer cet item ?";
let buttons = {
delete: {
icon: '<i class="fas fa-check"></i>',
label: "Yes, remove it",
label: "Oui !",
callback: () => {
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
li.slideUp(200, () => actorSheet.render(false));
@@ -601,12 +833,12 @@ export class HeritiersUtility {
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel"
label: "Non !"
}
}
msgTxt += "</p>";
let d = new Dialog({
title: "Confirm removal",
title: "Confirmer la suppression",
content: msgTxt,
buttons: buttons,
default: "cancel"
@@ -614,21 +846,56 @@ export class HeritiersUtility {
d.render(true);
}
/************************************************************************************/
static async __create_talents_table() {
let compName = "fvtt-les-heritiers.talents-cellule"
const compData = await HeritiersUtility.loadCompendium(compName)
let talents = compData.map(i => i.toObject())
let htmlTab = "<table border='1'><tbody>";
for (let entryData of talents) {
console.log(entryData)
htmlTab += `<tr><td>@UUID[Compendium.${compName}.${entryData._id}]{${entryData.name}}</td>`
htmlTab += `<td>${entryData.system.description}</td>`;
//htmlTab += `<td>${entryData.system.resumebonus}</td>`;
htmlTab += "</tr>\n";
static loadSort() {
// Create afolder in the item directory if it doesn't exist
if (!game.folders.getName("Magie du Clan")) {
Folder.create({
name: "Magie du Clan",
type: "Item",
color: "#3b1361"
});
}
htmlTab += "</table>";
await JournalEntry.create({ name: 'Liste des Talents de Cellule', content: htmlTab });
// Load the srcdata/sorts-druidisme.json file
return fetch("systems/fvtt-les-heritiers/srcdata/sort_magieduclan.json")
.then(response => response.json())
.then(data => {
console.log("Sorts Magie du Clan loaded:", data);
this.sortDruidisme = data;
// Loop through the spell and create the "sort "item based on the JSON content
data.forEach(spell => {
spell.name = spell.name;
spell.type = "sort";
spell.system = {
niveau: spell.niveau,
competence: spell.competence,
carac1: spell.carac1,
carac2: spell.carac2,
description: spell.description,
ingredients: spell.ingredients,
portee: spell.portee,
duree: spell.duree,
concentration: spell.concentration,
critique: spell.critique,
resistance: spell.resistance,
coutactivation: spell.coutactivation
};
spell.img = "systems/fvtt-les-heritiers/assets/icons/sort.webp";
spell.folder = game.folders.getName("Magie du Clan").id;
// Create the item in the world
Item.create(spell)
.then(item => {
console.log("Sort created:", item);
})
.catch(error => {
console.error("Error creating sort item:", error);
});
})
})
.catch(error => {
console.error("Error loading druidism spells:", error);
return [];
});
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

View File

@@ -0,0 +1 @@
MANIFEST-000204

View File

View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.392137 7f12ef7fe6c0 Recovering log #202
2025/08/11-22:51:18.402831 7f12ef7fe6c0 Delete type=3 #200
2025/08/11-22:51:18.403033 7f12ef7fe6c0 Delete type=0 #202
2025/08/11-22:52:41.281449 7f12edffb6c0 Level-0 table #207: started
2025/08/11-22:52:41.281484 7f12edffb6c0 Level-0 table #207: 0 bytes OK
2025/08/11-22:52:41.288560 7f12edffb6c0 Delete type=0 #205
2025/08/11-22:52:41.294969 7f12edffb6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.295038 7f12edffb6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)

View File

@@ -0,0 +1,8 @@
2025/08/11-21:34:20.213810 7f12eeffd6c0 Recovering log #198
2025/08/11-21:34:20.256044 7f12eeffd6c0 Delete type=3 #196
2025/08/11-21:34:20.256149 7f12eeffd6c0 Delete type=0 #198
2025/08/11-22:51:08.095390 7f12edffb6c0 Level-0 table #203: started
2025/08/11-22:51:08.095416 7f12edffb6c0 Level-0 table #203: 0 bytes OK
2025/08/11-22:51:08.101419 7f12edffb6c0 Delete type=0 #201
2025/08/11-22:51:08.115257 7f12edffb6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.115306 7f12edffb6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

@@ -0,0 +1 @@
MANIFEST-000204

View File

View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.427459 7f12effff6c0 Recovering log #202
2025/08/11-22:51:18.437741 7f12effff6c0 Delete type=3 #200
2025/08/11-22:51:18.437824 7f12effff6c0 Delete type=0 #202
2025/08/11-22:52:41.295170 7f12edffb6c0 Level-0 table #207: started
2025/08/11-22:52:41.295253 7f12edffb6c0 Level-0 table #207: 0 bytes OK
2025/08/11-22:52:41.301406 7f12edffb6c0 Delete type=0 #205
2025/08/11-22:52:41.321176 7f12edffb6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.321242 7f12edffb6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)

View File

@@ -0,0 +1,8 @@
2025/08/11-21:34:20.321725 7f12ee7fc6c0 Recovering log #198
2025/08/11-21:34:20.374068 7f12ee7fc6c0 Delete type=3 #196
2025/08/11-21:34:20.374213 7f12ee7fc6c0 Delete type=0 #198
2025/08/11-22:51:08.133789 7f12edffb6c0 Level-0 table #203: started
2025/08/11-22:51:08.133823 7f12edffb6c0 Level-0 table #203: 0 bytes OK
2025/08/11-22:51:08.139874 7f12edffb6c0 Delete type=0 #201
2025/08/11-22:51:08.147851 7f12edffb6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.158002 7f12edffb6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

@@ -0,0 +1 @@
MANIFEST-000204

View File

View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.358721 7f12eeffd6c0 Recovering log #202
2025/08/11-22:51:18.370416 7f12eeffd6c0 Delete type=3 #200
2025/08/11-22:51:18.370477 7f12eeffd6c0 Delete type=0 #202
2025/08/11-22:52:41.264660 7f12edffb6c0 Level-0 table #207: started
2025/08/11-22:52:41.264688 7f12edffb6c0 Level-0 table #207: 0 bytes OK
2025/08/11-22:52:41.270787 7f12edffb6c0 Delete type=0 #205
2025/08/11-22:52:41.294911 7f12edffb6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.295015 7f12edffb6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)

View File

@@ -0,0 +1,8 @@
2025/08/11-21:34:20.151917 7f12ee7fc6c0 Recovering log #198
2025/08/11-21:34:20.210898 7f12ee7fc6c0 Delete type=3 #196
2025/08/11-21:34:20.211020 7f12ee7fc6c0 Delete type=0 #198
2025/08/11-22:51:08.101600 7f12edffb6c0 Level-0 table #203: started
2025/08/11-22:51:08.101658 7f12edffb6c0 Level-0 table #203: 0 bytes OK
2025/08/11-22:51:08.109108 7f12edffb6c0 Delete type=0 #201
2025/08/11-22:51:08.115273 7f12edffb6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.115320 7f12edffb6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)

Binary file not shown.

BIN
packs/avantages/000179.ldb Normal file

Binary file not shown.

View File

1
packs/avantages/CURRENT Normal file
View File

@@ -0,0 +1 @@
MANIFEST-000204

0
packs/avantages/LOCK Normal file
View File

8
packs/avantages/LOG Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.304943 7f12ef7fe6c0 Recovering log #202
2025/08/11-22:51:18.317352 7f12ef7fe6c0 Delete type=3 #200
2025/08/11-22:51:18.317883 7f12ef7fe6c0 Delete type=0 #202
2025/08/11-22:52:41.257402 7f12edffb6c0 Level-0 table #207: started
2025/08/11-22:52:41.257472 7f12edffb6c0 Level-0 table #207: 0 bytes OK
2025/08/11-22:52:41.264373 7f12edffb6c0 Delete type=0 #205
2025/08/11-22:52:41.264537 7f12edffb6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.264567 7f12edffb6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)

8
packs/avantages/LOG.old Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-21:34:19.962488 7f12ee7fc6c0 Recovering log #198
2025/08/11-21:34:20.014408 7f12ee7fc6c0 Delete type=3 #196
2025/08/11-21:34:20.014461 7f12ee7fc6c0 Delete type=0 #198
2025/08/11-22:51:08.055412 7f12edffb6c0 Level-0 table #203: started
2025/08/11-22:51:08.055458 7f12edffb6c0 Level-0 table #203: 0 bytes OK
2025/08/11-22:51:08.062106 7f12edffb6c0 Delete type=0 #201
2025/08/11-22:51:08.085428 7f12edffb6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.085469 7f12edffb6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)

Binary file not shown.

BIN
packs/capacites/000179.ldb Normal file

Binary file not shown.

View File

1
packs/capacites/CURRENT Normal file
View File

@@ -0,0 +1 @@
MANIFEST-000204

0
packs/capacites/LOCK Normal file
View File

8
packs/capacites/LOG Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.341321 7f12ee7fc6c0 Recovering log #202
2025/08/11-22:51:18.354195 7f12ee7fc6c0 Delete type=3 #200
2025/08/11-22:51:18.354810 7f12ee7fc6c0 Delete type=0 #202
2025/08/11-22:52:41.237394 7f12edffb6c0 Level-0 table #207: started
2025/08/11-22:52:41.237434 7f12edffb6c0 Level-0 table #207: 0 bytes OK
2025/08/11-22:52:41.243722 7f12edffb6c0 Delete type=0 #205
2025/08/11-22:52:41.264503 7f12edffb6c0 Manual compaction at level-0 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.264544 7f12edffb6c0 Manual compaction at level-1 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)

8
packs/capacites/LOG.old Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-21:34:20.096085 7f12effff6c0 Recovering log #198
2025/08/11-21:34:20.149715 7f12effff6c0 Delete type=3 #196
2025/08/11-21:34:20.149828 7f12effff6c0 Delete type=0 #198
2025/08/11-22:51:08.062220 7f12edffb6c0 Level-0 table #203: started
2025/08/11-22:51:08.062246 7f12edffb6c0 Level-0 table #203: 0 bytes OK
2025/08/11-22:51:08.068241 7f12edffb6c0 Delete type=0 #201
2025/08/11-22:51:08.085439 7f12edffb6c0 Manual compaction at level-0 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.085475 7f12edffb6c0 Manual compaction at level-1 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

@@ -0,0 +1 @@
MANIFEST-000207

0
packs/competences/LOCK Normal file
View File

8
packs/competences/LOG Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.291417 7f12ee7fc6c0 Recovering log #204
2025/08/11-22:51:18.301512 7f12ee7fc6c0 Delete type=3 #202
2025/08/11-22:51:18.301601 7f12ee7fc6c0 Delete type=0 #204
2025/08/11-22:52:41.243942 7f12edffb6c0 Level-0 table #210: started
2025/08/11-22:52:41.244021 7f12edffb6c0 Level-0 table #210: 0 bytes OK
2025/08/11-22:52:41.250458 7f12edffb6c0 Delete type=0 #208
2025/08/11-22:52:41.264517 7f12edffb6c0 Manual compaction at level-0 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.264551 7f12edffb6c0 Manual compaction at level-1 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)

15
packs/competences/LOG.old Normal file
View File

@@ -0,0 +1,15 @@
2025/08/11-21:34:19.906242 7f12effff6c0 Recovering log #200
2025/08/11-21:34:19.959359 7f12effff6c0 Delete type=3 #198
2025/08/11-21:34:19.959494 7f12effff6c0 Delete type=0 #200
2025/08/11-22:51:08.074684 7f12edffb6c0 Level-0 table #205: started
2025/08/11-22:51:08.078126 7f12edffb6c0 Level-0 table #205: 31504 bytes OK
2025/08/11-22:51:08.085271 7f12edffb6c0 Delete type=0 #203
2025/08/11-22:51:08.085480 7f12edffb6c0 Manual compaction at level-0 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.085510 7f12edffb6c0 Manual compaction at level-1 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at '!items!zEl2NQsnCpELVWzh' @ 338 : 1
2025/08/11-22:51:08.085516 7f12edffb6c0 Compacting 1@1 + 1@2 files
2025/08/11-22:51:08.088988 7f12edffb6c0 Generated table #206@1: 77 keys, 31504 bytes
2025/08/11-22:51:08.089022 7f12edffb6c0 Compacted 1@1 + 1@2 files => 31504 bytes
2025/08/11-22:51:08.095088 7f12edffb6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2025/08/11-22:51:08.095209 7f12edffb6c0 Delete type=2 #197
2025/08/11-22:51:08.095332 7f12edffb6c0 Delete type=2 #205
2025/08/11-22:51:08.115239 7f12edffb6c0 Manual compaction at level-1 from '!items!zEl2NQsnCpELVWzh' @ 338 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

@@ -0,0 +1 @@
MANIFEST-000204

0
packs/desavantages/LOCK Normal file
View File

8
packs/desavantages/LOG Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.324133 7f12effff6c0 Recovering log #202
2025/08/11-22:51:18.335594 7f12effff6c0 Delete type=3 #200
2025/08/11-22:51:18.336174 7f12effff6c0 Delete type=0 #202
2025/08/11-22:52:41.250593 7f12edffb6c0 Level-0 table #207: started
2025/08/11-22:52:41.250618 7f12edffb6c0 Level-0 table #207: 0 bytes OK
2025/08/11-22:52:41.257077 7f12edffb6c0 Delete type=0 #205
2025/08/11-22:52:41.264527 7f12edffb6c0 Manual compaction at level-0 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.264560 7f12edffb6c0 Manual compaction at level-1 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)

View File

@@ -0,0 +1,8 @@
2025/08/11-21:34:20.017484 7f12eeffd6c0 Recovering log #198
2025/08/11-21:34:20.093316 7f12eeffd6c0 Delete type=3 #196
2025/08/11-21:34:20.093428 7f12eeffd6c0 Delete type=0 #198
2025/08/11-22:51:08.068405 7f12edffb6c0 Level-0 table #203: started
2025/08/11-22:51:08.068464 7f12edffb6c0 Level-0 table #203: 0 bytes OK
2025/08/11-22:51:08.074542 7f12edffb6c0 Delete type=0 #201
2025/08/11-22:51:08.085448 7f12edffb6c0 Manual compaction at level-0 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.085490 7f12edffb6c0 Manual compaction at level-1 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)

Binary file not shown.

View File

Binary file not shown.

View File

@@ -0,0 +1 @@
MANIFEST-000002

0
packs/magie-sorts/LOCK Normal file
View File

5
packs/magie-sorts/LOG Normal file
View File

@@ -0,0 +1,5 @@
2025/08/11-22:51:18.389099 7f12eeffd6c0 Delete type=3 #1
2025/08/11-22:52:41.270919 7f12edffb6c0 Level-0 table #5: started
2025/08/11-22:52:41.274955 7f12edffb6c0 Level-0 table #5: 72907 bytes OK
2025/08/11-22:52:41.281286 7f12edffb6c0 Delete type=0 #3
2025/08/11-22:52:41.294945 7f12edffb6c0 Manual compaction at level-0 from '!folders!NE8l8XLXdVUw0aZm' @ 72057594037927935 : 1 .. '!items!zjQQhJpujpdbG4zl' @ 0 : 0; will stop at (end)

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
packs/pouvoirs/000180.ldb Normal file

Binary file not shown.

View File

1
packs/pouvoirs/CURRENT Normal file
View File

@@ -0,0 +1 @@
MANIFEST-000205

0
packs/pouvoirs/LOCK Normal file
View File

8
packs/pouvoirs/LOG Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.409703 7f12eeffd6c0 Recovering log #203
2025/08/11-22:51:18.420789 7f12eeffd6c0 Delete type=3 #201
2025/08/11-22:51:18.420873 7f12eeffd6c0 Delete type=0 #203
2025/08/11-22:52:41.288698 7f12edffb6c0 Level-0 table #208: started
2025/08/11-22:52:41.288730 7f12edffb6c0 Level-0 table #208: 0 bytes OK
2025/08/11-22:52:41.294715 7f12edffb6c0 Delete type=0 #206
2025/08/11-22:52:41.294992 7f12edffb6c0 Manual compaction at level-0 from '!items!19r9ijZUyvnlIqgm' @ 72057594037927935 : 1 .. '!items!zON0h5SjFyANjPnA' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.295062 7f12edffb6c0 Manual compaction at level-1 from '!items!19r9ijZUyvnlIqgm' @ 72057594037927935 : 1 .. '!items!zON0h5SjFyANjPnA' @ 0 : 0; will stop at (end)

8
packs/pouvoirs/LOG.old Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-21:34:20.258603 7f12effff6c0 Recovering log #199
2025/08/11-21:34:20.318194 7f12effff6c0 Delete type=3 #197
2025/08/11-21:34:20.318250 7f12effff6c0 Delete type=0 #199
2025/08/11-22:51:08.109218 7f12edffb6c0 Level-0 table #204: started
2025/08/11-22:51:08.109241 7f12edffb6c0 Level-0 table #204: 0 bytes OK
2025/08/11-22:51:08.115092 7f12edffb6c0 Delete type=0 #202
2025/08/11-22:51:08.115290 7f12edffb6c0 Manual compaction at level-0 from '!items!19r9ijZUyvnlIqgm' @ 72057594037927935 : 1 .. '!items!zON0h5SjFyANjPnA' @ 0 : 0; will stop at (end)
2025/08/11-22:51:08.115335 7f12edffb6c0 Manual compaction at level-1 from '!items!19r9ijZUyvnlIqgm' @ 72057594037927935 : 1 .. '!items!zON0h5SjFyANjPnA' @ 0 : 0; will stop at (end)

Binary file not shown.

0
packs/profils/000204.log Normal file
View File

1
packs/profils/CURRENT Normal file
View File

@@ -0,0 +1 @@
MANIFEST-000202

0
packs/profils/LOCK Normal file
View File

7
packs/profils/LOG Normal file
View File

@@ -0,0 +1,7 @@
2025/08/11-22:51:18.440585 7f12ef7fe6c0 Recovering log #200
2025/08/11-22:51:18.452074 7f12ef7fe6c0 Delete type=3 #198
2025/08/11-22:51:18.452406 7f12ef7fe6c0 Delete type=0 #200
2025/08/11-22:52:41.301484 7f12edffb6c0 Level-0 table #205: started
2025/08/11-22:52:41.301507 7f12edffb6c0 Level-0 table #205: 0 bytes OK
2025/08/11-22:52:41.307731 7f12edffb6c0 Delete type=0 #203
2025/08/11-22:52:41.321197 7f12edffb6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)

7
packs/profils/LOG.old Normal file
View File

@@ -0,0 +1,7 @@
2025/08/11-21:34:20.376707 7f12eeffd6c0 Recovering log #196
2025/08/11-21:34:20.429317 7f12eeffd6c0 Delete type=3 #194
2025/08/11-21:34:20.429419 7f12eeffd6c0 Delete type=0 #196
2025/08/11-22:51:08.115446 7f12edffb6c0 Level-0 table #201: started
2025/08/11-22:51:08.115492 7f12edffb6c0 Level-0 table #201: 0 bytes OK
2025/08/11-22:51:08.121470 7f12edffb6c0 Delete type=0 #199
2025/08/11-22:51:08.147831 7f12edffb6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)

Binary file not shown.

BIN
packs/scenes/000148.ldb Normal file

Binary file not shown.

0
packs/scenes/000175.log Normal file
View File

1
packs/scenes/CURRENT Normal file
View File

@@ -0,0 +1 @@
MANIFEST-000173

0
packs/scenes/LOCK Normal file
View File

8
packs/scenes/LOG Normal file
View File

@@ -0,0 +1,8 @@
2025/08/11-22:51:18.458421 7f12eeffd6c0 Recovering log #171
2025/08/11-22:51:18.469978 7f12eeffd6c0 Delete type=3 #169
2025/08/11-22:51:18.470069 7f12eeffd6c0 Delete type=0 #171
2025/08/11-22:52:41.314747 7f12edffb6c0 Level-0 table #176: started
2025/08/11-22:52:41.314796 7f12edffb6c0 Level-0 table #176: 0 bytes OK
2025/08/11-22:52:41.320976 7f12edffb6c0 Delete type=0 #174
2025/08/11-22:52:41.321230 7f12edffb6c0 Manual compaction at level-0 from '!scenes!8DjkNeeujp2qff1N' @ 72057594037927935 : 1 .. '!scenes!ypDutqjqZcr7lx6I' @ 0 : 0; will stop at (end)
2025/08/11-22:52:41.321269 7f12edffb6c0 Manual compaction at level-1 from '!scenes!8DjkNeeujp2qff1N' @ 72057594037927935 : 1 .. '!scenes!ypDutqjqZcr7lx6I' @ 0 : 0; will stop at (end)

Some files were not shown because too many files have changed in this diff Show More