TyrealGray/Qin.js

View on GitHub
packages/qin.js/src/core/reactorCore/processReaction.js

Summary

Maintainability
B
4 hrs
Test Coverage
F
16%
//@flow
import Perlin from 'perlin.js';
import { REACTION } from './shuoCore/reactionType';
import randomSeed from './shuoCore/randomSeed';

const dynamicFunctionCache = {};

const roundNoise = (noise: number): number => {
    return parseFloat(((noise + 1.0) / 2.0).toFixed(2));
};

const getRandomDataSets = (seed) => {
    randomSeed.setSeed(seed);
    const randomBySeed = randomSeed.random();
    const randomByDate = randomSeed.randomByDate();

    return { randomBySeed, randomByDate };
};

export const checkChanceByTicker = (stamp: { seed: string, time: number }, rate: number): boolean => {
    const { randomBySeed, randomByDate } = getRandomDataSets(stamp.seed);

    Perlin.seed(stamp.seed);
    const noise = Perlin.perlin3(randomBySeed, randomByDate, stamp.time);

    return (roundNoise(noise) <= rate);
};

const checkChance = (data: Object, reaction: Object, stamp: { seed: string, time: number }): boolean => {
    const { randomBySeed, randomByDate } = getRandomDataSets(stamp.seed);

    Perlin.seed(getRandomDataSets(data.qinId).randomBySeed);
    const noise = Perlin.perlin3(randomBySeed, randomByDate, stamp.time.toFixed(2));

    return (roundNoise(noise) <= reaction.rate);
};

const checkDynamicParamFlag = (param: string): boolean => {

    switch (param) {
        case '_tb':
            return true;
    }

    return false;
};

const getDynamicParamValueByFlag = (param: string, value:string, action:{type: string, triggerBy: any, triggerTo: any, stamp: { seed: string, time: number }}): any => {
    const { peeledPropArray } = peelPropsString(value);

    switch (param) {
        case '_tb':
            return getObjectValueByPeeledPropArray(action.triggerBy, peeledPropArray);
    }

    return value;
};

const getObjectValueByPeeledPropArray = (object: any, peeledPropArray: string[]): any => {
    let value = object;
    for (let i = 0; i < peeledPropArray.length; i++) {
        value = value[peeledPropArray[i]];
    }

    return value;
};

const peelParamsString = (propString/* format e.g. xx&damage */, action:{type: string, triggerBy: any, triggerTo: any, stamp: { seed: string, time: number }}): Object => {

    const paramsName = propString.split('&')[0];

    let value = propString.split('&')[1];
    if (checkDynamicParamFlag(paramsName)) {
        value = getDynamicParamValueByFlag(paramsName, value, action);
    }


    return {
        paramsName,
        value,
    };
};

export const peelPropsString = (propsString: string) => {
    return {
        peeledPropArray: propsString.split('-'),
    };
};

const getConstructDynamic = (callback) => {
    if (!dynamicFunctionCache[callback]) {
        dynamicFunctionCache[callback] = eval(`(() => {return function(_p){${callback}};})()`);
    }
    return dynamicFunctionCache[callback];
};

const dynamicReact = (data: Object, reaction: Object, action:{type: string, triggerBy: any, triggerTo: any, stamp: { seed: string, time: number }}): void => {
    if (typeof reaction.rate !== 'undefined' && !checkChance(data, reaction, action.stamp)) {
        return;
    }

    const params = {};
    for (const dynamic in reaction.value) {
        for (const prop of reaction.value[dynamic]) {
            const { value, paramsName } = peelParamsString(prop, action);
            params[paramsName] = value;
        }
    }
    for (const funcName in data.dynamicFunction) {
        const func = getConstructDynamic(data.dynamicFunction[funcName]);
        func.call(data, params);
    }
};

const commonReact = (data: Object, reaction: Object, action:{type: string, triggerBy: any, triggerTo: any, stamp: { seed: string, time: number }}): void => {
    const { peeledPropArray } = peelPropsString(reaction.attribute);

    let value = data;
    let accessProp = null;
    for (let i = 0; i < peeledPropArray.length; i++) {
        if (peeledPropArray.length - 1 === i) {
            accessProp = peeledPropArray[i];
            break;
        }
        value = value[peeledPropArray[i]];
    }

    switch (reaction.type) {
        case REACTION.ADD:
            value[accessProp] += reaction.value;
            break;
        case REACTION.MAYBE_ADD:
            if (checkChance(data, reaction, action.stamp)) {
                value[accessProp] += reaction.value;
            }
            break;
        case REACTION.SET:
            value[accessProp] = reaction.value;
            break;
        case REACTION.MAYBE_SET:
            if (checkChance(data, reaction, action.stamp)) {
                value[accessProp] = reaction.value;
            }
            break;
    }
};

export const processReaction = (action: {type: string, triggerBy: any, triggerTo: any, stamp: { seed: string, time: number }}, reactions: Object, data: Object): Object => {
    for (const reaction of reactions) {
        switch (reaction.type) {
            case REACTION.ADD:
            case REACTION.MAYBE_ADD:
            case REACTION.SET:
            case REACTION.MAYBE_SET:
                commonReact(data, reaction, action);
                break;
            case REACTION.DYNAMIC:
                dynamicReact(data, reaction, action);
                break;
        }
    }

    return data;
};