Merge branch 'develop'

This commit is contained in:
2024-03-29 14:33:58 +01:00
30 changed files with 1689 additions and 683 deletions
+114
View File
@@ -0,0 +1,114 @@
/* global Handlebars, game, TextEditor, WOD5E */
import { M5Skill } from "./module/M5Base";
import { M5Character } from "./module/actors/M5Character";
/**
* Define any helpers necessary for working with Handlebars
* @return {Promise}
*/
export const loadHelpers = async function () {
Handlebars.registerHelper("times", (n: number, block) => {
var accum = "";
for (let i = 0; i < n; ++i) accum += block.fn(i);
return accum;
});
Handlebars.registerHelper("array", (arr: any[], index: number) => {
return arr[index];
});
Handlebars.registerHelper("m5concat", (...values) => {
const options = values.pop();
const join = options.hash?.join || "";
//return new Handlebars.SafeString(values.join(join));
return values.map((val) => val.toString()).join(join);
});
Handlebars.registerHelper("add", (...values) => {
const options = values.pop();
return values.reduce((prev, cur) => prev + cur);
});
Handlebars.registerHelper("localizeMidgard", (str: string) => {
const template = Handlebars.compile("{{localize value}}");
return template({
value: "midgard5." + str,
});
});
Handlebars.registerHelper("skillBonus", (actorId: string, skill: M5Skill) => {
const actor = (game as Game).actors.get(actorId) as M5Character;
return actor.skillBonus(skill).toString();
});
Handlebars.registerHelper("skillEw", (actorId: string, skill: M5Skill) => {
const actor = (game as Game).actors.get(actorId) as M5Character;
return actor.skillEw(skill).toString();
});
Handlebars.registerHelper("skill", (skillId: string) => {
return (game as Game).items.get(skillId);
});
Handlebars.registerHelper("itemValue", (id: string, path: string) => {
let obj = (game as Game).items.get(id);
path.split(".").forEach((p) => (obj = obj[p]));
return `${obj}`;
});
Handlebars.registerHelper("actorItemValue", (actorId: any, itemId: string, path: string, token?: boolean) => {
//console.log("actorItemValue", actorId, itemId, path)
const actor = (game as Game).actors.get(actorId);
let obj = actor.items.get(itemId)?.system;
path.split(".").forEach((p) => {
if (obj) obj = obj[p];
});
return `${obj}`;
});
Handlebars.registerHelper("icon", (relpath: string) => {
return `systems/midgard5/assets/icons/${relpath}`;
});
Handlebars.registerHelper("isSkillInList", (skillName: string, list: any) => {
for (let key in list) {
if (list[key]?.label?.toLowerCase() === skillName?.toLowerCase()) {
return true;
}
}
return false;
});
Handlebars.registerHelper("skillEwInList", (skillName: string, list: any) => {
for (let key in list) {
if (list[key]?.label?.toLowerCase() === skillName?.toLowerCase()) {
return list[key].calc.ew;
}
}
return false;
});
Handlebars.registerHelper("stripHtml", function (param) {
var regex = /(<([^>]+)>)/gi;
return param.replace(regex, "");
});
Handlebars.registerHelper("contains", (label: string, contains: string) => {
return label.toLowerCase().includes(contains.toLowerCase());
});
Handlebars.registerHelper("count", (object: any) => {
var length = 0;
for (var key in object) {
if (object.hasOwnProperty(key)) {
++length;
}
}
return length;
});
Handlebars.registerHelper("console", (object: any) => {
console.log(object);
});
};
+19 -91
View File
@@ -2,103 +2,18 @@ import Logger from "./utils/Logger";
import M5CharacterSheet from "./module/sheets/M5CharacterSheet";
import preloadTemplates from "./PreloadTemplates";
import { M5Character } from "./module/actors/M5Character";
import { M5ItemMod, M5ModOperation, M5Skill, M5TimeUnit } from "./module/M5Base";
import { M5ModOperation, M5TimeUnit } from "./module/M5Base";
import { M5ItemSheet } from "./module/sheets/M5ItemSheet";
import { M5Item } from "./module/items/M5Item";
import { reroll } from "./module/rolls/reroll";
import { loadHelpers } from "./helpers";
import { loadSettings } from "./settings";
Hooks.once("init", async () => {
Logger.log("M5 | Initialisierung Midgard 5");
Handlebars.registerHelper("times", (n: number, block) => {
var accum = "";
for (let i = 0; i < n; ++i) accum += block.fn(i);
return accum;
});
Handlebars.registerHelper("array", (arr: any[], index: number) => {
return arr[index];
});
Handlebars.registerHelper("m5concat", (...values) => {
const options = values.pop();
const join = options.hash?.join || "";
//return new Handlebars.SafeString(values.join(join));
return values.map((val) => val.toString()).join(join);
});
Handlebars.registerHelper("add", (...values) => {
const options = values.pop();
return values.reduce((prev, cur) => prev + cur);
});
Handlebars.registerHelper("localizeMidgard", (str: string) => {
const template = Handlebars.compile("{{localize value}}");
return template({
value: "midgard5." + str,
});
});
Handlebars.registerHelper("skillBonus", (actorId: string, skill: M5Skill) => {
const actor = (game as Game).actors.get(actorId) as M5Character;
return actor.skillBonus(skill).toString();
});
Handlebars.registerHelper("skillEw", (actorId: string, skill: M5Skill) => {
const actor = (game as Game).actors.get(actorId) as M5Character;
return actor.skillEw(skill).toString();
});
Handlebars.registerHelper("skill", (skillId: string) => {
return (game as Game).items.get(skillId);
});
Handlebars.registerHelper("itemValue", (id: string, path: string) => {
let obj = (game as Game).items.get(id);
path.split(".").forEach((p) => (obj = obj[p]));
return `${obj}`;
});
Handlebars.registerHelper("actorItemValue", (actorId: any, itemId: string, path: string, token?: boolean) => {
//console.log("actorItemValue", actorId, itemId, path)
const actor = (game as Game).actors.get(actorId);
let obj = actor.items.get(itemId)?.system;
path.split(".").forEach((p) => {
if (obj) obj = obj[p];
});
return `${obj}`;
});
Handlebars.registerHelper("icon", (relpath: string) => {
return `systems/midgard5/assets/icons/${relpath}`;
});
Handlebars.registerHelper("isSkillInList", (skillName: string, list: any) => {
for (let key in list) {
if (list[key]?.label?.toLowerCase() === skillName?.toLowerCase()) {
return true;
}
}
return false;
});
Handlebars.registerHelper("stripHtml", function (param) {
var regex = /(<([^>]+)>)/gi;
return param.replace(regex, "");
});
Handlebars.registerHelper("contains", (label: string, contains: string) => {
return label.toLowerCase().includes(contains.toLowerCase());
});
Handlebars.registerHelper("count", (object: any) => {
var length = 0;
for (var key in object) {
if (object.hasOwnProperty(key)) {
++length;
}
}
return length;
});
// Load settings into Foundry
loadSettings();
// Default Sheet für Items definieren und das Standardsheet deaktivieren
Items.unregisterSheet("core", ItemSheet);
@@ -112,6 +27,8 @@ Hooks.once("init", async () => {
CONFIG.Item.documentClass = M5Item;
//RegisterSettings();
await preloadTemplates();
loadHelpers();
});
Hooks.once("setup", () => {
@@ -163,6 +80,17 @@ Hooks.on("getChatLogEntryContext", function (html, options) {
return (game["user"].character || game["canvas"].tokens.controlled) && damageRolls > 0;
},
callback: (li) => applyDamage(li, -2),
},
{
name: "Redo",
icon: '<i class="far fa-arrow-rotate-left"></i>',
condition: (li) => {
const message = (game as Game).messages.get(li.attr("data-message-id"));
// All must be true to show the reroll dialogue
return (game["user"].isGM || game["user"].character?.id === (game as Game).actors.get(message["speaker"].actor)?.id) && !message["flags"].rerolled;
},
callback: (li) => reroll(li),
}
);
});
+9 -16
View File
@@ -28,8 +28,9 @@ export interface M5Attribute {
export interface M5RollData {
c: any;
i: any;
b: any;
iType: string;
rolls: {};
rolls: any;
res: {
label: string;
};
@@ -103,17 +104,9 @@ export enum M5Stats {
AP = "ap",
PROTECTION_LP = "lpProtection",
PROTECTION_AP = "apProtection",
PERCEPTION = "perception",
DRINKING = "drinking",
HOARD = "hoard",
HOARD_NEXT = "hoardNext",
HOARD_MIN = "hoardMin",
WEALTH = "wealth",
LOAD = "load",
HEAVY_LOAD = "heavyLoad",
LOAD_MAX = "loadMax",
THRUST_LOAD = "thrustLoad",
ENCUMBRANCE = "encumbrance",
DEPRIVATION_COLD = "deprivationCold",
DEPRIVATION_HEAT = "deprivationHeat",
DEPRIVATION_FOOD = "deprivationFood",
}
export enum M5ModType {
@@ -180,6 +173,7 @@ export interface M5CharacterCalculatedData {
pa: M5AttributeCalculated;
wk: M5AttributeCalculated;
};
stats: {
lp: M5ModResult;
ap: M5ModResult;
@@ -197,10 +191,9 @@ export interface M5CharacterCalculatedData {
brawlFw: number;
poisonResistance: M5ModResult;
enduranceBonus: number;
perception: M5ModResult;
perceptionFW: number;
drinking: M5ModResult;
drinkingFW: number;
deprivationCold: M5ModResult;
deprivationHeat: M5ModResult;
deprivationFood: M5ModResult;
hoard: number;
hoardNext: number;
hoardMin: number;
+48 -87
View File
@@ -1,18 +1,5 @@
import { M5Item } from "../items/M5Item";
import {
M5Attribute,
M5CharacterCalculatedData,
M5ItemMod,
M5ItemType,
M5ModOperation,
M5ModResult,
M5ModType,
M5RollData,
M5Skill,
M5SkillCalculated,
M5SkillLearned,
M5SkillType,
} from "../M5Base";
import { M5Attribute, M5CharacterCalculatedData, M5ItemMod, M5ItemType, M5ModOperation, M5ModResult, M5RollData, M5Skill, M5SkillCalculated } from "../M5Base";
import M5ModAggregate from "./M5ModAggregate";
export class M5Character extends Actor {
// constructor(
@@ -94,6 +81,7 @@ export class M5Character extends Actor {
containers?: boolean;
kampfkuenste?: boolean;
encumbrance?: boolean;
class?: boolean;
} = {}
): M5CharacterCalculatedData {
let ret: M5CharacterCalculatedData = {
@@ -126,10 +114,9 @@ export class M5Character extends Actor {
brawlFw: 0,
poisonResistance: { value: 0, mods: [] },
enduranceBonus: 0,
perception: { value: 0, mods: [] },
perceptionFW: 0,
drinking: { value: 0, mods: [] },
drinkingFW: 0,
deprivationCold: { value: 0, mods: [] },
deprivationHeat: { value: 0, mods: [] },
deprivationFood: { value: 0, mods: [] },
hoard: 0,
encumbrance: 0,
load: 0,
@@ -194,21 +181,16 @@ export class M5Character extends Actor {
ret.stats.attackBonus = this.modResult(ret.attributes.gs.bonus);
ret.stats.defenseBonus = this.modResult(ret.attributes.gw.bonus);
ret.stats.movement = this.modResult(data.movement);
ret.stats.resistanceMind = this.modResult(
(data.info.magicUsing ? 2 : 0) + ret.stats.defense.value + (data.info.race === "Mensch" ? ret.attributes.in.bonus : this.raceBonus(data.info.race))
);
ret.stats.resistanceBody = this.modResult(
(data.info.magicUsing ? 2 : 1) + ret.stats.defense.value + (data.info.race === "Mensch" ? ret.attributes.ko.bonus : this.raceBonus(data.info.race))
);
ret.stats.resistanceMind = this.modResult(ret.stats.defense.value + (data.info.race === "Mensch" ? ret.attributes.in.bonus : this.raceBonus(data.info.race)));
ret.stats.resistanceBody = this.modResult(ret.stats.defense.value + (data.info.race === "Mensch" ? ret.attributes.ko.bonus : this.raceBonus(data.info.race)));
ret.stats.spellCasting = this.modResult((data.info.magicUsing ? M5Character.spellCastingFromLevel(ret.level) : 3) + ret.attributes.zt.bonus);
ret.stats.brawl = this.modResult(Math.floor((ret.attributes.st.value + ret.attributes.gw.value) / 20));
ret.stats.brawlFw = ret.stats.brawl.value + ret.stats.attackBonus.value + (data.info.race === "Zwerg" ? 1 : 0);
ret.stats.poisonResistance = this.modResult(30 + Math.floor(ret.attributes.ko.value / 2));
ret.stats.enduranceBonus = Math.floor(ret.attributes.ko.value / 10) + Math.floor(ret.attributes.st.value / 20);
ret.stats.perception = this.modResult(0);
ret.stats.perceptionFW = 6;
ret.stats.drinking = this.modResult(0);
ret.stats.drinkingFW = Math.floor(ret.attributes.ko.value / 10);
ret.stats.deprivationCold = this.modResult(Math.floor(ret.attributes.ko.value / 2));
ret.stats.deprivationHeat = this.modResult(Math.floor(ret.attributes.ko.value / 2));
ret.stats.deprivationFood = this.modResult(Math.floor(40 + ret.attributes.ko.value / 2));
ret.stats.hoardMin = M5Character.levelThreshold.at(ret.level - 1) / 2;
ret.stats.hoardNext = M5Character.levelThreshold.at(ret.level) / 2;
ret.stats.wealth = parseFloat((data.info.gold + data.info.silver / 10 + data.info.copper / 100).toPrecision(3));
@@ -223,7 +205,10 @@ export class M5Character extends Actor {
const aggregate = new M5ModAggregate(data, ret);
context.items
?.filter((item) => (item.type === "item" || item.type === "effect" || item.type === "armor" || item.type === "container") && item.system.equipped)
?.filter(
(item) =>
(item.type === "item" || item.type === "skill" || item.type === "effect" || item.type === "armor" || item.type === "container" || item.type === "class") && item.system.equipped
)
.forEach((item) => {
const mods = item.system.mods;
//console.log("Actor item mods", mods)
@@ -266,6 +251,7 @@ export class M5Character extends Actor {
calc: item.system.calc,
equipped: item.system?.equipped,
weight: item.system.weight || 0,
capacity: item.system.capacity || 0,
value: item.system.value || 0,
currency: item.system.currency || "",
quantity: item.system.quantity || 0,
@@ -363,6 +349,7 @@ export class M5Character extends Actor {
ret.gear.weapons[item.id] = {
label: label,
icon: item.img,
skillId: item.system.skillId,
magic: item.system.magic,
valuable: item.system?.valuable,
@@ -405,6 +392,7 @@ export class M5Character extends Actor {
ret.gear.defensiveWeapons[item.id] = {
label: label,
icon: item.img,
skillId: item.system.skillId,
magic: item.system.magic,
valuable: item.system?.valuable,
@@ -448,6 +436,7 @@ export class M5Character extends Actor {
ret.gear.armor[item.id] = {
label: label,
icon: item.img,
magic: item.system.magic,
valuable: item.system?.valuable,
hoarded: item.system?.hoarded,
@@ -460,56 +449,26 @@ export class M5Character extends Actor {
containerId: item.system.containerId || "",
};
});
}
// if (!skip?.encumbrance) {
// const item = context.items.filter((x) => x.name === "Belastung");
// if (ret.stats.encumbrance > ret.stats.heavyLoad) {
// if (item.length === 0) {
// this.createEffect("Belastung", [{ id: "movement", operation: M5ModOperation.DIVISION, type: M5ModType.STAT, value: 2 }]);
// } else if (item.length === 1) {
// item[0].update({
// data: {
// equipped: true,
// },
// });
// } else if (item.length === 2) {
// item[1]?.delete();
// }
// } else if (ret.stats.encumbrance <= ret.stats.heavyLoad) {
// if (item.length === 1) {
// item[0]?.update({
// data: {
// equipped: false,
// },
// });
// }
// }
// }
if (!skip?.class) {
context.items
?.filter((item) => item.type === "class")
.sort((a, b) => b?.system.magicUsing - a?.system.magicUsing)
.forEach((item, index) => {
if (index !== 0) {
item.system.equipped = false;
} else {
item.system.equipped = true;
data.info.magicUsing = item.system.magicUsing;
data.lernKostenZauber = item.system.lernKostenZauber;
}
// if (!skip?.encumbrance) {
// const item = context.items.filter((x) => x.name === "Höchstlast");
// if (ret.stats.encumbrance > ret.stats.loadMax) {
// if (item.length === 0) {
// this.createEffect("Höchstlast", [{ id: "ap", operation: M5ModOperation.SUBTRACT, type: M5ModType.STAT, value: 1 }]);
// } else if (item.length === 1) {
// item[0].update({
// data: {
// equipped: true,
// },
// });
// } else if (item.length === 2) {
// item[1]?.delete();
// }
// } else if (ret.stats.encumbrance <= ret.stats.loadMax) {
// if (item.length === 1) {
// item[0]?.update({
// data: {
// equipped: false,
// },
// });
// }
// }
// }
if (typeof data.info.class === "string") {
data.info.class = {};
}
data.info.class[item.id] = item.name;
});
}
if (!skip?.effects) {
@@ -526,6 +485,7 @@ export class M5Character extends Actor {
ret.gear.effects[item.id] = {
label: label,
icon: item.img,
magic: item.system.magic,
calc: item.system.calc,
equipped: item.system?.equipped || false,
@@ -543,21 +503,12 @@ export class M5Character extends Actor {
const skillMap = ret.skills[item.system.type];
skillMap[item.id] = {
label: item.name,
icon: item.img,
fw: item.system.fw,
attribute: item.system.attribute,
pp: item.system.pp,
calc: item.system.calc,
} as M5SkillCalculated;
// Adjust attribute Aussehen based on Athletik skill
if (item.name === "Athletik") {
ret.attributes.au.value += Math.floor(item.system.fw / 3);
}
// Adjust stat Bewegungsweite based on Laufen skill
if (item.name === "Laufen") {
ret.stats.movement.value += Math.floor(item.system.fw / 3);
}
});
}
@@ -570,8 +521,17 @@ export class M5Character extends Actor {
ret.spells[item.id] = {
label: item.name,
icon: item.img,
process: "midgard5.spell-process-" + item.system.process,
calc: item.system.calc,
type: item.system.type,
castDuration: item.system.castDuration || 0,
ap: item.system.ap || 0,
range: item.system.range || 0,
effectTarget: item.system.effectTarget,
effectArea: item.system.effectArea,
effectDuration: item.system.effectDuration || 0,
equipped: item.system?.equipped || false,
};
});
}
@@ -585,6 +545,7 @@ export class M5Character extends Actor {
ret.kampfkuenste[item.id] = {
label: item.name,
icon: item.img,
isKido: item.system.isKido,
type: item.system.type,
variante: item.system.variante,
+3 -2
View File
@@ -41,8 +41,9 @@ export default class M5ModAggregate {
this.push({ type: M5ModType.STAT, id: M5Stats.AP, operation: M5ModOperation.SET, value: calc.stats.ap.value }, characterString);
this.push({ type: M5ModType.STAT, id: M5Stats.PROTECTION_LP, operation: M5ModOperation.SET, value: calc.stats.lpProtection.value }, characterString);
this.push({ type: M5ModType.STAT, id: M5Stats.PROTECTION_AP, operation: M5ModOperation.SET, value: calc.stats.apProtection.value }, characterString);
this.push({ type: M5ModType.STAT, id: M5Stats.PERCEPTION, operation: M5ModOperation.SET, value: calc.stats.perception.value }, characterString);
this.push({ type: M5ModType.STAT, id: M5Stats.DRINKING, operation: M5ModOperation.SET, value: calc.stats.drinking.value }, characterString);
this.push({ type: M5ModType.STAT, id: M5Stats.DEPRIVATION_COLD, operation: M5ModOperation.SET, value: calc.stats.deprivationCold.value }, characterString);
this.push({ type: M5ModType.STAT, id: M5Stats.DEPRIVATION_HEAT, operation: M5ModOperation.SET, value: calc.stats.deprivationHeat.value }, characterString);
this.push({ type: M5ModType.STAT, id: M5Stats.DEPRIVATION_FOOD, operation: M5ModOperation.SET, value: calc.stats.deprivationFood.value }, characterString);
}
push(mod: M5ItemMod, source: string) {
+36 -7
View File
@@ -13,12 +13,13 @@ export class M5Item extends Item {
const character = actor as M5Character;
const itemData = (this as any).system;
const calc = itemData.calc;
const name = (this as any).name;
if (itemType === "item") {
calc.containers = null;
if (actor) {
const actorCalc = actor.derivedData({ containers: false, items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true });
const actorCalc = actor.derivedData({ containers: false, items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true, class: true });
if (actorCalc) {
calc.containers = actorCalc.gear.containers;
}
@@ -45,14 +46,39 @@ export class M5Item extends Item {
},
];
// Adjust attribute Aussehen based on Athletik skill
if (name === "Athletik") {
itemData.mods[0] = { type: "attribute", id: "au", operation: "add100", value: Math.floor(calc.fw / 3) };
}
// Adjust stat Bewegungsweite based on Laufen skill
if (name === "Laufen") {
itemData.mods[0] = { type: "stat", id: "movement", operation: "add", value: Math.floor(calc.fw / 3) };
}
// Adjust stat Kälte based on Überleben (Gebirge) skill
if (name === "Überleben (Gebirge)") {
itemData.mods[0] = { type: "stat", id: "deprivationCold", operation: "add", value: Math.floor(calc.fw * 5) };
}
// // Adjust stat Kälte based on Überleben (Steppe) skill
if (name === "Überleben (Steppe)") {
itemData.mods[0] = { type: "stat", id: "deprivationHeat", operation: "add", value: Math.floor(calc.fw * 5) };
}
// // Adjust stat Durst & Hunger based on Robustheit skill
if (name === "Robustheit") {
itemData.mods[0] = { type: "stat", id: "deprivationFood", operation: "add", value: Math.floor(calc.fw * 5) };
}
if (character) {
const actorCalc = character.derivedData({
containers: true,
skills: true,
items: true,
spells: true,
effects: true,
kampfkuenste: true,
encumbrance: true,
class: true,
});
if (actorCalc?.skillMods && Object.keys(actorCalc.skillMods).indexOf(itemId) !== -1) {
pairs = pairs.concat(actorCalc.skillMods[itemId]);
@@ -89,7 +115,7 @@ export class M5Item extends Item {
calc.containers = null;
if (actor) {
const actorCalc = character.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true });
const actorCalc = character.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true, class: true });
if (actorCalc) {
calc.ew += actorCalc.stats.attackBonus.value;
calc.combatSkills = actorCalc.skills.combat;
@@ -124,7 +150,7 @@ export class M5Item extends Item {
calc.containers = null;
if (actor) {
const actorCalc = character.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true });
const actorCalc = character.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true, class: true });
if (actorCalc) {
calc.ew += actorCalc.stats.defense.value + actorCalc.stats.defenseBonus.value;
calc.combatSkills = actorCalc.skills.combat;
@@ -157,7 +183,7 @@ export class M5Item extends Item {
itemData.mods[5] = { type: "stat", id: "apProtection", operation: "set", value: itemData.apProtection };
calc.containers = null;
if (actor) {
const actorCalc = actor.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true });
const actorCalc = actor.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true, class: true });
if (actorCalc) {
calc.containers = actorCalc.gear.containers;
}
@@ -171,7 +197,7 @@ export class M5Item extends Item {
} else if (itemType === "spell") {
calc.fw = 0;
if (actor) {
const actorCalc = character.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true });
const actorCalc = character.derivedData({ containers: true, items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true, class: true });
if (actorCalc) {
calc.ew = actorCalc.stats.spellCasting.value;
}
@@ -183,7 +209,7 @@ export class M5Item extends Item {
calc.generalSkills = null;
if (actor) {
const actorCalc = character.derivedData({ items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true });
const actorCalc = character.derivedData({ containers: true, items: true, spells: true, effects: true, kampfkuenste: true, encumbrance: true, class: true });
if (actorCalc) {
calc.generalSkills = actorCalc.skills.general;
}
@@ -197,6 +223,9 @@ export class M5Item extends Item {
itemData.rolls.formulas[0].label = skill.name;
}
}
} else if (itemType === "class") {
itemData.mods[0] = { type: "stat", id: "resistanceBody", operation: "add", value: itemData.resistanceBody };
itemData.mods[1] = { type: "stat", id: "resistanceMind", operation: "add", value: itemData.resistanceMind };
}
if (itemData?.mods) {
calc.mods = {};
@@ -318,7 +347,7 @@ export class M5Item extends Item {
}
}
const roll = new M5Roll(rollData, this.actor, item.name);
const roll = new M5Roll(rollData, this.actor, item.name, item.id);
return roll.toMessage();
} else {
ChatMessage.create({
+141 -15
View File
@@ -11,7 +11,7 @@ export class M5Roll {
public _total: number = 0;
public pool: PoolTerm = null;
constructor(public data: M5RollData, public actor: any, public label: string) {
constructor(public data: M5RollData, public actor: any, public label: string, public id?: string) {
//super(null)
//this.data = rollData
}
@@ -26,10 +26,10 @@ export class M5Roll {
.map((rollName, index) => {
indexMap.set(index, rollName);
const formula = this.data.rolls[rollName];
formula.formula = index === 0 && this.id !== "-1" ? formula.formula.replace(/(\d*d\d*)/, `{$1 + ${this.data.b.modifier}}`) : formula.formula;
const roll = new Roll(formula.formula, this.data);
return roll;
});
this.pool = PoolTerm.fromRolls(rolls);
console.log("evaluate", this._evaluated, this.pool);
return this.pool.evaluate({ async: true }).then((results) => {
@@ -66,7 +66,7 @@ export class M5Roll {
const parseResult = M5Roll.parseDiceSides(rollResult.formula);
//console.log("evaluate roll", parseResult)
if (parseResult?.sides === 20) {
if (roll.total < 20) {
if (roll.total < this.data.b.difficulty) {
if (rowRes === M5EwResult.TBD || rowRes === M5EwResult.HIGH) rowRes = M5EwResult.FAIL;
} else {
if (rowRes === M5EwResult.TBD) rowRes = M5EwResult.PASS;
@@ -88,6 +88,50 @@ export class M5Roll {
});
this.data.res.label = this.label;
if ((game as Game).settings.get("midgard5", "automatedPP") && this.data.iType !== null) {
if ((this.data.i.type === "language" || this.data.i.type === "general") && this.data.rolls[0].dice[0] >= 16) {
this.actor.items.get(this.id).update({
system: {
pp: this.data.i.pp + 1,
},
});
} else if (this.data.rolls[0].dice[0] === 20) {
if (this.data.i.type === "combat") {
// Rolling through skill
this.actor.items.get(this.id).update({
system: {
pp: this.data.i.pp + 1,
},
});
} else if (this.data.iType === "weapon") {
// Rolling through Weapon Item
const skill = this.actor.items.get(this.data.i.skillId);
skill.update({
system: {
pp: skill.system.pp + 1,
},
});
} else if (this.data.iType === "defensiveWeapon") {
// Rolling through defensiveWeapon Item
const skill = this.actor.items.get(this.data.i.skillId);
skill.update({
system: {
pp: skill.system.pp + 1,
},
});
} else if (this.data.iType === "spell") {
// Rolling through Spell Item
const klasse = this.actor.items.find((x) => x.type === "class" && x.system.equipped);
klasse.update({
system: {
lernKostenZauber: {
[this.data.i.process]: { pp: klasse.system.lernKostenZauber[this.data.i.process].pp + 1 },
},
},
});
}
}
}
this._evaluated = true;
return this;
@@ -99,20 +143,28 @@ export class M5Roll {
}
async toMessage() {
let checkOptions = await this.popUp({ isPW: this.data.rolls[0].label === (game as Game).i18n.localize("midgard5.pw") });
if (checkOptions["cancelled"]) {
return;
} else {
this.data.b = checkOptions;
}
if (!this._evaluated) await this.evaluate();
const faces = this.pool.dice.map((x) => x.faces);
const rMode = (game as Game).settings.get("core", "rollMode");
const rMode = checkOptions["rollMode"] || (game as Game).settings.get("core", "rollMode");
const chatData = {
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
content: await this.render(),
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
sound: CONFIG.sounds.dice,
roll: Roll.fromTerms([this.pool]),
flags: { data: this.data, rerolled: false, faces: faces },
};
ChatMessage.applyRollMode(chatData, rMode);
return ChatMessage.create(chatData);
let foo = ChatMessage.applyRollMode(chatData, rMode);
return ChatMessage.implementation["create"](foo, { rollMode: rMode });
}
static fromAttributeValue(actor: any, attributeKey: string, attributeValue: number) {
@@ -195,13 +247,13 @@ export class M5Roll {
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.brawl"));
}
static perception(actor: any) {
static deprivationCold(actor: any) {
const rollData = actor.getRollData() as M5RollData;
rollData.rolls["0"] = {
formula: "1d20 + @c.calc.stats.perception.value + @c.calc.stats.perceptionFW",
formula: "@c.calc.stats.deprivationCold.value -1D100",
enabled: true,
label: (game as Game).i18n.localize("midgard5.perception"),
label: (game as Game).i18n.localize("midgard5.deprivationCold"),
result: "",
total: 0,
totalStr: "",
@@ -209,16 +261,16 @@ export class M5Roll {
css: "",
} as M5RollResult;
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.perception"));
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.deprivationCold"));
}
static drinking(actor: any) {
static deprivationHeat(actor: any) {
const rollData = actor.getRollData() as M5RollData;
rollData.rolls["0"] = {
formula: "1d20 + @c.calc.stats.drinking.value + @c.calc.stats.drinkingFW",
formula: "@c.calc.stats.deprivationHeat.value -1D100",
enabled: true,
label: (game as Game).i18n.localize("midgard5.drinking"),
label: (game as Game).i18n.localize("midgard5.deprivationHeat"),
result: "",
total: 0,
totalStr: "",
@@ -226,7 +278,41 @@ export class M5Roll {
css: "",
} as M5RollResult;
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.drinking"));
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.deprivationHeat"));
}
static deprivationFood(actor: any) {
const rollData = actor.getRollData() as M5RollData;
rollData.rolls["0"] = {
formula: "@c.calc.stats.deprivationFood.value -1D100",
enabled: true,
label: (game as Game).i18n.localize("midgard5.deprivationFood"),
result: "",
total: 0,
totalStr: "",
dice: {},
css: "",
} as M5RollResult;
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.deprivationFood"));
}
static cleanSpell(actor: any) {
const rollData = actor.getRollData() as M5RollData;
rollData.rolls["0"] = {
formula: "1d20 + @c.calc.stats.spellCasting.value",
enabled: true,
label: (game as Game).i18n.localize("midgard5.spellCasting"),
result: "",
total: 0,
totalStr: "",
dice: {},
css: "",
} as M5RollResult;
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.spellCasting"));
}
static defense(actor: any) {
@@ -313,6 +399,46 @@ export class M5Roll {
return null;
}
async popUp({
useFortune = false,
difficulty = 20,
modifier = 0,
rollModes = CONFIG.Dice.rollModes,
rollMode = "",
template = "systems/midgard5/templates/chat/task-check-dialog.hbs",
isPW = false,
} = {}) {
const html = await renderTemplate(template, { useFortune, difficulty, modifier, rollModes, rollMode, isPW });
return new Promise((resolve) => {
const data = {
title: (game as Game).i18n.localize("midgard5.chat.roll"),
content: html,
buttons: {
roll: {
label: (game as Game).i18n.localize("midgard5.chat.roll"),
callback: (html) => resolve(this._processTaskCheckOptions(html[0].querySelector("form"))),
},
cancel: {
label: (game as Game).i18n.localize("midgard5.chat.cancel"),
callback: (html) => resolve({ cancelled: true }),
},
},
default: "roll",
close: () => resolve({ cancelled: true }),
};
new Dialog(data, null).render(true);
});
}
_processTaskCheckOptions(form) {
return {
difficulty: parseInt(form.difficulty?.value),
modifier: parseInt(form.modifier?.value),
rollMode: form.rollMode?.value,
};
}
}
interface FormulaParseResult {
+108
View File
@@ -0,0 +1,108 @@
import { M5RollData, M5RollResult } from "../M5Base";
import { M5Roll } from "./M5Roll";
export const reroll = async (roll) => {
const message = (game as Game).messages.get(roll.attr("data-message-id"));
const actor = (game as Game).actors.get(message["speaker"].actor);
const template = "systems/midgard5/templates/chat/reroll-dialog.hbs";
const html = await renderTemplate(template, { sg: actor.system.sg, gp: actor.system.gp });
// Button defining
let buttons = {};
buttons = {
destiny: {
icon: '<i class="fas fa-rotate-left"></i>',
label: (game as Game).i18n.localize("midgard5.chat.destiny"),
callback: () => rerollDie("destiny", "sg"),
},
luckPoints: {
icon: '<i class="fas fa-rotate-left"></i>',
label: (game as Game).i18n.localize("midgard5.chat.luckPoint"),
callback: () => rerollDie("luckPoint", "gp"),
},
modify: {
icon: '<i class="fas fa-plus"></i>',
label: (game as Game).i18n.localize("midgard5.chat.modify") + " +" + (message["flags"].faces[0] === 100 ? 10 : 2),
callback: () => rerollDie("modify", "gp"),
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: (game as Game).i18n.localize("midgard5.chat.cancel"),
},
};
// Dialog object
new Dialog(
{
title: (game as Game).i18n.localize("midgard5.chat.reroll"),
content: html,
buttons,
render: function () {},
default: "luckPoints",
},
{
classes: ["midgard5"],
}
).render(true);
async function rerollDie(type, target) {
// Update the "content" field
let rollData = actor.getRollData() as M5RollData;
const flagData = message["flags"].data;
rollData.c = flagData.c;
rollData.i = flagData.i;
rollData.b = flagData.b;
rollData.iType = flagData.iType;
rollData.res.label = flagData.res.label + " (" + (game as Game).i18n.localize(`midgard5.chat.${type}`) + ")";
actor.update({
system: {
[target]: actor.system[target] - 1,
},
});
if (type !== "modify") {
for (var key in flagData.rolls) {
if (!!flagData.rolls[key]) {
rollData.rolls[key] = {
formula: flagData.rolls[key]?.formula,
enabled: flagData.rolls[key]?.enabled,
label: flagData.rolls[key]?.label,
result: "",
total: 0,
totalStr: "",
dice: {},
css: "",
} as M5RollResult;
}
}
} else {
for (var key in flagData.rolls) {
if (!!flagData.rolls[key]) {
rollData.rolls[key] = {
formula: key === "0" ? flagData.rolls[key]?.result + " + " + (message["flags"].faces[0] === 100 ? 10 : 2) : flagData.rolls[key]?.result,
enabled: flagData.rolls[key]?.enabled,
label: flagData.rolls[key]?.label,
result: "",
total: 0,
totalStr: "",
dice: {},
css: "",
} as M5RollResult;
}
}
}
const newRoll = new M5Roll(rollData, actor, rollData.res.label, "-1");
if (!newRoll._evaluated) await newRoll.evaluate();
const chatData = {
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
content: await newRoll.render(),
speaker: ChatMessage.getSpeaker({ actor: actor }),
sound: CONFIG.sounds.dice,
roll: Roll.fromTerms([newRoll.pool]),
flags: { rerolled: true },
};
message.update(chatData);
}
};
+52 -5
View File
@@ -77,7 +77,6 @@ export default class M5CharacterSheet extends ActorSheet {
let target = event.target.closest("[data-attribute]") as HTMLElement;
let attributeValue = target ? parseInt(target.dataset.value) : null;
let attributeStr = target ? target.dataset.attribute : null;
const roll = M5Roll.fromAttributeValue(this.actor, attributeStr, attributeValue);
await roll.toMessage();
});
@@ -194,6 +193,36 @@ export default class M5CharacterSheet extends ActorSheet {
});
});
html.find(".pp-increase").on("click", async (event) => {
let target = event.target.closest("[data-pp-name]") as HTMLElement;
let ppName = target ? target.dataset.ppName : null;
const context = this.actor as any;
const item = context.items.find((x) => x.type === "class" && x.system.equipped);
item.update({
system: {
lernKostenZauber: {
[ppName]: { pp: context.system.lernKostenZauber[ppName].pp + 1 },
},
},
});
this.render();
});
html.find(".pp-decrease").on("click", async (event) => {
let target = event.target.closest("[data-pp-name]") as HTMLElement;
let ppName = target ? target.dataset.ppName : null;
const context = this.actor as any;
const item = context.items.find((x) => x.type === "class" && x.system.equipped);
item.update({
system: {
lernKostenZauber: {
[ppName]: { pp: context.system.lernKostenZauber[ppName].pp - 1 },
},
},
});
this.render();
});
html.find(".fw-increase").on("click", async (event) => {
let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = target ? target.dataset.itemId : null;
@@ -247,13 +276,23 @@ export default class M5CharacterSheet extends ActorSheet {
await roll.toMessage();
});
html.find(".roll-perception-button").on("click", async (event) => {
const roll = M5Roll.perception(this.actor);
html.find(".roll-cleanSpell-button").on("click", async (event) => {
const roll = M5Roll.cleanSpell(this.actor);
await roll.toMessage();
});
html.find(".roll-drinking-button").on("click", async (event) => {
const roll = M5Roll.drinking(this.actor);
html.find(".roll-deprivationCold-button").on("click", async (event) => {
const roll = M5Roll.deprivationCold(this.actor);
await roll.toMessage();
});
html.find(".roll-deprivationHeat-button").on("click", async (event) => {
const roll = M5Roll.deprivationHeat(this.actor);
await roll.toMessage();
});
html.find(".roll-deprivationFood-button").on("click", async (event) => {
const roll = M5Roll.deprivationFood(this.actor);
await roll.toMessage();
});
@@ -433,6 +472,14 @@ export default class M5CharacterSheet extends ActorSheet {
}
});
html.find(".class-item-edit").on("click", async (event) => {
this.actor.items.find((x) => x.type === "class").sheet.render(true);
});
html.find(".class-item-delete").on("click", async (event) => {
this.actor.items.find((x) => x.type === "class").delete();
});
// Drag & Drop
const dragDrop = new DragDrop({
dragSelector: ".items-list .item",
+7
View File
@@ -7,6 +7,13 @@ export class M5ItemSheet extends ItemSheet {
width: 640,
height: 480,
classes: ["midgard5", "sheet", "item"],
tabs: [
{
navSelector: ".sheet-navigation",
contentSelector: ".sheet-content",
initial: "base_values",
},
],
});
}
+16
View File
@@ -0,0 +1,16 @@
/* global game */
/**
* Define all game settings here
* @return {Promise}
*/
export const loadSettings = async function () {
(game as Game).settings.register("midgard5", "automatedPP", {
name: "Automatische Praxispunkte",
hint: "Falls aktiv, werden Praxispunkte automatisch angerechnet.",
scope: "world",
config: true,
default: true,
type: Boolean,
});
};
+32
View File
@@ -374,4 +374,36 @@
}
}
}
.chip {
display: inline-block;
padding: 0 25px;
height: 35px;
font-size: 16px;
line-height: 35px;
border-radius: 25px;
background-color: #f1f1f1;
}
.closebtn {
padding-left: 10px;
color: #888;
font-weight: bold;
float: right;
font-size: 20px;
cursor: pointer;
}
.closebtn:hover {
color: #000;
}
.pp-listing {
margin: 0 2rem;
flex: 1 0 16%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: baseline;
}
}
+5 -4
View File
@@ -1,6 +1,6 @@
// main: midgard5.less
.midgard5.sheet.item {
.midgard5.sheet.item {
form {
display: flex;
flex-direction: column;
@@ -15,10 +15,11 @@
}
.item-img {
height: 64px;
width: 64px;
width: 64px;
}
td, th {
td,
th {
padding: 0 0.5rem 0 0.5rem;
&.center {
@@ -40,7 +41,7 @@
.col-create {
width: 3rem;
text-align: center;
button {
background: rgba(255, 255, 255, 0.5);
}
+3 -3
View File
@@ -3,7 +3,7 @@
"name": "midgard5",
"title": "Midgard 5. Edition",
"description": "The German RPG Midgard 5. Edition",
"version": "2.5.0",
"version": "2.6.0",
"compatibility": {
"minimum": "10",
"verified": "11",
@@ -24,8 +24,8 @@
"primaryTokenAttribute": "lp",
"secondaryTokenAttribute": "ap",
"url": "https://git.byroks.de/MidgardVTT-Entwicklung/foundry-vtt-system-midgard5",
"manifest": "https://git.byroks.de/MidgardVTT-Entwicklung/foundry-vtt-system-midgard5/releases/download/v2.5.0/system.json",
"download": "https://git.byroks.de/MidgardVTT-Entwicklung/foundry-vtt-system-midgard5/releases/download/v2.5.0/midgard5-v2.5.0.zip",
"manifest": "https://git.byroks.de/MidgardVTT-Entwicklung/foundry-vtt-system-midgard5/releases/download/v2.6.0/system.json",
"download": "https://git.byroks.de/MidgardVTT-Entwicklung/foundry-vtt-system-midgard5/releases/download/v2.6.0/midgard5-v2.6.0.zip",
"initiative": "@c.calc.attributes.gw.value",
"license": "LICENSE.txt"
}
+205 -30
View File
@@ -6,7 +6,7 @@
"info": {
"description": "",
"background": "",
"class": "",
"class": {},
"race": "",
"magicUsing": false,
"showAllItems": false,
@@ -101,7 +101,11 @@
"meditieren": { "fw": 0, "attribute": "wk", "initial": 8, "pp": 0 },
"menschenkenntnis": { "fw": 3, "attribute": "in", "initial": 8, "pp": 0 },
"meucheln": { "fw": 0, "attribute": "gs", "initial": 8, "pp": 0 },
"musizieren": { "fw": 0, "attribute": "gs", "initial": 12, "pp": 0 },
"musizierenFloete": { "fw": 0, "attribute": "gs", "initial": 12, "pp": 0 },
"musizierenBlas": { "fw": 0, "attribute": "gs", "initial": 12, "pp": 0 },
"musizierenRythmus": { "fw": 0, "attribute": "gs", "initial": 12, "pp": 0 },
"musizierenStreich": { "fw": 0, "attribute": "gs", "initial": 12, "pp": 0 },
"musizierenZupf": { "fw": 0, "attribute": "gs", "initial": 12, "pp": 0 },
"ninjutsu": { "fw": 0, "attribute": "gw", "initial": 8, "pp": 0 },
"naturkunde": { "fw": 0, "attribute": "in", "initial": 8, "pp": 0 },
"orakelkunst": { "fw": 0, "attribute": "in", "initial": 8, "pp": 0 },
@@ -131,7 +135,9 @@
"tauchen": { "fw": 6, "attribute": "ko", "initial": 8, "pp": 0 },
"tanzen": { "fw": 6, "attribute": "ko", "initial": 8, "pp": 0 },
"tierkunde": { "fw": 0, "attribute": "in", "initial": 8, "pp": 0 },
"ueberleben": { "fw": 6, "attribute": "in", "initial": 8, "pp": 0 },
"ueberlebenWald": { "fw": 6, "attribute": "in", "initial": 8, "pp": 0 },
"ueberlebenSteppe": { "fw": 6, "attribute": "in", "initial": 8, "pp": 0 },
"ueberlebenGebirge": { "fw": 6, "attribute": "in", "initial": 8, "pp": 0 },
"verfuehren": { "fw": 3, "attribute": "pa", "initial": 8, "pp": 0 },
"verhoeren": { "fw": 3, "attribute": "pa", "initial": 8, "pp": 0 },
"verstellen": { "fw": 3, "attribute": "pa", "initial": 8, "pp": 0 },
@@ -140,12 +146,11 @@
"wahrsagen": { "fw": 0, "attribute": "zt", "initial": 8, "pp": 0 },
"wasserkampf": { "fw": 0, "attribute": "gw", "initial": 8, "pp": 0 },
"zauberkunde": { "fw": 0, "attribute": "in", "initial": 8, "pp": 0 }
}
}
}
},
"gear": {
"gear": {
}
"gear": {}
}
},
"character": {
@@ -154,7 +159,7 @@
}
},
"Item": {
"types": ["skill", "weapon", "defensiveWeapon", "armor", "spell", "kampfkunst", "item", "effect", "container"],
"types": ["skill", "weapon", "defensiveWeapon", "armor", "spell", "kampfkunst", "item", "effect", "container", "class"],
"templates": {
"itemDescription": {
"description": ""
@@ -207,16 +212,17 @@
"equipped": false
},
"valuable": {
"valuable": false,
"valuable": false,
"item-wealth": true
},
"hoarded": {
"hoarded": false,
"hoarded": false,
"inHoard": true
},
"physical": {
"value": 0,
"weight": 0,
"capacity": 0,
"containerId": "",
"magic": false
},
@@ -231,29 +237,36 @@
"spellSelection": {
"spellProcessSelection": {
"none": "midgard5.spell-process-none",
"artefakte": "midgard5.spell-process-artefakte",
"beherrschen": "midgard5.spell-process-beherrschen",
"bewegen": "midgard5.spell-process-bewegen",
"blutzauber": "midgard5.spell-process-blutzauber",
"beschwoeren": "midgard5.spell-process-beschwoeren",
"blutmagie": "midgard5.spell-process-blutmagie",
"chaoswunder": "midgard5.spell-process-chaoswunder",
"dweomer": "midgard5.spell-process-dweomer",
"erhaltung": "midgard5.spell-process-erhaltung",
"erkennen": "midgard5.spell-process-erkennen",
"erschaffen": "midgard5.spell-process-erschaffen",
"formen": "midgard5.spell-process-formen",
"finstere_magie": "midgard5.spell-process-finstere_magie",
"veraendern": "midgard5.spell-process-veraendern",
"zerstoeren": "midgard5.spell-process-zerstoeren",
"wundertat": "midgard5.spell-process-wundertat",
"dweomer": "midgard5.spell-process-dweomer",
"wilder_dweomer": "midgard5.spell-process-wilder_dweomer",
"zauberlied": "midgard5.spell-process-zauberlied",
"salz": "midgard5.spell-process-salz",
"thaumagraphie": "midgard5.spell-process-thaumagraphie",
"beschwoeren": "midgard5.spell-process-beschwoeren",
"kampfverse": "midgard5.spell-process-kampfverse",
"namensmagie": "midgard5.spell-process-namensmagie",
"nekromantie": "midgard5.spell-process-nekromantie",
"thaumatherapie": "midgard5.spell-process-thaumatherapie",
"runenstaebe": "midgard5.spell-process-zauberrunen",
"thaumatherapie": "midgard5.spell-process-runenstaebe",
"veraendern": "midgard5.spell-process-veraendern",
"vigilsignien": "midgard5.spell-process-vigilsignien",
"wilder_dweomer": "midgard5.spell-process-wilder_dweomer",
"wundertat": "midgard5.spell-process-wundertat",
"zauberblaetter": "midgard5.spell-process-zauberblaetter",
"zauberlied": "midgard5.spell-process-zauberlied",
"zaubermittel": "midgard5.spell-process-zaubermittel",
"zauberschutz": "midgard5.spell-process-zauberschutz",
"zauberrunen": "midgard5.spell-process-zauberrunen",
"zaubersiegel": "midgard5.spell-process-siegel"
"zaubersalz": "midgard5.spell-process-zaubersalz",
"zauberschutz": "midgard5.spell-process-zauberschutz",
"zaubersiegel": "midgard5.spell-process-zaubersiegel",
"zaubertaenze": "midgard5.spell-process-zaubertaenze",
"zerstoeren": "midgard5.spell-process-zerstoeren"
},
"spellTypeSelection": {
"gedanke": "midgard5.spell-type-gedanke",
@@ -264,7 +277,8 @@
"umgebung": "midgard5.spell-target-umgebung",
"geist": "midgard5.spell-target-geist",
"koerper": "midgard5.spell-target-koerper"
}
},
"spellSpecialization": "none"
},
"kampfkunstSelection": {
"kampfkunstTypeSelection": {
@@ -273,7 +287,7 @@
"finte": "midgard5.kampfkunst-type-finte",
"geist": "midgard5.kampfkunst-type-geist",
"schießkunst": "midgard5.kampfkunst-type-schießkunst",
"fechten": "midgard5.kampfkunst-type-fechten"
"fechtkunst": "midgard5.kampfkunst-type-fechtkunst"
},
"kidoTypeSelection": {
"angriff": "midgard5.kido-type-angriff",
@@ -284,7 +298,12 @@
"kampfkunstVarianteSelection": {
"anstuermen": "midgard5.kampfkunst-variante-anstuermen",
"attackieren": "midgard5.kampfkunst-variante-attackieren",
"entwaffnen": "midgard5.kampfkunst-variante-entwaffnen"
"entwaffnen": "midgard5.kampfkunst-variante-entwaffnen",
"fechten": "midgard5.kampfkunst-variante-fechten",
"schusstechnik": "midgard5.kampfkunst-variante-schusstechnik",
"finten": "midgard5.kampfkunst-variante-finten",
"geistestechnik": "midgard5.kampfkunst-variante-geistestechnik",
"verteidigung": "midgard5.kampfkunst-variante-verteidigung"
},
"kidoVarianteSelection": {
"none": "midgard5.spell-process-none",
@@ -303,6 +322,7 @@
"templates": ["itemDescription", "attributeSelection"],
"fw": 0,
"attribute": "st",
"equipped": true,
"skill": "",
"type": "general",
"rolls": {
@@ -316,10 +336,11 @@
"output": ""
},
"pp": 0,
"calc": {}
"calc": {},
"mods": {}
},
"item": {
"templates": ["itemDescription", "equippable", "physical","valuable","hoarded"],
"templates": ["itemDescription", "equippable", "physical", "valuable", "hoarded"],
"rolls": {
"formulas": {},
"output": ""
@@ -346,7 +367,7 @@
"calc": {}
},
"weapon": {
"templates": ["itemDescription", "stats", "equippable", "physical","valuable","hoarded"],
"templates": ["itemDescription", "stats", "equippable", "physical", "valuable", "hoarded"],
"special": false,
"ranged": false,
"valuable": false,
@@ -371,7 +392,7 @@
"calc": {}
},
"defensiveWeapon": {
"templates": ["itemDescription", "stats", "equippable", "physical","valuable","hoarded"],
"templates": ["itemDescription", "stats", "equippable", "physical", "valuable", "hoarded"],
"special": false,
"valuable": false,
"hoarded": false,
@@ -389,7 +410,7 @@
"calc": {}
},
"armor": {
"templates": ["itemDescription", "stats", "equippable", "attributeMod", "physical","valuable","hoarded"],
"templates": ["itemDescription", "stats", "equippable", "attributeMod", "physical", "valuable", "hoarded"],
"lpProtection": 0,
"apProtection": 0,
"valuable": false,
@@ -436,6 +457,12 @@
"variante": "",
"isKido": false,
"ap": "",
"weapon": "",
"ep": "",
"rank": "",
"enemy": "",
"color": "",
"style": "",
"rolls": {
"formulas": {
"0": {
@@ -447,6 +474,154 @@
"output": ""
},
"calc": {}
},
"class": {
"templates": ["itemDescription"],
"magicUsing": false,
"equipped": true,
"resistanceBody": 1,
"resistanceMind": 0,
"calc": {},
"mods": {},
"lernKostenAllgemein": {
"alltag": 20,
"freiland": 20,
"halbwelt": 20,
"kampf": 20,
"koerper": 20,
"sozial": 20,
"unterwelt": 20,
"waffen": 20,
"wissen": 20
},
"lernKostenZauber": {
"beherrschen": {
"kosten": 0,
"pp": 0
},
"bewegen": {
"kosten": 0,
"pp": 0
},
"erkennen": {
"kosten": 0,
"pp": 0
},
"erschaffen": {
"kosten": 0,
"pp": 0
},
"formen": {
"kosten": 0,
"pp": 0
},
"veraendern": {
"kosten": 0,
"pp": 0
},
"zerstoeren": {
"kosten": 0,
"pp": 0
},
"wundertat": {
"kosten": 0,
"pp": 0
},
"dweomer": {
"kosten": 0,
"pp": 0
},
"zauberlied": {
"kosten": 0,
"pp": 0
},
"kampfverse": {
"kosten": 0,
"pp": 0
},
"zaubertaenze": {
"kosten": 0,
"pp": 0
},
"zaubersalz": {
"kosten": 0,
"pp": 0
},
"runenstaebe": {
"kosten": 0,
"pp": 0
},
"zaubersiegel": {
"kosten": 0,
"pp": 0
},
"zauberrunen": {
"kosten": 0,
"pp": 0
},
"thaumagraphie": {
"kosten": 0,
"pp": 0
},
"erhaltung": {
"kosten": 0,
"pp": 0
},
"zaubermittel": {
"kosten": 0,
"pp": 0
},
"zauberschutz": {
"kosten": 0,
"pp": 0
},
"zauberblaetter": {
"kosten": 0,
"pp": 0
},
"vigilsignien": {
"kosten": 0,
"pp": 0
},
"artefakte": {
"kosten": 0,
"pp": 0
},
"chaoswunder": {
"kosten": 0,
"pp": 0
},
"wilder_dweomer": {
"kosten": 0,
"pp": 0
},
"nekromantie": {
"kosten": 0,
"pp": 0
},
"finstere_magie": {
"kosten": 0,
"pp": 0
},
"blutmagie": {
"kosten": 0,
"pp": 0
},
"beschwoeren": {
"kosten": 0,
"pp": 0
},
"namensmagie": {
"kosten": 0,
"pp": 0
}
},
"lernKostenKamptechnik": {
"kampfkunst": 90,
"fechtkunst": 90,
"schiesskunst": 90,
"kido": 90
}
}
}
}