2020-06-24 14:13:41 -04:00
/ * *
* The Star Wars 5 th Edition game system for Foundry Virtual Tabletop
* Author : Kakeman89
* Software License : GNU GPLv3
* Content License : https : //media.wizards.com/2016/downloads/SW5ERD-OGL_V5.1.pdf
* Repository : https : //gitlab.com/foundrynet/sw5e
* Issue Tracker : https : //gitlab.com/foundrynet/sw5e/issues
* /
// Import Modules
import { SW5E } from "./module/config.js" ;
import { registerSystemSettings } from "./module/settings.js" ;
import { preloadHandlebarsTemplates } from "./module/templates.js" ;
import { _getInitiativeFormula } from "./module/combat.js" ;
import { measureDistance , getBarAttribute } from "./module/canvas.js" ;
import { Actor5e } from "./module/actor/entity.js" ;
import { ActorSheet5eCharacter } from "./module/actor/sheets/character.js" ;
import { Item5e } from "./module/item/entity.js" ;
import { ItemSheet5e } from "./module/item/sheet.js" ;
import { ActorSheet5eNPC } from "./module/actor/sheets/npc.js" ;
import { Dice5e } from "./module/dice.js" ;
import * as chat from "./module/chat.js" ;
import * as migrations from "./module/migration.js" ;
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
Hooks . once ( "init" , function ( ) {
console . log ( ` SW5e | Initializing Star Wars 5th Edition System \n ${ SW5E . ASCII } ` ) ;
// Create a SW5E namespace within the game global
game . sw5e = {
Actor5e ,
Dice5e ,
Item5e ,
migrations ,
rollItemMacro
} ;
// Record Configuration Values
CONFIG . SW5E = SW5E ;
CONFIG . Actor . entityClass = Actor5e ;
CONFIG . Item . entityClass = Item5e ;
// Register System Settings
registerSystemSettings ( ) ;
// Patch Core Functions
Combat . prototype . _getInitiativeFormula = _getInitiativeFormula ;
// Register sheet application classes
Actors . unregisterSheet ( "core" , ActorSheet ) ;
Actors . registerSheet ( "sw5e" , ActorSheet5eCharacter , { types : [ "character" ] , makeDefault : true } ) ;
Actors . registerSheet ( "sw5e" , ActorSheet5eNPC , { types : [ "npc" ] , makeDefault : true } ) ;
Items . unregisterSheet ( "core" , ItemSheet ) ;
2020-10-23 12:36:42 -04:00
<< << << < Updated upstream
2020-06-24 14:13:41 -04:00
Items . registerSheet ( "sw5e" , ItemSheet5e , { makeDefault : true } ) ;
2020-10-23 12:36:42 -04:00
=== === =
Items . registerSheet ( "sw5e" , ItemSheet5e , {
types : [ 'weapon' , 'equipment' , 'consumable' , 'tool' , 'loot' , 'class' , 'power' , 'feat' , 'species' , 'backpack' , 'archetype' , 'classfeature' , 'background' ] ,
makeDefault : true ,
label : "SW5E.SheetClassItem"
} ) ;
>>> >>> > Stashed changes
2020-06-24 14:13:41 -04:00
// Preload Handlebars Templates
preloadHandlebarsTemplates ( ) ;
} ) ;
/* -------------------------------------------- */
/* Foundry VTT Setup */
/* -------------------------------------------- */
/ * *
* This function runs after game data has been requested and loaded from the servers , so entities exist
* /
Hooks . once ( "setup" , function ( ) {
// Localize CONFIG objects once up-front
const toLocalize = [
"abilities" , "alignments" , "conditionTypes" , "consumableTypes" , "currencies" , "damageTypes" , "distanceUnits" , "equipmentTypes" ,
"healingTypes" , "itemActionTypes" , "limitedUsePeriods" , "senses" , "skills" , "powerComponents" , "powerLevels" , "powerPreparationModes" ,
"powerSchools" , "powerScalingModes" , "targetTypes" , "timePeriods" , "weaponProperties" , "weaponTypes" , "languages" , "polymorphSettings" ,
2020-07-13 19:51:27 -03:00
"armorProficiencies" , "weaponProficiencies" , "toolProficiencies" , "abilityActivationTypes" , "actorSizes" , "proficiencyLevels" , "armorpropertiesTypes"
2020-06-24 14:13:41 -04:00
] ;
for ( let o of toLocalize ) {
CONFIG . SW5E [ o ] = Object . entries ( CONFIG . SW5E [ o ] ) . reduce ( ( obj , e ) => {
obj [ e [ 0 ] ] = game . i18n . localize ( e [ 1 ] ) ;
return obj ;
} , { } ) ;
}
} ) ;
/* -------------------------------------------- */
/ * *
* Once the entire VTT framework is initialized , check to see if we should perform a data migration
* /
Hooks . once ( "ready" , function ( ) {
// Determine whether a system migration is required and feasible
const currentVersion = game . settings . get ( "sw5e" , "systemMigrationVersion" ) ;
const NEEDS _MIGRATION _VERSION = 0.84 ;
const COMPATIBLE _MIGRATION _VERSION = 0.80 ;
let needMigration = ( currentVersion < NEEDS _MIGRATION _VERSION ) || ( currentVersion === null ) ;
const canMigrate = currentVersion >= COMPATIBLE _MIGRATION _VERSION ;
// Perform the migration
if ( needMigration && game . user . isGM ) {
if ( currentVersion && ( currentVersion < COMPATIBLE _MIGRATION _VERSION ) ) {
ui . notifications . error ( ` Your SW5E system data is from too old a Foundry version and cannot be reliably migrated to the latest version. The process will be attempted, but errors may occur. ` , { permanent : true } ) ;
}
migrations . migrateWorld ( ) ;
}
// Wait to register hotbar drop hook on ready so that modules could register earlier if they want to
Hooks . on ( "hotbarDrop" , ( bar , data , slot ) => create5eMacro ( data , slot ) ) ;
} ) ;
/* -------------------------------------------- */
/* Canvas Initialization */
/* -------------------------------------------- */
Hooks . on ( "canvasInit" , function ( ) {
// Extend Diagonal Measurement
canvas . grid . diagonalRule = game . settings . get ( "sw5e" , "diagonalMovement" ) ;
SquareGrid . prototype . measureDistance = measureDistance ;
// Extend Token Resource Bars
Token . prototype . getBarAttribute = getBarAttribute ;
} ) ;
/* -------------------------------------------- */
/* Other Hooks */
/* -------------------------------------------- */
Hooks . on ( "renderChatMessage" , ( app , html , data ) => {
// Display action buttons
chat . displayChatActionButtons ( app , html , data ) ;
// Highlight critical success or failure die
chat . highlightCriticalSuccessFailure ( app , html , data ) ;
// Optionally collapse the content
if ( game . settings . get ( "sw5e" , "autoCollapseItemCards" ) ) html . find ( ".card-content" ) . hide ( ) ;
} ) ;
Hooks . on ( "getChatLogEntryContext" , chat . addChatMessageContextOptions ) ;
Hooks . on ( "renderChatLog" , ( app , html , data ) => Item5e . chatListeners ( html ) ) ;
Hooks . on ( 'getActorDirectoryEntryContext' , Actor5e . addDirectoryContextOptions ) ;
2020-08-31 16:32:00 -04:00
2020-06-24 14:13:41 -04:00
/* -------------------------------------------- */
/* Hotbar Macros */
/* -------------------------------------------- */
/ * *
* Create a Macro from an Item drop .
* Get an existing item macro if one exists , otherwise create a new one .
* @ param { Object } data The dropped data
* @ param { number } slot The hotbar slot to use
* @ returns { Promise }
* /
async function create5eMacro ( data , slot ) {
if ( data . type !== "Item" ) return ;
if ( ! ( "data" in data ) ) return ui . notifications . warn ( "You can only create macro buttons for owned Items" ) ;
const item = data . data ;
// Create the macro command
const command = ` game.sw5e.rollItemMacro(" ${ item . name } "); ` ;
let macro = game . macros . entities . find ( m => ( m . name === item . name ) && ( m . command === command ) ) ;
if ( ! macro ) {
macro = await Macro . create ( {
name : item . name ,
type : "script" ,
img : item . img ,
command : command ,
flags : { "sw5e.itemMacro" : true }
} ) ;
}
game . user . assignHotbarMacro ( macro , slot ) ;
return false ;
}
/* -------------------------------------------- */
/ * *
* Create a Macro from an Item drop .
* Get an existing item macro if one exists , otherwise create a new one .
* @ param { string } itemName
* @ return { Promise }
* /
function rollItemMacro ( itemName ) {
const speaker = ChatMessage . getSpeaker ( ) ;
let actor ;
if ( speaker . token ) actor = game . actors . tokens [ speaker . token ] ;
if ( ! actor ) actor = game . actors . get ( speaker . actor ) ;
// Get matching items
const items = actor ? actor . items . filter ( i => i . name === itemName ) : [ ] ;
if ( items . length > 1 ) {
ui . notifications . warn ( ` Your controlled Actor ${ actor . name } has more than one Item with name ${ itemName } . The first matched item will be chosen. ` ) ;
} else if ( items . length === 0 ) {
return ui . notifications . warn ( ` Your controlled Actor does not have an item named ${ itemName } ` ) ;
}
const item = items [ 0 ] ;
// Trigger the item roll
if ( item . data . type === "power" ) return actor . usePower ( item ) ;
return item . roll ( ) ;
}