Skip to content

Commit

Permalink
feat: combatant merger
Browse files Browse the repository at this point in the history
  • Loading branch information
dsrkafuu committed Sep 22, 2021
1 parent 3c89a0f commit fd9c4a9
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 10 deletions.
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ npm install ffxiv-overlay-api --save
Or import the library from jsDelivr CDN:

```html
<script src="https://cdn.jsdelivr.net/npm/ffxiv-overlay-api@3.5/lib/overlay.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/ffxiv-overlay-api@3.6/lib/overlay.min.js"></script>
<script>
const overlay = new OverlayAPI({
extendData: true,
Expand Down Expand Up @@ -95,56 +95,62 @@ Checkout [Development](#development) section for more details.

You can find all events available in <https://ngld.github.io/OverlayPlugin/devs/event_types>.

### `OverlayAPI.addListener(event, cb)`
### `new OverlayAPI().addListener(event, cb)`

add an event listener

- `@param {EventType} event` event to listen
- `@param {Function} cb` callback function

### `OverlayAPI.removeListener(event, cb)`
### `new OverlayAPI().removeListener(event, cb)`

remove a listener

- `@param {EventType} event` event type which listener belongs to
- `@param {Function} cb` function which listener to remove

### `OverlayAPI.removeAllListener(event)`
### `new OverlayAPI().removeAllListener(event)`

remove all listener of one event type

- `@param {EventType} event` event type which listener belongs to

### `OverlayAPI.getAllListener(event)`
### `new OverlayAPI().getAllListener(event)`

get all listeners of a event

- `@param {EventType} event` event type which listener belongs to
- `@return {Array<Function>}`

### `OverlayAPI.startEvent()`
### `new OverlayAPI().startEvent()`

start listening event

### `OverlayAPI.endEncounter()`
### `new OverlayAPI().endEncounter()`

ends current encounter and save it

- `@return {Promise<any>}`

### `OverlayAPI.callHandler(msg)`
### `new OverlayAPI().callHandler(msg)`

this function allows you to call an overlay handler, these handlers are declared by Event Sources, either built into OverlayPlugin or loaded through addons like Cactbot

- `@param {HandlerMessage} msg` message send to OverlayPlugin
- `@return {Promise<EventMessage>}`

### `OverlayAPI.simulateData(msg)`
### `new OverlayAPI().simulateData(msg)`

simulate triggering event once

- `@param {EventMessage} msg` data same as those from OverlayPluginApi like in <https://github.com/dsrkafuu/ffxiv-overlay-api/tree/master/test>

### `OverlayAPI.mergeCombatant(...args)`

static function for merging combatant like pets into first player arg

- `@param {...CombatantData} args`

## Development

Clone this repo, then:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ffxiv-overlay-api",
"version": "3.5.2",
"version": "3.6.0",
"description": "Build your own modern FFXIV overlay with npm.",
"keywords": [
"ffxiv",
Expand Down
213 changes: 213 additions & 0 deletions src/components/mergeCombatant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/**
* common number adds
* @param {...number} args
* @returns {number}
*/
function addNumber(...args) {
if (!args.length) {
return 0;
}
let sum = 0;
for (let i = 0; i < args.length; i++) {
sum += args[i] || 0;
}
return sum;
}

/**
* damagePct, healsPct, etc.
* @param {...string} args
* @returns {string}
*/
function addPct(...args) {
if (!args.length) {
return '0%';
}
let sum = 0;
for (let i = 0; i < args.length; i++) {
const exp = /([0-9]+)%/gi.exec(args[i]);
if (exp && exp[1]) {
sum += Number.parseInt(exp[1]) || 0;
}
}
return `${sum}%`;
}

/**
* directHitPct, critHitPct, etc.
* @param {...{ hits: number, totalHits: number }} args
* @returns { hits: number, hitPct: string }
*/
function mergeHitPct(...args) {
if (!args.length) {
return { hits: 0, hitPct: '0%' };
}
let numerator = 0;
let denominator = 0;
for (let i = 0; i < args.length; i++) {
numerator += args[i].hits || 0;
denominator += args[i].totalHits || 0;
}
if (denominator === 0 || numerator === 0) {
return { hits: 0, hitPct: '0%' };
}
return {
hits: numerator,
hitPct: `${Math.round((numerator / denominator) * 100)}%`,
};
}

/**
* @param {...string} args
* @returns {string}
*/
function mergeOverHealPct(...args) {
if (!args.length) {
return '0%';
}
let tsum = 0;
let tnum = 0;
for (let i = 0; i < args.length; i++) {
const exp = /([0-9]+)%/gi.exec(args[i]);
if (exp && exp[1]) {
const num = Number.parseInt(exp[1]) || 0;
if (num > 0) {
tsum += num;
tnum++;
}
}
}
if (tnum === 0) {
return '0%';
}
return `${Math.round(tsum / tnum)}%`;
}

/**
* maxHit, maxHeal, etc.
* @param {...{ hit: string, hitDamage: number }} args
* @returns { hit: string, hitDamage: number }
*/
function mergeMax(...args) {
if (!args.length) {
return { hit: '', hitDamage: 0 };
}
let max = { hit: '', hitDamage: 0 };
for (let i = 0; i < args.length; i++) {
if (args[i].hitDamage > max.hitDamage) {
max = args[i];
}
}
return max;
}

/**
* @param {...CombatantData} args
*/
export function mergeCombatant(...args) {
if (!args.length) {
return null;
}

const dps = [];
const last10DPS = [];
const last30DPS = [];
const last60DPS = [];
const hps = [];

const swings = [];
const hits = [];
const deaths = [];

const direct = [];
const crit = [];
const directCrit = [];

const damage = [];
const damageTaken = [];
const damagePct = [];

const healed = [];
const healsTaken = [];
const healsPct = [];
const overHeal = [];
const overHealPct = [];

const maxHit = [];
const maxHeal = [];

args.forEach((item) => {
dps.push(item.dps);
last10DPS.push(item.last10DPS);
last30DPS.push(item.last30DPS);
last60DPS.push(item.last60DPS);
hps.push(item.hps);

swings.push(item.swings);
hits.push(item.hits);
deaths.push(item.deaths);

direct.push({ hits: item.directHits, totalHits: item.hits });
crit.push({ hits: item.critHits, totalHits: item.hits });
directCrit.push({ hits: item.directCritHits, totalHits: item.hits });

damage.push(item.damage);
damageTaken.push(item.damageTaken);
damagePct.push(item.damagePct);

healed.push(item.healed);
healsTaken.push(item.healsTaken);
healsPct.push(item.healsPct);
overHeal.push(item.overHeal);
overHealPct.push(item.overHealPct);

maxHit.push({ hit: item.maxHit, hitDamage: item.maxHitDamage });
maxHeal.push({ hit: item.maxHeal, hitDamage: item.maxHealDamage });
});

const ret = {
name: args[0].name,

job: args[0].job,
jobType: args[0].jobType,

dps: addNumber(...dps),
last10DPS: addNumber(...last10DPS),
last30DPS: addNumber(...last30DPS),
last60DPS: addNumber(...last60DPS),
hps: addNumber(...hps),

swings: addNumber(...swings),
hits: addNumber(...hits),
deaths: addNumber(...deaths),

damage: addNumber(...damage),
damageTaken: addNumber(...damageTaken),
damagePct: addPct(...damagePct),

healed: addNumber(...healed),
healsTaken: addNumber(...healsTaken),
healsPct: addPct(...healsPct),
overHeal: addNumber(...overHeal),
overHealPct: mergeOverHealPct(...overHealPct),
};

let temp = mergeHitPct(...direct);
ret.directHits = temp.hits;
ret.directHitPct = temp.hitPct;
temp = mergeHitPct(...crit);
ret.critHits = temp.hits;
ret.critHitPct = temp.hitPct;
temp = mergeHitPct(...directCrit);
ret.directCritHits = temp.hits;
ret.directCritHitPct = temp.hitPct;

temp = mergeMax(...maxHit);
ret.maxHit = temp.hit;
ret.maxHitDamage = temp.hitDamage;
temp = mergeMax(...maxHeal);
ret.maxHeal = temp.hit;
ret.maxHealDamage = temp.hitDamage;

return ret;
}
1 change: 1 addition & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ interface HandlerMessage {
}

export default class OverlayAPI {
static mergeCombatant(...args: CombatantData[]): CombatantData;
constructor(options: OverlayOptions);
addListener(event: EventType, cb: EventCallback): void;
removeListener(event: EventType, cb: EventCallback): void;
Expand Down
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { logInfo, logError } from './components/logger';
import { defaultOptions } from './components/defaultOptions';
import { extendData } from './components/extendData';
import { mergeCombatant } from './components/mergeCombatant';

export default class OverlayAPI {
// singleton
static _instance = null;
// function for merging combatant like pets into first player arg
static mergeCombatant = mergeCombatant;

// settings
_options = {};
Expand Down

0 comments on commit fd9c4a9

Please sign in to comment.