104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
import { getSingleProperty } from '/imports/api/engine/loadCreatures';
|
|
import ParseNode from '/imports/parser/parseTree/ParseNode';
|
|
import array from '/imports/parser/parseTree/array';
|
|
import constant, { isFiniteNode } from '/imports/parser/parseTree/constant';
|
|
|
|
//set up the collection for creature variables
|
|
const CreatureVariables = new Mongo.Collection('creatureVariables');
|
|
|
|
// Unique index on _creatureId
|
|
if (Meteor.isServer) {
|
|
CreatureVariables._ensureIndex({ _creatureId: 1 }, { unique: true })
|
|
}
|
|
|
|
/** No schema because the structure isn't known until compute time
|
|
* Expect documents to look like:
|
|
* {
|
|
* _id: "nE8Ngd6K4L4jSxLY2",
|
|
* _creatureId: "nE8Ngd6K4L4jSxLY2", // indexed reference to the creature
|
|
* explicitlyDefinedVariableName: {...some creatureProperty},
|
|
* // Must be found in CreatureProperties before using:
|
|
* linkedProperty: { _propId: "nE8Ngd6K1234SxLY2" }
|
|
* implicitVariableName: {value: 10},
|
|
* undefinedVariableName: {},
|
|
* }
|
|
* Where top level fields that don't start with `_` are variables on the sheet
|
|
**/
|
|
|
|
/**
|
|
* Get the property from the given scope, respecting properties that are just a link to the actual
|
|
* property document
|
|
*/
|
|
export function getFromScope(name: string, scope) {
|
|
let value = scope?.[name];
|
|
if (value?._propId) {
|
|
const [propId, rowIdentifier, rowNumber] = value._propId.split('_');
|
|
value = getSingleProperty(scope._creatureId, propId);
|
|
if (rowIdentifier === 'row' && value?.type === 'pointBuy') {
|
|
value = value.values[rowNumber];
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function getNumberFromScope(name, scope) {
|
|
const parseNode = getParseNodeFromScope(name, scope);
|
|
if (!parseNode || !isFiniteNode(parseNode)) {
|
|
return undefined;
|
|
}
|
|
return parseNode.value;
|
|
}
|
|
|
|
export async function getConstantValueFromScope(
|
|
name, scope
|
|
) {
|
|
const parseNode = getParseNodeFromScope(name, scope);
|
|
if (!parseNode) return;
|
|
if (parseNode.parseType !== 'constant') return;
|
|
return parseNode.value;
|
|
}
|
|
|
|
export function getParseNodeFromScope(name, scope): ParseNode | undefined {
|
|
let value = getFromScope(name, scope);
|
|
if (!value) return;
|
|
let valueType = getType(value);
|
|
// Iterate into object.values
|
|
while (valueType === 'object') {
|
|
// Prefer the valueNode over the value
|
|
if (value.valueNode) {
|
|
value = value.valueNode;
|
|
} else {
|
|
value = value.value;
|
|
}
|
|
valueType = getType(value);
|
|
}
|
|
// Return a discovered parse node
|
|
if (valueType === 'parseNode') {
|
|
return value;
|
|
}
|
|
// Return a parse node based on the constant type returned
|
|
if (valueType === 'string' || valueType === 'number' || valueType === 'boolean') {
|
|
return constant.create({ value });
|
|
}
|
|
// Return a parser array
|
|
if (valueType === 'array') {
|
|
// If the first value is a parse node, assume all the values are
|
|
if (getType(value[0]) === 'parseNode') {
|
|
return array.create({
|
|
values: value,
|
|
});
|
|
}
|
|
// Create the array from js primitives instead
|
|
return array.fromConstantArray(value);
|
|
}
|
|
}
|
|
|
|
function getType(val) {
|
|
if (!val) return typeof val;
|
|
if (Array.isArray(val)) return 'array';
|
|
if (val.parseType) return 'parseNode';
|
|
return typeof val;
|
|
}
|
|
|
|
export default CreatureVariables;
|