mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-22 23:18:05 +03:00
feat: folder goal exemptions for metrics with chartDependentMax (#1591)
* feat: conditional chartDependentMax * requested fixes * run fix again
This commit is contained in:
@@ -355,7 +355,7 @@ export function ValidateMetric(gameConfig: GameConfig, metricName: string, metri
|
||||
return "Cannot validate a graph or nullable graph metric.";
|
||||
}
|
||||
|
||||
if (conf.chartDependentMax) {
|
||||
if (conf.chartDependentMax === true) {
|
||||
return `This metric is chart dependent and not appropriate to check in this context.`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { INTERNAL_GAME_CONFIG, INTERNAL_GAME_GROUP_CONFIG } from "../../types/internals";
|
||||
@@ -48,6 +49,8 @@ export const GAME_ARCAEA_CONF = {
|
||||
score: {
|
||||
type: "INTEGER",
|
||||
chartDependentMax: true,
|
||||
validate: p.isPositiveInteger,
|
||||
allowFolderGoalsIf: (v: number) => v < 10_000_000,
|
||||
formatter: FmtNum,
|
||||
description:
|
||||
"The score value. This is between 0 and 10 million, plus bonus points dependent on how many shiny PUREs you get.",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { INTERNAL_GAME_CONFIG, INTERNAL_GAME_GROUP_CONFIG } from "../../types/internals";
|
||||
@@ -62,6 +63,8 @@ export const GAME_MAIMAI_CONF = {
|
||||
percent: {
|
||||
type: "DECIMAL",
|
||||
chartDependentMax: true,
|
||||
allowFolderGoalsIf: (v) => v >= 0 && v < 100.0,
|
||||
validate: p.isPositive,
|
||||
formatter: FmtPercent,
|
||||
description:
|
||||
"The percent this score was worth. Sometimes called 'rate' in game. This is upper-bounded by how many BREAK notes the chart has.",
|
||||
|
||||
@@ -45,6 +45,7 @@ interface ConfDecimalScoreMetricChartDependent {
|
||||
* @example: IIDX's EX Score is upperbounded at 2x the chart's notecount.
|
||||
*/
|
||||
chartDependentMax: true;
|
||||
allowFolderGoalsIf?: never;
|
||||
}
|
||||
|
||||
interface ConfIntegerScoreMetricChartDependent {
|
||||
@@ -57,14 +58,51 @@ interface ConfIntegerScoreMetricChartDependent {
|
||||
* @example: IIDX's EX Score is upperbounded at 2x the chart's notecount.
|
||||
*/
|
||||
chartDependentMax: true;
|
||||
allowFolderGoalsIf?: never;
|
||||
}
|
||||
|
||||
interface ConfDecimalScoreMetricChartDependentWithExemption {
|
||||
type: "DECIMAL";
|
||||
formatter: (v: number) => string;
|
||||
validate: (v: number) => string | true;
|
||||
|
||||
/**
|
||||
* When the value is chart dependent,
|
||||
* should folder-wide goals be allowed conditionally?
|
||||
*
|
||||
* @example:
|
||||
* Arcaea's score is upperbounded at 10M+notecount, but scores below 10M
|
||||
* behave as if the max was 10M.
|
||||
*/
|
||||
allowFolderGoalsIf: (v: number) => boolean;
|
||||
chartDependentMax: true;
|
||||
}
|
||||
|
||||
interface ConfIntegerScoreMetricChartDependentWithExemption {
|
||||
type: "INTEGER";
|
||||
formatter: (v: number) => string;
|
||||
validate: (v: number) => string | true;
|
||||
|
||||
/**
|
||||
* When the value is chart dependent,
|
||||
* should folder-wide goals be allowed conditionally?
|
||||
*
|
||||
* @example:
|
||||
* Arcaea's score is upperbounded at 10M+notecount, but scores below 10M
|
||||
* behave as if the max was 10M.
|
||||
*/
|
||||
allowFolderGoalsIf: (v: number) => boolean;
|
||||
chartDependentMax: true;
|
||||
}
|
||||
|
||||
export type ConfDecimalScoreMetric =
|
||||
| ConfDecimalScoreMetricChartDependent
|
||||
| ConfDecimalScoreMetricChartDependentWithExemption
|
||||
| ConfDecimalScoreMetricNormal;
|
||||
|
||||
export type ConfIntegerScoreMetric =
|
||||
| ConfIntegerScoreMetricChartDependent
|
||||
| ConfIntegerScoreMetricChartDependentWithExemption
|
||||
| ConfIntegerScoreMetricNormal;
|
||||
|
||||
/**
|
||||
|
||||
@@ -268,7 +268,10 @@ export async function ValidateGoalChartsAndCriteria(
|
||||
switch (config.type) {
|
||||
case "DECIMAL":
|
||||
case "INTEGER": {
|
||||
if (config.chartDependentMax && charts.type !== "single") {
|
||||
const allowFolderGoals =
|
||||
config.chartDependentMax !== true || config.allowFolderGoalsIf?.(criteria.value);
|
||||
|
||||
if (!allowFolderGoals && charts.type !== "single") {
|
||||
throw new Error(
|
||||
`Creating ${criteria.key} goals on multiple charts where the maximum value is relative to the chart is a terrible idea, and has been disabled.`,
|
||||
);
|
||||
@@ -276,7 +279,7 @@ export async function ValidateGoalChartsAndCriteria(
|
||||
|
||||
let err;
|
||||
|
||||
if (config.chartDependentMax) {
|
||||
if (!allowFolderGoals) {
|
||||
const chart = await GetChartByIdForGame(game, charts.data as string);
|
||||
|
||||
if (!chart) {
|
||||
@@ -288,6 +291,7 @@ export async function ValidateGoalChartsAndCriteria(
|
||||
// @ts-expect-error this is fine leave me alone
|
||||
err = gptImpl.chartSpecificValidators[criteria.key](criteria.value, chart);
|
||||
} else {
|
||||
// @ts-expect-error if allowFolderGoals is true, validate has to exist, and tsc's opinion has no weight here.
|
||||
err = config.validate(criteria.value);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user