2020-11-08 00:22:04 +01:00
/************************************************************************************/
2020-11-08 23:12:52 +01:00
// Some internal test strings
2020-11-08 00:22:04 +01:00
let str1 = ` JABBERSLYTHE
2020-11-07 13:46:15 +01:00
M WS BS S T I Agi Dex
Int WP Fel W
7 45 40 55
50 20 35 - 10 20 - 20
Traits : Armour 3 , Bestial , Bite + 9 , Bounce , Corrosive
Blood , Distracting , Infected , Maddening Aura ( see
page 17 ) , Night Vision , Size ( Enormous ) , Tail + 8 ,
Tongue Attack + 5 ( 12 ) , Venom , Weapon + 9.
` ;
2020-11-08 00:22:04 +01:00
let str = ` REINER AND DIETER LEDERMANN
SMUGGLERS ( BRASS 3 )
M WS BS S
T
I
Agi Dex Int WP Fel W
4
33 33 32 35 38 41 39 33 37 38 12
Traits : Weapon ( Dagger + 5 , Sword + 7 )
Skills : Bribery 43 , Charm 43 , Cool 42 ,
Consume Alcohol 45 , Gossip 43 , Haggle 43 ,
Lore ( Local 38 ) , Perception 43 ,
Secret Signs ( Smuggler ) 37
Talents : Briber , Criminal , Dealmaker ,
Etiquette ( Criminals , Doktor , Guilder )
Trappings : Dagger , Hand Weapon ( Sword )
`
2020-11-07 13:46:15 +01:00
2020-11-08 23:12:52 +01:00
/************************************************************************************/
2020-11-07 13:46:15 +01:00
import "./xregexp-all.js" ;
const us _carac = 'm\\s+ws\\s+bs\\s+s\\s+t\\s+i\\s+agi?\\s+dex\\s+int\\s+\\wp\\s+fel\\s+w' ;
const fr _carac = 'm\\s+ws\\s+bs\\s+s\\s+t\\s+i\\s+agi?\\s+dex\\s+int\\s+\\wp\\s+fel\\s+w' ;
2020-12-02 22:15:26 +01:00
const carac _val = '(?<m>[0-9-]+)\\s+(?<ws>[0-9-]+)\\s+(?<bs>[0-9-]+)\\s+(?<s>[0-9-]+)\\s+(?<t>[0-9-]+)\\s+(?<i>[0-9-]+)\\s+(?<ag>[0-9-]+)\\s+(?<dex>[0-9-]+)\\s+(?<int>[0-9-]+)\\s+(?<wp>[0-9-]+)\\s+(?<fel>[0-9-]+)\\s+(?<w>[0-9-\*]+)' ;
2020-11-10 15:01:06 +01:00
const name _val = '(?<name>[a-zA-Z\\s\\-,]*)[\\s\\r\\na-zA-Z]*(?<tiers>.*|[\\(\\)a-z0-9]+)' ;
2020-11-08 00:22:04 +01:00
let sectionData = [
{ name : "trait" , toFind : "Traits\\s*:" , secondParse : '(?<name>[a-z\\s]*)[\\s\\+]*(?<value>.*|[0-9]+)' , index : - 1 } ,
2020-11-08 23:39:47 +01:00
{ name : "skill" , toFind : "Skills\\s*:" , secondParse : '(?<name>[a-z\\s\\(\\)]*)[\\s\\+]*(?<value>.*|[0-9]+)' , index : - 1 } ,
2020-11-11 19:08:20 +01:00
{ name : "talent" , toFind : "Talents\\s*:" , secondParse : '(?<name>[a-z\\-\\s!/]*)[\\s\\+]*(?<value>.*|[0-9]+)' , index : - 1 } ,
{ name : "trapping" , toFind : "Trappings\\s*:" , secondParse : '(?<name>[a-z\\s]*)[\\s\\+]*(?<value>.*|[0-9]+)' , index : - 1 }
2020-11-08 00:22:04 +01:00
] ;
let regSep = XRegExp ( '\\s*,\\s*' , 'gi' ) ; // Term separator, with auto trim
2020-11-08 23:39:47 +01:00
let regLine1 = XRegExp ( '[\\r\\n\\.]' , 'gi' ) ; // Term separator, with auto trim
2020-11-08 23:12:52 +01:00
let regName = XRegExp ( name _val , 'gi' ) ;
2020-11-07 13:46:15 +01:00
2020-11-08 00:22:04 +01:00
/************************************************************************************/
2020-11-08 23:12:52 +01:00
async function _ _findItem ( itemName , itemType , location = null ) {
itemName = itemName . trim ( ) ;
let items = game . items . entities . filter ( i => i . type == itemType )
// Search imported items first
for ( let i of items ) {
if ( i . name == itemName && i . type == itemType )
return i ;
}
let itemList
// find pack -> search pack -> return entity
if ( location ) {
let pack = game . packs . find ( p => {
location . split ( "." ) [ 0 ] == p . metadata . package &&
location . split ( "." ) [ 1 ] == p . metadata . name
} )
if ( pack ) {
if ( pack . translations [ itemName ] ) {
let translItemName = pack . translations [ itemName ] . name ;
await pack . getIndex ( ) . then ( index => itemList = index ) ;
let searchResult = itemList . find ( t => t . name == translItemName )
if ( searchResult )
return await pack . getEntity ( searchResult . _id )
}
}
}
// If all else fails, search each pack
for ( let p of game . packs . filter ( p => p . metadata . tags && p . metadata . tags . includes ( itemType ) ) ) {
if ( p . translations [ itemName ] ) {
let translItemName = p . translations [ itemName ] . name ;
await p . getIndex ( ) . then ( index => itemList = index ) ;
let searchResult = itemList . find ( t => t . name == translItemName )
if ( searchResult )
return await p . getEntity ( searchResult . _id )
}
}
}
2020-11-07 13:46:15 +01:00
2020-11-08 23:12:52 +01:00
/************************************************************************************/
async function _ _findSkill ( skillName ) {
skillName = skillName . trim ( ) ;
// First try world items
let worldItem = game . items . entities . filter ( i => i . type == "skill" && i . name == skillName ) [ 0 ] ;
if ( worldItem ) return worldItem
let skillList = [ ] ;
let packs = game . packs . filter ( p => p . metadata . tags && p . metadata . tags . includes ( "skill" ) )
for ( let pack of packs ) {
2020-12-02 22:15:26 +01:00
//console.log("SEARCH : ", skillName, pack);
2020-11-08 23:12:52 +01:00
if ( pack . translations [ skillName ] ) {
let translSkillName = pack . translations [ skillName ] . name ;
skillList = await pack . getIndex ( )
// Search for specific skill (won't find unlisted specializations)
let searchResult = skillList . find ( s => s . name == translSkillName )
if ( ! searchResult )
searchResult = skillList . find ( s => s . name . split ( "(" ) [ 0 ] . trim ( ) == skillName . split ( "(" ) [ 0 ] . trim ( ) )
if ( searchResult ) {
let dbSkill ;
await pack . getEntity ( searchResult . _id ) . then ( packSkill => dbSkill = packSkill ) ;
dbSkill . data . name = translSkillName ; // This is important if a specialized skill wasn't found. Without it, <Skill ()> would be added instead of <Skill (Specialization)>
return dbSkill ;
}
}
}
throw "Could not find skill (or specialization of) " + skillName + " in compendum or world"
}
/************************************************************************************/
async function _ _findTalent ( talentName ) {
talentName = talentName . trim ( ) ;
// First try world items
let worldItem = game . items . entities . filter ( i => i . type == "talent" && i . name == talentName ) [ 0 ] ;
if ( worldItem ) return worldItem
let talentList = [ ] ;
let packs = game . packs . filter ( p => p . metadata . tags && p . metadata . tags . includes ( "talent" ) )
for ( let pack of packs ) {
if ( pack . translations [ talentName ] ) {
let translTalentName = pack . translations [ talentName ] . name ;
talentList = await pack . getIndex ( )
// Search for specific talent (won't find unlisted specializations)
let searchResult = talentList . find ( t => t . name == translTalentName )
if ( ! searchResult )
searchResult = talentList . find ( t => t . name . split ( "(" ) [ 0 ] . trim ( ) == talentName . split ( "(" ) [ 0 ] . trim ( ) )
if ( searchResult ) {
let dbTalent ;
await pack . getEntity ( searchResult . _id ) . then ( packTalent => dbTalent = packTalent ) ;
dbTalent . data . name = translTalentName ; // This is important if a specialized talent wasn't found. Without it, <Talent ()> would be added instead of <Talent (Specialization)>
return dbTalent ;
}
}
}
throw "Could not find talent (or specialization of) " + talentName + " in compendium or world"
}
/************************************************************************************/
export default async function statParserFR ( statString , type = "npc" ) {
let model = duplicate ( game . system . model . Actor [ type ] ) ;
2020-11-08 00:22:04 +01:00
2020-11-07 13:46:15 +01:00
let reg1 = XRegExp ( us _carac , 'gi' ) ;
2020-11-08 23:12:52 +01:00
let res = reg1 . test ( statString ) ;
2020-11-08 00:22:04 +01:00
if ( res ) { //stat block identified go on
2020-11-08 23:12:52 +01:00
// Extract the name
let res1 = XRegExp . exec ( statString , reg1 ) ;
2020-12-02 22:15:26 +01:00
console . log ( "REG" , res1 ) ;
2020-11-08 23:12:52 +01:00
let pnjStr = statString . substring ( 0 , res1 . index ) ;
let nameRes = XRegExp . exec ( pnjStr , regName ) ;
console . log ( nameRes ) ;
if ( nameRes . tiers && nameRes . tiers . length > 0 && hasProperty ( model , "details.status.value" ) ) {
let regTiers = XRegExp ( "(?<name>[A-Za-z]*)\\s+(?<level>[0-9]*)" ) ;
let resTiers = XRegExp . exec ( nameRes . tiers , regTiers ) ;
console . log ( resTiers ) ;
model . details . status . value = game . i18n . localize ( resTiers . name . trim ( ) ) + " " + resTiers . level ;
}
// Compute the PNJ name
let pnjName = nameRes . name . split ( "—" ) [ 0 ] . split ( " " ) . filter ( f => ! ! f ) ;
pnjName = pnjName . map ( word => {
if ( word == "VON" )
return word . toLowerCase ( ) ;
word = word . toLowerCase ( ) ;
word = word [ 0 ] . toUpperCase ( ) + word . substring ( 1 , word . length ) ;
return word ;
} )
pnjName = pnjName . join ( " " )
// Get the carac values
2020-11-08 00:22:04 +01:00
let reg2 = XRegExp ( carac _val , 'gi' ) ;
2020-11-08 23:12:52 +01:00
let resCarac = XRegExp . exec ( statString , reg2 ) ; // resr contains all carac found
// Setup carac
if ( resCarac [ "Agi" ] ) resCarac [ "Ag" ] = resCarac [ "Agi" ] ; // Auto patch
model . details . move . value = Number ( resCarac [ "m" ] ) ;
for ( let key in model . characteristics ) {
if ( resCarac [ key ] === '-' ) resCarac [ key ] = 0 ;
model . characteristics [ key ] . initial = Number ( resCarac [ key ] ) ;
}
//console.log("CARAC", model.characteristics);
2020-11-08 00:22:04 +01:00
// Search position of skills/talents/...
for ( let def of sectionData ) {
def . regDef = XRegExp ( def . toFind , 'gi' ) ;
2020-11-08 23:12:52 +01:00
let res = XRegExp . exec ( statString , def . regDef ) ;
2020-11-08 00:22:04 +01:00
if ( res ) def . index = res . index ; // Get the index in the string
//console.log(" Parsing", def.name, res);
}
2020-11-08 23:12:52 +01:00
// Sort to split position of various substring
2020-11-08 00:22:04 +01:00
sectionData . sort ( function ( a , b ) { return a . index - b . index ; } ) ;
2020-11-08 23:12:52 +01:00
let globalItemList = [ ] ;
// Then loop again and process each item type
2020-11-08 00:22:04 +01:00
for ( let i = 0 ; i < sectionData . length ; i ++ ) {
let def = sectionData [ i ] ;
if ( def . index > - 1 ) {
2020-11-08 23:12:52 +01:00
let maxIndex = statString . length ;
2020-11-08 00:22:04 +01:00
if ( sectionData [ i + 1 ] && sectionData [ i + 1 ] . index > - 1 )
maxIndex = sectionData [ i + 1 ] . index ;
2020-11-08 23:12:52 +01:00
def . substring = statString . substring ( def . index , maxIndex ) ;
2020-11-08 00:22:04 +01:00
def . substring = XRegExp . replace ( def . substring , def . regDef , "" ) ;
def . substring = XRegExp . replace ( def . substring , regLine1 , " " ) ;
2020-11-08 23:12:52 +01:00
// At this point, def.substring contains the items list as a string
// Then create a table of it in termList, with specific sub-parsing rules
2020-11-08 00:22:04 +01:00
let termList = XRegExp . split ( def . substring , regSep ) ;
for ( let name of termList ) {
2020-11-08 23:12:52 +01:00
let itemFound , subres ;
2020-11-08 00:22:04 +01:00
if ( def . secondParse ) {
2020-11-08 23:12:52 +01:00
subres = XRegExp . exec ( name , XRegExp ( def . secondParse , 'gi' ) ) ;
2020-11-08 00:22:04 +01:00
name = subres . name . trim ( ) ;
2020-11-08 23:12:52 +01:00
}
if ( def . name == 'trait' ) {
try {
itemFound = await _ _findItem ( name , "trait" ) ;
}
catch { }
if ( itemFound && subres && subres . value . length > 0 ) {
subres . value = XRegExp . replace ( subres . value , "(" , "" ) ;
subres . value = XRegExp . replace ( subres . value , ")" , "" ) ;
itemFound . data . data . specification . value = game . i18n . localize ( subres . value ) ;
}
if ( ! itemFound )
ui . notifications . error ( "Trait non trouvé, à ajouter manuellemen : " + name , { permanent : true } )
} else if ( def . name == 'skill' ) {
try {
itemFound = await _ _findSkill ( name ) ;
}
catch { }
if ( itemFound && subres && subres . value ) {
itemFound . data . data . advances . value = Number ( subres . value ) - Number ( resCarac [ itemFound . data . data . characteristic . value ] ) ;
2020-11-08 13:53:15 +01:00
}
2020-11-08 23:12:52 +01:00
if ( ! itemFound )
ui . notifications . error ( "Compétence non trouvée, à ajouter manuellement : " + name , { permanent : true } )
} else if ( def . name == 'talent' ) {
try {
itemFound = await _ _findTalent ( name ) ;
}
catch { }
if ( itemFound && subres && subres . value )
itemFound . data . data . advances . value = Number ( subres . value ) ;
if ( ! itemFound )
ui . notifications . error ( "Talent non trouvé, à ajouter manuellement : " + name , { permanent : true } )
} else if ( def . name == 'trapping' ) {
try {
itemFound = await _ _findItem ( name , "trapping" ) ;
}
catch { }
if ( ! itemFound ) {
itemFound = new game . wfrp4e . entities . ItemWfrp4e ( { img : "systems/wfrp4e/icons/blank.png" , name : name , type : "trapping" , data : game . system . model . Item . trapping } )
itemFound . data . data . trappingType . value = "misc"
}
2020-11-08 00:22:04 +01:00
}
2020-11-08 23:12:52 +01:00
if ( itemFound )
globalItemList . push ( itemFound ) ;
2020-11-08 00:22:04 +01:00
}
}
}
2020-11-08 23:12:52 +01:00
let moneyItems = await game . wfrp4e . utility . allMoneyItems ( ) || [ ] ;
moneyItems = moneyItems . sort ( ( a , b ) => ( a . data . coinValue . value > b . data . coinValue . value ) ? - 1 : 1 ) ;
moneyItems . forEach ( m => m . data . quantity . value = 0 )
globalItemList = globalItemList . concat ( moneyItems ) ;
//console.log("My liste :", globalItemList);
let name = pnjName ;
return { name , type , data : model , items : globalItemList }
2020-11-07 13:46:15 +01:00
}
2020-11-08 23:12:52 +01:00
// If the carac string has not been found
ui . notifications . error ( "Impossible de convertir ces statitiques, les caractéristiques n'ont pas été trouvées" , { permanent : true } )
}
/************************************************************************************/
Hooks . once ( 'ready' , ( ) => {
//var fullskills = game.packs.get('wfrp4e-core.skills');
//console.log("Skills", game.wfrp4e.apps.StatBlockParser.prototype);
2020-11-08 00:22:04 +01:00
} )
2020-11-07 13:46:15 +01:00