/* */var API_Meta = API_Meta || {};
var API_Meta = API_Meta || {};
API_Meta.Rest = { offset: Number.MAX_SAFE_INTEGER, lineCount: -1 };
{ try { throw new Error(''); } catch (e) { API_Meta.Rest.offset = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - (4)); } }
const Rest = (() => {
    const scriptName = 'Rest';
    API_Meta[scriptName].version = '1.0.0';
    let rest = {
        isOpen: false,
        startingValues: {}, // object tracking food, water, and hp for each character involved
        involved: [], // array of character IDs who can choose to eat/recover
        claimed: [], // array of character IDs of those who have elected to eat/recover
        open() {
            this.close();
            this.isOpen = true;
        },
        close() {
            this.isOpen = false;
            let report = this.involved.filter(cid => !this.claimed.includes(cid)).reduce((m,cid) => {
                (hp = findObjs({ type: 'attribute', characterid: cid, name: 'hp' })[0])?.set('current', Math.max(0, parseIntOrZero(hp.get('current')) - 2)); // Apply penalty
                return [...m, cid];
            },[]);
            this.startingValues = {};
            this.involved = [];
            this.claimed = [];
            if (report.length) {
                sendChat(scriptName, `/w gm The following characters suffered a healing penalty due to lack of sustenance: ${report.map(cid => getObj('character', cid).get('name')).join(', ')}`);
            }
        }
    };
    const getPlayerCharacters = () => findObjs({ type: 'character' })
        .filter(c => (pid = (c.get('controlledby') || '').split(/\s*,\s*/)[0]).length && pid.toLowerCase() !== 'all' && !playerIsGM(pid));
    const getCharacter = (q, pid) => {
        if (typeof q !== 'string') { return; }
        let someCheck = id => id.toLowerCase() === 'all' || id === pid;
        const hasAccess = (c) => {
            if (!c) { return; }
            return (c.get('controlledby') || '').split(/\s*,\s*/).some(someCheck);
        };
        let query = q.trim();
        let character = findObjs({ type: 'character' }).filter(c => [c.id, c.get('name')].includes(query) && (pid ? hasAccess(c) : true))[0];
        if (character) {
            return character;
        }
        character = getObj('character', (getObj('graphic', query) || { get: () => { return ''; } }).get('represents'));
        if (character) {
            if (!pid || (pid && hasAccess(character))) {
                return character;
            } else { return; }
        }
    };
    const gmRequired = pid => sendchat(scriptName, 'You must be a GM to do that.');
    const parseIntOrZero = (val) => isNaN(tempPI = parseInt(val,10)) ? 0 : tempPI;
    const getWhisperTo = (who) => who.toLowerCase() === 'api' ? 'gm' : who.replace(/\s\(gm\)$/i, '');
    on('ready', function () {
        on('chat:message', msg => {
            /**
             * !rest
             * !rest --[open/close]
             * !rest --recover|characterid
             * !rest --rollback|characterid
             * !rest --request|characterid
             * !rest --share|[water/food]|characterid-give|characterid-receive
             */
            if (!(msg.type === 'api' && /^!rest/i.test(msg.content))) { return; }
            let args = (msg.content.split(/\s+--/)).slice(1).map(a => [(ret = (/([^|#]+)(?:(?:\||#)(.*))?/.exec(a)))[1].toLowerCase(), ret[2] ? ret[2].trim() : undefined]);
            let chars = getPlayerCharacters();
            args.forEach(arg => {
                let food, water, hp, shareAttr, recAttr, char, shareChar;
                switch (arg[0]) {
                    case 'close':
                        if (!playerIsGM(msg.playerid)) {
                            gmRequired(msg.playerid);
                            return;
                        }
                        if (!rest.isOpen) { return; }
                        rest.close();
                        sendChat(scriptName, '/w gm Rest period is closed. No further recoveries will be allowed.');
                        sendChat(scriptName, `&{template:default}{{name=Rest Over}}{{=This opportunity for rest and recovery is now closed. You may still share ` +
                            `rations using existing <b>Request</b> and <b>Share</b> buttons, but there will be no opportunity for recovery until you rest again.}}`);
                        break;
                    case 'recover':
                        char = chars.filter(c => [c.id, c.get('name')].includes(arg[1]))[0];
                        if (!char) { // no character supplied, or character not found
                            sendChat(scriptName, `/w ${getWhisperTo(msg.who)} &{template:default}{{name=No Character}}` +
                                `{{=You must supply a character who is involved in this rest.}}`);
                            return;
                        }
                        if (!rest.involved.includes(arg[1])) { // character not involved in rest
                            sendChat(scriptName, `/w ${getWhisperTo(msg.who)} &{template:default}{{name=Character Not Resting}}` +
                                `{{=You must supply a character who is involved in this rest.}}`);
                            return;
                        }
                        if (rest.claimed.includes(arg[1])) { // recovery already claimed
                            sendChat(scriptName, `/w ${getWhisperTo(msg.who)} &{template:default}{{name=${char.get('name')} Already Recovered}}` +
                                `{{=This character already recovered during this rest.}}`);
                            return;
                        }
                        if (!rest.isOpen) { // rest was closed by GM
                            sendChat(scriptName, `/w ${char.get('name')} &{template:default} {{name=No Recovery Available}}` +
                                `{{=The opportunity to recover during this rest has passed.}}`);
                            return;
                        }
                        food = findObjs({ type: 'attribute', characterid: char.id, name: 'food' })[0];
                        water = findObjs({ type: 'attribute', characterid: char.id, name: 'water' })[0];
                        hp = findObjs({ type: 'attribute', characterid: char.id, name: 'hp' })[0];
                        if (parseIntOrZero(food.get('current')) < 1 || parseIntOrZero(water.get('current')) < 1) {
                            sendChat(scriptName, `/w ${char.get('name')} &{template:default}{{name=Not Enough Rations}}` +
                                `{{=You lack the necessary rations to recover. Most likely you shared with a party memeber.}}`);
                            return;
                        }
                        let currentHP = hp?.get('current');
                        let adjustedHP = Math.min(parseIntOrZero(hp?.get('max')), parseIntOrZero(hp?.get('current')) + 5); // Adjust healing value as needed
                        hp?.set('current', adjustedHP);
                        food?.set('current', parseIntOrZero(food.get('current')) - 1);
                        water?.set('current', parseIntOrZero(water.get('current')) - 1);
                        rest.claimed.push(char.id);
                        sendChat(scriptName, `/w ${char.get('name')} &{template:default}{{name=Recovered}} {{=You rested and recovered ${adjustedHP - currentHP}hp ` +
                            `to be at ${adjustedHP}hp. ${`${adjustedHP}` === `${hp?.get('max')}` ? 'You are at full health.' : ''} }}`);
                        break;
                    case 'request':
                        char = getCharacter(arg[1], msg.playerid);
                        if (!char) { return; }
                        let needFood = parseIntOrZero(findObjs({ type: 'attribute', characterid: char.id, name: 'food' })[0]?.get('current')) < 1;
                        let needWater = parseIntOrZero(findObjs({ type: 'attribute', characterid: char.id, name: 'water' })[0]?.get('current')) < 1;
                        (rest.isOpen ? rest.involved : chars.map(c => c.id)).filter(cid => cid !== arg[1]).forEach(cid => {
                            shareChar = getObj('character', cid);
                            food = parseIntOrZero(findObjs({ type: 'attribute', characterid: shareChar.id, name: 'food' })[0]?.get('current'));
                            water = parseIntOrZero(findObjs({ type: 'attribute', characterid: shareChar.id, name: 'water' })[0]?.get('current'));
                            hp = `${(tempAttr = findObjs({ type: 'attribute', characterid: shareChar.id, name: 'hp' })[0]).get('current')} / ${tempAttr.get('max')}`;
                            let foodRequest = needFood ? `{{ =<div style="text-align:right"><a href="!&#13;!rest --share|food|${shareChar.id}|${char.id}">Share Food</a></div>}}` : '';
                            let waterRequest = needWater ? `{{  =<div style="text-align:right"><a href="!&#13;!rest --share|water|${shareChar.id}|${char.id}">Share Water</a></div>}}` : '';
                            if ((food < 1 && water < 1) || (needFood && !needWater && food < 1) || (needWater && !needFood && water < 1)) { return; }
                            sendChat(scriptName, `/w ${shareChar.get('name')} &{template:default}{{name=Sharing Request}}{{=${char.get('name')} lacks ` +
                                `adequate rations to recover and is asking for help. Will you share?%NEWLINE%%NEWLINE%**YOUR STATUS:**<ul>` +
                                `<li><b>Food</b>: ${food}</li>` +
                                `<li><b>Water</b>: ${water}</li>` +
                                `<li><b>HP</b>: ${hp}</li>` +
                                `</ul>}}` +
                                `${foodRequest}${waterRequest}`);
                        });
                        sendChat(scriptName, `/w ${char.get('name')} &{template:default}{{name=Request Made}}{{=Your request has been made.}}`);
                        break;
                    case 'share':
                        let parts = arg[1].split(/(?:\||#)/);
                        let shareType = ['food', 'water'].includes(parts[0].toLowerCase()) ? parts[0].toLowerCase() : undefined;
                        shareChar = getCharacter(parts[1], msg.playerid);
                        char = getCharacter(parts[2]);
                        if (!shareType) {
                            sendChat(scriptName, `/w ${getWhisperTo(msg.who)} &{template:default}{{name=Invalid Share Type}}{{=You must include either ` +
                                `'food' or 'water' as the thing to share.}}`);
                            return;
                        } else if (!shareChar || !char) {
                            sendChat(scriptName, `/w ${getWhisperTo(msg.who)} &{template:default}{{name=Can't Find Characters}}{{=Could not find one or both ` +
                                `of the characters required based on the information you supplied.}}`);
                            return;
                        }
                        // if we're still here, then this character has chosen to share
                        // sharing character reduction
                        shareAttr = findObjs({ type: 'attribute', characterid: shareChar.id, name: shareType })[0];
                        if (shareAttr && parseIntOrZero(shareAttr.get('current')) >= 1) {
                            shareAttr.set('current', parseIntOrZero(shareAttr.get('current')) - 1);
                            if (rest.isOpen) {
                                rest.startingValues[shareChar.id][shareType] = rest.startingValues[shareChar.id][shareType] - 1;
                            }
                            // receiving character adjustment
                            recAttr = findObjs({ type: 'attribute', characterid: char.id, name: shareType })[0];
                            if (recAttr) {
                                recAttr.set('current', parseIntOrZero(recAttr.get('current')) + 1);
                                if (rest.isOpen) {
                                    rest.startingValues[char.id][shareType] = rest.startingValues[char.id][shareType] + 1;
                                }
                            }
                            // report to sharing character
                            food = rest.isOpen
                                ? rest.startingValues[shareChar.id].food
                                : parseIntOrZero(findObjs({ type: 'attribute', characterid: shareChar.id, name: 'food' })[0].get('current'))
                                ;
                            water = rest.isOpen
                                ? rest.startingValues[shareChar.id].water
                                : parseIntOrZero(findObjs({ type: 'attribute', characterid: shareChar.id, name: 'water' })[0].get('current'))
                                ;
                            hp = `${(tempAttr = findObjs({ type: 'attribute', characterid: shareChar.id, name: 'hp' })[0]).get('current')} / ${tempAttr.get('max')}`;
                            sendChat(scriptName, `/w ${shareChar.get('name')} &{template:default}{{name=Success}}{{=You shared with ${char.get('name')}. ` +
                                `Don't ever let them forget it.%NEWLINE%%NEWLINE%**STATUS:**<ul>` +
                                `<li><b>Food</b>: ${food}</li>` +
                                `<li><b>Water</b>: ${water}</li>` +
                                `<li><b>HP</b>: ${hp}</li>` +
                                `</ul>}}`);
                            // report to receiving character
                            food = rest.isOpen
                                ? rest.startingValues[char.id].food
                                : parseIntOrZero(findObjs({ type: 'attribute', characterid: char.id, name: 'food' })[0].get('current'))
                                ;
                            water = rest.isOpen
                                ? rest.startingValues[char.id].water
                                : parseIntOrZero(findObjs({ type: 'attribute', characterid: char.id, name: 'water' })[0].get('current'))
                                ;
                            hp = `${(tempAttr = findObjs({ type: 'attribute', characterid: char.id, name: 'hp' })[0]).get('current')} / ${tempAttr.get('max')}`;
                            let lackingRation = food >= 1 && water >= 1
                                ? ''
                                : food < 1
                                    ? 'food'
                                    : 'water'
                                ;
                            let status = `%NEWLINE%%NEWLINE%**STATUS:**<ul>` +
                                `<li><b>Food</b>: ${food}</li>` +
                                `<li><b>Water</b>: ${water}</li>` +
                                `<li><b>HP</b>: ${hp}</li>` +
                                `</ul>`;
                            let nextAction = rest.isOpen
                                ? lackingRation.length
                                    ? `You still lack ${lackingRation} rations before you can recover.${status}}}`
                                    : `You may now recover.${status}}}{{ =<div style="text-align:right"><a href="!&#13;!rest --recover|${char.id}">Recover</a></div>}}`
                                : lackingRation.length
                                    ? `This rest period is closed, but you still lack a ${lackingRation} before you can recover in the next rest period.${status}}}`
                                    : `This rest period is closed, but you now have sufficient rations to recover the next time you are resting.${status}}}`
                                ;
                            sendChat(scriptName, `/w ${char.get('name')} &{template:default}{{name=You Have Received a Gift}}{{=${shareChar.get('name')} ` +
                                `shared ${shareType} with you. ${nextAction}`);
                        } else {
                            food = parseIntOrZero(findObjs({ type: 'attribute', characterid: shareChar.id, name: 'food' })[0].get('current'));
                            water = parseIntOrZero(findObjs({ type: 'attribute', characterid: shareChar.id, name: 'water' })[0].get('current'));
                            hp = `${(tempAttr = findObjs({ type: 'attribute', characterid: shareChar.id, name: 'hp' })[0]).get('current')} / ${tempAttr.get('max')}`;
                            sendChat(scriptName, `/w ${getWhisperTo(msg.who)} &{template:default}{{name=Unable to Share}}{{=You no longer have enough ${shareType} ` +
                                `to share. It is possible you recovered and consumed your last ration, or that you already shared it.` +
                                `%NEWLINE%%NEWLINE%**STATUS:**<ul>` +
                                `<li><b>Food</b>: ${food}</li>` +
                                `<li><b>Water</b>: ${water}</li>` +
                                `<li><b>HP</b>: ${hp}</li>` +
                                `</ul>` +
                                `}}`);
                            return;
                        }
                        break;
                    case 'rollback':
                        if (!playerIsGM(msg.playerid)) {
                            gmRequired(msg.playerid);
                            return;
                        }
                        char = getCharacter(arg[1]);
                        if (rest.startingValues.hasOwnProperty(char.id)) {
                            findObjs({ type: 'attribute', characterid: char.id, name: 'food' })[0]?.set('current', rest.startingValues[char.id].food);
                            findObjs({ type: 'attribute', characterid: char.id, name: 'water' })[0]?.set('current', rest.startingValues[char.id].water);
                            findObjs({ type: 'attribute', characterid: char.id, name: 'hp' })[0]?.set('current', rest.startingValues[char.id].hp);
                            rest.claimed = rest.claimed.filter(cid => cid !== char.id);
                            sendChat(scriptName, `/w gm Successfully rolled back that character. Their **[Recovery]** button should work again.`);
                        }
                        break;
                    case 'open':
                        if (!playerIsGM(msg.playerid)) {
                            gmRequired(msg.playerid);
                            return;
                        }
                        rest.open();
                        if (!chars.length) {
                            sendChat(scriptName, '/w gm No player characters found.');
                            return;
                        }
                        rest = {
                            ...rest,
                            ...chars.reduce((m, c) => {
                                let foodAttr = findObjs({ type: 'attribute', characterid: c.id, name: 'food' })[0];
                                let waterAttr = findObjs({ type: 'attribute', characterid: c.id, name: 'water' })[0];
                                let hpAttr = findObjs({ type: 'attribute', characterid: c.id, name: 'hp' })[0];
                                if (!hpAttr || !waterAttr || !foodAttr) { // character is missing attributes
                                    sendChat(scriptName, `/w gm ${c.get('name')} does not have all three attributes (hp, food, water) required ` +
                                        `to take part in the Rest script. They will be excluded until you correct that situation, then open the ` +
                                        `rest period again.`);
                                } else {
                                    food = parseIntOrZero(foodAttr.get('current'));
                                    water = parseIntOrZero(waterAttr.get('current'));
                                    hp = parseIntOrZero(hpAttr.get('current'));
                                    m.involved.push(c.id);
                                    m.startingValues = {
                                        ...m.startingValues,
                                        [c.id]: { hp, food, water }
                                    };
                                }
                                return m;
                            }, rest)
                        };
                        let menuParts = chars.map(c => {
                            food = rest.startingValues[c.id].food;
                            water = rest.startingValues[c.id].water;
                            hp = `${(tempAttr = findObjs({ type: 'attribute', characterid: c.id, name: 'hp' })[0]).get('current')} / ${tempAttr.get('max')}`;
                            if (rest.involved.includes(c.id)) {
                                if (food < 1 || water < 1) {
                                    sendChat(scriptName, `/w ${c.get('name')} &{template:default} {{name=${c.get('name')} No Recovery Opportunity}}` +
                                        `{{=You are resting, but you lack the necessary food and water in order to recover HP and/or ` +
                                        `avoid taking damage from a lack of sustenance. Do you wish to request help?%NEWLINE%%NEWLINE%**STATUS:**<ul>` +
                                        `<li><b>Food</b>: ${food}</li>` +
                                        `<li><b>Water</b>: ${water}</li>` +
                                        `<li><b>HP</b>: ${hp}</li>` +
                                        `</ul>}}` +
                                        `{{ =<div style="text-align:right"><a href="!&#13;!rest --request|${c.id}">Request</a></div>}}`);
                                } else {
                                    sendChat(scriptName, `/w ${c.get('name')} &{template:default} {{name=${c.get('name')} Recovery Opportunity}}` +
                                        `{{=You are resting. Do you wish to consume food and water rations in order to gain HP?%NEWLINE%%NEWLINE%**STATUS:**<ul>` +
                                        `<li><b>Food</b>: ${food}</li>` +
                                        `<li><b>Water</b>: ${water}</li>` +
                                        `<li><b>HP</b>: ${hp}</li>` +
                                        `</ul>}}` +
                                        `{{ =<div style="text-align:right"><a href="!&#13;!rest --recover|${c.id}">Recover</a></div>}}`);
                                }
                                return `{{${c.get('name')}%NEWLINE%` +
                                    `F: ${food}, W: ${water}, HP: ${hp}=` +
                                    `<a href="!&#13;!rest --rollback|${c.id}">Rollback</a>}}`;
                            }
                        });
                        sendChat(scriptName, `/w gm &{template:default}{{name=Rest Opened}}{{Rest period has opened, and the characters have received their messages. ` +
                            `Use this menu to rollback any character who requires it, or to close the rest period.}} ${menuParts.join('')} ` +
                            `{{Close Rest Period=<a href="!&#13;!rest --close">Close</a>}}`);
                    default:
                }
            });
        });
    });
})();
{ try { throw new Error(''); } catch (e) { API_Meta.Rest.lineCount = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - API_Meta.Rest.offset); } }
/* */  .