Adds gear and spells as items.
Adds custom roll logic, inclusing chat message.
This commit is contained in:
@@ -8,7 +8,9 @@ const preloadTemplates = async (): Promise<Handlebars.TemplateDelegate<any>[]> =
|
||||
const templates: Array<string> = [
|
||||
"sheets/character/base_values.hbs",
|
||||
"sheets/character/skills.hbs",
|
||||
"sheets/character/gear.hbs"
|
||||
"sheets/character/gear.hbs",
|
||||
"sheets/character/spells.hbs",
|
||||
"chat/roll-m5.hbs"
|
||||
]
|
||||
return loadTemplates(templates.map(s => rootPath + s))
|
||||
}
|
||||
|
||||
+34
-4
@@ -9,14 +9,23 @@ import { M5Item } from "./module/items/M5Item"
|
||||
Hooks.once("init", async () => {
|
||||
Logger.log("M5 | Initialisierung Midgard 5")
|
||||
|
||||
Handlebars.registerHelper("eq", (lhs: any, rhs: any) => {
|
||||
return lhs === rhs
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
// static concat(...values) {
|
||||
// const options = values.pop();
|
||||
// const join = options.hash?.join || "";
|
||||
// return new Handlebars.SafeString(values.join(join));
|
||||
// }
|
||||
|
||||
Handlebars.registerHelper("localizeMidgard", (str: string) => {
|
||||
const template = Handlebars.compile("{{localize value}}")
|
||||
return template({
|
||||
@@ -42,6 +51,27 @@ Hooks.once("init", async () => {
|
||||
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) => {
|
||||
//console.log("actorItemValue", actorId, itemId, path)
|
||||
const actor = (game as Game).actors.get(actorId)
|
||||
let obj = actor.data.items.get(itemId).data.data
|
||||
path.split(".").forEach(p => {
|
||||
if (obj)
|
||||
obj = obj[p]
|
||||
})
|
||||
return `${obj}`
|
||||
})
|
||||
|
||||
Handlebars.registerHelper("icon", (relpath: string) => {
|
||||
return `systems/midgard5/assets/icons/${relpath}`
|
||||
})
|
||||
|
||||
// Default Sheet für Items definieren und das Standardsheet deaktivieren
|
||||
Items.unregisterSheet("core", ItemSheet)
|
||||
Items.registerSheet("midgard5", M5ItemSheet, { makeDefault: true })
|
||||
|
||||
+28
-4
@@ -19,8 +19,32 @@ export interface M5Attribute {
|
||||
}
|
||||
|
||||
export interface M5RollData {
|
||||
c: any,
|
||||
i: any,
|
||||
rolls: any,
|
||||
res: any
|
||||
c: any
|
||||
i: any
|
||||
iType: string
|
||||
rolls: {}
|
||||
res: {
|
||||
label: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface M5RollResult {
|
||||
formula: string
|
||||
label: string
|
||||
type: string
|
||||
|
||||
total: number
|
||||
totalStr: string
|
||||
result: string
|
||||
dice: {}
|
||||
css: string
|
||||
}
|
||||
|
||||
export enum M5EwResult {
|
||||
TBD = "",
|
||||
FUMBLE = "roll-ew-result-fumble",
|
||||
CRITICAL = "roll-ew-result-critical",
|
||||
HIGH = "roll-ew-result-high",
|
||||
FAIL = "roll-ew-result-fail",
|
||||
PASS = "roll-ew-result-pass"
|
||||
}
|
||||
@@ -25,10 +25,12 @@ export interface M5CharacterCalculatedData {
|
||||
resistanceBody: number
|
||||
spellCasting: number
|
||||
brawl: number
|
||||
brawlEw: number
|
||||
poisonResistance: number
|
||||
enduranceBonus: number
|
||||
}
|
||||
skills: {
|
||||
innate: {}
|
||||
general: {}
|
||||
combat: {}
|
||||
language: {}
|
||||
@@ -36,9 +38,11 @@ export interface M5CharacterCalculatedData {
|
||||
}
|
||||
gear: {
|
||||
weapons: {}
|
||||
defensiveWeapons: {}
|
||||
armor: {}
|
||||
items: {}
|
||||
}
|
||||
spells: {}
|
||||
}
|
||||
|
||||
export class M5Character extends Actor {
|
||||
@@ -68,7 +72,7 @@ export class M5Character extends Actor {
|
||||
return -2
|
||||
}
|
||||
|
||||
derivedData(skipSkills: boolean, skipWeapons: boolean): M5CharacterCalculatedData {
|
||||
derivedData(skip: { skills?: boolean, weapons?: boolean, defensiveWeapons?: boolean, armor?: boolean, items?: boolean, spells?: boolean } = {} ): M5CharacterCalculatedData {
|
||||
let ret: M5CharacterCalculatedData = {
|
||||
level: 0,
|
||||
attributes: {
|
||||
@@ -93,10 +97,12 @@ export class M5Character extends Actor {
|
||||
resistanceBody: 0,
|
||||
spellCasting: 0,
|
||||
brawl: 0,
|
||||
brawlEw: 0,
|
||||
poisonResistance: 0,
|
||||
enduranceBonus: 0
|
||||
},
|
||||
skills: {
|
||||
innate: {},
|
||||
general: {},
|
||||
combat: {},
|
||||
language: {},
|
||||
@@ -104,9 +110,11 @@ export class M5Character extends Actor {
|
||||
},
|
||||
gear: {
|
||||
weapons: {},
|
||||
defensiveWeapons: {},
|
||||
armor: {},
|
||||
items: {}
|
||||
}
|
||||
},
|
||||
spells: {}
|
||||
} as M5CharacterCalculatedData
|
||||
|
||||
const context = (this as any).data
|
||||
@@ -143,10 +151,11 @@ export class M5Character extends Actor {
|
||||
ret.stats.resistanceBody = ret.stats.defense + 1
|
||||
ret.stats.spellCasting = (data.info.magicUsing ? M5Character.spellCastingFromLevel(ret.level) : 3) + ret.attributes.zt.bonus
|
||||
ret.stats.brawl = Math.floor((ret.attributes.st.value + ret.attributes.gw.value) / 20)
|
||||
ret.stats.brawlEw = ret.stats.brawl + ret.stats.attackBonus
|
||||
ret.stats.poisonResistance = 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)
|
||||
|
||||
if (!skipSkills) {
|
||||
if (!skip.skills) {
|
||||
context.items?.filter(item => item.data.type === "skill").forEach(item => {
|
||||
item.prepareDerivedData()
|
||||
const skillMap = ret.skills[item.data.data.type]
|
||||
@@ -159,7 +168,7 @@ export class M5Character extends Actor {
|
||||
})
|
||||
}
|
||||
|
||||
if (!skipWeapons) {
|
||||
if (!skip.weapons) {
|
||||
context.items?.filter(item => item.data.type === "weapon").forEach(item => {
|
||||
item.prepareDerivedData()
|
||||
|
||||
@@ -175,25 +184,91 @@ export class M5Character extends Actor {
|
||||
ret.gear.weapons[item.data._id] = {
|
||||
label: label,
|
||||
skillId: item.data.data.skillId,
|
||||
defensive: item.data.data.defensive,
|
||||
magic: item.data.data.magic,
|
||||
calc: item.data.data.calc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!skip.defensiveWeapons) {
|
||||
context.items?.filter(item => item.data.type === "defensiveWeapon").forEach(item => {
|
||||
item.prepareDerivedData()
|
||||
|
||||
let label = item.data.name
|
||||
if (item.data.data.magic) {
|
||||
label += "*("
|
||||
+ (item.data.data.stats.defenseBonus < 0 ? "" : "+")
|
||||
+ item.data.data.stats.defenseBonus + ")"
|
||||
}
|
||||
|
||||
ret.gear.defensiveWeapons[item.data._id] = {
|
||||
label: label,
|
||||
skillId: item.data.data.skillId,
|
||||
magic: item.data.data.magic,
|
||||
calc: item.data.data.calc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!skip.armor) {
|
||||
context.items?.filter(item => item.data.type === "armor").forEach(item => {
|
||||
item.prepareDerivedData()
|
||||
|
||||
let label = item.data.name
|
||||
if (item.data.data.magic) {
|
||||
label += "*"
|
||||
}
|
||||
|
||||
ret.gear.armor[item.data._id] = {
|
||||
label: label,
|
||||
magic: item.data.data.magic,
|
||||
calc: item.data.data.calc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!skip.items) {
|
||||
context.items?.filter(item => item.data.type === "item").forEach(item => {
|
||||
item.prepareDerivedData()
|
||||
|
||||
let label = item.data.name
|
||||
if (item.data.data.magic) {
|
||||
label += "*"
|
||||
}
|
||||
|
||||
ret.gear.items[item.data._id] = {
|
||||
label: label,
|
||||
magic: item.data.data.magic,
|
||||
calc: item.data.data.calc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!skip.spells) {
|
||||
context.items?.filter(item => item.data.type === "spell").forEach(item => {
|
||||
item.prepareDerivedData()
|
||||
|
||||
ret.spells[item.data._id] = {
|
||||
label: item.data.name,
|
||||
process: "midgard5.spell-process-" + item.data.data.process,
|
||||
calc: item.data.data.calc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
const context = (this as any).data
|
||||
context.data.calc = this.derivedData(false, false)
|
||||
context.data.calc = this.derivedData({})
|
||||
}
|
||||
|
||||
override getRollData(): any {
|
||||
return {
|
||||
c: (this as any).data.data,
|
||||
i: null,
|
||||
iType: null,
|
||||
rolls: {},
|
||||
res: {}
|
||||
} as M5RollData
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { M5Character } from "../actors/M5Character"
|
||||
import { M5RollData, M5Skill } from "../M5Base"
|
||||
import { M5RollData, M5RollResult, M5Skill } from "../M5Base"
|
||||
import { M5Roll } from "../rolls/M5Roll"
|
||||
|
||||
export class M5Item extends Item {
|
||||
static readonly SKILL = "skill"
|
||||
@@ -13,22 +14,21 @@ export class M5Item extends Item {
|
||||
if (context.type === "skill") {
|
||||
calc.bonus = 0
|
||||
|
||||
if (context.data.attribute && context.data.attribute !== "") {
|
||||
if (context.data?.attribute && context.data?.attribute !== "" && character) {
|
||||
const attribute = character.attribute(context.data.attribute)
|
||||
calc.bonus += M5Character.attributeBonus(attribute)
|
||||
}
|
||||
|
||||
if (context._id === actor.data?.data?.skills.preferredCombatSkill) {
|
||||
calc.bonus += 2
|
||||
}
|
||||
|
||||
calc.ew = context.data.fw + calc.bonus
|
||||
} else if (context.type === "weapon") {
|
||||
calc.ew = context.data.stats.attackBonus
|
||||
calc.fw = 0
|
||||
calc.bonus = 0
|
||||
calc.special = context.data.special ? 2 : 0
|
||||
calc.ew = calc.special + context.data.stats.attackBonus
|
||||
calc.combatSkills = null
|
||||
|
||||
if (actor) {
|
||||
const actorCalc = character.derivedData(false, true)
|
||||
const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true })
|
||||
calc.ew += actorCalc.stats.attackBonus
|
||||
|
||||
const skill = character.getSkill(context.data.skillId) as any
|
||||
@@ -37,10 +37,41 @@ export class M5Item extends Item {
|
||||
skill.prepareDerivedData()
|
||||
const skillData = skill.data.data
|
||||
calc.ew += skillData.calc.ew
|
||||
calc.bonus += skillData.calc.bonus
|
||||
calc.fw += skillData.fw
|
||||
}
|
||||
|
||||
calc.combatSkills = actorCalc.skills.combat
|
||||
}
|
||||
} else if (context.type === "defensiveWeapon") {
|
||||
calc.fw = 0
|
||||
calc.bonus = 0
|
||||
calc.special = context.data.special ? 2 : 0
|
||||
calc.ew = calc.special + context.data.stats.defenseBonus
|
||||
calc.combatSkills = null
|
||||
|
||||
if (actor) {
|
||||
const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true })
|
||||
calc.ew += actorCalc.stats.defense + actorCalc.stats.defenseBonus
|
||||
|
||||
const skill = character.getSkill(context.data.skillId) as any
|
||||
//console.log("M5Item.prepareDerivedData:weapon", context.data, skill?.data?.data)
|
||||
if (skill) {
|
||||
skill.prepareDerivedData()
|
||||
const skillData = skill.data.data
|
||||
calc.ew += skillData.calc.ew
|
||||
calc.bonus += skillData.calc.bonus
|
||||
calc.fw += skillData.fw
|
||||
}
|
||||
|
||||
calc.combatSkills = actorCalc.skills.combat
|
||||
}
|
||||
} else if (context.type === "spell") {
|
||||
calc.ew = context.data.bonus
|
||||
if (actor) {
|
||||
const actorCalc = character.derivedData({ weapons: true, defensiveWeapons: true, armor: true, items: true, spells: true })
|
||||
calc.ew += actorCalc.stats.spellCasting
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,11 +82,13 @@ export class M5Item extends Item {
|
||||
let ret: M5RollData = actor?.getRollData() ?? {
|
||||
c: null,
|
||||
i: null,
|
||||
iType: null,
|
||||
rolls: {},
|
||||
res: {}
|
||||
}
|
||||
|
||||
ret.i = context.data
|
||||
ret.iType = context.type
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -71,21 +104,21 @@ export class M5Item extends Item {
|
||||
const formulaNames = item.data.rolls?.formulas ? Object.keys(item.data.rolls.formulas) : []
|
||||
if (formulaNames.length > 0) {
|
||||
const rollData = this.getRollData()
|
||||
let ret = []
|
||||
|
||||
formulaNames.forEach(formulaName => {
|
||||
const formula = item.data.rolls.formulas[formulaName]
|
||||
const roll = new Roll(formula.formula, rollData)
|
||||
|
||||
roll.toMessage({
|
||||
speaker: speaker,
|
||||
rollMode: rollMode,
|
||||
flavor: label,
|
||||
})
|
||||
ret.push(roll)
|
||||
rollData.rolls[formulaName] = {
|
||||
formula: formula.formula,
|
||||
label: formula.label,
|
||||
type: formula.type,
|
||||
result: "",
|
||||
total: 0,
|
||||
totalStr: "",
|
||||
dice: {}
|
||||
} as M5RollResult
|
||||
})
|
||||
|
||||
return ret
|
||||
|
||||
const roll = new M5Roll(rollData, this.actor, item.name)
|
||||
return roll.toMessage()
|
||||
} else {
|
||||
ChatMessage.create({
|
||||
speaker: speaker,
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
import { Evaluated } from "@league-of-foundry-developers/foundry-vtt-types/src/foundry/client/dice/roll";
|
||||
import { M5Character } from "../actors/M5Character";
|
||||
import { M5EwResult, M5RollData, M5RollResult } from "../M5Base";
|
||||
|
||||
export class M5Roll { // extends Roll<M5RollData>
|
||||
static readonly TEMPLATE_PATH = "systems/midgard5/templates/chat/roll-m5.hbs"
|
||||
|
||||
public _evaluated: boolean = false
|
||||
public _total: number = 0
|
||||
public pool: PoolTerm = null
|
||||
|
||||
constructor(public data: M5RollData, public actor: any, public label: string) {
|
||||
//super(null)
|
||||
//this.data = rollData
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
//override evaluate(options?: InexactPartial<RollTerm.EvaluationOptions>): Evaluated<Roll<M5RollData>> | Promise<Evaluated<Roll<M5RollData>>> {
|
||||
evaluate() {
|
||||
const rollNames = Object.keys(this.data.rolls)
|
||||
const rolls = rollNames.map(rollName => {
|
||||
const formula = this.data.rolls[rollName]
|
||||
const roll = new Roll(formula.formula, this.data)
|
||||
return roll
|
||||
})
|
||||
|
||||
this.pool = PoolTerm.fromRolls(rolls)
|
||||
return this.pool.evaluate({ async: true }).then(results => {
|
||||
this._total = 0
|
||||
|
||||
results.rolls.forEach((roll, index) => {
|
||||
const rollResult = this.data.rolls[index.toString()] as M5RollResult
|
||||
rollResult.result = roll.result
|
||||
rollResult.total = roll.total
|
||||
rollResult.totalStr = roll.total.toString()
|
||||
|
||||
this._total += roll.total
|
||||
|
||||
let rowRes = M5EwResult.TBD
|
||||
roll.dice.forEach((d, dIndex) => {
|
||||
rollResult.dice[dIndex.toString()] = d.total
|
||||
|
||||
if (rowRes === M5EwResult.TBD && dIndex === 0) {
|
||||
if (rollResult.type === "ew") {
|
||||
if (d.total === 1)
|
||||
rowRes = M5EwResult.FUMBLE
|
||||
else if (d.total === 20)
|
||||
rowRes = M5EwResult.CRITICAL
|
||||
else if (d.total >= 16)
|
||||
rowRes = M5EwResult.HIGH
|
||||
} else if (rollResult.type === "pw") {
|
||||
if (d.total === 1)
|
||||
rowRes = M5EwResult.FUMBLE
|
||||
else if (d.total === 20)
|
||||
rowRes = M5EwResult.CRITICAL
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (rollResult.type === "ew") {
|
||||
if (roll.total < 20) {
|
||||
if (rowRes === M5EwResult.TBD || rowRes === M5EwResult.HIGH)
|
||||
rowRes = M5EwResult.FAIL
|
||||
} else {
|
||||
if (rowRes === M5EwResult.TBD)
|
||||
rowRes = M5EwResult.PASS
|
||||
}
|
||||
} else if (rollResult.type === "pw") {
|
||||
if (roll.total < 0) {
|
||||
if (rowRes === M5EwResult.TBD)
|
||||
rowRes = M5EwResult.FAIL
|
||||
} else {
|
||||
if (rowRes === M5EwResult.TBD)
|
||||
rowRes = M5EwResult.PASS
|
||||
}
|
||||
}
|
||||
rollResult.css = rowRes
|
||||
})
|
||||
|
||||
this.data.res.label = this.label
|
||||
|
||||
this._evaluated = true
|
||||
return this
|
||||
})
|
||||
}
|
||||
|
||||
async render(): Promise<string> {
|
||||
return renderTemplate(M5Roll.TEMPLATE_PATH, this.data)
|
||||
}
|
||||
|
||||
async toMessage() {
|
||||
if (!this._evaluated)
|
||||
await this.evaluate()
|
||||
|
||||
const rMode = (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])
|
||||
}
|
||||
|
||||
ChatMessage.applyRollMode(chatData, rMode)
|
||||
return ChatMessage.create(chatData)
|
||||
}
|
||||
|
||||
static fromAttribute(actor: any, attributeKey: string) {
|
||||
const character = actor as M5Character
|
||||
const attribute = character.attribute(attributeKey)
|
||||
|
||||
const rollData = actor.getRollData() as M5RollData
|
||||
rollData.i = attribute.value + attribute.bonus
|
||||
rollData.rolls["0"] = {
|
||||
formula: "@i - 1d100",
|
||||
type: "pw",
|
||||
label: (game as Game).i18n.localize("midgard5.pw"),
|
||||
result: "",
|
||||
total: 0,
|
||||
totalStr: "",
|
||||
dice: {},
|
||||
css: ""
|
||||
} as M5RollResult
|
||||
|
||||
return new M5Roll(rollData, actor, (game as Game).i18n.localize(`midgard5.actor-${attributeKey}-long`))
|
||||
}
|
||||
|
||||
static brawl(actor: any) {
|
||||
const rollData = actor.getRollData() as M5RollData
|
||||
rollData.i = {
|
||||
attackBonus: 0,
|
||||
damageBonus: 0
|
||||
}
|
||||
|
||||
rollData.rolls["0"] = {
|
||||
formula: "1d20 + @c.calc.stats.brawl + @c.calc.stats.attackBonus + @i.attackBonus",
|
||||
type: "ew",
|
||||
label: (game as Game).i18n.localize("midgard5.attack"),
|
||||
result: "",
|
||||
total: 0,
|
||||
totalStr: "",
|
||||
dice: {},
|
||||
css: ""
|
||||
} as M5RollResult
|
||||
|
||||
rollData.rolls["1"] = {
|
||||
formula: "1d6 - 4 + @c.calc.stats.damageBonus + @i.damageBonus",
|
||||
type: "dmg",
|
||||
label: (game as Game).i18n.localize("midgard5.damage"),
|
||||
result: "",
|
||||
total: 0,
|
||||
totalStr: "",
|
||||
dice: {},
|
||||
css: ""
|
||||
} as M5RollResult
|
||||
|
||||
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.brawl"))
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,14 @@ import Logger from "../../utils/Logger"
|
||||
import { M5Character } from "../actors/M5Character"
|
||||
import { M5Item } from "../items/M5Item"
|
||||
import { M5SkillLearned, M5SkillUnlearned } from "../M5Base"
|
||||
import { M5Roll } from "../rolls/M5Roll"
|
||||
|
||||
export default class M5CharacterSheet extends ActorSheet {
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
template: "systems/midgard5/templates/sheets/character/main.hbs",
|
||||
width: 600,
|
||||
width: 800,
|
||||
height: 800,
|
||||
classes: ["midgard5", "sheet", "character"],
|
||||
tabs: [{ navSelector: ".sheet-navigation", contentSelector: ".sheet-content", initial: "base_values" }]
|
||||
@@ -37,29 +38,28 @@ export default class M5CharacterSheet extends ActorSheet {
|
||||
override activateListeners(html: JQuery) {
|
||||
super.activateListeners(html)
|
||||
|
||||
html.find(".roll-attribute-button").on("click", async (event) => {
|
||||
const attributeStr = event.target.dataset["attribute"]
|
||||
const roll = M5Roll.fromAttribute(this.actor, attributeStr)
|
||||
console.log("roll-attribute-button", roll)
|
||||
await roll.toMessage()
|
||||
})
|
||||
|
||||
html.find(".edit-item").on("click", async (event) => {
|
||||
const row = event.target.parentElement
|
||||
let row = event.target.parentElement
|
||||
let itemId = row.dataset["item"]
|
||||
while (!itemId) {
|
||||
row = row.parentElement
|
||||
if (!row)
|
||||
return
|
||||
itemId = row.dataset["item"]
|
||||
}
|
||||
|
||||
const context = this.actor.data
|
||||
const item = context.items.get(itemId)
|
||||
item.sheet.render(true)
|
||||
})
|
||||
|
||||
html.find(".change-special-combat-skill").on("click", async (event) => {
|
||||
const row = event.target.parentElement.parentElement
|
||||
let skillId = row.dataset["item"]
|
||||
|
||||
const actor = this.actor as any
|
||||
actor.update({
|
||||
data: {
|
||||
skills: {
|
||||
preferredCombatSkill: skillId
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
html.find(".roll-learned-button").on("click", async (event) => {
|
||||
const row = event.target.parentElement.parentElement
|
||||
let skillId = row.dataset["item"]
|
||||
@@ -72,24 +72,6 @@ export default class M5CharacterSheet extends ActorSheet {
|
||||
await item.roll()
|
||||
})
|
||||
|
||||
html.find(".create-skill-button").on("click", async (event) => {
|
||||
const button = event.target
|
||||
const skillType = button.dataset["skilltype"]
|
||||
|
||||
const character = this.actor as M5Character
|
||||
character.createSkill((game as Game).i18n.localize("midgard5.new-skill")).then(skill => {
|
||||
const item = skill as any
|
||||
item.update({
|
||||
data: {
|
||||
fw: 5,
|
||||
attribute: "",
|
||||
skill: "",
|
||||
type: skillType
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
html.find(".roll-general-button").on("click", async (event) => {
|
||||
const row = event.target.parentElement.parentElement
|
||||
let skillName = row.dataset["skill"]
|
||||
@@ -151,6 +133,11 @@ export default class M5CharacterSheet extends ActorSheet {
|
||||
await item.roll()
|
||||
})
|
||||
|
||||
html.find(".roll-brawl-button").on("click", async (event) => {
|
||||
const roll = M5Roll.brawl(this.actor)
|
||||
await roll.toMessage()
|
||||
})
|
||||
|
||||
// Drag & Drop
|
||||
const dragDrop = new DragDrop({
|
||||
dragSelector: ".items-list .item",
|
||||
@@ -175,7 +162,7 @@ export default class M5CharacterSheet extends ActorSheet {
|
||||
const item = this.actor.items.get(li.dataset.itemId)
|
||||
|
||||
// limit transfer on personal weapons/armour/gear
|
||||
if (["weapon"].includes(item.data.type)) {
|
||||
if (["skill", "item", "weapon", "defensiveWeapon", "armor", "spell"].includes(item.data.type)) {
|
||||
const dragData = {
|
||||
type: "Transfer",
|
||||
actorId: this.actor.id,
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
input.fixed {
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.new-skill {
|
||||
font-style: italic;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
@@ -62,4 +66,16 @@
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
button.roll-button {
|
||||
background: url(/icons/svg/d20-black.svg) no-repeat;
|
||||
background-size: 24px 24px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
span.spell-process {
|
||||
color:rgb(93, 93, 93);
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
.m5-roll {
|
||||
.roll-title {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding: 0.3rem 0 0.1rem 0;
|
||||
font-weight: bold;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.roll-spell-details {
|
||||
text-align: right;
|
||||
padding-right: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.roll-result {
|
||||
text-align: right;
|
||||
padding-right: 1rem;
|
||||
font-weight: bold;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.roll-total {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.roll-detail {
|
||||
width: 100%;
|
||||
margin-left: -100%;
|
||||
}
|
||||
}
|
||||
|
||||
.roll-row:not( :hover ) {
|
||||
.roll-total {
|
||||
visibility: visible;
|
||||
}
|
||||
.roll-detail {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.roll-row:hover {
|
||||
.roll-total {
|
||||
visibility: hidden;
|
||||
}
|
||||
.roll-detail {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.roll-ew-result-fumble {
|
||||
background-color: rgb(202, 54, 54, 0.5);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.roll-ew-result-critical {
|
||||
background-color: rgb(202, 197, 54, 0.5);
|
||||
color: rgb(0, 0, 0);
|
||||
}
|
||||
|
||||
.roll-ew-result-high {
|
||||
background-color: rgb(54, 138, 202, 0.5);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.roll-ew-result-fail {
|
||||
background-color: rgb(117, 63, 131, 0.5);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.roll-ew-result-pass {
|
||||
background-color: rgb(54, 202, 88, 0.5);
|
||||
color: rgb(0, 0, 0);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
{
|
||||
"name": "blaupause-gegenstaende",
|
||||
"label": "Blaupausen für Gegenstände",
|
||||
"path": "./packs/actors/blaupause-gegenstaende.db",
|
||||
"path": "./packs/items/blaupause-gegenstaende.db",
|
||||
"type": "Item"
|
||||
},
|
||||
{
|
||||
|
||||
+97
-16
@@ -53,8 +53,6 @@
|
||||
},
|
||||
"skills": {
|
||||
"skills": {
|
||||
"preferredCombatSkill": "",
|
||||
"innate": {},
|
||||
"general": {
|
||||
"akrobatik": { "fw": 6, "attribute": "gw", "initial": 8 },
|
||||
"alchimie": { "fw": 0, "attribute": "in", "initial": 8 },
|
||||
@@ -107,8 +105,7 @@
|
||||
"verstellen": { "fw": 3, "attribute": "pa", "initial": 8 },
|
||||
"wagenlenken": { "fw": 3, "attribute": "gs", "initial": 8 },
|
||||
"zauberkunde": { "fw": 0, "attribute": "in", "initial": 8 }
|
||||
},
|
||||
"combat": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -121,7 +118,7 @@
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
"types": ["skill", "item", "weapon", "armor", "spell"],
|
||||
"types": ["skill", "item", "weapon", "defensiveWeapon", "armor", "spell"],
|
||||
"templates": {
|
||||
"itemDescription": {
|
||||
"description": ""
|
||||
@@ -150,6 +147,19 @@
|
||||
"wk": { "short": "midgard5.actor-wk", "long": "midgard5.actor-wk-long" }
|
||||
}
|
||||
},
|
||||
"attributeMod": {
|
||||
"attributeMod": {
|
||||
"st": 0,
|
||||
"gs": 0,
|
||||
"gw": 0,
|
||||
"ko": 0,
|
||||
"in": 0,
|
||||
"zt": 0,
|
||||
"au": 0,
|
||||
"pa": 0,
|
||||
"wk": 0
|
||||
}
|
||||
},
|
||||
"rollable": {
|
||||
"rolls": {
|
||||
"formulas": {},
|
||||
@@ -159,6 +169,38 @@
|
||||
"equippable": {
|
||||
"equippable": false,
|
||||
"equipped": true
|
||||
},
|
||||
"spellSelection": {
|
||||
"spellProcessSelection": {
|
||||
"none": "midgard5.spell-process-none",
|
||||
"beherrschen": "midgard5.spell-process-beherrschen",
|
||||
"bewegen": "midgard5.spell-process-bewegen",
|
||||
"erkennen": "midgard5.spell-process-erkennen",
|
||||
"erschaffen": "midgard5.spell-process-erschaffen",
|
||||
"formen": "midgard5.spell-process-formen",
|
||||
"veraendern": "midgard5.spell-process-veraendern",
|
||||
"zerstoeren": "midgard5.spell-process-zerstoeren",
|
||||
"wundertat": "midgard5.spell-process-wundertat",
|
||||
"dweomer": "midgard5.spell-process-dweomer",
|
||||
"zauberlied": "midgard5.spell-process-zauberlied",
|
||||
"salz": "midgard5.spell-process-salz",
|
||||
"thaumagraphie": "midgard5.spell-process-thaumagraphie",
|
||||
"beschwoeren": "midgard5.spell-process-beschwoeren",
|
||||
"nekromantie": "midgard5.spell-process-nekromantie",
|
||||
"thaumatherapie": "midgard5.spell-process-thaumatherapie",
|
||||
"zaubermittel": "midgard5.spell-process-zaubermittel",
|
||||
"zauberschutz": "midgard5.spell-process-zauberschutz"
|
||||
},
|
||||
"spellTypeSelection": {
|
||||
"gedanke": "midgard5.spell-type-gedanke",
|
||||
"geste": "midgard5.spell-type-geste",
|
||||
"wort": "midgard5.spell-type-wort"
|
||||
},
|
||||
"spellTargetSelection": {
|
||||
"umgebung": "midgard5.spell-target-umgebung",
|
||||
"geist": "midgard5.spell-target-geist",
|
||||
"koerper": "midgard5.spell-target-koerper"
|
||||
}
|
||||
}
|
||||
},
|
||||
"skill": {
|
||||
@@ -169,9 +211,10 @@
|
||||
"type": "general",
|
||||
"rolls": {
|
||||
"formulas": {
|
||||
"1": {
|
||||
"0": {
|
||||
"formula": "1d20 + @i.fw + @i.calc.bonus",
|
||||
"type": "ew"
|
||||
"type": "ew",
|
||||
"label": "EW"
|
||||
}
|
||||
},
|
||||
"output": ""
|
||||
@@ -194,20 +237,39 @@
|
||||
},
|
||||
"weapon": {
|
||||
"templates": ["itemDescription", "stats", "equippable"],
|
||||
"special": false,
|
||||
"magic": false,
|
||||
"ranged": false,
|
||||
"defensive": false,
|
||||
"skillId": "",
|
||||
"damageBase": "1d6",
|
||||
"rolls": {
|
||||
"formulas": {
|
||||
"1": {
|
||||
"formula": "1d20 + @i.calc.ew",
|
||||
"type": "ew"
|
||||
"0": {
|
||||
"formula": "1d20 + @i.calc.fw + @i.calc.bonus + @i.calc.special + @c.calc.stats.attackBonus + @i.stats.attackBonus",
|
||||
"type": "ew",
|
||||
"label": "Angriff"
|
||||
},
|
||||
"2": {
|
||||
"1": {
|
||||
"formula": "@i.damageBase + @i.stats.damageBonus + @c.calc.stats.damageBonus",
|
||||
"type": "dmg"
|
||||
"type": "dmg",
|
||||
"label": "Schaden"
|
||||
}
|
||||
},
|
||||
"output": ""
|
||||
},
|
||||
"calc": {}
|
||||
},
|
||||
"defensiveWeapon": {
|
||||
"templates": ["itemDescription", "stats", "equippable"],
|
||||
"special": false,
|
||||
"magic": false,
|
||||
"skillId": "",
|
||||
"rolls": {
|
||||
"formulas": {
|
||||
"0": {
|
||||
"formula": "1d20 + @i.calc.fw + @i.calc.bonus + @i.calc.special + @c.calc.stats.defense + @c.calc.stats.defenseBonus + @i.stats.defenseBonus",
|
||||
"type": "ew",
|
||||
"label": "Abwehr"
|
||||
}
|
||||
},
|
||||
"output": ""
|
||||
@@ -215,7 +277,10 @@
|
||||
"calc": {}
|
||||
},
|
||||
"armor": {
|
||||
"templates": ["itemDescription", "stats", "equippable"],
|
||||
"templates": ["itemDescription", "stats", "equippable", "attributeMod"],
|
||||
"magic": false,
|
||||
"lpProtection": 0,
|
||||
"apProtection": 0,
|
||||
"rolls": {
|
||||
"formulas": {},
|
||||
"output": ""
|
||||
@@ -223,9 +288,25 @@
|
||||
"calc": {}
|
||||
},
|
||||
"spell": {
|
||||
"templates": ["itemDescription"],
|
||||
"templates": ["itemDescription", "spellSelection"],
|
||||
"bonus": 0,
|
||||
"type": "",
|
||||
"process": "",
|
||||
"ap": 0,
|
||||
"castDuration": "",
|
||||
"range": "",
|
||||
"effectTarget": "",
|
||||
"effectArea": "",
|
||||
"effectDuration": "",
|
||||
"origin": "",
|
||||
"rolls": {
|
||||
"formulas": {},
|
||||
"formulas": {
|
||||
"0": {
|
||||
"formula": "1d20 + @c.calc.stats.spellCasting + @i.bonus",
|
||||
"type": "ew",
|
||||
"label": "Zaubern"
|
||||
}
|
||||
},
|
||||
"output": ""
|
||||
},
|
||||
"calc": {}
|
||||
|
||||
Reference in New Issue
Block a user