diff --git a/images/icons/icon_vice.webp b/images/icons/icon_vice.webp
new file mode 100644
index 0000000..c16b213
Binary files /dev/null and b/images/icons/icon_vice.webp differ
diff --git a/images/icons/icon_virtue.webp b/images/icons/icon_virtue.webp
new file mode 100644
index 0000000..9e0b006
Binary files /dev/null and b/images/icons/icon_virtue.webp differ
diff --git a/lang/en.json b/lang/en.json
index 077404a..fdf14cd 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -1,3 +1,25 @@
{
-
+ "ITEM": {
+ "TypeRace": "Race",
+ "TypeRole": "Role",
+ "TypeAbility": "Ability",
+ "TypeSpecialisation": "Specialisation",
+ "TypePerk": "Perk",
+ "TypePower": "Power",
+ "TypeArmor": "Armor",
+ "TypeShield": "Shield",
+ "TypeEquipment": "Equipment",
+ "TypeWeapon": "Weapon",
+ "TypeEffect": "Effect",
+ "TypeMoney": "Money",
+ "TypeVirtue": "Virtue",
+ "TypeVice": "Vice",
+ "TypeVehiclehull": "Vehicule Hull",
+ "TypePowercoremodule": "Power Core Module",
+ "TypeMobilitymodule": "Mobility Module",
+ "TypeCombatmodule": "Combat Module",
+ "TypeVehiclemodule": "Vehicle Module",
+ "TypeVehicleweaponmodule" : "Vehicle Weapon Module",
+ "TypePropulsionmodule": "Propulsion module"
+ }
}
\ No newline at end of file
diff --git a/modules/pegasus-actor-sheet.js b/modules/pegasus-actor-sheet.js
index 2c9e865..f1e6b44 100644
--- a/modules/pegasus-actor-sheet.js
+++ b/modules/pegasus-actor-sheet.js
@@ -3,8 +3,8 @@
* @extends {ActorSheet}
*/
-import { PegasusUtility } from "./pegasus-utility.js";
-import { PegasusRollDialog } from "./pegasus-roll-dialog.js";
+import { PegasusUtility } from "./pegasus-utility.js"
+import { PegasusRollDialog } from "./pegasus-roll-dialog.js"
/* -------------------------------------------- */
export class PegasusActorSheet extends ActorSheet {
@@ -78,15 +78,8 @@ export class PegasusActorSheet extends ActorSheet {
/* -------------------------------------------- */
async openGenericRoll() {
- let rollData = PegasusUtility.getBasicRollData()
- rollData.alias = "Dice Pool Roll",
- rollData.mode = "generic"
- rollData.title = `Dice Pool Roll`
- rollData.img = "icons/dice/d12black.svg"
- rollData.isGeneric = true
+ let rollData = PegasusUtility.initGenericRoll()
rollData.traumaState = this.actor.getTraumaState()
- rollData.diceList = PegasusUtility.getDiceList()
- rollData.dicePool = []
let rollDialog = await PegasusRollDialog.create( this.actor, rollData);
rollDialog.render( true );
diff --git a/modules/pegasus-actor.js b/modules/pegasus-actor.js
index 8345301..7d3698f 100644
--- a/modules/pegasus-actor.js
+++ b/modules/pegasus-actor.js
@@ -464,6 +464,9 @@ export class PegasusActor extends Actor {
ui.notifications.warn("Stun level cannot go below 0")
}
let stunAbove = combat.stunlevel - combat.stunthreshold
+ if (stunAbove > 0) {
+ ChatMessage.create( { content: `${this.name} Stun threshold has been exceeded.`})
+ }
if (incDec > 0 && stunAbove > 0) {
let delirium = duplicate(this.data.data.secondary.delirium)
delirium.value -= incDec
@@ -561,6 +564,27 @@ export class PegasusActor extends Actor {
/* -------------------------------------------- */
async preprocessItem(event, item, onDrop = false) {
+
+ // Pre-filter effects
+ if (item.data.type == 'effect' ) {
+ if ( this.checkMentalDisruption() && item.data.data.type == "mental" && item.data.data.genre == "positive") {
+ ChatMessage.create( { content: "Effects of this type cannot be applied while Disruption is applied, Use a Soft Action to remove Disruption"})
+ return
+ }
+ if ( this.checkPhysicalDisruption() && item.data.data.type == "physical" && item.data.data.genre == "positive") {
+ ChatMessage.create( { content: "Effects of this type cannot be applied while Disruption is applied, Use a Soft Action to remove Disruption"})
+ return
+ }
+ if ( this.checkMentalImmunity() && item.data.data.type == "mental" && item.data.data.genre == "negative") {
+ ChatMessage.create( { content: "Effects of this type cannot be applied while Immunity is applied"})
+ return
+ }
+ if ( this.checkPhysicalImmunity() && item.data.data.type == "physical" && item.data.data.genre == "negative") {
+ ChatMessage.create( { content: "Effects of this type cannot be applied while Immunity is applied"})
+ return
+ }
+ }
+
if (item.data.type == 'race') {
this.applyRace(item.data)
} else if (item.data.type == 'role') {
@@ -833,6 +857,10 @@ export class PegasusActor extends Actor {
if (item) {
if (item.data.data.status == status) return;// Ensure we are really changing the status
+ if (this.checkNoPerksAllowed() ) {
+ ChatMessage( {content: "No perks activation allowed due to effect !"})
+ return
+ }
// Severe Trauma management
if (this.getTraumaState() == "severetrauma") {
@@ -977,7 +1005,79 @@ export class PegasusActor extends Actor {
ChatMessage.create({ content: `${this.name} has used a Hero Level to reroll !` })
return biodata.currentlevelremaining
}
-
+
+ /* -------------------------------------------- */
+ checkIgnoreHealth() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.ignorehealthpenalty) {
+ return true
+ }
+ }
+ return false
+ }
+ /* -------------------------------------------- */
+ checkMentalDisruption() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.mentaldisruption) {
+ return true
+ }
+ }
+ return false
+ }
+ /* -------------------------------------------- */
+ checkPhysicalDisruption() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.physicaldisruption) {
+ return true
+ }
+ }
+ return false
+ }
+ /* -------------------------------------------- */
+ checkMentalImmunity() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.mentalimmunity) {
+ return true
+ }
+ }
+ return false
+ }
+ /* -------------------------------------------- */
+ checkPhysicalImmunity() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.physicalimmunity) {
+ return true
+ }
+ }
+ return false
+ }
+ /* -------------------------------------------- */
+ checkNoBonusDice() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.nobonusdice) {
+ return true
+ }
+ }
+ return false
+ }
+ /* -------------------------------------------- */
+ checkNoPerksAllowed() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.noperksallowed) {
+ return true
+ }
+ }
+ return false
+ }
+ /* -------------------------------------------- */
+ checkIfPossible() {
+ for (let effect of this.data.items) {
+ if (effect.type == "effect" && effect.data.data.isthispossible.length > 0) {
+ ChatMessage.create( { content: effect.data.data.isthispossible} )
+ }
+ }
+ }
+
/* -------------------------------------------- */
async computeNRGHealth() {
if (this.isOwner || game.user.isGM) {
@@ -1021,9 +1121,10 @@ export class PegasusActor extends Actor {
updates['data.nrg.value'] = nrgValue
}
- nrgValue = PegasusUtility.getDiceValue(this.data.data.statistics.mnd.value) + this.data.data.statistics.mnd.mod;
- if (nrgValue != this.data.data.combat.stunthreshold) {
- updates['data.combat.stunthreshold'] = nrgValue
+ let stunth = PegasusUtility.getDiceValue(this.data.data.statistics.phy.value) + PegasusUtility.getDiceValue(this.data.data.statistics.mnd.value) + PegasusUtility.getDiceValue(this.data.data.statistics.foc.value)
+ + this.data.data.statistics.mnd.mod + this.data.data.statistics.phy.mod + this.data.data.statistics.foc.mod
+ if (stunth != this.data.data.combat.stunthreshold) {
+ updates['data.combat.stunthreshold'] = stunth
}
let momentum = this.data.data.statistics.foc.value + this.data.data.statistics.foc.mod
@@ -1038,7 +1139,6 @@ export class PegasusActor extends Actor {
updates['data.mr.value'] = mrLevel
}
-
let moralitythreshold = - (Number(PegasusUtility.getDiceValue(this.data.data.statistics.foc.value)) + Number(this.data.data.statistics.foc.mod))
if (moralitythreshold != this.data.data.biodata.moralitythreshold) {
updates['data.biodata.moralitythreshold'] = moralitythreshold
@@ -1063,20 +1163,20 @@ export class PegasusActor extends Actor {
}
if (Object.entries(updates).length > 0) {
await this.update(updates)
- this.computeThreatLevel()
}
-
+ this.computeThreatLevel()
}
if (this.isOwner || game.user.isGM) {
// Update current hindrance level
let hindrance = this.data.data.combat.hindrancedice
- if (this.data.data.secondary.health.value < 0) {
- if (this.data.data.secondary.health.value < -Math.floor((this.data.data.secondary.health.max + 1) / 2)) { // Severe wounded
- hindrance += 3
- } else {
- hindrance += 1
-
+ if ( !this.checkIgnoreHealth() ) {
+ if (this.data.data.secondary.health.value < 0) {
+ if (this.data.data.secondary.health.value < -Math.floor((this.data.data.secondary.health.max + 1) / 2)) { // Severe wounded
+ hindrance += 3
+ } else {
+ hindrance += 1
+ }
}
}
this.data.data.combat.hindrancedice = hindrance
@@ -1347,6 +1447,7 @@ export class PegasusActor extends Actor {
rollData.levelRemaining = this.getLevelRemaining()
rollData.activePerks = duplicate(this.getActivePerks())
rollData.diceList = PegasusUtility.getDiceList()
+ rollData.noBonusDice = this.checkNoBonusDice()
rollData.dicePool = []
if (statKey) {
diff --git a/modules/pegasus-item.js b/modules/pegasus-item.js
index c6e6b98..c1a16bc 100644
--- a/modules/pegasus-item.js
+++ b/modules/pegasus-item.js
@@ -15,6 +15,8 @@ export const defaultItemImg = {
weapon: "systems/fvtt-pegasus-rpg/images/icons/icon_meleeweapon.webp",
shield: "systems/fvtt-pegasus-rpg/images/icons/icon_shield.webp",
money: "systems/fvtt-pegasus-rpg/images/icons/icon_money.webp",
+ vice: "systems/fvtt-pegasus-rpg/images/icons/icon_vice.webp",
+ virtue: "systems/fvtt-pegasus-rpg/images/icons/icon_virtue.webp",
}
/**
diff --git a/modules/pegasus-roll-dialog.js b/modules/pegasus-roll-dialog.js
index f7a5b12..a609326 100644
--- a/modules/pegasus-roll-dialog.js
+++ b/modules/pegasus-roll-dialog.js
@@ -33,8 +33,8 @@ export class PegasusRollDialog extends Dialog {
super(conf, options);
- this.actor = actor;
- this.rollData = rollData;
+ this.actor = actor
+ this.rollData = rollData
}
/* -------------------------------------------- */
@@ -106,6 +106,7 @@ export class PegasusRollDialog extends Dialog {
manageWeapons(weaponIdx, toggled) {
let weapon = this.rollData.weaponsList[weaponIdx]
if (weapon) {
+ this.rollData.weapon = duplicate(weapon)
if (toggled) {
this.rollData.weaponName = weapon.weapon.name
} else {
diff --git a/modules/pegasus-utility.js b/modules/pegasus-utility.js
index 63eab47..a898609 100644
--- a/modules/pegasus-utility.js
+++ b/modules/pegasus-utility.js
@@ -2,6 +2,7 @@
import { PegasusCombat } from "./pegasus-combat.js";
import { PegasusCommands } from "./pegasus-commands.js";
import { PegasusActorCreate } from "./pegasus-create-char.js";
+import { PegasusRollDialog } from "./pegasus-roll-dialog.js";
/* -------------------------------------------- */
const __level2Dice = ["d0", "d4", "d6", "d8", "d10", "d12"]
@@ -14,7 +15,10 @@ export class PegasusUtility {
/* -------------------------------------------- */
static async init() {
- Hooks.on('renderChatLog', (log, html, data) => PegasusUtility.chatListeners(html));
+ Hooks.on('renderChatLog', (log, html, data) => PegasusUtility.chatListeners(html))
+ Hooks.on('targetToken', (user, token, flag) => PegasusUtility.targetToken(user, token, flag))
+ Hooks.on('renderSidebarTab', (app, html, data) => PegasusUtility.addDiceRollButton(app, html, data))
+
Hooks.on("getCombatTrackerEntryContext", (html, options) => {
PegasusUtility.pushInitiativeOptions(html, options);
});
@@ -54,6 +58,41 @@ export class PegasusUtility {
})
}
+ /* -------------------------------------------- */
+ static initGenericRoll() {
+ let rollData = PegasusUtility.getBasicRollData()
+ rollData.alias = "Dice Pool Roll",
+ rollData.mode = "generic"
+ rollData.title = `Dice Pool Roll`
+ rollData.img = "icons/dice/d12black.svg"
+ rollData.isGeneric = true
+ rollData.diceList = PegasusUtility.getDiceList()
+ rollData.dicePool = []
+ rollData.traumaState = "none"
+ return rollData
+ }
+
+ /* -------------------------------------------- */
+ static async addDiceRollButton(app, html, data) {
+ if (app.tabName !== 'chat') return
+ let $chat_form = html.find('#chat-form')
+ const template = 'systems/fvtt-pegasus-rpg/templates/chat-roll-button.html'
+ renderTemplate(template, {}).then(c => {
+ if (c.length > 0) {
+ let $content = $(c)
+ $chat_form.before($content)
+ $content.find('#pegasus-chat-roll-button').on('click', async event => {
+ event.preventDefault()
+ let rollData = PegasusUtility.initGenericRoll()
+ rollData.isChatRoll = true
+ let rollDialog = await PegasusRollDialog.create( undefined, rollData)
+ rollDialog.render( true )
+ })
+
+ }
+ })
+ }
+
/* -------------------------------------------- */
static pushInitiativeOptions(html, options) {
options.push({ name: "Apply -10", condition: true, icon: '', callback: target => { PegasusCombat.decInitBy10(target.data('combatant-id'), -10); } })
@@ -345,6 +384,7 @@ export class PegasusUtility {
ui.notifications.warn(`No character linked to the player : reroll not allowed.`)
return
}
+ console.log("Going to reroll", character, rollId)
let rollData = this.getRollData(rollId)
if (character.getLevelRemaining() > 0) {
rollData.rerollHero = true
@@ -361,6 +401,13 @@ export class PegasusUtility {
game.socket.emit("system.fvtt-pegasus-rpg", { name: "msg_reroll_hero", data: { userId: userId, rollId: rollId } })
}
+ /* -------------------------------------------- */
+ static targetToken( user, token, flag) {
+ if (flag) {
+ token.actor.checkIfPossible()
+ }
+ }
+
/* -------------------------------------------- */
static async chatListeners(html) {
@@ -509,7 +556,7 @@ export class PegasusUtility {
/* -------------------------------------------- */
static getTarget() {
- if (game.user.targets && game.user.targets.size == 1) {
+ if (game.user.targets) {
for (let target of game.user.targets) {
return target
}
@@ -546,11 +593,12 @@ export class PegasusUtility {
let id = rollData.rollId
let oldRollData = this.rollDataStore[id] || {}
let newRollData = mergeObject(oldRollData, rollData)
+ console.log("Rolldata saved", id)
this.rollDataStore[id] = newRollData
}
/* -------------------------------------------- */
static saveRollData(rollData) {
- game.socket.emit("system.pegasus-rpg", {
+ game.socket.emit("system.fvtt-pegasus-rpg", {
name: "msg_update_roll", data: rollData
}); // Notify all other clients of the roll
this.updateRollData(rollData)
@@ -581,6 +629,7 @@ export class PegasusUtility {
this.addItemDropToActor(actor, item)
}
if (msg.name == "msg_reroll_hero") {
+ console.log("Reroll requested")
this.rerollHeroRemaining(msg.data.userId, msg.data.rollId)
}
if (msg.name == "msg_gm_remove_effect") {
@@ -681,7 +730,7 @@ export class PegasusUtility {
if (game.user.isGM) {
this.removeForeignEffect(effect)
} else {
- game.socket.emit("system.fvtt-pegasus-rgp", { msg: "msg_gm_remove_effect", data: effect })
+ game.socket.emit("system.fvtt-pegasus-rpg", { msg: "msg_gm_remove_effect", data: effect })
}
} else {
toRem.push(effect.effect._id)
@@ -863,7 +912,7 @@ export class PegasusUtility {
chatGM.whisper = this.getUsers(user => user.isGM);
chatGM.content = "Blinde message of " + game.user.name + "
" + chatOptions.content;
console.log("blindMessageToGM", chatGM);
- game.socket.emit("system.fvtt-pegasus-rgp", { msg: "msg_gm_chat_message", data: chatGM });
+ game.socket.emit("system.fvtt-pegasus-rpg", { msg: "msg_gm_chat_message", data: chatGM });
}
@@ -950,7 +999,7 @@ export class PegasusUtility {
console.log("TARGET ", target)
let defenderActor = target.actor
rollData.defenderTokenId = target.id
- rollData.attackerId = this.id
+ //rollData.attackerId = this.id
console.log("DEFENDER", defenderActor)
defenderActor.addHindrancesList(rollData.effectsList)
}
diff --git a/styles/simple.css b/styles/simple.css
index f23384b..9221f64 100644
--- a/styles/simple.css
+++ b/styles/simple.css
@@ -1159,6 +1159,10 @@ ul, li {
position:relative;
top:1px;
}
+.pegasus-chat-roll-button {
+ height: 38px;
+ max-height: 38px;
+}
.plus-minus-button {
box-shadow: inset 0px 1px 0px 0px #a6827e;
@@ -1282,7 +1286,7 @@ Focus FOC: #ff0084
background: black;
}
.color-class-agi,
-.color-class-range {
+.color-class-ranged-attack {
background-color: #02a41d;
background: #02a41d;
}
@@ -1318,7 +1322,7 @@ Focus FOC: #ff0084
background-color: #505050;
}
.color-class-per,
-.color-class-ranged {
+.color-class-ranged-damage {
background-color: #f9c801;
}
.color-class-foc {
diff --git a/system.json b/system.json
index e401dc1..5160da4 100644
--- a/system.json
+++ b/system.json
@@ -180,9 +180,9 @@
"styles": [
"styles/simple.css"
],
- "templateVersion": 99,
+ "templateVersion": 100,
"title": "Pegasus RPG",
"url": "https://www.uberwald.me/data/files/fvtt-pegasus-rpg",
- "version": "0.6.8",
+ "version": "0.6.10",
"background" : "./images/ui/pegasus_welcome_page.webp"
}
diff --git a/template.json b/template.json
index 86ecf23..d32d063 100644
--- a/template.json
+++ b/template.json
@@ -361,6 +361,14 @@
"effectstatlevel": false,
"effectstat": "",
"oneuse": false,
+ "ignorehealthpenalty": false,
+ "isthispossible": "",
+ "mentaldisruption": false,
+ "physicaldisruption": false,
+ "mentalimmunity": false,
+ "physicalimmunity": false,
+ "nobonusdice": false,
+ "noperksallowed": false,
"description": ""
},
"race": {
@@ -443,6 +451,8 @@
"effectsgained": [],
"category": "general",
"upgradable": false,
+ "activatedtext": "",
+ "deactivatedtext": "",
"features": {
"nrgcost": {
"label": "NRG cost to use",
diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html
index c94f6cd..385c3b1 100644
--- a/templates/actor-sheet.html
+++ b/templates/actor-sheet.html
@@ -110,16 +110,16 @@