|
{"version":3,"file":"main.js","mappings":";;;;;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,aAAa,oBAAoB;AACjC,aAAa,oBAAoB;AACjC;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,aAAa,oBAAoB;AACjC,aAAa,oBAAoB;AACjC;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,aAAa,oBAAoB;AACjC,aAAa,oBAAoB;AACjC;AACA;AACA;AACA;AACA,gBAAgB,oBAAoB;AACpC,eAAe,oBAAoB;AACnC,eAAe,oBAAoB;AACnC,cAAc,oBAAoB;AAClC,cAAc,oBAAoB;AAClC,KAAK;AACL;AACA;;AAEA;;AAEA,4BAA4B,sBAAsB;;AAElD,gDAAe,SAAS,EAAC;;;AC5DzB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO;AACP,IAAI,iDAAiD;AACrD,IAAI,4CAA4C;AAChD,IAAI,oEAAoE;AACxE,IAAI,8DAA8D;AAClE,IAAI,mDAAmD;AACvD,IAAI,6DAA6D;AACjE,IAAI,qEAAqE;AACzE,IAAI,uEAAuE;AAC3E,IAAI,kFAAkF;AACtF,IAAI,oFAAoF;AACxF,IAAI,sFAAsF;AAC1F,IAAI,gEAAgE;AACpE,IAAI,oFAAoF;AACxF,IAAI,mEAAmE;AACvE,IAAI,2DAA2D;AAC/D,IAAI,kEAAkE;AACtE,IAAI,kEAAkE;AACtE,IAAI,oFAAoF;AACxF,IAAI,+EAA+E;AACnF,IAAI,6EAA6E;AACjF,IAAI,mFAAmF;AACvF,IAAI,iFAAiF;AACrF,IAAI,0DAA0D;AAC9D,IAAI,6DAA6D;AACjE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,wBAAwB,UAAU,GAAG,SAAS,uBAAuB;AACzF;AACA;AACA;AACA;;;AAGO;AACP;AACA;AACA;;;AAGA;AACO;AACP;AACA;;AAEO;AACP;AACA;;;AC9DuC;;AAEvC;;AAEA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA,6BAA6B,qBAAqB;AAClD,GAAG;;AAEH;AACA,6BAA6B,qBAAqB;AAClD,GAAG;;AAEH;AACA,8BAA8B,mBAAmB;AACjD,oBAAoB,mBAAmB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,qCAAqC,mBAAmB,CAAC;AACzD;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;;AAGH;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,MAAM,EAAE,YAAY,EAAE,WAAW;AACpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,QAAQ;AACR;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,6CAA6C,qBAAqB,CAAC,UAAU,KAAK;AAClF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,GAAG;;AAEH;;;AAGA,gDAAe,KAAK,EAAC;;;ACvGrB;;AAEwC;AACR;;AAEhC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,MAAM,cAAK;AACX;AACA;AACA;AACA;;AAEA;AACA,IAAI,qDAAqD;AACzD,IAAI,uDAAuD;AAC3D,IAAI,iEAAiE;AACrE,IAAI,kEAAkE;AACtE,IAAI,mDAAmD;AACvD,IAAI,kEAAkE;AACtE,IAAI,oDAAoD;AACxD,IAAI,yDAAyD;AAC7D,IAAI,6CAA6C;AACjD,IAAI,uEAAuE;AAC3E,IAAI,oEAAoE;AACxE,IAAI,kEAAkE;AACtE,IAAI,yDAAyD;AAC7D,IAAI,mFAAmF;AACvF,IAAI,iFAAiF;AACrF,IAAI,+EAA+E;AACnF,IAAI,qFAAqF;AACzF,IAAI,+EAA+E;AACnF,IAAI,2FAA2F;AAC/F,IAAI,2DAA2D;AAC/D,IAAI,6DAA6D;AACjE,IAAI,iEAAiE;AACrE,IAAI,kDAAkD;AACtD,IAAI,wDAAwD;AAC5D,IAAI,gEAAgE;AACpE,IAAI,+EAA+E;AACnF,IAAI,6EAA6E;AACjF,IAAI,mEAAmE;AACvE,IAAI,kEAAkE;AACtE,IAAI,oEAAoE;AACxE,IAAI,8CAA8C;AAClD,IAAI,gDAAgD;AACpD,IAAI,uEAAuE;AAC3E,IAAI,gDAAgD;AACpD,IAAI,sDAAsD;AAC1D,IAAI,oEAAoE;AACxE,IAAI,8EAA8E;AAClF,IAAI,oDAAoD;AACxD,IAAI,oDAAoD;AACxD,IAAI,8CAA8C;AAClD,IAAI,mFAAmF;AACvF,IAAI,oEAAoE;AACxE,IAAI,gEAAgE;AACpE,IAAI,wDAAwD;AAC5D,IAAI,kEAAkE;AACtE,IAAI,+FAA+F;AACnG,IAAI,gEAAgE;AACpE,IAAI,4DAA4D;AAChE,IAAI,8DAA8D;AAClE,IAAI,mFAAmF;AACvF,IAAI,gDAAgD;AACpD,IAAI,uDAAuD;AAC3D,IAAI,wDAAwD;AAC5D,IAAI,yDAAyD;AAC7D,IAAI,6DAA6D;AACjE,IAAI,2DAA2D;AAC/D,IAAI,8DAA8D;AAClE,IAAI,0DAA0D;AAC9D,IAAI,yDAAyD;AAC7D,IAAI,8CAA8C;AAClD,IAAI,kDAAkD;AACtD,IAAI,sEAAsE;AAC1E,IAAI,qDAAqD;AACzD,IAAI,6DAA6D;AACjE,IAAI,4DAA4D;AAChE,IAAI,4EAA4E;AAChF,IAAI,kDAAkD;AACtD,IAAI,kDAAkD;AACtD,IAAI,kDAAkD;AACtD,IAAI,wEAAwE;AAC5E,IAAI,wEAAwE;AAC5E,IAAI,4DAA4D;AAChE,IAAI,wEAAwE;AAC5E,IAAI,gEAAgE;AACpE,IAAI,6DAA6D;AACjE,IAAI,6DAA6D;AACjE,IAAI,6EAA6E;AACjF,IAAI,iDAAiD;AACrD,IAAI,uDAAuD;AAC3D,IAAI,0DAA0D;AAC9D,IAAI,wEAAwE;AAC5E,IAAI,kEAAkE;AACtE,IAAI,kDAAkD;AACtD,IAAI,gDAAgD;AACpD,IAAI,gDAAgD;AACpD,IAAI,yFAAyF;AAC7F,IAAI,yDAAyD;AAC7D,IAAI,yDAAyD;AAC7D,IAAI,8CAA8C;AAClD,IAAI,8CAA8C;AAClD,IAAI,gDAAgD;AACpD,IAAI,4CAA4C;AAChD,IAAI,gDAAgD;AACpD,IAAI,8CAA8C;AAClD,IAAI,0CAA0C;AAC9C,IAAI,8CAA8C;AAClD,IAAI,wDAAwD;AAC5D,IAAI,kDAAkD;AACtD,IAAI,gDAAgD;AACpD,IAAI,8CAA8C;AAClD,IAAI,0CAA0C;AAC9C,IAAI,gDAAgD;AACpD,IAAI,8CAA8C;AAClD,IAAI,sDAAsD;AAC1D,IAAI,gDAAgD;AACpD,IAAI,0CAA0C;AAC9C,IAAI,4CAA4C;AAChD,IAAI,8CAA8C;AAClD;;AAEA,SAAS,6BAAoB;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,kDAAkD;AACtE;AACA;AACA;AACA;AACA;AACA,oBAAoB,kDAAkD;AACtE;AACA;AACA;AACA;AACA;AACA,oBAAoB,kDAAkD;AACtE;AACA;AACA;AACA;AACA;AACA,oBAAoB,kDAAkD;AACtE;AACA;AACA,oBAAoB,cAAK;AACzB;AACA;AACA,oBAAoB,wBAAwB,UAAU,GAAG,SAAS,uBAAuB;AACzF;AACA;AACA;AACA;;AAEO;AACP,gCAAgC,6BAAoB;AACpD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO;AACP,sBAAsB,iBAAa,CAAC,mCAAmC;AACvE;AACA;;;AClMuC;AACR;;AAE/B;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,iBAAa,CAAC,4BAA4B;AAC9D;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA,aAAa,qBAAqB,EAAE,IAAI,UAAU,IAAI,IAAI;AAC1D;AACA;AACA;AACA,0CAA0C;AAC1C,UAAU;AACV,8BAA8B;AAC9B;AACA;AACA;AACA;AACA,yCAAyC;AACzC,UAAU;AACV,6BAA6B;AAC7B;AACA;AACA;AACA;AACA,yCAAyC;AACzC,UAAU;AACV,6BAA6B;AAC7B;AACA;AACA;AACA;AACA,0CAA0C;AAC1C,UAAU;AACV,8BAA8B;AAC9B;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;AACH;AACA,iDAAe,MAAM,EAAC;;;ACrFtB;AACA;AACwC;AAC6D;AAChC;AACnC;AACF;;AAEzB;;AAEP;AACA;AACA,WAAW,oBAAoB;AAC/B;;AAEA;AACA;AACA;;AAEA;AACA;AACA,QAAQ,sDAAsD,uBAAuB,IAAI;AACzF,QAAQ,sDAAsD,oBAAgB,wCAAwC,IAAI;AAC1H,QAAQ,sDAAsD,oBAAgB,4CAA4C,IAAI;AAC9H,QAAQ,gEAAgE,kBAAkB,IAAI;AAC9F,QAAQ,gEAAgE,sBAAsB,IAAI;AAClG,QAAQ,gEAAgE,oBAAgB,yCAAyC,UAAU;AAC3I,QAAQ,gEAAgE,oBAAgB,6CAA6C,UAAU;AAC/I;AACA,WAAW,eAAe;AAC1B;;AAEA;AACA;AACA,sBAAsB;AACtB;;AAEA;AACA;AACA,WAAW,oBAAoB;AAC/B;;AAEA;AACA;AACA;AACA,WAAW,aAAa;AACxB;;AAEA;AACA;AACA,WAAW,iBAAiB;AAC5B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uBAAuB;AACvB;AACA,0FAA0F;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,yBAAyB;AACrC,YAAY,wBAAwB;AACpC,YAAY,iCAAiC;AAC7C,YAAY,sBAAsB;AAClC,YAAY,0BAA0B;AACtC,YAAY,uBAAuB;AACnC,YAAY,2BAA2B;AACvC;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oBAAoB,kBAAc;AAClC;AACA;AACA;AACA,6GAA6G,cAAc;AAC3H;AACA;AACA,QAAQ;AACR,kDAAkD,mBAAmB,CAAC,qCAAqC,eAAe;AAC1H;AACA,MAAM;AACN,mDAAmD,mBAAmB,CAAC;AACvE;AACA;;AAEA;AACA,cAAc,MAAM,GAAG,kBAAkB;AACzC;;AAEA;AACA,cAAc,MAAM,GAAG,sBAAsB;AAC7C;;AAEA;AACA,cAAc,MAAM,GAAG,qBAAqB;AAC5C;;AAEA;AACA,cAAc,MAAM,GAAG,qBAAqB;AAC5C;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA,yBAAyB,qBAAqB;AAC9C,MAAM;AACN,sBAAsB,qBAAqB;AAC3C,MAAM;AACN,sBAAsB,qBAAqB;AAC3C,MAAM;AACN,wBAAwB,qBAAqB;AAC7C,MAAM;AACN,sBAAsB,qBAAqB;AAC3C,MAAM;AACN,0BAA0B,qBAAqB;AAC/C,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,gBAAY,4BAA4B,2CAA2C;AAC3F;AACA;AACA;AACA;AACA,UAAU;AACV,kDAAkD,cAAc;AAChE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,+BAA+B,2CAA2C;AAC1E;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA,IAAI,gBAAY;AAChB;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,mCAAmC,kDAAkD;AACrF;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,mCAAmC,kDAAkD;AACrF;AACA,OAAO;AACP,IAAI,gBAAY;;AAEhB,IAAI,gBAAY;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC,2CAA2C;AACjF;AACA,OAAO;AACP,IAAI,gBAAY;;AAEhB,IAAI,gBAAY;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,IAAI,gBAAY;AAChB;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,sBAAsB,wBAAwB;AAC9C,QAAQ;AACR,sBAAsB,oBAAoB;AAC1C,QAAQ;AACR,sBAAsB,eAAe;AACrC;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,QAAQ,eAAW;AACnB;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,MAAM,eAAW;AACjB;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;AACvF;AACA;AACA;;AAEA;AACA;AACA;;AAEA,IAAI,gBAAY,eAAe,gBAAgB;;AAE/C,oBAAoB,YAAY,IAAI,eAAe;AACnD;AACA;AACA;AACA,yBAAyB,sBAAsB;AAC/C;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,wBAAwB,gCAAgC,IAAI,oCAAoC;AAChG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA,wCAAwC,gCAAgC,EAAE,mCAAmC;;AAE7G;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA,IAAI,gBAAY,0CAA0C,MAAM,GAAG,OAAO,OAAO,gBAAgB;AACjG;AACA,8CAA8C,yCAAyC;AACvF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,sBAAsB,uCAAuC,QAAQ;AACrE;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,sCAAsC,MAAM,KAAK,KAAK,iBAAiB,YAAY;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,MAAM,KAAK,KAAK,iBAAiB,YAAY;AACpF;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI,gBAAY,iCAAiC,eAAe,UAAU,YAAY;AACtF,wEAAwE,oBAAoB;AAC5F,iDAAiD,UAAU,KAAK,sCAAsC;AACtG,oDAAoD,qCAAqC;AACzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,4CAA4C,cAAc;AAC1D;AACA,QAAQ;;AAER;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oCAAoC,eAAW,4DAA4D,cAAc,0EAA0E,kBAAkB;AACrN;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,gBAAY,wBAAwB,sCAAsC;AAClF;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI,gBAAY,2BAA2B,cAAc,KAAK,qBAAqB;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAM,gBAAY;AAClB;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP,MAAM,gBAAY;AAClB;AACA,MAAM,gBAAY;AAClB;;AAEA;AACA;AACA;AACA;AACA,YAAY,gBAAY,wBAAwB,yDAAyD;AACzG;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAM;AACN,MAAM,gBAAY;AAClB;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,MAAM;AACN;AACA;;AAEA,IAAI,gBAAY,8BAA8B,mDAAmD;AACjG;;AAEA;;AAEA;AACA,2GAA2G;AAC3G;AACA;;AAEA;AACA;AACA,sBAAsB,mBAAmB;AACzC;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,mCAAmC,yBAAyB;AAC5D;AACA;AACA,QAAQ;AACR;AACA;AACA,UAAU,gBAAY;AACtB;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,QAAQ;AACR,QAAQ,gBAAY;AACpB;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;;AAEA;AACA,IAAI,gBAAY,0CAA0C,cAAc,QAAQ,+BAA+B;AAC/G,sGAAsG;AACtG,MAAM,gBAAY,6BAA6B,qCAAqC;AACpF,sCAAsC,mBAAmB;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,eAAW;AACrB;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,UAAU;AACV,UAAU,gBAAY,qBAAqB,OAAO,UAAU,cAAc;AAC1E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,aAAa,GAAG,SAAS;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,aAAa;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,aAAa,GAAG,SAAS;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,gBAAY;AACpB;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,MAAM;AACN,MAAM,gBAAY;AAClB;AACA;AACA;AACA,OAAO;AACP;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI,gBAAY,wBAAwB,cAAc;;AAEtD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,QAAQ,gBAAY,aAAa,eAAe,YAAY,cAAc;;AAE1E,+CAA+C,aAAa,GAAG,eAAe;;AAE9E,QAAQ,gBAAY;AACpB,iBAAiB,aAAa,GAAG,eAAe;AAChD;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,QAAQ,gBAAY,aAAa,cAAc,KAAK,KAAK;AACzD;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C,eAAe,EAAE,iBAAiB;AAChF,YAAY,gBAAY,YAAY,iBAAiB,YAAY,cAAc,gCAAgC,eAAe;AAC9H;AACA;AACA,UAAU,gBAAY,uBAAuB,iBAAiB,MAAM,eAAe;;AAEnF;AACA;AACA;AACA;AACA,6BAA6B;AAC7B,cAAc,gBAAY,wBAAwB,eAAe,YAAY,iBAAiB;AAC9F;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,eAAe,EAAE,iBAAiB;AAC5E;AACA;AACA;AACA,UAAU;AACV,UAAU,gBAAY,wBAAwB,yBAAyB;AACvE,2FAA2F,oBAAoB;AAC/G;AACA,+CAA+C,eAAe,GAAG,aAAa;AAC9E,UAAU;AACV,UAAU,gBAAY,6BAA6B,yBAAyB;AAC5E,2FAA2F,oBAAoB;AAC/G;AACA;AACA;AACA,4BAA4B,eAAe,GAAG,MAAM;AACpD;AACA;AACA,sCAAsC,QAAQ,SAAS,QAAQ;AAC/D,aAAa;AACb,sDAAsD,MAAM;AAC5D;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ,YAAY,gBAAY;AACxB;AACA;AACA,UAAU,eAAW;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM,gBAAY,wBAAwB,cAAc;AACxD;AACA;AACA;AACA;AACA;AACA,QAAQ,gBAAY,0BAA0B,cAAc,cAAc,IAAI;AAC9E;AACA;AACA;AACA,yBAAyB;AACzB,UAAU,eAAW;AACrB;AACA;AACA;AACA,wCAAwC,WAAW,EAAE,aAAa;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;;AAEvF;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA,UAAU;AACV;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,QAAQ,gBAAY;;AAEpB;AACA,8CAA8C,aAAa,GAAG,aAAa;AAC3E;AACA,UAAU,gBAAY,yBAAyB,YAAY,KAAK,8EAA8E;AAC9I,8CAA8C,4CAA4C;AAC1F;AACA;AACA;AACA;AACA,4CAA4C,eAAe,EAAE,gBAAgB;AAC7E,UAAU,gBAAY,+CAA+C,sCAAsC;AAC3G;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;;AAEvF;AACA;AACA,MAAM,gBAAY;AAClB;AACA;AACA,QAAQ,gBAAY,4BAA4B,aAAa,KAAK,wCAAwC;AAC1G,6CAA6C,gDAAgD;AAC7F;AACA;AACA;AACA;AACA,0CAA0C,eAAe,EAAE,gBAAgB;AAC3E,QAAQ,gBAAY,kDAAkD,wCAAwC;AAC9G;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;AACvF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,gBAAY,yCAAyC,aAAa;AAC5E;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,gBAAY;AAClB;AACA;AACA,QAAQ,gBAAY,oBAAoB,SAAS;AACjD,wBAAwB,gDAAgD,KAAK;AAC7E;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;;AAEvF;AACA;AACA;AACA;AACA;AACA,MAAM,gBAAY;AAClB;AACA;AACA,QAAQ,gBAAY,gCAAgC,OAAO;AAC3D,wBAAwB,6CAA6C,KAAK;AAC1E;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oGAAoG,oBAAoB;AACxH,oGAAoG,oBAAoB;AACxH,oGAAoG,oBAAoB;AACxH,oGAAoG,oBAAoB;AACxH;AACA;AACA,uFAAuF,oBAAoB;AAC3G;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;;AAEvF;AACA;AACA;AACA;AACA;AACA,MAAM,gBAAY;AAClB;AACA;AACA,0DAA0D,UAAU;AACpE;AACA;AACA,QAAQ,gBAAY,mCAAmC,OAAO;AAC9D,wBAAwB,4CAA4C,KAAK;AACzE;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,sGAAsG,oBAAoB;AAC1H,sGAAsG,oBAAoB;AAC1H,sGAAsG,oBAAoB;AAC1H,sGAAsG,oBAAoB;AAC1H;AACA;AACA,yFAAyF,oBAAoB;AAC7G;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,4BAA4B;;AAE5B,8BAA8B,oBAAgB,kBAAkB,EAAE,YAAY;;AAE9E;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT;AACA;AACA,sBAAsB;AACtB;AACA,SAAS;AACT,OAAO;AACP,8BAA8B,aAAa;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;;AAEvF;AACA,oEAAoE,yCAAyC;;AAE7G;AACA,MAAM,gBAAY;AAClB;AACA;AACA,MAAM,gBAAY;;AAElB;AACA;;AAEA;AACA;AACA,UAAU,gBAAY,oBAAoB,6DAA6D;;AAEvG;AACA;AACA;AACA,YAAY,gBAAY,0BAA0B,MAAM,KAAK,oDAAoD;AACjH,4BAA4B,yCAAyC,gEAAgE;AACrI;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uCAAuC,MAAM,mBAAmB;AAChE;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;AACvF;AACA,QAAQ,qCAAqC;AAC7C,QAAQ,iCAAiC;AACzC,QAAQ,mCAAmC;AAC3C,QAAQ,mCAAmC;AAC3C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;AACvF;;AAEA;AACA;AACA;AACA;AACA,UAAU,gBAAY,4BAA4B,YAAY,KAAK,kCAAkC;AACrG,0BAA0B,iDAAiD,oCAAoC;AAC/G;AACA;AACA;AACA,qBAAqB,gBAAgB;AACrC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oCAAoC,mBAAmB;AACvD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP,2DAA2D,cAAc;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,kBAAkB,IAAI;AACtB;AACA;AACA,WAAW;AACX,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;AACX;AACA;;AAEA;;AAEA,MAAM,gBAAY;AAClB,MAAM;AACN,MAAM,gBAAY;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,IAAI,gBAAY;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI,gBAAY;AAChB;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA,qGAAqG,cAAc;AACnH,2GAA2G,cAAc;AACzH,2GAA2G,cAAc;AACzH,+GAA+G,cAAc;AAC7H,qGAAqG,cAAc;AACnH,qGAAqG,cAAc;AACnH;AACA,kCAAkC,UAAU;AAC5C,oEAAoE,cAAc;AAClF;AACA,qGAAqG,cAAc;AACnH;AACA,8EAA8E,cAAc;AAC5F,6EAA6E,cAAc;AAC3F;AACA,6GAA6G,cAAc;AAC3H,yGAAyG,cAAc;AACvH;AACA,4EAA4E,cAAc;AAC1F,4EAA4E,cAAc;AAC1F;AACA,2GAA2G,cAAc;AACzH,qGAAqG,cAAc;AACnH;;AAEA;AACA;AACA;AACA;AACA,MAAM,gBAAY,sBAAsB,qCAAqC;AAC7E;AACA;AACA;AACA;AACA,oBAAoB,IAAI;AACxB;AACA;AACA,aAAa;AACb,WAAW;AACX;AACA;AACA,MAAM,gBAAY;AAClB;;AAEA;AACA;AACA;AACA;AACA,oBAAoB,IAAI;AACxB;AACA;AACA,aAAa;AACb,WAAW;AACX;AACA;AACA,MAAM,gBAAY;AAClB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,IAAI,gBAAY;AAChB;AACA;AACA;AACA;;AAEA;AACA;AACA,qEAAqE,+CAA+C,IAAI,SAAS;AACjI;AACA;AACA,wEAAwE,kDAAkD,IAAI,SAAS;AACvI;AACA;AACA,wEAAwE,kDAAkD,IAAI,SAAS;AACvI;AACA;AACA,0EAA0E,oDAAoD,IAAI,SAAS;AAC3I;AACA;AACA,+FAA+F,+CAA+C,IAAI,SAAS;AAC3J;AACA;AACA,oEAAoE,+CAA+C,IAAI,SAAS;AAChI;AACA;AACA;AACA;AACA;AACA,0BAA0B,+CAA+C,IAAI,eAAe;AAC5F;AACA;AACA,yEAAyE,mDAAmD,IAAI,SAAS;AACzI;AACA;AACA,uEAAuE,iDAAiD,IAAI,SAAS;AACrI;AACA;AACA,qEAAqE,+CAA+C,IAAI,SAAS;AACjI;AACA;AACA,4EAA4E,sDAAsD,IAAI,SAAS;AAC/I;AACA;AACA,sEAAsE,gDAAgD,IAAI,SAAS;AACnI;AACA;AACA,yEAAyE,mDAAmD,IAAI,SAAS;AACzI;AACA;AACA,wEAAwE,kDAAkD,IAAI,SAAS;AACvI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,uBAAuB,uEAAuE,UAAU,oBAAoB;AAC5H;AACA;AACA,4BAA4B,kEAAkE;AAC9F;;AAEA,IAAI,gBAAY;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA;;;ACv2DA;AACA;;AAEwC;AACN;AACF;;AAEhC;AACA;AACA;AACO;;;AAGP,iBAAiB,0BAA0B,IAAI;AAC/C;AACA;;AAEA;AACA;AACA,kBAAkB;AAClB;;AAEA;AACA;AACA;;;AAGA;AACA,6CAA6C,qBAAqB,CAAC,UAAU,KAAK;AAClF,+BAA+B,2BAAuB;AACtD;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,yCAAyC;AACvF;AACA;;AAEA;AACA;AACA;AACA,QAAQ,eAAW,gCAAgC,YAAY,KAAK,8BAA8B;AAClG,iCAAiC,iDAAiD,gCAAgC;AAClH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,iBAAiB,KAAK,UAAU;AAC3C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,wDAAwD,iBAAiB;AACzE;AACA,uFAAuF,cAAc;AACrG;AACA;;AAEA;;AAEA;AACA;AACA;AACA,QAAQ,eAAW,mBAAmB,cAAc;AACpD;AACA;AACA;AACA;AACA;;AAEA;;AAEA,IAAI,gBAAY;AAChB;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;ACvIwC;AACN;AACF;AACe;AACR;;AAEhC;;AAEP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,0CAA0C,mBAAmB,CAAC;AAC9D,0BAA0B,cAAc,CAAC;AACzC;AACA;AACA;AACA;AACA,sBAAsB,kEAAkE;AACxF;AACA;;AAEA;AACA;AACA,kBAAkB,kBAAc;;AAEhC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,+CAA+C,KAAK;AACpD;AACA,gBAAgB,kCAAkC;AAClD;AACA,iBAAiB,iDAAiD,GAAG,kCAAkC;AACvG;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAY;;AAEhB,UAAU,kBAAc;;AAExB,4BAA4B,WAAW;AACvC;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA,IAAI,gBAAY;AAChB;AACA,IAAI,gBAAY;AAChB;AACA,IAAI,gBAAY;AAChB;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA,0BAA0B,OAAO,GAAG,yDAAyD;AAC7F;AACA;AACA;AACA;AACA;AACA;;AAEA;;;ACxHoD;AACgB;AAC5B;AAC0C;AAC5B;AACtB;;AAEzB;AACP,mBAAmB,qBAAqB;AACxC,eAAe;AACf,uBAAuB;AACvB;AACA,uBAAuB,eAAe;AACtC,iBAAiB,oBAAoB;AACrC,2BAA2B,oBAAoB;AAC/C,aAAa,eAAe;AAC5B,KAAK;AACL,WAAW,SAAK;AAChB,aAAa;AACb;AACA;;;ACpBwC;;AAExC;AACA,4CAA4C,8BAA8B;AAC1E;AACA,4BAA4B,qBAAqB;AACjD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,mCAAmC,mBAAmB,CAAC;AACvD,4BAA4B,mBAAmB,CAAC,qBAAqB;AACrE,WAAW,mBAAmB,CAAC;AAC/B,QAAQ;AACR;AACA;AACA;AACA,uCAAuC,mBAAmB,CAAC;AAC3D;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA,uCAAuC,mBAAmB,CAAC;AAC3D,SAAS;AACT,OAAO;AACP;AACA,KAAK;AACL;AACA;;AAEO;AACP,6BAA6B,qBAAqB;AAClD,aAAa,mBAAmB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,aAAa,mBAAmB,CAAC;AACjC;AACA;AACA;AACA,GAAG;;AAEH,4CAA4C,8BAA8B;AAC1E,2BAA2B,qBAAqB;AAChD;;AAEA;;;ACnDoE;AAC5B;AACR;;AAEzB;;AAEP,2BAA2B,iBAAa,CAAC,sCAAsC;AAC/E;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,6DAA6D,0BAA0B,CAAC;;AAExF;AACA,4BAA4B,mBAAmB,CAAC,kCAAkC;AAClF;AACA,OAAO;;AAEP;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;;;AClC6C;AACU;AACC;;AAExD;AACA,EAAE,gBAAgB;AAClB,CAAC;;AAED;AACA,EAAE,mBAAmB;AACrB,EAAE,WAAW;AACb,CAAC","sources":["webpack://pathmuncher/./src/constants.js","webpack://pathmuncher/./src/data/equipment.js","webpack://pathmuncher/./src/utils.js","webpack://pathmuncher/./src/data/features.js","webpack://pathmuncher/./src/logger.js","webpack://pathmuncher/./src/app/Pathmuncher.js","webpack://pathmuncher/./src/app/PetShop.js","webpack://pathmuncher/./src/app/PathmuncherImporter.js","webpack://pathmuncher/./src/hooks/api.js","webpack://pathmuncher/./src/hooks/settings.js","webpack://pathmuncher/./src/hooks/sheets.js","webpack://pathmuncher/./src/module.js"],"sourcesContent":["const debouncedReload = foundry.utils.debounce(() => window.location.reload(), 100);\n\nconst CONSTANTS = {\n MODULE_NAME: \"pathmuncher\",\n MODULE_FULL_NAME: \"Pathmuncher\",\n FLAG_NAME: \"pathmuncher\",\n SETTINGS: {\n // Enable options\n LOG_LEVEL: \"log-level\",\n RESTRICT_TO_TRUSTED: \"restrict-to-trusted\",\n ADD_VISION_FEATS: \"add-vision-feats\",\n },\n\n GET_DEFAULT_SETTINGS() {\n return foundry.utils.deepClone(CONSTANTS.DEFAULT_SETTINGS);\n },\n};\n\nCONSTANTS.DEFAULT_SETTINGS = {\n // Enable options\n [CONSTANTS.SETTINGS.RESTRICT_TO_TRUSTED]: {\n name: `${CONSTANTS.FLAG_NAME}.Settings.RestrictToTrusted.Name`,\n hint: `${CONSTANTS.FLAG_NAME}.Settings.RestrictToTrusted.Hint`,\n scope: \"world\",\n config: true,\n type: Boolean,\n default: false,\n onChange: debouncedReload,\n },\n\n [CONSTANTS.SETTINGS.ADD_VISION_FEATS]: {\n name: `${CONSTANTS.FLAG_NAME}.Settings.AddVisionFeats.Name`,\n hint: `${CONSTANTS.FLAG_NAME}.Settings.AddVisionFeats.Hint`,\n scope: \"player\",\n config: true,\n type: Boolean,\n default: true,\n },\n\n // debug\n [CONSTANTS.SETTINGS.LOG_LEVEL]: {\n name: `${CONSTANTS.FLAG_NAME}.Settings.LogLevel.Name`,\n hint: `${CONSTANTS.FLAG_NAME}.Settings.LogLevel.Hint`,\n scope: \"world\",\n config: true,\n type: String,\n choices: {\n DEBUG: `${CONSTANTS.FLAG_NAME}.Settings.LogLevel.debug`,\n INFO: `${CONSTANTS.FLAG_NAME}.Settings.LogLevel.info`,\n WARN: `${CONSTANTS.FLAG_NAME}.Settings.LogLevel.warn`,\n ERR: `${CONSTANTS.FLAG_NAME}.Settings.LogLevel.error`,\n OFF: `${CONSTANTS.FLAG_NAME}.Settings.LogLevel.off`,\n },\n default: \"WARN\",\n }\n\n};\n\nCONSTANTS.PATH = `modules/${CONSTANTS.MODULE_NAME}`;\n\nexport default CONSTANTS;\n","const SWAPS = [\n /^(Greater) (.*)/,\n /^(Lesser) (.*)/,\n /^(Major) (.*)/,\n /^(Moderate) (.*)/,\n /^(Standard) (.*)/,\n];\n\n// this equipment is named differently in foundry vs pathbuilder\nexport const EQUIPMENT_RENAME_STATIC_MAP = [\n { pbName: \"Chain\", foundryName: \"Chain (10 feet)\" },\n { pbName: \"Oil\", foundryName: \"Oil (1 pint)\" },\n { pbName: \"Bracelets of Dashing\", foundryName: \"Bracelet of Dashing\" },\n { pbName: \"Fingerprinting Kit\", foundryName: \"Fingerprint Kit\" },\n { pbName: \"Ladder\", foundryName: \"Ladder (10-foot)\" },\n { pbName: \"Mezmerizing Opal\", foundryName: \"Mesmerizing Opal\" },\n { pbName: \"Explorer's Clothing\", foundryName: \"Clothing (Explorer's)\" },\n { pbName: \"Flaming Star (Greater)\", foundryName: \"Greater Flaming Star\" },\n { pbName: \"Potion of Lesser Darkvision\", foundryName: \"Darkvision Elixir (Lesser)\" },\n { pbName: \"Potion of Greater Darkvision\", foundryName: \"Darkvision Elixir (Greater)\" },\n { pbName: \"Potion of Moderate Darkvision\", foundryName: \"Darkvision Elixir (Moderate)\" },\n { pbName: \"Bottled Sunlight\", foundryName: \"Formulated Sunlight\" },\n { pbName: \"Magazine (Repeating Hand Crossbow)\", foundryName: \"Magazine with 5 Bolts\" },\n { pbName: \"Astrolabe (Standard)\", foundryName: \"Standard Astrolabe\" },\n { pbName: \"Skinitch Salve\", foundryName: \"Skinstitch Salve\" },\n { pbName: \"Flawless Scale\", foundryName: \"Abadar's Flawless Scale\" },\n { pbName: \"Construct Key\", foundryName: \"Cordelia's Construct Key\" },\n { pbName: \"Construct Key (Greater)\", foundryName: \"Cordelia's Greater Construct Key\" },\n { pbName: \"Lesser Swapping Stone\", foundryName: \"Lesser Bonmuan Swapping Stone\" },\n { pbName: \"Major Swapping Stone\", foundryName: \"Major Bonmuan Swapping Stone\" },\n { pbName: \"Moderate Swapping Stone\", foundryName: \"Moderate Bonmuan Swapping Stone\" },\n { pbName: \"Greater Swapping Stone\", foundryName: \"Greater Bonmuan Swapping Stone\" },\n { pbName: \"Heartstone\", foundryName: \"Skarja's Heartstone\" },\n { pbName: \"Bullets (10 rounds)\", foundryName: \"Sling Bullets\" },\n];\n\nfunction generateDynamicNames(pbName) {\n const result = [];\n // if we have a hardcoded map, don't return here\n for (const reg of SWAPS) {\n const match = pbName.match(reg);\n if (match) {\n result.push({ pbName, foundryName: `${match[2]} (${match[1]})`, details: match[2] });\n }\n }\n return result;\n}\n\n\nexport function EQUIPMENT_RENAME_MAP(pbName = null) {\n const postfixNames = pbName ? generateDynamicNames(pbName) : [];\n return postfixNames.concat(EQUIPMENT_RENAME_STATIC_MAP);\n}\n\n\n// this is equipment is special and shouldn't have the transformations applied to it\nexport const RESTRICTED_EQUIPMENT = [\n \"Bracers of Armor\",\n];\n\nexport const IGNORED_EQUIPMENT = [\n \"Unarmored\"\n];\n","import CONSTANTS from \"./constants.js\";\n\nconst utils = {\n\n wait: async (ms) => {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n },\n\n capitalize: (s) => {\n if (typeof s !== \"string\") return \"\";\n return s.charAt(0).toUpperCase() + s.slice(1);\n },\n\n setting: (key) => {\n return game.settings.get(CONSTANTS.MODULE_NAME, key);\n },\n\n updateSetting: async (key, value) => {\n return game.settings.set(CONSTANTS.MODULE_NAME, key, value);\n },\n\n getFlags: (actor) => {\n const flags = actor.flags[CONSTANTS.FLAG_NAME]\n ? actor.flags[CONSTANTS.FLAG_NAME]\n : {\n pathbuilderId: undefined,\n addFeats: true,\n addEquipment: true,\n addBackground: true,\n addHeritage: true,\n addAncestry: true,\n addSpells: true,\n addMoney: true,\n addTreasure: true,\n addLores: true,\n addWeapons: true,\n addArmor: true,\n addDeity: true,\n addName: true,\n addClass: true,\n addFamiliars: true,\n addFormulas: true,\n askForChoices: false,\n };\n return flags;\n },\n\n setFlags: async (actor, flags) => {\n let updateData = {};\n setProperty(updateData, `flags.${CONSTANTS.FLAG_NAME}`, flags);\n await actor.update(updateData);\n return actor;\n },\n\n resetFlags: async (actor) => {\n return utils.setFlags(actor, null);\n },\n\n\n getOrCreateFolder: async (root, entityType, folderName, folderColor = \"\") => {\n let folder = game.folders.contents.find((f) =>\n f.type === entityType && f.name === folderName\n // if a root folder we want to match the root id for the parent folder\n && (root ? root.id : null) === (f.folder?.id ?? null)\n );\n // console.warn(`Looking for ${root} ${entityType} ${folderName}`);\n // console.warn(folder);\n if (folder) return folder;\n folder = await Folder.create(\n {\n name: folderName,\n type: entityType,\n color: folderColor,\n parent: (root) ? root.id : null,\n },\n { displaySheet: false }\n );\n return folder;\n },\n\n // eslint-disable-next-line no-unused-vars\n getFolder: async (kind, subFolder = \"\", baseFolderName = \"Pathmuncher\", baseColor = \"#6f0006\", subColor = \"#98020a\", typeFolder = true) => {\n let entityTypes = new Map();\n entityTypes.set(\"pets\", \"Pets\");\n\n const folderName = game.i18n.localize(`${CONSTANTS.MODULE_NAME}.labels.${kind}`);\n const entityType = entityTypes.get(kind);\n const baseFolder = await utils.getOrCreateFolder(null, entityType, baseFolderName, baseColor);\n const entityFolder = typeFolder ? await utils.getOrCreateFolder(baseFolder, entityType, folderName, subColor) : baseFolder;\n if (subFolder !== \"\") {\n const subFolderName = subFolder.charAt(0).toUpperCase() + subFolder.slice(1);\n const typeFolder = await utils.getOrCreateFolder(entityFolder, entityType, subFolderName, subColor);\n return typeFolder;\n } else {\n return entityFolder;\n }\n },\n\n};\n\n\nexport default utils;\n","// these are features which are named differently in pathbuilder to foundry\n\nimport CONSTANTS from \"../constants.js\";\nimport utils from \"../utils.js\";\n\nconst POSTFIX_PB_REMOVALS = [\n /(.*) (Racket)$/,\n /(.*) (Style)$/,\n];\n\nconst PREFIX_PB_REMOVALS = [\n /^(Arcane Thesis): (.*)/,\n /^(Arcane School): (.*)/,\n /^(The) (.*)/,\n];\n\nconst PARENTHESIS = [\n /^(.*) \\((.*)\\)$/,\n];\n\nconst SPLITS = [\n /^(.*): (.*)/,\n];\n\nconst SWAPS = [\n /^(Greater) (.*)/,\n /^(Lesser) (.*)/,\n /^(Major) (.*)/,\n];\n\nconst FEAT_RENAME_STATIC_MAP = [\n { pbName: \"Aerialist\", foundryName: \"Shory Aerialist\" },\n { pbName: \"Aeromancer\", foundryName: \"Shory Aeromancer\" },\n { pbName: \"Ancient-Blooded\", foundryName: \"Ancient-Blooded Dwarf\" },\n { pbName: \"Antipaladin [Chaotic Evil]\", foundryName: \"Antipaladin\" },\n { pbName: \"Ape\", foundryName: \"Ape Animal Instinct\" },\n { pbName: \"Aquatic Eyes (Darkvision)\", foundryName: \"Aquatic Eyes\" },\n { pbName: \"Astrology\", foundryName: \"Saoc Astrology\" },\n { pbName: \"Battle Ready\", foundryName: \"Battle-Ready Orc\" },\n { pbName: \"Bite (Gnoll)\", foundryName: \"Bite\" },\n { pbName: \"Bloodline: Genie (Efreeti)\", foundryName: \"Bloodline: Genie\" },\n { pbName: \"Bloody Debilitations\", foundryName: \"Bloody Debilitation\" },\n { pbName: \"Cave Climber Kobold\", foundryName: \"Caveclimber Kobold\" },\n { pbName: \"Chosen One\", foundryName: \"Chosen of Lamashtu\" },\n { pbName: \"Cognative Mutagen (Greater)\", foundryName: \"Cognitive Mutagen (Greater)\" },\n { pbName: \"Cognative Mutagen (Lesser)\", foundryName: \"Cognitive Mutagen (Lesser)\" },\n { pbName: \"Cognative Mutagen (Major)\", foundryName: \"Cognitive Mutagen (Major)\" },\n { pbName: \"Cognative Mutagen (Moderate)\", foundryName: \"Cognitive Mutagen (Moderate)\" },\n { pbName: \"Cognitive Crossover\", foundryName: \"Kreighton's Cognitive Crossover\" },\n { pbName: \"Collegiate Attendant Dedication\", foundryName: \"Magaambyan Attendant Dedication\" },\n { pbName: \"Construct Carver\", foundryName: \"Tupilaq Carver\" },\n { pbName: \"Constructed (Android)\", foundryName: \"Constructed\" },\n { pbName: \"Deadly Hair\", foundryName: \"Syu Tak-nwa's Deadly Hair\" },\n { pbName: \"Deepvision\", foundryName: \"Deep Vision\" },\n { pbName: \"Deflect Arrows\", foundryName: \"Deflect Arrow\" },\n { pbName: \"Desecrator [Neutral Evil]\", foundryName: \"Desecrator\" },\n { pbName: \"Detective Dedication\", foundryName: \"Edgewatch Detective Dedication\" },\n { pbName: \"Duelist Dedication (LO)\", foundryName: \"Aldori Duelist Dedication\" },\n { pbName: \"Dwarven Hold Education\", foundryName: \"Dongun Education\" },\n { pbName: \"Ember's Eyes (Darkvision)\", foundryName: \"Ember's Eyes\" },\n { pbName: \"Enhanced Familiar Feat\", foundryName: \"Enhanced Familiar\" },\n { pbName: \"Enigma\", foundryName: \"Enigma Muse\" },\n { pbName: \"Escape\", foundryName: \"Fane's Escape\" },\n { pbName: \"Eye of the Arcane Lords\", foundryName: \"Eye of the Arclords\" },\n { pbName: \"Flip\", foundryName: \"Farabellus Flip\" },\n { pbName: \"Fourberie\", foundryName: \"Fane's Fourberie\" },\n { pbName: \"Ganzi Gaze (Low-Light Vision)\", foundryName: \"Ganzi Gaze\" },\n { pbName: \"Guild Agent Dedication\", foundryName: \"Pathfinder Agent Dedication\" },\n { pbName: \"Harmful Font\", foundryName: \"Divine Font\" },\n { pbName: \"Healing Font\", foundryName: \"Divine Font\" },\n { pbName: \"Heatwave\", foundryName: \"Heat Wave\" },\n { pbName: \"Heavenseeker Dedication\", foundryName: \"Jalmeri Heavenseeker Dedication\" },\n { pbName: \"Heir of the Astrologers\", foundryName: \"Heir of the Saoc\" },\n { pbName: \"High Killer Training\", foundryName: \"Vernai Training\" },\n { pbName: \"Ice-Witch\", foundryName: \"Irriseni Ice-Witch\" },\n { pbName: \"Impeccable Crafter\", foundryName: \"Impeccable Crafting\" },\n { pbName: \"Incredible Beastmaster's Companion\", foundryName: \"Incredible Beastmaster Companion\" },\n { pbName: \"Interrogation\", foundryName: \"Bolera's Interrogation\" },\n { pbName: \"Katana\", foundryName: \"Katana Weapon Familiarity\" },\n { pbName: \"Liberator [Chaotic Good]\", foundryName: \"Liberator\" },\n { pbName: \"Lumberjack Dedication\", foundryName: \"Turpin Rowe Lumberjack Dedication\" },\n { pbName: \"Maestro\", foundryName: \"Maestro Muse\" },\n { pbName: \"Major Lesson I\", foundryName: \"Major Lesson\" },\n { pbName: \"Major Lesson II\", foundryName: \"Major Lesson\" },\n { pbName: \"Major Lesson III\", foundryName: \"Major Lesson\" },\n { pbName: \"Mantis God's Grip\", foundryName: \"Achaekek's Grip\" },\n { pbName: \"Marked for Death\", foundryName: \"Mark for Death\" },\n { pbName: \"Miraculous Spells\", foundryName: \"Miraculous Spell\" },\n { pbName: \"Multifarious\", foundryName: \"Multifarious Muse\" },\n { pbName: \"Paladin [Lawful Good]\", foundryName: \"Paladin\" },\n { pbName: \"Parry\", foundryName: \"Aldori Parry\" },\n { pbName: \"Polymath\", foundryName: \"Polymath Muse\" },\n { pbName: \"Precise Debilitation\", foundryName: \"Precise Debilitations\" },\n { pbName: \"Quick Climber\", foundryName: \"Quick Climb\" },\n { pbName: \"Recognise Threat\", foundryName: \"Recognize Threat\" },\n { pbName: \"Redeemer [Neutral Good]\", foundryName: \"Redeemer\" },\n { pbName: \"Revivification Protocall\", foundryName: \"Revivification Protocol\" },\n { pbName: \"Riposte\", foundryName: \"Aldori Riposte\" },\n { pbName: \"Rkoan Arts\", foundryName: \"Rokoan Arts\" },\n { pbName: \"Saberteeth\", foundryName: \"Saber Teeth\" },\n { pbName: \"Scholarly Recollection\", foundryName: \"Uzunjati Recollection\" },\n { pbName: \"Scholarly Storytelling\", foundryName: \"Uzunjati Storytelling\" },\n { pbName: \"Secret Lesson\", foundryName: \"Janatimo's Lessons\" },\n { pbName: \"Sentry Dedication\", foundryName: \"Lastwall Sentry Dedication\" },\n { pbName: \"Stab and Snag\", foundryName: \"Stella's Stab and Snag\" },\n { pbName: \"Tenets of Evil\", foundryName: \"The Tenets of Evil\" },\n { pbName: \"Tenets of Good\", foundryName: \"The Tenets of Good\" },\n { pbName: \"Tongue of the Sun and Moon\", foundryName: \"Tongue of Sun and Moon\" },\n { pbName: \"Tribal Bond\", foundryName: \"Quah Bond\" },\n { pbName: \"Tyrant [Lawful Evil]\", foundryName: \"Tyrant\" },\n { pbName: \"Vestigal Wings\", foundryName: \"Vestigial Wings\" },\n { pbName: \"Virtue-Forged Tattooed\", foundryName: \"Virtue-Forged Tattoos\" },\n { pbName: \"Wakizashi\", foundryName: \"Wakizashi Weapon Familiarity\" },\n { pbName: \"Warden\", foundryName: \"Lastwall Warden\" },\n { pbName: \"Warrior\", foundryName: \"Warrior Muse\" },\n { pbName: \"Wary Eye\", foundryName: \"Eye of Ozem\" },\n { pbName: \"Wayfinder Resonance Infiltrator\", foundryName: \"Westyr's Wayfinder Repository\" },\n { pbName: \"Wind God's Fan\", foundryName: \"Wind God’s Fan\" },\n { pbName: \"Wind God’s Fan\", foundryName: \"Wind God's Fan\" },\n { pbName: \"Black\", foundryName: \"Black Dragon\" },\n { pbName: \"Brine\", foundryName: \"Brine Dragon\" },\n { pbName: \"Copper\", foundryName: \"Copper Dragon\" },\n { pbName: \"Blue\", foundryName: \"Blue Dragon\" },\n { pbName: \"Bronze\", foundryName: \"Bronze Dragon\" },\n { pbName: \"Cloud\", foundryName: \"Cloud Dragon\" },\n { pbName: \"Sky\", foundryName: \"Sky Dragon\" },\n { pbName: \"Brass\", foundryName: \"Brass Dragon\" },\n { pbName: \"Underworld\", foundryName: \"Underworld Dragon\" },\n { pbName: \"Crystal\", foundryName: \"Crystal Dragon\" },\n { pbName: \"Forest\", foundryName: \"Forest Dragon\" },\n { pbName: \"Green\", foundryName: \"Green Dragon\" },\n { pbName: \"Sea\", foundryName: \"Sea Dragon\" },\n { pbName: \"Silver\", foundryName: \"Silver Dragon\" },\n { pbName: \"White\", foundryName: \"White Dragon\" },\n { pbName: \"Sovereign\", foundryName: \"Sovereign Dragon\" },\n { pbName: \"Umbral\", foundryName: \"Umbral Dragon\" },\n { pbName: \"Red\", foundryName: \"Red Dragon\" },\n { pbName: \"Gold\", foundryName: \"Gold Dragon\" },\n { pbName: \"Magma\", foundryName: \"Magma Dragon\" },\n];\n\nfunction generateDynamicNames(pbName) {\n const result = [];\n // if we have a hardcoded map, don't return here\n if (FEAT_RENAME_STATIC_MAP.some((e) => e.pbName === pbName)) return result;\n for (const reg of POSTFIX_PB_REMOVALS) {\n const match = pbName.match(reg);\n if (match) {\n result.push({ pbName, foundryName: match[1], details: match[2] });\n }\n }\n for (const reg of PREFIX_PB_REMOVALS) {\n const match = pbName.match(reg);\n if (match) {\n result.push({ pbName, foundryName: match[2], details: match[1] });\n }\n }\n for (const reg of SPLITS) {\n const match = pbName.match(reg);\n if (match) {\n result.push({ pbName, foundryName: match[2], details: match[1] });\n }\n }\n for (const reg of PARENTHESIS) {\n const match = pbName.match(reg);\n if (match) {\n result.push({ pbName, foundryName: match[1], details: match[2] });\n }\n }\n for (const reg of SWAPS) {\n const match = pbName.match(reg);\n if (match) {\n result.push({ pbName, foundryName: `${match[2]} (${match[1]})`, details: match[2] });\n }\n }\n return result;\n}\n\nexport function FEAT_RENAME_MAP(pbName = null) {\n const postfixNames = pbName ? generateDynamicNames(pbName) : [];\n return postfixNames.concat(FEAT_RENAME_STATIC_MAP);\n}\n\nconst IGNORED_FEATS_LIST = [\n \"Unarmored\",\n \"Simple Weapon Expertise\",\n \"Spellbook\",\n \"Energy Emanation\", // pathbuilder does not pass through a type for this\n \"Imprecise Sense\", // this gets picked up and added by granted features\n];\n\nexport function IGNORED_FEATS() {\n const visionFeats = utils.setting(CONSTANTS.SETTINGS.ADD_VISION_FEATS) ? [] : [\"Low-Light Vision\", \"Darkvision\"];\n return IGNORED_FEATS_LIST.concat(visionFeats);\n}\n","import CONSTANTS from \"./constants.js\";\nimport utils from \"./utils.js\";\n\nconst logger = {\n _showMessage: (logLevel, data) => {\n if (!logLevel || !data || typeof logLevel !== \"string\") {\n return false;\n }\n\n const setting = utils.setting(CONSTANTS.SETTINGS.LOG_LEVEL);\n const logLevels = [\"DEBUG\", \"INFO\", \"WARN\", \"ERR\", \"OFF\"];\n const logLevelIndex = logLevels.indexOf(logLevel.toUpperCase());\n if (setting == \"OFF\" || logLevelIndex === -1 || logLevelIndex < logLevels.indexOf(setting)) {\n return false;\n }\n return true;\n },\n log: (logLevel, ...data) => {\n if (!logger._showMessage(logLevel, data)) {\n return;\n }\n\n logLevel = logLevel.toUpperCase();\n\n let msg = \"No logging message provided. Please see the payload for more information.\";\n let payload = data.slice();\n if (data[0] && typeof (data[0] == \"string\")) {\n msg = data[0];\n if (data.length > 1) {\n payload = data.slice(1);\n } else {\n payload = null;\n }\n }\n msg = `${CONSTANTS.MODULE_NAME} | ${logLevel} > ${msg}`;\n switch (logLevel) {\n case \"DEBUG\":\n if (payload) {\n console.debug(msg, ...payload); // eslint-disable-line no-console\n } else {\n console.debug(msg); // eslint-disable-line no-console\n }\n break;\n case \"INFO\":\n if (payload) {\n console.info(msg, ...payload); // eslint-disable-line no-console\n } else {\n console.info(msg); // eslint-disable-line no-console\n }\n break;\n case \"WARN\":\n if (payload) {\n console.warn(msg, ...payload); // eslint-disable-line no-console\n } else {\n console.warn(msg); // eslint-disable-line no-console\n }\n break;\n case \"ERR\":\n if (payload) {\n console.error(msg, ...payload); // eslint-disable-line no-console\n } else {\n console.error(msg); // eslint-disable-line no-console\n }\n break;\n default:\n break;\n }\n },\n\n debug: (...data) => {\n logger.log(\"DEBUG\", ...data);\n },\n\n info: (...data) => {\n logger.log(\"INFO\", ...data);\n },\n\n warn: (...data) => {\n logger.log(\"WARN\", ...data);\n },\n\n error: (...data) => {\n logger.log(\"ERR\", ...data);\n },\n};\nexport default logger;\n","/* eslint-disable no-await-in-loop */\n/* eslint-disable no-continue */\nimport CONSTANTS from \"../constants.js\";\nimport { EQUIPMENT_RENAME_MAP, RESTRICTED_EQUIPMENT, IGNORED_EQUIPMENT } from \"../data/equipment.js\";\nimport { FEAT_RENAME_MAP, IGNORED_FEATS } from \"../data/features.js\";\nimport logger from \"../logger.js\";\nimport utils from \"../utils.js\";\n\nexport class Pathmuncher {\n\n // eslint-disable-next-line class-methods-use-this\n EQUIPMENT_RENAME_MAP(name) {\n return EQUIPMENT_RENAME_MAP(name);\n }\n\n getFoundryEquipmentName(pbName) {\n return this.EQUIPMENT_RENAME_MAP(pbName).find((map) => map.pbName == pbName)?.foundryName ?? pbName;\n }\n\n FEAT_RENAME_MAP(name) {\n const dynamicItems = [\n { pbName: \"Shining Oath\", foundryName: `Shining Oath (${this.getChampionType()})` },\n { pbName: \"Counterspell\", foundryName: `Counterspell (${utils.capitalize(this.getClassSpellCastingType() ?? \"\")})` },\n { pbName: \"Counterspell\", foundryName: `Counterspell (${utils.capitalize(this.getClassSpellCastingType(true) ?? \"\")})` },\n { pbName: \"Cantrip Expansion\", foundryName: `Cantrip Expansion (${this.source.class})` },\n { pbName: \"Cantrip Expansion\", foundryName: `Cantrip Expansion (${this.source.dualClass})` },\n { pbName: \"Cantrip Expansion\", foundryName: `Cantrip Expansion (${utils.capitalize(this.getClassSpellCastingType() ?? \"\")} Caster)` },\n { pbName: \"Cantrip Expansion\", foundryName: `Cantrip Expansion (${utils.capitalize(this.getClassSpellCastingType(true) ?? \"\")} Caster)` },\n ];\n return FEAT_RENAME_MAP(name).concat(dynamicItems);\n }\n\n getFoundryFeatureName(pbName) {\n const match = this.FEAT_RENAME_MAP(pbName).find((map) => map.pbName == pbName);\n return match ?? { pbName, foundryName: pbName, details: undefined };\n }\n\n // eslint-disable-next-line class-methods-use-this\n get RESTRICTED_EQUIPMENT() {\n return RESTRICTED_EQUIPMENT;\n }\n\n // specials that are handled by Foundry and shouldn't be added\n // eslint-disable-next-line class-methods-use-this\n get IGNORED_FEATURES() {\n return IGNORED_FEATS();\n };\n\n // eslint-disable-next-line class-methods-use-this\n get IGNORED_EQUIPMENT() {\n return IGNORED_EQUIPMENT;\n };\n\n getChampionType() {\n if (this.source.alignment == \"LG\") return \"Paladin\";\n else if (this.source.alignment == \"CG\") return \"Liberator\";\n else if (this.source.alignment == \"NG\") return \"Redeemer\";\n else if (this.source.alignment == \"LE\") return \"Tyrant\";\n else if (this.source.alignment == \"CE\") return \"Antipaladin\";\n else if (this.source.alignment == \"NE\") return \"Desecrator\";\n return \"Unknown\";\n }\n\n constructor(actor, { addFeats = true, addEquipment = true, addSpells = true, addMoney = true, addLores = true,\n addWeapons = true, addArmor = true, addTreasure = true, addDeity = true, addName = true, addClass = true,\n addBackground = true, addHeritage = true, addAncestry = true, askForChoices = false } = {}\n ) {\n this.actor = actor;\n // note not all these options do anything yet!\n this.options = {\n addTreasure,\n addMoney,\n addFeats,\n addSpells,\n addEquipment,\n addLores,\n addWeapons,\n addArmor,\n addDeity,\n addName,\n addClass,\n addBackground,\n addHeritage,\n addAncestry,\n askForChoices,\n };\n this.source = null;\n this.parsed = {\n specials: [],\n feats: [],\n equipment: [],\n armor: [],\n weapons: [],\n };\n this.usedLocations = new Set();\n this.usedLocationsAlternateRules = new Set();\n this.autoAddedFeatureIds = new Set();\n this.autoAddedFeatureItems = {};\n this.allFeatureRules = {};\n this.autoAddedFeatureRules = {};\n this.grantItemLookUp = {};\n this.autoFeats = [];\n this.result = {\n character: {\n _id: this.actor.id,\n prototypeToken: {},\n },\n class: [],\n deity: [],\n heritage: [],\n ancestry: [],\n background: [],\n casters: [],\n spells: [],\n feats: [],\n weapons: [],\n armor: [],\n equipment: [],\n lores: [],\n money: [],\n treasure: [],\n adventurersPack: {\n item: null,\n contents: [\n { slug: \"bedroll\", qty: 1 },\n { slug: \"chalk\", qty: 10 },\n { slug: \"flint-and-steel\", qty: 1 },\n { slug: \"rope\", qty: 1 },\n { slug: \"rations\", qty: 14 },\n { slug: \"torch\", qty: 5 },\n { slug: \"waterskin\", qty: 1 },\n ],\n },\n focusPool: 0,\n };\n this.check = {};\n this.bad = [];\n }\n\n async fetchPathbuilder(pathbuilderId) {\n if (!pathbuilderId) {\n const flags = utils.getFlags(this.actor);\n pathbuilderId = flags?.pathbuilderId;\n }\n if (pathbuilderId) {\n const jsonData = await foundry.utils.fetchJsonWithTimeout(`https://www.pathbuilder2e.com/json.php?id=${pathbuilderId}`);\n if (jsonData.success) {\n this.source = jsonData.build;\n } else {\n ui.notifications.warn(game.i18n.format(`${CONSTANTS.FLAG_NAME}.Dialogs.Pathmuncher.FetchFailed`, { pathbuilderId }));\n }\n } else {\n ui.notifications.error(game.i18n.localize(`${CONSTANTS.FLAG_NAME}.Dialogs.Pathmuncher.NoId`));\n }\n }\n\n getClassAdjustedSpecialNameLowerCase(name) {\n return `${name} (${this.source.class})`.toLowerCase();\n }\n\n getDualClassAdjustedSpecialNameLowerCase(name) {\n return `${name} (${this.source.dualClass})`.toLowerCase();\n }\n\n getAncestryAdjustedSpecialNameLowerCase(name) {\n return `${name} (${this.source.ancestry})`.toLowerCase();\n }\n\n getHeritageAdjustedSpecialNameLowerCase(name) {\n return `${name} (${this.source.heritage})`.toLowerCase();\n }\n\n static getMaterialGrade(material) {\n if (material.toLowerCase().includes(\"high-grade\")) {\n return \"high\";\n } else if (material.toLowerCase().includes(\"standard-grade\")) {\n return \"standard\";\n }\n return \"low\";\n }\n\n static getFoundryFeatLocation(pathbuilderFeatType, pathbuilderFeatLevel) {\n if (pathbuilderFeatType === \"Ancestry Feat\") {\n return `ancestry-${pathbuilderFeatLevel}`;\n } else if (pathbuilderFeatType === \"Class Feat\") {\n return `class-${pathbuilderFeatLevel}`;\n } else if (pathbuilderFeatType === \"Skill Feat\") {\n return `skill-${pathbuilderFeatLevel}`;\n } else if (pathbuilderFeatType === \"General Feat\") {\n return `general-${pathbuilderFeatLevel}`;\n } else if (pathbuilderFeatType === \"Background Feat\") {\n return `skill-${pathbuilderFeatLevel}`;\n } else if (pathbuilderFeatType === \"Archetype Feat\") {\n return `archetype-${pathbuilderFeatLevel}`;\n } else {\n return null;\n }\n }\n\n #generateFoundryFeatLocation(document, feature) {\n if (feature.type && feature.level) {\n const ancestryParagonVariant = game.settings.get(\"pf2e\", \"ancestryParagonVariant\");\n const dualClassVariant = game.settings.get(\"pf2e\", \"dualClassVariant\");\n // const freeArchetypeVariant = game.settings.get(\"pf2e\", \"freeArchetypeVariant\");\n const location = Pathmuncher.getFoundryFeatLocation(feature.type, feature.level);\n if (location && !this.usedLocations.has(location)) {\n document.system.location = location;\n this.usedLocations.add(location);\n } else if (location && this.usedLocations.has(location)) {\n logger.debug(\"Variant feat location\", { ancestryParagonVariant, location, feature });\n // eslint-disable-next-line max-depth\n if (ancestryParagonVariant && feature.type === \"Ancestry Feat\") {\n document.system.location = \"ancestry-bonus\";\n this.usedLocationsAlternateRules.add(location);\n } else if (dualClassVariant && feature.type === \"Class Feat\") {\n document.system.location = `dualclass-${feature.level}`;\n this.usedLocationsAlternateRules.add(location);\n }\n }\n }\n }\n\n #processSpecialData(name) {\n if (name.includes(\"Domain: \")) {\n const domainName = name.split(\" \")[1];\n this.parsed.feats.push({ name: \"Deity's Domain\", extra: domainName });\n return true;\n } else {\n return false;\n }\n }\n\n #nameMap() {\n logger.debug(\"Starting Equipment Rename\");\n this.source.equipment\n .filter((e) => e[0] && e[0] !== \"undefined\")\n .forEach((e) => {\n const name = this.getFoundryEquipmentName(e[0]);\n const item = { pbName: name, qty: e[1], added: false };\n this.parsed.equipment.push(item);\n });\n this.source.armor\n .filter((e) => e && e !== \"undefined\")\n .forEach((e) => {\n const name = this.getFoundryEquipmentName(e.name);\n const item = mergeObject({ pbName: name, originalName: e.name, added: false }, e);\n this.parsed.armor.push(item);\n });\n this.source.weapons\n .filter((e) => e && e !== \"undefined\")\n .forEach((e) => {\n const name = this.getFoundryEquipmentName(e.name);\n const item = mergeObject({ pbName: name, originalName: e.name, added: false }, e);\n this.parsed.weapons.push(item);\n });\n logger.debug(\"Finished Equipment Rename\");\n\n logger.debug(\"Starting Special Rename\");\n this.source.specials\n .filter((special) => special\n && special !== \"undefined\"\n && special !== \"Not Selected\"\n && special !== this.source.heritage\n )\n .forEach((special) => {\n const name = this.getFoundryFeatureName(special).foundryName;\n if (!this.#processSpecialData(name) && !this.IGNORED_FEATURES.includes(name)) {\n this.parsed.specials.push({ name, originalName: special, added: false });\n }\n });\n logger.debug(\"Finished Special Rename\");\n\n logger.debug(\"Starting Feat Rename\");\n this.source.feats\n .filter((feat) => feat[0]\n && feat[0] !== \"undefined\"\n && feat[0] !== \"Not Selected\"\n && feat[0] !== this.source.heritage\n )\n .forEach((feat) => {\n const name = this.getFoundryFeatureName(feat[0]).foundryName;\n const data = {\n name,\n extra: feat[1],\n added: false,\n type: feat[2],\n level: feat[3],\n originalName: feat[0],\n };\n this.parsed.feats.push(data);\n });\n logger.debug(\"Finished Feat Rename\");\n }\n\n #prepare() {\n this.#nameMap();\n }\n\n static getSizeValue(size) {\n switch (size) {\n case 0:\n return \"tiny\";\n case 1:\n return \"sm\";\n case 3:\n return \"lg\";\n default:\n return \"med\";\n }\n }\n\n async #processSenses() {\n const senses = [];\n this.source.specials.forEach((special) => {\n if (special === \"Low-Light Vision\") {\n senses.push({ type: \"lowLightVision\" });\n } else if (special === \"Darkvision\") {\n senses.push({ type: \"darkvision\" });\n } else if (special === \"Scent\") {\n senses.push({ type: \"scent\" });\n }\n });\n setProperty(this.result.character, \"system.traits.senses\", senses);\n }\n\n async #addDualClass(klass) {\n if (!game.settings.get(\"pf2e\", \"dualClassVariant\")) {\n if (this.source.dualClass && this.source.dualClass !== \"\") {\n logger.warn(`Imported character is dual class but system is not configured for dual class`, {\n class: this.source.class,\n dualClass: this.source.dualClass,\n });\n ui.notifications.warn(`Imported character is dual class but system is not configured for dual class`);\n }\n return;\n }\n if (!this.source.dualClass || this.source.dualClass === \"\") {\n logger.warn(`Imported character not dual class but system is configured for dual class`, {\n class: this.source.class,\n });\n ui.notifications.warn(`Imported character not dual class but system is configured for dual class`);\n return;\n }\n\n // find the dual class\n const compendium = await game.packs.get(\"pf2e.classes\");\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n const foundryName = this.getFoundryFeatureName(this.source.dualClass).foundryName;\n const indexMatch = index.find((i) => i.system.slug === game.pf2e.system.sluggify(foundryName))\n ?? index.find((i) => i.system.slug === game.pf2e.system.sluggify(this.source.dualClass));\n\n if (!indexMatch) return;\n const doc = await compendium.getDocument(indexMatch._id);\n const dualClass = doc.toObject();\n\n logger.debug(`Dual Class ${dualClass.name} found, squashing things together.`);\n\n klass.name = `${klass.name} - ${dualClass.name}`;\n const ruleEntry = {\n \"domain\": \"all\",\n \"key\": \"RollOption\",\n \"option\": `class:${dualClass.system.slug}`\n };\n\n // Attacks\n [\"advanced\", \"martial\", \"simple\", \"unarmed\"].forEach((key) => {\n if (dualClass.system.attacks[key] > klass.system.attacks[key]) {\n klass.system.attacks[key] = dualClass.system.attacks[key];\n }\n });\n if (klass.system.attacks.martial <= dualClass.system.attacks.other.rank) {\n if (dualClass.system.attacks.other.rank === klass.system.attacks.other.rank) {\n let mashed = `${klass.system.attacks.other.name}, ${dualClass.system.attacks.other.name}`;\n mashed = mashed.replace(\"and \", \"\");\n klass.system.attacks.other.name = [...new Set(mashed.split(','))].join(',');\n }\n if (dualClass.system.attacks.other.rank > klass.system.attacks.other.rank) {\n klass.system.attacks.other.name = dualClass.system.attacks.other.name;\n klass.system.attacks.other.rank = dualClass.system.attacks.other.rank;\n }\n }\n if (klass.system.attacks.martial >= dualClass.system.attacks.other.rank\n && klass.system.attacks.martial >= klass.system.attacks.other.rank\n ) {\n klass.system.attacks.other.rank = 0;\n klass.system.attacks.other.name = \"\";\n }\n\n // Class DC\n if (dualClass.system.classDC > klass.system.classDC) {\n klass.system.classDC = dualClass.system.classDC;\n }\n\n // Defenses\n [\"heavy\", \"light\", \"medium\", \"unarmored\"].forEach((key) => {\n if (dualClass.system.defenses[key] > klass.system.defenses[key]) {\n klass.system.defenses[key] = dualClass.system.defenses[key];\n }\n });\n\n // Description\n klass.system.description.value = `${klass.system.description.value} ${dualClass.system.description.value}`;\n\n // HP\n if (dualClass.system.hp > klass.system.hp) {\n klass.system.hp = dualClass.system.hp;\n }\n\n // Items\n Object.entries(dualClass.system.items).forEach((i) => {\n if (Object.values(klass.system.items).some((x) => x.uuid === i[1].uuid && x.level > i[1].level)) {\n Object.values(klass.system.items).find((x) => x.uuid === i[1].uuid).level = i[1].level;\n } else if (!Object.values(klass.system.items).some((x) => x.uuid === i[1].uuid && x.level <= i[1].level)) {\n klass.system.items[i[0]] = i[1];\n }\n });\n\n // Key Ability\n dualClass.system.keyAbility.value.forEach((v) => {\n if (!klass.system.keyAbility.value.includes(v)) {\n klass.system.keyAbility.value.push(v);\n }\n });\n\n // Perception\n if (dualClass.system.perception > klass.system.perception) klass.system.perception = dualClass.system.perception;\n\n // Rules\n klass.system.rules.push(ruleEntry);\n dualClass.system.rules.forEach((r) => {\n if (!klass.system.rules.includes(r)) {\n klass.system.rules.push(r);\n }\n });\n klass.system.rules.forEach((r, i) => {\n if (r.path !== undefined) {\n const check = r.path.split('.');\n if (check.includes(\"data\")\n && check.includes(\"martial\")\n && check.includes(\"rank\")\n && klass.system.attacks.martial >= r.value\n ) {\n klass.system.rules.splice(i, 1);\n }\n }\n });\n\n // Saving Throws\n [\"fortitude\", \"reflex\", \"will\"].forEach((key) => {\n if (dualClass.system.savingThrows[key] > klass.system.savingThrows[key]) {\n klass.system.savingThrows[key] = dualClass.system.savingThrows[key];\n }\n });\n\n // Skill Feat Levels\n dualClass.system.skillFeatLevels.value.forEach((v) => {\n klass.system.skillFeatLevels.value.push(v);\n });\n klass.system.skillFeatLevels.value = [...new Set(klass.system.skillFeatLevels.value)].sort((a, b) => {\n return a - b;\n });\n\n // Skill Increase Levels\n dualClass.system.skillIncreaseLevels.value.forEach((v) => {\n klass.system.skillIncreaseLevels.value.push(v);\n });\n klass.system.skillIncreaseLevels.value = [...new Set(klass.system.skillIncreaseLevels.value)].sort((a, b) => {\n return a - b;\n });\n\n // Trained Skills\n if (dualClass.system.trainedSkills.additional > klass.system.trainedSkills.additional) {\n klass.system.trainedSkills.additional = dualClass.system.trainedSkills.additional;\n }\n dualClass.system.trainedSkills.value.forEach((v) => {\n if (!klass.system.trainedSkills.value.includes(v)) {\n klass.system.trainedSkills.value.push(v);\n }\n });\n\n this.result.dualClass = dualClass;\n }\n\n // eslint-disable-next-line class-methods-use-this\n async #processGenericCompendiumLookup(compendiumLabel, name, target) {\n logger.debug(`Checking for compendium documents for ${name} (${target}) in ${compendiumLabel}`);\n const compendium = await game.packs.get(compendiumLabel);\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n const foundryName = this.getFoundryFeatureName(name).foundryName;\n const indexMatch = index.find((i) => i.system.slug === game.pf2e.system.sluggify(foundryName))\n ?? index.find((i) => i.system.slug === game.pf2e.system.sluggify(name));\n\n if (indexMatch) {\n const doc = await compendium.getDocument(indexMatch._id);\n const itemData = doc.toObject();\n if (target === \"class\") {\n itemData.system.keyAbility.selected = this.source.keyability;\n await this.#addDualClass(itemData);\n }\n itemData._id = foundry.utils.randomID();\n this.#generateGrantItemData(itemData);\n this.result[target].push(itemData);\n await this.#addGrantedItems(itemData);\n return true;\n } else {\n this.bad.push({ pbName: name, type: target, details: { name } });\n return false;\n }\n }\n\n // for grants, e.g. ont he champion \"Deity and Cause\" where there are choices.\n // how do we determine and match these? should we?\n // \"pf2e\": {\n // \"itemGrants\": {\n // \"adanye\": {\n // \"id\": \"4GHcp3iaREfj2ZgN\",\n // \"onDelete\": \"detach\"\n // },\n // \"paladin\": {\n // \"id\": \"HGWkTEatliHgDaEu\",\n // \"onDelete\": \"detach\"\n // }\n // }\n // }\n\n // \"Paladin\" (granted by deity and casue)\n // \"pf2e\": {\n // \"grantedBy\": {\n // \"id\": \"xnrkrJa2YE1UOAVy\",\n // \"onDelete\": \"cascade\"\n // },\n // \"itemGrants\": {\n // \"retributiveStrike\": {\n // \"id\": \"WVHbj9LljCTovdsv\",\n // \"onDelete\": \"detach\"\n // }\n // }\n // }\n\n // retributive strike\n // \"pf2e\": {\n // \"grantedBy\": {\n // \"id\": \"HGWkTEatliHgDaEu\",\n // \"onDelete\": \"cascade\"\n // }\n\n #parsedFeatureMatch(type, slug, ignoreAdded) {\n // console.warn(`Trying to find ${slug} in ${type}, ignoreAdded? ${ignoreAdded}`);\n const parsedMatch = this.parsed[type].find((f) =>\n (!ignoreAdded || (ignoreAdded && !f.added))\n && (\n slug === game.pf2e.system.sluggify(f.name)\n || slug === game.pf2e.system.sluggify(this.getClassAdjustedSpecialNameLowerCase(f.name))\n || slug === game.pf2e.system.sluggify(this.getAncestryAdjustedSpecialNameLowerCase(f.name))\n || slug === game.pf2e.system.sluggify(this.getHeritageAdjustedSpecialNameLowerCase(f.name))\n || slug === game.pf2e.system.sluggify(f.originalName)\n || slug === game.pf2e.system.sluggify(this.getClassAdjustedSpecialNameLowerCase(f.originalName))\n || slug === game.pf2e.system.sluggify(this.getAncestryAdjustedSpecialNameLowerCase(f.originalName))\n || slug === game.pf2e.system.sluggify(this.getHeritageAdjustedSpecialNameLowerCase(f.originalName))\n || (game.settings.get(\"pf2e\", \"dualClassVariant\")\n && (slug === game.pf2e.system.sluggify(this.getDualClassAdjustedSpecialNameLowerCase(f.name))\n || slug === game.pf2e.system.sluggify(this.getDualClassAdjustedSpecialNameLowerCase(f.originalName))\n )\n )\n )\n );\n // console.warn(`Results of find ${slug} in ${type}, ignoreAdded? ${ignoreAdded}`, {\n // slug,\n // parsedMatch,\n // parsed: duplicate(this.parsed),\n // });\n return parsedMatch;\n }\n\n #generatedResultMatch(type, slug) {\n const featMatch = this.result[type].find((f) => slug === f.system.slug);\n return featMatch;\n }\n\n #findAllFeatureMatch(slug, ignoreAdded) {\n const featMatch = this.#parsedFeatureMatch(\"feats\", slug, ignoreAdded);\n if (featMatch) return featMatch;\n const specialMatch = this.#parsedFeatureMatch(\"specials\", slug, ignoreAdded);\n if (specialMatch) return specialMatch;\n const deityMatch = this.#generatedResultMatch(\"deity\", slug);\n return deityMatch;\n // const classMatch = this.#generatedResultMatch(\"class\", slug);\n // return classMatch;\n // const equipmentMatch = this.#generatedResultMatch(\"equipment\", slug);\n // return equipmentMatch;\n }\n\n #createGrantedItem(document, parent) {\n logger.debug(`Adding granted item flags to ${document.name} (parent ${parent.name})`);\n const camelCase = game.pf2e.system.sluggify(document.system.slug, { camel: \"dromedary\" });\n setProperty(parent, `flags.pf2e.itemGrants.${camelCase}`, { id: document._id, onDelete: \"detach\" });\n setProperty(document, \"flags.pf2e.grantedBy\", { id: parent._id, onDelete: \"cascade\" });\n this.autoFeats.push(document);\n if (!this.options.askForChoices) {\n this.result.feats.push(document);\n }\n const featureMatch = this.#findAllFeatureMatch(document.system.slug, true)\n ?? (document.name.includes(\"(\")\n ? this.#findAllFeatureMatch(game.pf2e.system.sluggify(document.name.split(\"(\")[0].trim()), true)\n : undefined\n );\n\n // console.warn(`Matching feature for ${document.name}?`, {\n // featureMatch,\n // });\n\n if (featureMatch) {\n if (hasProperty(featureMatch, \"added\")) {\n featureMatch.added = true;\n this.#generateFoundryFeatLocation(document, featureMatch);\n }\n\n return;\n }\n if (document.type !== \"action\") logger.warn(`Unable to find parsed feature match for granted feature ${document.name}. This might not be an issue, but might indicate feature duplication.`, { document, parent });\n }\n\n async #featureChoiceMatch(choices, ignoreAdded, adjustName) {\n for (const choice of choices) {\n const doc = adjustName\n ? game.i18n.localize(choice.label)\n : await fromUuid(choice.value);\n if (!doc) continue;\n const slug = adjustName\n ? game.pf2e.system.sluggify(doc)\n : doc.system.slug;\n const featMatch = this.#findAllFeatureMatch(slug, ignoreAdded);\n if (featMatch) {\n if (adjustName && hasProperty(featMatch, \"added\")) featMatch.added = true;\n logger.debug(\"Choices evaluated\", { choices, document, featMatch, choice });\n return choice;\n }\n }\n return undefined;\n }\n\n async #evaluateChoices(document, choiceSet) {\n logger.debug(`Evaluating choices for ${document.name}`, { document, choiceSet });\n const tempActor = await this.#generateTempActor();\n const cleansedChoiceSet = deepClone(choiceSet);\n try {\n const item = tempActor.getEmbeddedDocument(\"Item\", document._id);\n const choiceSetRules = new game.pf2e.RuleElements.all.ChoiceSet(cleansedChoiceSet, item);\n const rollOptions = [tempActor.getRollOptions(), item.getRollOptions(\"item\")].flat();\n const choices = (await choiceSetRules.inflateChoices()).filter((c) => !c.predicate || c.predicate.test(rollOptions));\n\n logger.debug(\"Starting choice evaluation\", {\n document,\n choiceSet,\n item,\n choiceSetRules,\n rollOptions,\n choices,\n });\n\n logger.debug(\"Evaluating choiceset\", cleansedChoiceSet);\n const choiceMatch = await this.#featureChoiceMatch(choices, true, cleansedChoiceSet.adjustName);\n logger.debug(\"choiceMatch result\", choiceMatch);\n if (choiceMatch) return choiceMatch;\n\n if (typeof cleansedChoiceSet.choices === \"string\" || Array.isArray(choices)) {\n for (const choice of choices) {\n const featMatch = this.#findAllFeatureMatch(choice.value, true, cleansedChoiceSet.adjustName);\n if (featMatch) {\n logger.debug(\"Choices evaluated\", { cleansedChoiceSet, choices, document, featMatch, choice });\n featMatch.added = true;\n choice.nouuid = true;\n return choice;\n }\n }\n }\n\n } catch (err) {\n logger.error(\"Whoa! Something went major bad wrong during choice evaluation\", {\n err,\n tempActor: tempActor.toObject(),\n document: duplicate(document),\n choiceSet: duplicate(cleansedChoiceSet),\n });\n throw err;\n } finally {\n await Actor.deleteDocuments([tempActor._id]);\n }\n\n logger.debug(\"Evaluate Choices failed\", { choiceSet: cleansedChoiceSet, tempActor, document });\n return undefined;\n\n }\n\n async #resolveInjectedUuid(source, propertyData) {\n if (source === null || typeof source === \"number\" || (typeof source === \"string\" && !source.includes(\"{\"))) {\n return source;\n }\n\n // Walk the object tree and resolve any string values found\n if (Array.isArray(source)) {\n for (let i = 0; i < source.length; i++) {\n source[i] = this.#resolveInjectedUuid(source[i]);\n }\n } else if (typeof source === 'object' && source !== null) {\n for (const [key, value] of Object.entries(source)) {\n if (typeof value === \"string\" || (typeof value === 'object' && value !== null)) {\n source[key] = this.#resolveInjectedUuid(value);\n }\n }\n return source;\n } else if (typeof source === \"string\") {\n const match = source.match(/{(actor|item|rule)\\|(.*?)}/);\n if (match && match[1] === \"actor\") {\n return String(getProperty(this.result.character, match[1]));\n } else if (match) {\n const value = this.grantItemLookUp[match[0]].uuid;\n if (!value) {\n logger.error(\"Failed to resolve injected property\", {\n source,\n propertyData,\n key: match[1],\n prop: match[2],\n });\n }\n return String(value);\n } else {\n logger.error(\"Failed to resolve injected property\", {\n source,\n propertyData,\n });\n }\n }\n\n return source;\n }\n\n async #generateGrantItemData(document) {\n logger.debug(`Generating grantItem rule lookups for ${document.name}...`, { document: deepClone(document) });\n for (const rule of document.system.rules.filter((r) => r.key === \"GrantItem\" && r.uuid.includes(\"{\"))) {\n logger.debug(\"Generating rule for...\", { document: deepClone(document), rule });\n const match = rule.uuid.match(/{(item|rule)\\|(.*?)}/);\n if (match) {\n const flagName = match[2].split(\".\").pop();\n const choiceSet = document.system.rules.find((rule) => rule.key === \"ChoiceSet\" && rule.flag === flagName)\n ?? document.system.rules.find((rule) => rule.key === \"ChoiceSet\");\n const choice = choiceSet ? (await this.#evaluateChoices(document, choiceSet)) : undefined;\n const value = choice?.value ?? undefined;\n if (!value) {\n logger.warn(\"Failed to resolve injected uuid\", {\n ruleData: choiceSet,\n flagName,\n key: match[1],\n prop: match[2],\n value,\n });\n } else {\n logger.debug(`Generated lookup ${value} for key ${document.name}`);\n }\n this.grantItemLookUp[rule.uuid] = {\n docId: document.id,\n key: rule.uuid,\n choice,\n uuid: value,\n flag: flagName,\n choiceSet,\n };\n this.grantItemLookUp[`${document._id}-${flagName}`] = {\n docId: document.id,\n key: rule.uuid,\n choice,\n uuid: value,\n flag: flagName,\n choiceSet,\n };\n this.grantItemLookUp[`${document._id}`] = {\n docId: document.id,\n key: rule.uuid,\n choice,\n uuid: value,\n flag: flagName,\n choiceSet,\n };\n this.grantItemLookUp[`${document._id}-${flagName}`] = {\n docId: document.id,\n key: rule.uuid,\n choice,\n uuid: value,\n flag: flagName,\n choiceSet,\n };\n } else {\n logger.error(\"Failed to resolve injected uuid\", {\n document,\n rule,\n });\n }\n }\n }\n\n async #checkRule(document, rule) {\n const tempActor = await this.#generateTempActor([document]);\n const cleansedRule = deepClone(rule);\n try {\n const item = tempActor.getEmbeddedDocument(\"Item\", document._id);\n const ruleElement = cleansedRule.key === \"ChoiceSet\"\n ? new game.pf2e.RuleElements.all.ChoiceSet(cleansedRule, item)\n : new game.pf2e.RuleElements.all.GrantItem(cleansedRule, item);\n const rollOptions = [tempActor.getRollOptions(), item.getRollOptions(\"item\")].flat();\n const choices = cleansedRule.key === \"ChoiceSet\"\n ? (await ruleElement.inflateChoices()).filter((c) => !c.predicate || c.predicate.test(rollOptions))\n : [ruleElement.resolveValue()];\n\n const isGood = cleansedRule.key === \"ChoiceSet\"\n ? (await this.#featureChoiceMatch(choices, false)) !== undefined\n : ruleElement.test(rollOptions);\n\n return isGood;\n } catch (err) {\n logger.error(\"Something has gone most wrong during rule checking\", {\n document,\n rule: cleansedRule,\n tempActor,\n });\n throw err;\n } finally {\n await Actor.deleteDocuments([tempActor._id]);\n }\n }\n\n // eslint-disable-next-line complexity\n async #addGrantedRules(document) {\n if (document.system.rules.length === 0) return;\n logger.debug(`addGrantedRules for ${document.name}`, duplicate(document));\n\n if (hasProperty(document, \"system.level.value\")\n && document.system.level.value > this.result.character.system.details.level.value\n ) {\n return;\n }\n\n // const rulesToKeep = document.system.rules.filter((r) => ![\"GrantItem\", \"ChoiceSet\", \"MartialProficiency\"].includes(r.key));\n const rulesToKeep = [];\n this.allFeatureRules[document._id] = deepClone(document.system.rules);\n this.autoAddedFeatureRules[document._id] = deepClone(document.system.rules.filter((r) => ![\"GrantItem\", \"ChoiceSet\"].includes(r.key)));\n await this.#generateGrantItemData(document);\n\n const grantRules = document.system.rules.filter((r) => r.key === \"GrantItem\");\n const choiceRules = document.system.rules.filter((r) => r.key === \"ChoiceSet\");\n\n for (const ruleTypes of [choiceRules, grantRules]) {\n for (const rawRuleEntry of ruleTypes) {\n const ruleEntry = deepClone(rawRuleEntry);\n logger.debug(`Checking ${document.name} rule key: ${ruleEntry.key}`);\n\n const lookupName = ruleEntry.flag ? `${document._id}-${ruleEntry.flag}` : document._id;\n\n logger.debug(\"Rule check, looking up\", {\n id: `${document._id}-${ruleEntry.flag}`,\n lookup: this.grantItemLookUp[lookupName],\n lookups: this.grantItemLookUp,\n ruleEntry,\n lookupName,\n });\n\n // have we pre-evaluated this choice?\n const choice = ruleEntry.key === \"ChoiceSet\"\n ? this.grantItemLookUp[lookupName]?.choice\n ? this.grantItemLookUp[lookupName].choice\n : await this.#evaluateChoices(document, ruleEntry)\n : undefined;\n\n const uuid = ruleEntry.key === \"GrantItem\"\n ? await this.#resolveInjectedUuid(ruleEntry.uuid, ruleEntry)\n : choice?.value;\n\n logger.debug(`UUID for ${document.name}: \"${uuid}\"`, document, ruleEntry, choice);\n const ruleFeature = uuid ? await fromUuid(uuid) : undefined;\n if (ruleFeature) {\n const featureDoc = ruleFeature.toObject();\n featureDoc._id = foundry.utils.randomID();\n if (featureDoc.system.rules) this.allFeatureRules[document._id] = deepClone(document.system.rules);\n setProperty(featureDoc, \"flags.pathmuncher.origin.uuid\", uuid);\n if (this.autoAddedFeatureIds.has(`${ruleFeature.id}${ruleFeature.type}`)) {\n logger.debug(`Feature ${featureDoc.name} found for ${document.name}, but has already been added (${ruleFeature.id})`, ruleFeature);\n continue;\n }\n logger.debug(`Found rule feature ${featureDoc.name} for ${document.name} for`, ruleEntry);\n\n if (ruleEntry.predicate) {\n const testResult = await this.#checkRule(featureDoc, ruleEntry);\n // eslint-disable-next-line max-depth\n if (!testResult) {\n const data = { document, ruleEntry, featureDoc, testResult };\n logger.debug(`The test failed for ${document.name} rule key: ${ruleFeature.key} (This is probably not a problem).`, data);\n continue;\n }\n }\n if (choice) {\n ruleEntry.selection = choice.value;\n }\n this.autoAddedFeatureIds.add(`${ruleFeature.id}${ruleFeature.type}`);\n featureDoc._id = foundry.utils.randomID();\n this.#createGrantedItem(featureDoc, document);\n if (hasProperty(ruleFeature, \"system.rules.length\")) await this.#addGrantedRules(featureDoc);\n } else if (choice?.nouuid) {\n logger.debug(\"Parsed no id rule\", { choice, uuid, ruleEntry });\n if (!ruleEntry.flag) ruleEntry.flag = game.pf2e.system.sluggify(document.name, { camel: \"dromedary\" });\n ruleEntry.selection = choice.value;\n if (choice.label) document.name = `${document.name} (${choice.label})`;\n } else if (choice && uuid && !hasProperty(ruleEntry, \"selection\")) {\n logger.debug(\"Parsed odd choice rule\", { choice, uuid, ruleEntry });\n if (!ruleEntry.flag) ruleEntry.flag = game.pf2e.system.sluggify(document.name, { camel: \"dromedary\" });\n ruleEntry.selection = choice.value;\n if (ruleEntry.adjustName && choice.label) {\n const label = game.i18n.localize(choice.label);\n const name = `${document.name} (${label})`;\n const pattern = (() => {\n const escaped = RegExp.escape(label);\n return new RegExp(`\\\\(${escaped}\\\\) \\\\(${escaped}\\\\)$`);\n })();\n document.name = name.replace(pattern, `(${label})`);\n }\n } else {\n const data = {\n uuid: ruleEntry.uuid,\n document,\n ruleEntry,\n choice,\n lookup: this.grantItemLookUp[ruleEntry.uuid],\n };\n if (ruleEntry.key === \"GrantItem\" && this.grantItemLookUp[ruleEntry.uuid]) {\n rulesToKeep.push(ruleEntry);\n // const lookup = this.grantItemLookUp[ruleEntry.uuid].choiceSet\n // eslint-disable-next-line max-depth\n // if (!rulesToKeep.some((r) => r.key == lookup && r.prompt === lookup.prompt)) {\n // rulesToKeep.push(this.grantItemLookUp[ruleEntry.uuid].choiceSet);\n // }\n } else if (ruleEntry.key === \"ChoiceSet\" && !hasProperty(ruleEntry, \"flag\")) {\n logger.debug(\"Prompting user for choices\", ruleEntry);\n rulesToKeep.push(ruleEntry);\n }\n logger.warn(\"Unable to determine granted rule feature, needs better parser\", data);\n }\n this.autoAddedFeatureRules[document._id].push(ruleEntry);\n }\n }\n if (!this.options.askForChoices) {\n // eslint-disable-next-line require-atomic-updates\n document.system.rules = rulesToKeep;\n }\n }\n\n async #addGrantedItems(document) {\n if (hasProperty(document, \"system.items\")) {\n logger.debug(`addGrantedItems for ${document.name}`, duplicate(document));\n if (!this.autoAddedFeatureItems[document._id]) {\n this.autoAddedFeatureItems[document._id] = duplicate(document.system.items);\n }\n const failedFeatureItems = {};\n for (const [key, grantedItemFeature] of Object.entries(document.system.items)) {\n logger.debug(`Checking granted item ${document.name}, with key: ${key}`, grantedItemFeature);\n if (grantedItemFeature.level > getProperty(this.result.character, \"system.details.level.value\")) continue;\n const feature = await fromUuid(grantedItemFeature.uuid);\n if (!feature) {\n const data = { uuid: grantedItemFeature.uuid, grantedFeature: grantedItemFeature, feature };\n logger.warn(\"Unable to determine granted item feature, needs better parser\", data);\n failedFeatureItems[key] = grantedItemFeature;\n continue;\n }\n this.autoAddedFeatureIds.add(`${feature.id}${feature.type}`);\n const featureDoc = feature.toObject();\n featureDoc._id = foundry.utils.randomID();\n setProperty(featureDoc.system, \"location\", document._id);\n this.#createGrantedItem(featureDoc, document);\n if (hasProperty(featureDoc, \"system.rules\")) await this.#addGrantedRules(featureDoc);\n }\n if (!this.options.askForChoices) {\n // eslint-disable-next-line require-atomic-updates\n document.system.items = failedFeatureItems;\n }\n }\n if (hasProperty(document, \"system.rules\")) await this.#addGrantedRules(document);\n\n }\n\n async #detectGrantedFeatures() {\n if (this.result.class.length > 0) await this.#addGrantedItems(this.result.class[0]);\n if (this.result.ancestry.length > 0) await this.#addGrantedItems(this.result.ancestry[0]);\n if (this.result.heritage.length > 0) await this.#addGrantedItems(this.result.heritage[0]);\n if (this.result.background.length > 0) await this.#addGrantedItems(this.result.background[0]);\n }\n\n async #processCore() {\n setProperty(this.result.character, \"name\", this.source.name);\n setProperty(this.result.character, \"prototypeToken.name\", this.source.name);\n setProperty(this.result.character, \"system.details.level.value\", this.source.level);\n if (this.source.age !== \"Not set\") setProperty(this.result.character, \"system.details.age.value\", this.source.age);\n if (this.source.gender !== \"Not set\") setProperty(this.result.character, \"system.details.gender.value\", this.source.gender);\n setProperty(this.result.character, \"system.details.alignment.value\", this.source.alignment);\n setProperty(this.result.character, \"system.details.keyability.value\", this.source.keyability);\n if (this.source.deity !== \"Not set\") setProperty(this.result.character, \"system.details.deity.value\", this.source.deity);\n setProperty(this.result.character, \"system.traits.size.value\", Pathmuncher.getSizeValue(this.source.size));\n setProperty(this.result.character, \"system.traits.languages.value\", this.source.languages.map((l) => l.toLowerCase()));\n\n this.#processSenses();\n\n setProperty(this.result.character, \"system.abilities.str.value\", this.source.abilities.str);\n setProperty(this.result.character, \"system.abilities.dex.value\", this.source.abilities.dex);\n setProperty(this.result.character, \"system.abilities.con.value\", this.source.abilities.con);\n setProperty(this.result.character, \"system.abilities.int.value\", this.source.abilities.int);\n setProperty(this.result.character, \"system.abilities.wis.value\", this.source.abilities.wis);\n setProperty(this.result.character, \"system.abilities.cha.value\", this.source.abilities.cha);\n\n setProperty(this.result.character, \"system.saves.fortitude.tank\", this.source.proficiencies.fortitude / 2);\n setProperty(this.result.character, \"system.saves.reflex.value\", this.source.proficiencies.reflex / 2);\n setProperty(this.result.character, \"system.saves.will.value\", this.source.proficiencies.will / 2);\n\n setProperty(this.result.character, \"system.martial.advanced.rank\", this.source.proficiencies.advanced / 2);\n setProperty(this.result.character, \"system.martial.heavy.rank\", this.source.proficiencies.heavy / 2);\n setProperty(this.result.character, \"system.martial.light.rank\", this.source.proficiencies.light / 2);\n setProperty(this.result.character, \"system.martial.medium.rank\", this.source.proficiencies.medium / 2);\n setProperty(this.result.character, \"system.martial.unarmored.rank\", this.source.proficiencies.unarmored / 2);\n setProperty(this.result.character, \"system.martial.martial.rank\", this.source.proficiencies.martial / 2);\n setProperty(this.result.character, \"system.martial.simple.rank\", this.source.proficiencies.simple / 2);\n setProperty(this.result.character, \"system.martial.unarmed.rank\", this.source.proficiencies.unarmed / 2);\n\n setProperty(this.result.character, \"system.skills.acr.rank\", this.source.proficiencies.acrobatics / 2);\n setProperty(this.result.character, \"system.skills.arc.rank\", this.source.proficiencies.arcana / 2);\n setProperty(this.result.character, \"system.skills.ath.rank\", this.source.proficiencies.athletics / 2);\n setProperty(this.result.character, \"system.skills.cra.rank\", this.source.proficiencies.crafting / 2);\n setProperty(this.result.character, \"system.skills.dec.rank\", this.source.proficiencies.deception / 2);\n setProperty(this.result.character, \"system.skills.dip.rank\", this.source.proficiencies.diplomacy / 2);\n setProperty(this.result.character, \"system.skills.itm.rank\", this.source.proficiencies.intimidation / 2);\n setProperty(this.result.character, \"system.skills.med.rank\", this.source.proficiencies.medicine / 2);\n setProperty(this.result.character, \"system.skills.nat.rank\", this.source.proficiencies.nature / 2);\n setProperty(this.result.character, \"system.skills.occ.rank\", this.source.proficiencies.occultism / 2);\n setProperty(this.result.character, \"system.skills.prf.rank\", this.source.proficiencies.performance / 2);\n setProperty(this.result.character, \"system.skills.rel.rank\", this.source.proficiencies.religion / 2);\n setProperty(this.result.character, \"system.skills.soc.rank\", this.source.proficiencies.society / 2);\n setProperty(this.result.character, \"system.skills.ste.rank\", this.source.proficiencies.stealth / 2);\n setProperty(this.result.character, \"system.skills.sur.rank\", this.source.proficiencies.survival / 2);\n setProperty(this.result.character, \"system.skills.thi.rank\", this.source.proficiencies.thievery / 2);\n\n setProperty(this.result.character, \"system.attributes.perception.rank\", this.source.proficiencies.perception / 2);\n setProperty(this.result.character, \"system.attributes.classDC.rank\", this.source.proficiencies.classDC / 2);\n }\n\n #indexFind(index, arrayOfNameMatches) {\n for (const name of arrayOfNameMatches) {\n const indexMatch = index.find((i) =>\n i.system.slug === game.pf2e.system.sluggify(name)\n || i.system.slug === game.pf2e.system.sluggify(this.getClassAdjustedSpecialNameLowerCase(name))\n || i.system.slug === game.pf2e.system.sluggify(this.getAncestryAdjustedSpecialNameLowerCase(name))\n || i.system.slug === game.pf2e.system.sluggify(this.getHeritageAdjustedSpecialNameLowerCase(name))\n || (game.settings.get(\"pf2e\", \"dualClassVariant\")\n && (i.system.slug === game.pf2e.system.sluggify(this.getDualClassAdjustedSpecialNameLowerCase(name))\n )\n )\n );\n if (indexMatch) return indexMatch;\n }\n return undefined;\n }\n\n async #generateFeatItems(compendiumLabel) {\n const compendium = await game.packs.get(compendiumLabel);\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n\n this.parsed.feats.sort((f1, f2) => {\n const f1RefUndefined = !(typeof f1.type === \"string\" || f1.type instanceof String);\n const f2RefUndefined = !(typeof f2.type === \"string\" || f2.type instanceof String);\n if (f1RefUndefined || f2RefUndefined) {\n if (f1RefUndefined && f2RefUndefined) {\n return 0;\n } else if (f1RefUndefined) {\n return 1;\n } else {\n return -1;\n }\n }\n return 0;\n });\n for (const featArray of [this.parsed.feats, this.parsed.specials]) {\n for (const pBFeat of featArray) {\n if (pBFeat.added) continue;\n logger.debug(\"Generating feature for\", pBFeat);\n\n const indexMatch = this.#indexFind(index, [pBFeat.name, pBFeat.originalName]);\n const displayName = pBFeat.extra ? `${pBFeat.name} (${pBFeat.extra})` : pBFeat.name;\n if (!indexMatch) {\n logger.debug(`Unable to match feat ${displayName}`, { displayName, name: pBFeat.name, extra: pBFeat.extra, pBFeat, compendiumLabel });\n this.check[pBFeat.originalName] = { name: displayName, type: \"feat\", details: { displayName, name: pBFeat.name, originalName: pBFeat.originalName, extra: pBFeat.extra, pBFeat, compendiumLabel } };\n continue;\n }\n if (this.check[pBFeat.originalName]) delete this.check[pBFeat.originalName];\n pBFeat.added = true;\n if (this.autoAddedFeatureIds.has(`${indexMatch._id}${indexMatch.type}`)) {\n logger.debug(\"Feat included in class features auto add\", { displayName, pBFeat, compendiumLabel });\n continue;\n }\n\n const doc = await compendium.getDocument(indexMatch._id);\n const item = doc.toObject();\n item._id = foundry.utils.randomID();\n item.name = displayName;\n\n this.#generateFoundryFeatLocation(item, pBFeat);\n this.result.feats.push(item);\n await this.#addGrantedItems(item);\n }\n }\n }\n\n async #generateSpecialItems(compendiumLabel) {\n const compendium = await game.packs.get(compendiumLabel);\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n\n for (const special of this.parsed.specials) {\n if (special.added) continue;\n logger.debug(\"Generating special for\", special);\n const indexMatch = this.#indexFind(index, [special.name, special.originalName]);\n if (!indexMatch) {\n logger.debug(`Unable to match special ${special.name}`, { special: special.name, compendiumLabel });\n this.check[special.originalName] = { name: special.name, type: \"special\", details: { displayName: special.name, name: special.name, originalName: special.originalName, special } };\n continue;\n }\n special.added = true;\n if (this.check[special.originalName]) delete this.check[special.originalName];\n if (this.autoAddedFeatureIds.has(`${indexMatch._id}${indexMatch.type}`)) {\n logger.debug(\"Special included in class features auto add\", { special: special.name, compendiumLabel });\n continue;\n }\n\n const doc = await compendium.getDocument(indexMatch._id);\n const docData = doc.toObject();\n docData._id = foundry.utils.randomID();\n this.result.feats.push(docData);\n await this.#addGrantedItems(docData);\n }\n }\n\n async #generateEquipmentItems(pack = \"pf2e.equipment-srd\") {\n const compendium = game.packs.get(pack);\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n const compendiumBackpack = await compendium.getDocument(\"3lgwjrFEsQVKzhh7\");\n\n const adventurersPack = this.parsed.equipment.find((e) => e.pbName === \"Adventurer's Pack\");\n const backpackInstance = adventurersPack ? compendiumBackpack.toObject() : null;\n if (backpackInstance) {\n adventurersPack.added = true;\n backpackInstance._id = foundry.utils.randomID();\n this.result.adventurersPack.item = adventurersPack;\n this.result.equipment.push(backpackInstance);\n for (const content of this.result.adventurersPack.contents) {\n const indexMatch = index.find((i) => i.system.slug === content.slug);\n if (!indexMatch) {\n logger.error(`Unable to match adventurers kit item ${content.name}`, content);\n continue;\n }\n\n const doc = await compendium.getDocument(indexMatch._id);\n const itemData = doc.toObject();\n itemData._id = foundry.utils.randomID();\n itemData.system.quantity = content.qty;\n itemData.system.containerId = backpackInstance?._id;\n this.result.equipment.push(itemData);\n }\n }\n\n for (const e of this.parsed.equipment) {\n if (e.pbName === \"Adventurer's Pack\") continue;\n if (e.added) continue;\n if (this.IGNORED_EQUIPMENT.includes(e.pbName)) {\n e.added = true;\n continue;\n }\n logger.debug(\"Generating item for\", e);\n const indexMatch = index.find((i) => i.system.slug === game.pf2e.system.sluggify(e.pbName));\n if (!indexMatch) {\n logger.error(`Unable to match ${e.pbName}`, e);\n this.bad.push({ pbName: e.pbName, type: \"equipment\", details: { e } });\n continue;\n }\n\n const doc = await compendium.getDocument(indexMatch._id);\n if (doc.type != \"kit\") {\n const itemData = doc.toObject();\n itemData._id = foundry.utils.randomID();\n itemData.system.quantity = e.qty;\n const type = doc.type === \"treasure\" ? \"treasure\" : \"equipment\";\n this.result[type].push(itemData);\n }\n // eslint-disable-next-line require-atomic-updates\n e.added = true;\n }\n }\n\n async #generateWeaponItems() {\n const compendium = game.packs.get(\"pf2e.equipment-srd\");\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n\n for (const w of this.parsed.weapons) {\n if (this.IGNORED_EQUIPMENT.includes(w.pbName)) {\n w.added = true;\n continue;\n }\n logger.debug(\"Generating weapon for\", w);\n const indexMatch = index.find((i) => i.system.slug === game.pf2e.system.sluggify(w.pbName));\n if (!indexMatch) {\n logger.error(`Unable to match weapon item ${w.name}`, w);\n this.bad.push({ pbName: w.pbName, type: \"weapon\", details: { w } });\n continue;\n }\n\n const doc = await compendium.getDocument(indexMatch._id);\n const itemData = doc.toObject();\n itemData._id = foundry.utils.randomID();\n itemData.system.quantity = w.qty;\n itemData.system.damage.die = w.die;\n itemData.system.potencyRune.value = w.pot;\n itemData.system.strikingRune.value = w.str;\n\n if (w.runes[0]) itemData.system.propertyRune1.value = game.pf2e.system.sluggify(w.runes[0], { camel: \"dromedary\" });\n if (w.runes[1]) itemData.system.propertyRune2.value = game.pf2e.system.sluggify(w.runes[1], { camel: \"dromedary\" });\n if (w.runes[2]) itemData.system.propertyRune3.value = game.pf2e.system.sluggify(w.runes[2], { camel: \"dromedary\" });\n if (w.runes[3]) itemData.system.propertyRune4.value = game.pf2e.system.sluggify(w.runes[3], { camel: \"dromedary\" });\n if (w.mat) {\n const material = w.mat.split(\" (\")[0];\n itemData.system.preciousMaterial.value = game.pf2e.system.sluggify(material, { camel: \"dromedary\" });\n itemData.system.preciousMaterialGrade.value = Pathmuncher.getMaterialGrade(w.mat);\n }\n if (w.display) itemData.name = w.display;\n\n this.result.weapons.push(itemData);\n w.added = true;\n }\n }\n\n async #generateArmorItems() {\n const compendium = game.packs.get(\"pf2e.equipment-srd\");\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n\n for (const a of this.parsed.armor) {\n if (this.IGNORED_EQUIPMENT.includes(a.pbName)) {\n a.added = true;\n continue;\n }\n logger.debug(\"Generating armor for\", a);\n const indexMatch = index.find((i) =>\n i.system.slug === game.pf2e.system.sluggify(a.pbName)\n || i.system.slug === game.pf2e.system.sluggify(`${a.pbName} Armor`)\n );\n if (!indexMatch) {\n logger.error(`Unable to match armor kit item ${a.name}`, a);\n this.bad.push({ pbName: a.pbName, type: \"armor\", details: { a } });\n continue;\n }\n\n const doc = await compendium.getDocument(indexMatch._id);\n const itemData = doc.toObject();\n itemData._id = foundry.utils.randomID();\n itemData.system.equipped.value = a.worn ?? false;\n if (!this.RESTRICTED_EQUIPMENT.some((i) => itemData.name.startsWith(i))) {\n itemData.system.equipped.inSlot = a.worn ?? false;\n itemData.system.quantity = a.qty;\n itemData.system.category = a.prof;\n itemData.system.potencyRune.value = a.pot;\n itemData.system.resiliencyRune.value = a.res;\n\n const isShield = itemData.system.category === \"shield\";\n itemData.system.equipped.handsHeld = isShield && a.worn ? 1 : 0;\n itemData.system.equipped.carryType = isShield && a.worn ? \"held\" : \"worn\";\n\n if (a.runes[0]) itemData.system.propertyRune1.value = game.pf2e.system.sluggify(a.runes[0], { camel: \"dromedary\" });\n if (a.runes[1]) itemData.system.propertyRune2.value = game.pf2e.system.sluggify(a.runes[1], { camel: \"dromedary\" });\n if (a.runes[2]) itemData.system.propertyRune3.value = game.pf2e.system.sluggify(a.runes[2], { camel: \"dromedary\" });\n if (a.runes[3]) itemData.system.propertyRune4.value = game.pf2e.system.sluggify(a.runes[3], { camel: \"dromedary\" });\n if (a.mat) {\n const material = a.mat.split(\" (\")[0];\n itemData.system.preciousMaterial.value = game.pf2e.system.sluggify(material, { camel: \"dromedary\" });\n itemData.system.preciousMaterialGrade.value = Pathmuncher.getMaterialGrade(a.mat);\n }\n }\n if (a.display) itemData.name = a.display;\n\n this.result.armor.push(itemData);\n // eslint-disable-next-line require-atomic-updates\n a.added = true;\n }\n }\n\n getClassSpellCastingType(dual = false) {\n const classCaster = dual\n ? this.source.spellCasters.find((caster) => caster.name === this.source.dualClass)\n : this.source.spellCasters.find((caster) => caster.name === this.source.class);\n const type = classCaster?.spellcastingType;\n if (type || this.source.spellCasters.length === 0) return type ?? \"spontaneous\";\n // if no type and multiple spell casters, then return the first spell casting type\n return this.source.spellCasters[0].spellcastingType ?? \"spontaneous\";\n }\n\n // aims to determine the class magic tradition for a spellcasting block\n getClassMagicTradition(caster) {\n const classCaster = [this.source.class, this.source.dualClass].includes(caster.name);\n const tradition = classCaster\n ? caster?.magicTradition\n : undefined;\n // if a caster tradition or no spellcasters, return divine\n if (tradition || this.source.spellCasters.length === 0) return tradition ?? \"divine\";\n // this spell caster type is not a class, determine class tradition based on ability\n const abilityTradition = this.source.spellCasters.find((c) =>\n [this.source.class, this.source.dualClass].includes(c.name)\n && c.ability === caster.ability\n );\n if (abilityTradition) return abilityTradition.magicTradition;\n // final fallback\n // if no type and multiple spell casters, then return the first spell casting type\n return this.source.spellCasters[0].magicTradition && this.source.spellCasters[0].magicTradition !== \"focus\"\n ? this.source.spellCasters[0].magicTradition\n : \"divine\";\n }\n\n async #generateSpellCaster(caster) {\n const isFocus = caster.magicTradition === \"focus\";\n const magicTradition = this.getClassMagicTradition(caster);\n const spellcastingType = isFocus ? \"focus\" : caster.spellcastingType;\n const flexible = false; // placeholder\n\n const name = isFocus ? `${utils.capitalize(magicTradition)} ${caster.name}` : caster.name;\n\n const spellcastingEntity = {\n ability: {\n value: caster.ability,\n },\n proficiency: {\n value: caster.proficiency / 2,\n },\n spelldc: {\n item: 0,\n },\n tradition: {\n value: magicTradition,\n },\n prepared: {\n value: spellcastingType,\n flexible,\n },\n slots: {\n slot0: {\n max: caster.perDay[0],\n prepared: {},\n value: caster.perDay[0],\n },\n slot1: {\n max: caster.perDay[1],\n prepared: {},\n value: caster.perDay[1],\n },\n slot2: {\n max: caster.perDay[2],\n prepared: {},\n value: caster.perDay[2],\n },\n slot3: {\n max: caster.perDay[3],\n prepared: {},\n value: caster.perDay[3],\n },\n slot4: {\n max: caster.perDay[4],\n prepared: {},\n value: caster.perDay[4],\n },\n slot5: {\n max: caster.perDay[5],\n prepared: {},\n value: caster.perDay[5],\n },\n slot6: {\n max: caster.perDay[6],\n prepared: {},\n value: caster.perDay[6],\n },\n slot7: {\n max: caster.perDay[7],\n prepared: {},\n value: caster.perDay[7],\n },\n slot8: {\n max: caster.perDay[8],\n prepared: {},\n value: caster.perDay[8],\n },\n slot9: {\n max: caster.perDay[9],\n prepared: {},\n value: caster.perDay[9],\n },\n slot10: {\n max: caster.perDay[10],\n prepared: {},\n value: caster.perDay[10],\n },\n },\n showUnpreparedSpells: { value: true },\n };\n const data = {\n _id: foundry.utils.randomID(),\n name,\n type: \"spellcastingEntry\",\n system: spellcastingEntity,\n };\n this.result.casters.push(data);\n return data;\n }\n\n async #processSpells() {\n const compendium = game.packs.get(\"pf2e.spells-srd\");\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n\n const psiCompendium = game.packs.get(\"pf2e-psychic-amps.psychic-psi-cantrips\");\n const psiIndex = psiCompendium ? await psiCompendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] }) : undefined;\n\n for (const caster of this.source.spellCasters) {\n logger.debug(\"Generating caster for\", caster);\n if (Number.isInteger(parseInt(caster.focusPoints))) this.result.focusPool += caster.focusPoints;\n const instance = await this.#generateSpellCaster(caster);\n logger.debug(\"Generated caster instance\", instance);\n\n for (const spellSelection of caster.spells) {\n const level = spellSelection.spellLevel;\n\n for (const [i, spell] of spellSelection.list.entries()) {\n const spellName = spell.split(\"(\")[0].trim();\n logger.debug(\"spell details\", { spell, spellName, spellSelection, list: spellSelection.list });\n\n const psiMatch = psiIndex ? psiIndex.find((i) => i.name === spell) : undefined;\n const indexMatch = index.find((i) => i.system.slug === game.pf2e.system.sluggify(spellName));\n if (!indexMatch && !psiMatch) {\n logger.error(`Unable to match spell ${spell}`, { spell, spellName, spellSelection, caster, instance });\n this.bad.push({ pbName: spell, type: \"spell\", details: { originalName: spell, name: spellName, spellSelection, caster } });\n continue;\n }\n\n const doc = psiMatch\n ? await psiCompendium.getDocument(psiMatch._id)\n : await compendium.getDocument(indexMatch._id);\n const itemData = doc.toObject();\n itemData._id = foundry.utils.randomID();\n itemData.system.location.heightenedLevel = level;\n itemData.system.location.value = instance._id;\n this.result.spells.push(itemData);\n\n instance.system.slots[`slot${level}`].prepared[i] = { id: itemData._id };\n }\n }\n }\n\n setProperty(this.result.character, \"system.resources.focus.max\", this.result.focusPool);\n setProperty(this.result.character, \"system.resources.focus.value\", this.result.focusPool);\n }\n\n async #generateLores() {\n for (const lore of this.source.lores) {\n const data = {\n name: lore[0],\n type: \"lore\",\n system: {\n proficient: {\n value: lore[1] / 2,\n },\n featType: \"\",\n mod: {\n value: 0,\n },\n item: {\n value: 0,\n },\n },\n };\n this.result.lores.push(data);\n }\n }\n\n async #generateMoney() {\n const compendium = game.packs.get(\"pf2e.equipment-srd\");\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n const moneyLookup = [\n { slug: \"platinum-pieces\", type: \"pp\" },\n { slug: \"gold-pieces\", type: \"gp\" },\n { slug: \"silver-pieces\", type: \"sp\" },\n { slug: \"copper-pieces\", type: \"cp\" },\n ];\n\n for (const lookup of moneyLookup) {\n const indexMatch = index.find((i) => i.system.slug === lookup.slug);\n if (indexMatch) {\n const doc = await compendium.getDocument(indexMatch._id);\n const itemData = doc.toObject();\n itemData._id = foundry.utils.randomID();\n itemData.system.quantity = this.source.money[lookup.type];\n this.result.money.push(itemData);\n }\n }\n }\n\n async #processFormulas() {\n const compendium = game.packs.get(\"pf2e.equipment-srd\");\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n const uuids = [];\n\n for (const formulaSource of this.source.formula) {\n for (const formulaName of formulaSource.known) {\n const indexMatch = index.find((i) => i.system.slug === game.pf2e.system.sluggify(formulaName));\n if (!indexMatch) {\n logger.error(`Unable to match formula ${formulaName}`, { formulaSource, name: formulaName });\n this.bad.push({ pbName: formulaName, type: \"formula\", details: { formulaSource, name: formulaName } });\n continue;\n }\n const doc = await compendium.getDocument(indexMatch._id);\n uuids.push({ uuid: doc.uuid });\n }\n }\n setProperty(this.result.character, \"system.crafting.formulas\", uuids);\n }\n\n async #processFeats() {\n await this.#generateFeatItems(\"pf2e.feats-srd\");\n await this.#generateFeatItems(\"pf2e.ancestryfeatures\");\n await this.#generateSpecialItems(\"pf2e.ancestryfeatures\");\n await this.#generateSpecialItems(\"pf2e.classfeatures\");\n await this.#generateSpecialItems(\"pf2e.actionspf2e\");\n }\n\n async #processEquipment() {\n await this.#generateEquipmentItems();\n await this.#generateWeaponItems();\n await this.#generateArmorItems();\n await this.#generateMoney();\n }\n\n async #generateTempActor(documents = []) {\n const actorData = mergeObject({ type: \"character\" }, this.result.character);\n actorData.name = \"Mr Temp\";\n const actor = await Actor.create(actorData);\n const currentState = duplicate(this.result);\n\n const currentItems = [\n ...(this.options.askForChoices ? this.autoFeats : []),\n ...currentState.feats,\n ...currentState.class,\n ...currentState.background,\n ...currentState.ancestry,\n ...currentState.heritage,\n ...currentState.deity,\n ...currentState.lores,\n ];\n for (const doc of documents) {\n if (!currentItems.some((d) => d._id === doc._id)) {\n currentItems.push(doc);\n }\n }\n try {\n const items = duplicate(currentItems).map((i) => {\n if (i.system.items) i.system.items = [];\n if (i.system.rules) i.system.rules = [];\n return i;\n });\n\n await actor.createEmbeddedDocuments(\"Item\", items, { keepId: true });\n const ruleIds = currentItems.map((i) => i._id);\n const ruleUpdates = [];\n for (const [key, value] of Object.entries(this.allFeatureRules)) {\n if (ruleIds.includes(key)) {\n ruleUpdates.push({\n _id: key,\n system: {\n // rules: value,\n rules: value.filter((r) => [\"GrantItem\", \"ChoiceSet\", \"RollOption\"].includes(r.key)),\n },\n });\n }\n }\n // console.warn(\"rule updates\", ruleUpdates);\n await actor.updateEmbeddedDocuments(\"Item\", ruleUpdates);\n\n const itemUpdates = [];\n for (const [key, value] of Object.entries(this.autoAddedFeatureItems)) {\n itemUpdates.push({\n _id: `${key}`,\n system: {\n items: deepClone(value),\n },\n });\n }\n\n for (const doc of documents) {\n if (getProperty(doc, \"system.rules\")?.length > 0 && !ruleUpdates.some((r) => r._id === doc._id)) {\n ruleUpdates.push({\n _id: doc._id,\n system: {\n rules: deepClone(doc.system.rules),\n },\n });\n }\n }\n\n await actor.updateEmbeddedDocuments(\"Item\", itemUpdates);\n\n logger.debug(\"Final temp actor\", actor);\n } catch (err) {\n logger.error(\"Temp actor creation failed\", {\n actor,\n documents,\n thisData: deepClone(this.result),\n actorData,\n err,\n currentItems,\n this: this,\n });\n }\n return actor;\n }\n\n async processCharacter() {\n if (!this.source) return;\n this.#prepare();\n await this.#processCore();\n await this.#processFormulas();\n await this.#processGenericCompendiumLookup(\"pf2e.deities\", this.source.deity, \"deity\");\n await this.#processGenericCompendiumLookup(\"pf2e.backgrounds\", this.source.background, \"background\");\n await this.#processGenericCompendiumLookup(\"pf2e.classes\", this.source.class, \"class\");\n await this.#processGenericCompendiumLookup(\"pf2e.ancestries\", this.source.ancestry, \"ancestry\");\n await this.#processGenericCompendiumLookup(\"pf2e.heritages\", this.source.heritage, \"heritage\");\n await this.#detectGrantedFeatures();\n await this.#processFeats();\n await this.#processEquipment();\n await this.#processSpells();\n await this.#generateLores();\n }\n\n async #removeDocumentsToBeUpdated() {\n const moneyIds = this.actor.items.filter((i) =>\n i.type === \"treasure\"\n && [\"Platinum Pieces\", \"Gold Pieces\", \"Silver Pieces\", \"Copper Pieces\"].includes(i.name)\n );\n const classIds = this.actor.items.filter((i) => i.type === \"class\").map((i) => i._id);\n const deityIds = this.actor.items.filter((i) => i.type === \"deity\").map((i) => i._id);\n const backgroundIds = this.actor.items.filter((i) => i.type === \"background\").map((i) => i._id);\n const heritageIds = this.actor.items.filter((i) => i.type === \"heritage\").map((i) => i._id);\n const ancestryIds = this.actor.items.filter((i) => i.type === \"ancestry\").map((i) => i._id);\n const treasureIds = this.actor.items.filter((i) => i.type === \"treasure\" && !moneyIds.includes(i.id)).map((i) => i._id);\n const featIds = this.actor.items.filter((i) => i.type === \"feat\").map((i) => i._id);\n const actionIds = this.actor.items.filter((i) => i.type === \"action\").map((i) => i._id);\n const equipmentIds = this.actor.items.filter((i) =>\n i.type === \"equipment\" || i.type === \"backpack\" || i.type === \"consumable\"\n ).map((i) => i._id);\n const weaponIds = this.actor.items.filter((i) => i.type === \"weapon\").map((i) => i._id);\n const armorIds = this.actor.items.filter((i) => i.type === \"armor\").map((i) => i._id);\n const loreIds = this.actor.items.filter((i) => i.type === \"lore\").map((i) => i._id);\n const spellIds = this.actor.items.filter((i) => i.type === \"spell\" || i.type === \"spellcastingEntry\").map((i) => i._id);\n const formulaIds = this.actor.system.formulas;\n\n logger.debug(\"ids\", {\n moneyIds,\n deityIds,\n classIds,\n backgroundIds,\n heritageIds,\n ancestryIds,\n treasureIds,\n featIds,\n actionIds,\n equipmentIds,\n weaponIds,\n armorIds,\n loreIds,\n spellIds,\n formulaIds,\n });\n // eslint-disable-next-line complexity\n const keepIds = this.actor.items.filter((i) =>\n (!this.options.addMoney && moneyIds.includes(i._id))\n || (!this.options.addClass && classIds.includes(i._id))\n || (!this.options.addDeity && deityIds.includes(i._id))\n || (!this.options.addBackground && backgroundIds.includes(i._id))\n || (!this.options.addHeritage && heritageIds.includes(i._id))\n || (!this.options.addAncestry && ancestryIds.includes(i._id))\n || (!this.options.addTreasure && treasureIds.includes(i._id))\n || (!this.options.addFeats && (featIds.includes(i._id) || actionIds.includes(i._id)))\n || (!this.options.addEquipment && equipmentIds.includes(i._id))\n || (!this.options.addWeapons && weaponIds.includes(i._id))\n || (!this.options.addArmor && armorIds.includes(i._id))\n || (!this.options.addLores && loreIds.includes(i._id))\n || (!this.options.addSpells && spellIds.includes(i._id))\n ).map((i) => i._id);\n\n const deleteIds = this.actor.items.filter((i) => !keepIds.includes(i._id)).map((i) => i._id);\n logger.debug(\"ids\", {\n deleteIds,\n keepIds,\n });\n await this.actor.deleteEmbeddedDocuments(\"Item\", deleteIds);\n\n }\n\n async #createActorEmbeddedDocuments() {\n if (this.options.addDeity) await this.actor.createEmbeddedDocuments(\"Item\", this.result.deity, { keepId: true });\n if (this.options.addAncestry) await this.actor.createEmbeddedDocuments(\"Item\", this.result.ancestry, { keepId: true });\n if (this.options.addHeritage) await this.actor.createEmbeddedDocuments(\"Item\", this.result.heritage, { keepId: true });\n if (this.options.addBackground) await this.actor.createEmbeddedDocuments(\"Item\", this.result.background, { keepId: true });\n if (this.options.addClass) await this.actor.createEmbeddedDocuments(\"Item\", this.result.class, { keepId: true });\n if (this.options.addLores) await this.actor.createEmbeddedDocuments(\"Item\", this.result.lores, { keepId: true });\n // for (const feat of this.result.feats.reverse()) {\n // console.warn(`creating ${feat.name}`, feat);\n // await this.actor.createEmbeddedDocuments(\"Item\", [feat], { keepId: true });\n // }\n if (this.options.addFeats) await this.actor.createEmbeddedDocuments(\"Item\", this.result.feats, { keepId: true });\n if (this.options.addSpells) {\n await this.actor.createEmbeddedDocuments(\"Item\", this.result.casters, { keepId: true });\n await this.actor.createEmbeddedDocuments(\"Item\", this.result.spells, { keepId: true });\n }\n if (this.options.addEquipment) await this.actor.createEmbeddedDocuments(\"Item\", this.result.equipment, { keepId: true });\n if (this.options.addWeapons) await this.actor.createEmbeddedDocuments(\"Item\", this.result.weapons, { keepId: true });\n if (this.options.addArmor) {\n await this.actor.createEmbeddedDocuments(\"Item\", this.result.armor, { keepId: true });\n await this.actor.updateEmbeddedDocuments(\"Item\", this.result.armor, { keepId: true });\n }\n if (this.options.addTreasure) await this.actor.createEmbeddedDocuments(\"Item\", this.result.treasure, { keepId: true });\n if (this.options.addMoney) await this.actor.createEmbeddedDocuments(\"Item\", this.result.money, { keepId: true });\n }\n\n async #restoreEmbeddedRuleLogic() {\n const importedItems = this.actor.items.map((i) => i._id);\n // Loop back over items and add rule and item progression data back in.\n if (!this.options.askForChoices) {\n logger.debug(\"Restoring logic\", { currentActor: duplicate(this.actor) });\n const ruleUpdates = [];\n for (const [key, value] of Object.entries(this.autoAddedFeatureRules)) {\n if (importedItems.includes(key)) {\n ruleUpdates.push({\n _id: `${key}`,\n system: {\n rules: deepClone(value),\n },\n });\n }\n }\n logger.debug(\"Restoring rule logic\", ruleUpdates);\n await this.actor.updateEmbeddedDocuments(\"Item\", ruleUpdates);\n\n const itemUpdates = [];\n for (const [key, value] of Object.entries(this.autoAddedFeatureItems)) {\n if (importedItems.includes(key)) {\n itemUpdates.push({\n _id: `${key}`,\n system: {\n items: deepClone(value),\n },\n });\n }\n }\n logger.debug(\"Restoring granted item logic\", itemUpdates);\n await this.actor.updateEmbeddedDocuments(\"Item\", itemUpdates);\n }\n }\n\n async updateActor() {\n await this.#removeDocumentsToBeUpdated();\n\n if (!this.options.addName) {\n delete this.result.character.name;\n delete this.result.character.prototypeToken.name;\n }\n if (!this.options.addFormulas) {\n delete this.result.character.system.formulas;\n }\n\n logger.debug(\"Generated result\", this.result);\n await this.actor.update(this.result.character);\n await this.#createActorEmbeddedDocuments();\n await this.#restoreEmbeddedRuleLogic();\n }\n\n async postImportCheck() {\n const badClass = this.options.addClass\n ? this.bad.filter((b) => b.type === \"class\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Class\")}: ${b.pbName}</li>`)\n : [];\n const badHeritage = this.options.addHeritage\n ? this.bad.filter((b) => b.type === \"heritage\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Heritage\")}: ${b.pbName}</li>`)\n : [];\n const badAncestry = this.options.addAncestry\n ? this.bad.filter((b) => b.type === \"ancestry\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Ancestry\")}: ${b.pbName}</li>`)\n : [];\n const badBackground = this.options.addBackground\n ? this.bad.filter((b) => b.type === \"background\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Background\")}: ${b.pbName}</li>`)\n : [];\n const badDeity = this.options.addDeity\n ? this.bad.filter((b) => b.type === \"deity\" && b.pbName !== \"Not set\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Deity\")}: ${b.pbName}</li>`)\n : [];\n const badFeats = this.options.addFeats\n ? this.bad.filter((b) => b.type === \"feat\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Feats\")}: ${b.pbName}</li>`)\n : [];\n const badFeats2 = this.options.addFeats\n ? Object.values(this.check).filter((b) =>\n (b.type === \"feat\" || b.type === \"special\")\n && this.parsed.feats.concat(this.parsed.specials).some((f) => f.name === b.details.name && !f.added)\n ).map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Feats\")}: ${b.details.name}</li>`)\n : [];\n const badEquipment = this.options.addEquipment\n ? this.bad.filter((b) => b.type === \"equipment\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Equipment\")}: ${b.pbName}</li>`)\n : [];\n const badWeapons = this.options.addWeapons\n ? this.bad.filter((b) => b.type === \"weapons\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Weapons\")}: ${b.pbName}</li>`)\n : [];\n const badArmor = this.options.addArmor\n ? this.bad.filter((b) => b.type === \"armor\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Armor\")}: ${b.pbName}</li>`)\n : [];\n const badSpellcasting = this.options.addSpells\n ? this.bad.filter((b) => b.type === \"spellcasting\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Spellcasting\")}: ${b.pbName}</li>`)\n : [];\n const badSpells = this.options.addSpells\n ? this.bad.filter((b) => b.type === \"spells\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Spells\")}: ${b.pbName}</li>`)\n : [];\n const badFamiliars = this.options.addFamiliars\n ? this.bad.filter((b) => b.type === \"familiars\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Familiars\")}: ${b.pbName}</li>`)\n : [];\n const badFormulas = this.options.addFormulas\n ? this.bad.filter((b) => b.type === \"formulas\").map((b) => `<li>${game.i18n.localize(\"pathmuncher.Labels.Formulas\")}: ${b.pbName}</li>`)\n : [];\n const totalBad = [\n ...badClass,\n ...badAncestry,\n ...badHeritage,\n ...badBackground,\n ...badDeity,\n ...badFeats,\n ...badFeats2,\n ...badEquipment,\n ...badWeapons,\n ...badArmor,\n ...badSpellcasting,\n ...badSpells,\n ...badFamiliars,\n ...badFormulas,\n ];\n\n let warning = \"\";\n\n if (totalBad.length > 0) {\n warning += `<p>${game.i18n.localize(\"pathmuncher.Dialogs.Pathmuncher.MissingItemsOpen\")}</p><ul>${totalBad.join(\"\\n\")}</ul><br>`;\n }\n if (this.result.focusPool > 0) {\n warning += `<strong>${game.i18n.localize(\"pathmuncher.Dialogs.Pathmuncher.FocusSpells\")}</strong><br>`;\n }\n\n logger.debug(\"Bad thing check\", {\n badClass,\n badAncestry,\n badHeritage,\n badBackground,\n badDeity,\n badFeats,\n badFeats2,\n badEquipment,\n badWeapons,\n badArmor,\n badSpellcasting,\n badSpells,\n badFamiliars,\n badFormulas,\n totalBad,\n count: totalBad.length,\n focusPool: this.result.focusPool,\n warning,\n });\n\n if (totalBad.length > 0 || this.result.focusPool > 0) {\n ui.notifications.warn(game.i18n.localize(\"pathmuncher.Dialogs.Pathmuncher.CompletedWithNotes\"));\n new Dialog({\n title: game.i18n.localize(\"pathmuncher.Dialogs.Pathmuncher.ImportNotes\"),\n content: warning,\n buttons: {\n yes: {\n icon: \"<i class='fas fa-check'></i>\",\n label: game.i18n.localize(\"pathmuncher.Labels.Finished\"),\n },\n },\n default: \"yes\",\n }).render(true);\n } else {\n ui.notifications.info(game.i18n.localize(\"pathmuncher.Dialogs.Pathmuncher.CompletedSuccess\"));\n }\n }\n}\n","/* eslint-disable no-await-in-loop */\n/* eslint-disable no-continue */\n\nimport CONSTANTS from \"../constants.js\";\nimport logger from \"../logger.js\";\nimport utils from \"../utils.js\";\n\n/**\n * The PetShop class looks for familiars in a Pathmunch data set and creates/updates as appropriate.\n */\nexport class PetShop {\n\n\n constructor ({ parent, pathbuilderJson } = {}) {\n this.parent = parent;\n this.pathbuilderJson = pathbuilderJson;\n\n this.result = {\n pets: [],\n features: {},\n };\n\n this.bad = {};\n this.folders = {};\n }\n\n\n async ensureFolder(type) {\n const folderName = game.i18n.localize(`${CONSTANTS.MODULE_NAME}.Labels.${type}s`);\n this.folders[type] = await utils.getOrCreateFolder(parent.folder, \"Actor\", folderName);\n }\n\n async #existingPetCheck(familiarName, type) {\n const existingPet = game.actors.find((a) =>\n a.type === type.toLowerCase()\n && a.name === familiarName\n && a.system.master.id === this.parent._id\n );\n\n if (existingPet) return existingPet.toObject();\n\n const actorData = {\n type: type.toLowerCase(),\n name: familiarName,\n system: {\n master: {\n id: this.parent._id,\n ability: this.parent.system.details.keyability.value,\n },\n },\n prototypeToken: {\n name: familiarName,\n },\n folder: this.folders[type].id,\n };\n const actor = await Actor.create(actorData);\n return actor.toObject();\n\n }\n\n #buildCore(petData) {\n setProperty(petData, \"system.attributes.value\", this.parent.system.details.level.value * 5);\n return petData;\n }\n\n async #generatePetFeatures(pet, json) {\n const compendium = game.packs.get(\"pf2e.familiar-abilities\");\n const index = await compendium.getIndex({ fields: [\"name\", \"type\", \"system.slug\"] });\n this.result.features[pet._id] = [];\n this.bad[pet._id] = [];\n\n for (const featureName of json.abilities) {\n const indexMatch = index.find((i) => i.system.slug === game.pf2e.system.sluggify(featureName));\n if (!indexMatch) {\n logger.warn(`Unable to match pet feature ${featureName}`, { pet, json, name: featureName });\n this.bad[pet._id].push({ pbName: featureName, type: \"feature\", details: { pet, json, name: featureName } });\n continue;\n }\n const doc = (await compendium.getDocument(indexMatch._id)).toObject();\n doc._id = foundry.utils.randomID();\n this.result.features[pet._id].push(doc);\n }\n }\n\n async buildPet(json) {\n const name = json.name === json.type || !json.name.includes(\"(\")\n ? `${this.parent.name}'s ${json.type}`\n : json.name.split(\"(\")[1].split(\")\")[0];\n const petData = await this.#existingPetCheck(name, json.type);\n const pet = this.#buildCore(petData);\n await this.#generatePetFeatures(pet, json);\n this.result.pets.push(pet);\n }\n\n async updatePets() {\n for (const petData of this.result.pets) {\n const actor = game.actors.get(petData._id);\n await actor.deleteEmbeddedDocuments(\"Item\", [], { deleteAll: true });\n await actor.update(petData);\n await actor.createEmbeddedDocuments(\"Item\", this.result.features[petData._id], { keepId: true });\n }\n }\n\n async processPets() {\n\n for (const petJson of this.pathbuilderJson.pets) {\n // only support familiars at this time\n if (petJson.type !== \"Familiar\") {\n logger.warn(`Pets with type ${petJson.type} are not supported at this time`);\n continue;\n }\n await this.ensureFolder(petJson.type);\n await this.buildPet(petJson);\n }\n\n await this.updatePets();\n\n logger.debug(\"Pets\", {\n results: this.results,\n bad: this.bad,\n });\n }\n\n async addPetEffects() {\n const features = [];\n for (const petData of this.result.pets) {\n for (const feature of this.result.features[petData._id].filter((f) => f.system.rules?.some((r) => r.key === \"ActiveEffectLike\"))) {\n if (!this.parent.items.some((i) => i.type === \"effect\" && i.system.slug === feature.system.slug)) {\n features.push(feature);\n }\n }\n }\n await this.parent.createEmbeddedDocuments(\"Item\", features);\n }\n\n}\n","import CONSTANTS from \"../constants.js\";\nimport logger from \"../logger.js\";\nimport utils from \"../utils.js\";\nimport { Pathmuncher } from \"./Pathmuncher.js\";\nimport { PetShop } from \"./PetShop.js\";\n\nexport class PathmuncherImporter extends FormApplication {\n\n constructor(options, actor) {\n super(options);\n this.actor = game.actors.get(actor.id ? actor.id : actor._id);\n this.backup = duplicate(this.actor);\n this.mode = \"number\";\n }\n\n static get defaultOptions() {\n const options = super.defaultOptions;\n options.title = game.i18n.localize(`${CONSTANTS.FLAG_NAME}.Dialogs.PathmuncherImporter.Title`);\n options.template = `${CONSTANTS.PATH}/templates/pathmuncher.hbs`;\n options.classes = [\"pathmuncher\"];\n options.id = \"pathmuncher\";\n options.width = 400;\n options.closeOnSubmit = false;\n options.tabs = [{ navSelector: \".tabs\", contentSelector: \"form\", initial: \"number\" }];\n return options;\n }\n\n /** @override */\n async getData() {\n const flags = utils.getFlags(this.actor);\n\n return {\n flags,\n id: flags?.pathbuilderId ?? \"\",\n actor: this.actor,\n };\n }\n\n /** @override */\n activateListeners(html) {\n super.activateListeners(html);\n $(\"#pathmuncher\").css(\"height\", \"auto\");\n\n $(html)\n .find('.item')\n .on(\"click\", (event) => {\n if (!event.target?.dataset?.tab) return;\n this.mode = event.target.dataset.tab;\n });\n }\n\n static _updateProgress(total, count, type) {\n const localizedType = `pathmuncher.Label.${type}`;\n $(\".import-progress-bar\")\n .width(`${Math.trunc((count / total) * 100)}%`)\n .html(\n `<span>${game.i18n.localize(\"pathmuncher.Label.Working\")} (${game.i18n.localize(localizedType)})...</span>`\n );\n }\n\n async _updateObject(event, formData) {\n const pathbuilderId = formData.textBoxBuildID;\n const options = {\n pathbuilderId,\n addMoney: formData.checkBoxMoney,\n addFeats: formData.checkBoxFeats,\n addSpells: formData.checkBoxSpells,\n addEquipment: formData.checkBoxEquipment,\n addTreasure: formData.checkBoxTreasure,\n addLores: formData.checkBoxLores,\n addWeapons: formData.checkBoxWeapons,\n addArmor: formData.checkBoxArmor,\n addDeity: formData.checkBoxDeity,\n addName: formData.checkBoxName,\n addClass: formData.checkBoxClass,\n addBackground: formData.checkBoxBackground,\n addHeritage: formData.checkBoxHeritage,\n addAncestry: formData.checkBoxAncestry,\n addFamiliars: formData.checkBoxFamiliars,\n addFormulas: formData.checkBoxFormulas,\n askForChoices: formData.checkBoxAskForChoices,\n };\n logger.debug(\"Pathmuncher options\", options);\n\n await utils.setFlags(this.actor, options);\n\n const pathmuncher = new Pathmuncher(this.actor, options);\n if (this.mode === \"number\") {\n await pathmuncher.fetchPathbuilder(pathbuilderId);\n } else if (this.mode === \"json\") {\n try {\n const jsonData = JSON.parse(formData.textBoxBuildJSON);\n pathmuncher.source = jsonData.build;\n } catch (err) {\n ui.notifications.error(\"Unable to parse JSON data\");\n return;\n }\n }\n\n logger.debug(\"Pathmuncher Source\", pathmuncher.source);\n await pathmuncher.processCharacter();\n logger.debug(\"Post processed character\", pathmuncher);\n await pathmuncher.updateActor();\n logger.debug(\"Final import details\", {\n actor: this.actor,\n pathmuncher,\n options,\n pathbuilderSource: pathmuncher.source,\n pathbuilderId,\n });\n\n if (options.addFamiliars) {\n const petShop = new PetShop({ parent: this.actor, pathbuilderJson: pathmuncher.source });\n await petShop.processPets();\n await petShop.addPetEffects();\n }\n this.close();\n await pathmuncher.postImportCheck();\n }\n\n}\n","import { Pathmuncher } from \"../app/Pathmuncher.js\";\nimport { PathmuncherImporter } from \"../app/PathmuncherImporter.js\";\nimport CONSTANTS from \"../constants.js\";\nimport { EQUIPMENT_RENAME_MAP, RESTRICTED_EQUIPMENT } from \"../data/equipment.js\";\nimport { FEAT_RENAME_MAP } from \"../data/features.js\";\nimport utils from \"../utils.js\";\n\nexport function registerAPI() {\n game.modules.get(CONSTANTS.MODULE_NAME).api = {\n Pathmuncher,\n PathmuncherImporter,\n data: {\n generateFeatMap: FEAT_RENAME_MAP,\n equipment: EQUIPMENT_RENAME_MAP,\n restrictedEquipment: RESTRICTED_EQUIPMENT,\n feats: FEAT_RENAME_MAP(),\n },\n utils: utils,\n CONSTANTS,\n };\n}\n","import CONSTANTS from \"../constants.js\";\n\nasync function resetSettings() {\n for (const [name, data] of Object.entries(CONSTANTS.GET_DEFAULT_SETTINGS())) {\n // eslint-disable-next-line no-await-in-loop\n await game.settings.set(CONSTANTS.MODULE_NAME, name, data.default);\n }\n window.location.reload();\n}\n\nclass ResetSettingsDialog extends FormApplication {\n constructor(...args) {\n super(...args);\n // eslint-disable-next-line no-constructor-return\n return new Dialog({\n title: game.i18n.localize(`${CONSTANTS.FLAG_NAME}.Dialogs.ResetSettings.Title`),\n content: `<p class=\"${CONSTANTS.FLAG_NAME}-dialog-important\">${game.i18n.localize(\n `${CONSTANTS.FLAG_NAME}.Dialogs.ResetSettings.Content`\n )}</p>`,\n buttons: {\n confirm: {\n icon: '<i class=\"fas fa-check\"></i>',\n label: game.i18n.localize(`${CONSTANTS.FLAG_NAME}.Dialogs.ResetSettings.Confirm`),\n callback: () => {\n resetSettings();\n },\n },\n cancel: {\n icon: '<i class=\"fas fa-times\"></i>',\n label: game.i18n.localize(`${CONSTANTS.FLAG_NAME}.Dialogs.ResetSettings.Cancel`),\n },\n },\n default: \"cancel\",\n });\n }\n}\n\nexport function registerSettings() {\n game.settings.registerMenu(CONSTANTS.MODULE_NAME, \"resetToDefaults\", {\n name: `${CONSTANTS.FLAG_NAME}.Settings.Reset.Title`,\n label: `${CONSTANTS.FLAG_NAME}.Settings.Reset.Label`,\n hint: `${CONSTANTS.FLAG_NAME}.Settings.Reset.Hint`,\n icon: \"fas fa-refresh\",\n type: ResetSettingsDialog,\n restricted: true,\n });\n\n for (const [name, data] of Object.entries(CONSTANTS.GET_DEFAULT_SETTINGS())) {\n game.settings.register(CONSTANTS.MODULE_NAME, name, data);\n }\n\n}\n","import { PathmuncherImporter } from \"../app/PathmuncherImporter.js\";\nimport CONSTANTS from \"../constants.js\";\nimport utils from \"../utils.js\";\n\nexport function registerSheetButton() {\n\n const trustedUsersOnly = utils.setting(CONSTANTS.SETTINGS.RESTRICT_TO_TRUSTED);\n if (trustedUsersOnly && !game.user.isTrusted) return;\n\n /**\n * Character sheets\n */\n const pcSheetNames = Object.values(CONFIG.Actor.sheetClasses.character)\n .map((sheetClass) => sheetClass.cls)\n .map((sheet) => sheet.name);\n\n pcSheetNames.forEach((sheetName) => {\n Hooks.on(\"render\" + sheetName, (app, html, data) => {\n // only for GMs or the owner of this character\n if (!data.owner || !data.actor) return;\n\n const button = $(`<a class=\"pathmuncher-open\" title=\"${CONSTANTS.MODULE_FULL_NAME}\"><i class=\"fas fa-hat-wizard\"></i> Pathmuncher</a>`);\n\n button.click(() => {\n const muncher = new PathmuncherImporter(PathmuncherImporter.defaultOptions, data.actor);\n muncher.render(true);\n });\n\n html.closest('.app').find('.pathmuncher-open').remove();\n let titleElement = html.closest('.app').find('.window-title');\n if (!app._minimized) button.insertAfter(titleElement);\n });\n });\n\n}\n","import { registerAPI } from \"./hooks/api.js\";\nimport { registerSettings } from \"./hooks/settings.js\";\nimport { registerSheetButton } from \"./hooks/sheets.js\";\n\nHooks.once(\"init\", () => {\n registerSettings();\n});\n\nHooks.once(\"ready\", () => {\n registerSheetButton();\n registerAPI();\n});\n"],"names":[],"sourceRoot":""}
|