Skip to content

Commit

Permalink
feat: Initial Psionic Ability feature (#1679)
Browse files Browse the repository at this point in the history
This release adds Psionic Abilities / Talents to the Traveller info tab.  More details can be found here: https://github.com/xdy/twodsix-foundryvtt/wiki/Psionic-Abilities.  Thanks to @Zee for the idea and testing. Thanks to @Vespilo helped with testing, too.
  • Loading branch information
marvin9257 authored Nov 7, 2024
1 parent d89d6b1 commit f20dfa1
Show file tree
Hide file tree
Showing 42 changed files with 577 additions and 191 deletions.
2 changes: 1 addition & 1 deletion src/migrations/2023_09_16_08_232_fix_bad_Equipped_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async function checkEquippedState (actor: TwodsixActor): Promise<void> {
}

async function checkItemEquippedState (item:TwodsixItem): Promise<void> {
if (!["skills", "trait", "spell", "component", "ship_position"].includes(item.type)) {
if (!["skills", "trait", "spell", "component", "ship_position", "psiAbility"].includes(item.type)) {
if (typeof item.system.equipped !== "string") {
await item.update({"system.equipped": "backpack"});
console.log("Migrated " + item.name + (item.actor ? " on " + item.actor.name : ""));
Expand Down
61 changes: 40 additions & 21 deletions src/module/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ const RULESETS = Object.freeze({
addEffectToDamage: false,
addEffectToManualDamage: false,
weightModifierForWornArmor: "0",
chainBonus: "0, 0, 0, 0, 0, 0"
chainBonus: "0, 0, 0, 0, 0, 0",
psiTalentsRequireRoll: false
}
},
CE: {
Expand Down Expand Up @@ -146,7 +147,8 @@ const RULESETS = Object.freeze({
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "-2, -1, -1, 1, 1, 2"
chainBonus: "-2, -1, -1, 1, 1, 2",
psiTalentsRequireRoll: true
}
},
CEL: {
Expand Down Expand Up @@ -192,7 +194,8 @@ const RULESETS = Object.freeze({
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 0, 0, 0"
chainBonus: "0, 0, 0, 0, 0, 0",
psiTalentsRequireRoll: false
}
},
CEFTL: {
Expand Down Expand Up @@ -237,7 +240,8 @@ const RULESETS = Object.freeze({
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 0, 0, 0"
chainBonus: "0, 0, 0, 0, 0, 0",
psiTalentsRequireRoll: false
},
},
CEATOM: {
Expand Down Expand Up @@ -282,7 +286,8 @@ const RULESETS = Object.freeze({
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 0, 0, 0"
chainBonus: "0, 0, 0, 0, 0, 0",
psiTalentsRequireRoll: false
}
},
BARBARIC: {
Expand Down Expand Up @@ -326,7 +331,8 @@ const RULESETS = Object.freeze({
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 0, 0, 0"
chainBonus: "0, 0, 0, 0, 0, 0",
psiTalentsRequireRoll: false
},
},
CEQ: {
Expand Down Expand Up @@ -371,7 +377,8 @@ const RULESETS = Object.freeze({
targetDMList: "",
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
chainBonus: "0, 0, 0, 0, 0, 0"
chainBonus: "0, 0, 0, 0, 0, 0",
psiTalentsRequireRoll: false
}
},
CD: {
Expand Down Expand Up @@ -425,7 +432,8 @@ const RULESETS = Object.freeze({
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 1, 1, 1",
reverseHealingOrder: true
reverseHealingOrder: true,
psiTalentsRequireRoll: false
}
},
CDEE: {
Expand Down Expand Up @@ -479,7 +487,8 @@ const RULESETS = Object.freeze({
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 1, 1, 1",
reverseHealingOrder: true
reverseHealingOrder: true,
psiTalentsRequireRoll: false
}
},
CLU: {
Expand Down Expand Up @@ -533,7 +542,8 @@ const RULESETS = Object.freeze({
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 1, 1, 1",
reverseHealingOrder: true
reverseHealingOrder: true,
psiTalentsRequireRoll: false
}
},
SOC: {
Expand Down Expand Up @@ -632,7 +642,8 @@ const RULESETS = Object.freeze({
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "0, 0, 0, 0, 0, 0"
chainBonus: "0, 0, 0, 0, 0, 0",
psiTalentsRequireRoll: false
}
},
CU: {
Expand Down Expand Up @@ -684,7 +695,8 @@ const RULESETS = Object.freeze({
armorDamageFormula: "@damage - @effectiveArmor",
addEffectToDamage: true,
weightModifierForWornArmor: "1",
chainBonus: "-2, -1, -1, 1, 1, 2"
chainBonus: "-2, -1, -1, 1, 1, 2",
psiTalentsRequireRoll: false
}
},
OTHER: {
Expand All @@ -706,6 +718,8 @@ const ROLLTYPES = Object.freeze({
Disadvantage: {key: 'Disadvantage', formula: "3d6kl2"}
});

const WeightlessItems = ["skills", "trait", "spell", "psiAbility"];

const CONSUMABLES = Object.freeze({
air: "TWODSIX.Items.Consumable.Types.air",
drugs: "TWODSIX.Items.Consumable.Types.drugs",
Expand Down Expand Up @@ -1152,15 +1166,17 @@ export const AUG_LOCATIONS = {
};

export const ITEM_TYPE_SELECT = {
augment: "TWODSIX.Items.Items.AssignAugment",
weapon: "TWODSIX.Items.Items.AssignWeapon",
armor: "TWODSIX.Items.Items.AssignArmor",
equipment: "TWODSIX.Items.Items.AssignEquipment",
consumable: "TWODSIX.Items.Items.AssignConsumable",
augment: "TWODSIX.Items.Items.AssignAugment",
computer: "TWODSIX.Items.Items.AssignComputer",
tool: "TWODSIX.Items.Items.AssignTool",
consumable: "TWODSIX.Items.Items.AssignConsumable",
equipment: "TWODSIX.Items.Items.AssignEquipment",
junk: "TWODSIX.Items.Items.AssignJunk",
storage: "TWODSIX.Items.Items.MoveStorage"
psiAbility: "TWODSIX.Items.Items.AssignPsiAbility",
storage: "TWODSIX.Items.Items.MoveStorage",
spell: "TWODSIX.Items.Items.AssignSpell",
tool: "TWODSIX.Items.Items.AssignTool",
weapon: "TWODSIX.Items.Items.AssignWeapon"
};

export const CU_DAMAGE_TYPES = {
Expand All @@ -1174,7 +1190,8 @@ export const CU_DAMAGE_TYPES = {
melee: "TWODSIX.DamageType.Melee",
plasma: "TWODSIX.DamageType.Plasma",
poison: "TWODSIX.DamageType.Poison",
stun: "TWODSIX.DamageType.Stun"
stun: "TWODSIX.DamageType.Stun",
psionic: "TWODSIX.DamageType.Psionic"
};

export const DAMAGECOLORS = Object.freeze({
Expand Down Expand Up @@ -1231,7 +1248,8 @@ export type TWODSIX = {
ITEM_TYPE_SELECT: typeof ITEM_TYPE_SELECT,
CU_DAMAGE_TYPES: typeof CU_DAMAGE_TYPES,
effectType: typeof effectType,
DAMAGECOLORS: typeof DAMAGECOLORS
DAMAGECOLORS: typeof DAMAGECOLORS,
WeightlessItems: typeof WeightlessItems
};

export const TWODSIX = {
Expand Down Expand Up @@ -1274,5 +1292,6 @@ export const TWODSIX = {
ITEM_TYPE_SELECT: ITEM_TYPE_SELECT,
CU_DAMAGE_TYPES: CU_DAMAGE_TYPES,
effectType: effectType,
DAMAGECOLORS: DAMAGECOLORS
DAMAGECOLORS: DAMAGECOLORS,
WeightlessItems: WeightlessItems
};
18 changes: 18 additions & 0 deletions src/module/data/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,24 @@ export class SpellData extends TraitData {
}
}

export class PsiAbilityData extends TraitData {
static defineSchema() {
const schema = super.defineSchema();
schema.target = makeTargetTemplate();
schema.duration = new fields.StringField({...requiredBlankString});
schema.associatedSkillName = new fields.StringField({...requiredBlankString});
schema.skill = new fields.StringField({...requiredBlankString});
schema.range = new fields.StringField({...requiredBlankString});
schema.rangeBand = new fields.StringField({required: true, blank: false, initial: "none" });
schema.damage = new fields.StringField({...requiredBlankString});
schema.damageType = new fields.StringField({required: true, blank: false, initial: "psionic" });
schema.psiCost = new fields.NumberField({...requiredInteger, initial: 0});
schema.difficulty = new fields.StringField({required: true, blank: false, initial: "Average" });
schema.skillModifier = new fields.NumberField({...requiredInteger, initial: 0});
return schema;
}
}

export class ConsumableData extends GearData {
static defineSchema() {
const schema = super.defineSchema();
Expand Down
22 changes: 18 additions & 4 deletions src/module/entities/TwodsixActor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ export default class TwodsixActor extends Actor {

getActorEncumbrance():number {
let encumbrance = 0;
const actorItems = this.items.filter( i => !["skills", "trait", "ship_position", "storage", "spell"].includes(i.type));
const actorItems = this.items.filter( i => ![...TWODSIX.WeightlessItems, "ship_position", "storage"].includes(i.type));
for (const item of actorItems) {
encumbrance += getEquipmentWeight(item);
}
Expand Down Expand Up @@ -1048,7 +1048,7 @@ export default class TwodsixActor extends Actor {

//Create Item
const addedItem = (await this.createEmbeddedDocuments("Item", [transferData]))[0];
if (game.settings.get('twodsix', 'useEncumbranceStatusIndicators') && this.type === 'traveller' && !["skills", "trait", "spell"].includes(addedItem.type)) {
if (game.settings.get('twodsix', 'useEncumbranceStatusIndicators') && this.type === 'traveller' && !TWODSIX.WeightlessItems.includes(addedItem.type)) {
await applyEncumberedEffect(this);
}
console.log(`Twodsix | Added Item ${itemData.name} to character`);
Expand Down Expand Up @@ -1083,7 +1083,7 @@ export default class TwodsixActor extends Actor {
}
break;
case 'ship':
if (!["skills", "trait", "spell"].includes(itemData.type)) {
if (!TWODSIX.WeightlessItems.includes(itemData.type)) {
return await this._addDroppedEquipment(itemData);
}
break;
Expand Down Expand Up @@ -1267,6 +1267,20 @@ export default class TwodsixActor extends Actor {
return 0;
}
}

/**
* Removes (damages) psionic characteristic and spreads excess to regular damage
* @param {number} psiCost The number of psi points to remove
*/
public async removePsiPoints(psiCost: number): Promise<void> {
if (psiCost > 0) {
const netPoints = Math.min(this.system.characteristics.psionicStrength.current, psiCost);
await this.update({'system.characteristics.psionicStrength.damage': this.system.characteristics.psionicStrength.damage + netPoints});
if (netPoints < psiCost) {
await this.damageActor({damageValue: psiCost - netPoints, armorPiercingValue: 9999, damageType: "psionic", damageLabel: game.i18n.localize("TWODSIX.DamageType.Psionic"), canBeParried: false}, false);
}
}
}
}

/**
Expand Down Expand Up @@ -1346,7 +1360,7 @@ async function deleteIdFromShipPositions(actorId: string) {
* @function
*/
function getEquipmentWeight(item:TwodsixItem):number {
if (!["skills", "spell", "trait"].includes(item.type)) {
if (!TWODSIX.WeightlessItems.includes(item.type)) {
if (["backpack", "equipped"].includes(item.system.equipped)) {
let q = item.system.quantity || 0;
const w = item.system.weight || 0;
Expand Down
Loading

0 comments on commit f20dfa1

Please sign in to comment.