zenno/lib: legacy and affinity stuff
This commit is contained in:
35
zenno/src/lib/data/affinity.ts
Normal file
35
zenno/src/lib/data/affinity.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import globalJSON from '../../../../global/affinity.json';
|
||||
|
||||
/**
|
||||
* Precomputed character pair and trio affinity.
|
||||
*/
|
||||
export interface Affinity {
|
||||
/**
|
||||
* First character in the relation.
|
||||
*/
|
||||
chara_a: number;
|
||||
/**
|
||||
* Second character in the relation.
|
||||
* chara_a < chara_b is an invariant.
|
||||
*/
|
||||
chara_b: number;
|
||||
/**
|
||||
* Third character in the relation, if it is a trio relation.
|
||||
* If defined, chara_b < chara_c is an invariant.
|
||||
*/
|
||||
chara_c?: number;
|
||||
/**
|
||||
* Total base compatibility between characters in the relation.
|
||||
*/
|
||||
affinity: number;
|
||||
}
|
||||
|
||||
export const affinity = {
|
||||
global: globalJSON as Affinity[],
|
||||
} as const;
|
||||
|
||||
export function lookup(aff: Affinity[], chara_a: number, chara_b: number, chara_c?: number): number {
|
||||
const [a, b, c] = [chara_a, chara_b, chara_c ?? Infinity].sort((a, b) => a - b);
|
||||
const r = aff.find((v) => v.chara_a === a && v.chara_b === b && (v.chara_c ?? Infinity) === c);
|
||||
return r?.affinity ?? 0;
|
||||
}
|
||||
75
zenno/src/lib/data/uma.ts
Normal file
75
zenno/src/lib/data/uma.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import globalJSON from '../../../../global/uma.json';
|
||||
|
||||
/**
|
||||
* Uma or character card definitions.
|
||||
*/
|
||||
export interface Uma {
|
||||
/**
|
||||
* Uma ID.
|
||||
*/
|
||||
chara_card_id: number;
|
||||
/**
|
||||
* Character ID that the Uma is a variant of.
|
||||
*/
|
||||
chara_id: number;
|
||||
/**
|
||||
* Regional name of the Uma, comprised of the variant name and the character name.
|
||||
* E.g. "[Special Dreamer] Special Week".
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Regional variant name.
|
||||
* E.g. "[Special Dreamer]".
|
||||
*/
|
||||
variant: string;
|
||||
|
||||
sprint: AptitudeLevel;
|
||||
mile: AptitudeLevel;
|
||||
medium: AptitudeLevel;
|
||||
long: AptitudeLevel;
|
||||
front: AptitudeLevel;
|
||||
pace: AptitudeLevel;
|
||||
late: AptitudeLevel;
|
||||
end: AptitudeLevel;
|
||||
turf: AptitudeLevel;
|
||||
dirt: AptitudeLevel;
|
||||
|
||||
/**
|
||||
* ID of the Uma's unique skill.
|
||||
*/
|
||||
unique: number;
|
||||
/**
|
||||
* ID of the Uma's first built-in skill.
|
||||
*/
|
||||
skill1: number;
|
||||
/**
|
||||
* ID of the Uma's second built-in skill.
|
||||
*/
|
||||
skill2: number;
|
||||
/**
|
||||
* ID of the Uma's third built-in skill.
|
||||
*/
|
||||
skill3: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 2.
|
||||
*/
|
||||
skill_pl2: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 3.
|
||||
*/
|
||||
skill_pl3: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 4.
|
||||
*/
|
||||
skill_pl4: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 5.
|
||||
*/
|
||||
skill_pl5: number;
|
||||
}
|
||||
|
||||
export type AptitudeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
||||
|
||||
export const uma = {
|
||||
global: globalJSON as Uma[],
|
||||
};
|
||||
72
zenno/src/lib/legacy.ts
Normal file
72
zenno/src/lib/legacy.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { affinity, lookup } from './data/affinity';
|
||||
import { uma, type Uma } from './data/uma';
|
||||
|
||||
/**
|
||||
* A legacy, or parents and grandparents.
|
||||
* Defined as an applicative over generic types to reduce the API surface.
|
||||
* @see mapLegacy
|
||||
*/
|
||||
export interface Legacy<T> {
|
||||
p1: T;
|
||||
s11: T;
|
||||
s12: T;
|
||||
p2: T;
|
||||
s21: T;
|
||||
s22: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applicative fmap for legacies.
|
||||
* @param l Input legacy
|
||||
* @param f Mapping function
|
||||
* @returns Transformed legacy
|
||||
*/
|
||||
export function mapLegacy<U, V>(l: Legacy<U>, f: (u: U) => V): Legacy<V> {
|
||||
return {
|
||||
p1: f(l.p1),
|
||||
s11: f(l.s11),
|
||||
s12: f(l.s12),
|
||||
p2: f(l.p2),
|
||||
s21: f(l.s21),
|
||||
s22: f(l.s22),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A veteran, or the result of a completed career.
|
||||
*/
|
||||
export interface Veteran {
|
||||
uma: number;
|
||||
sparks: number[];
|
||||
saddles: number[];
|
||||
}
|
||||
|
||||
function findUma(umas: Uma[], u: number): Uma | null {
|
||||
return umas.find((v) => v.chara_card_id === u) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute individual affinities for a legacy using the global region ruleset.
|
||||
* @param trainee Uma (not character) ID of the trainee Uma
|
||||
* @param legacy Legacy veterans
|
||||
* @returns Individual affinities
|
||||
*/
|
||||
export function globalAffinity(trainee: number, legacy: Legacy<Veteran>): Legacy<number> {
|
||||
const t = findUma(uma.global, trainee)?.chara_id ?? 0;
|
||||
const charas = mapLegacy(legacy, (u) => findUma(uma.global, u.uma)?.chara_id ?? 0);
|
||||
const saddles = mapLegacy(legacy, (u) => new Set(u.saddles));
|
||||
const aff = affinity.global;
|
||||
const pp = lookup(aff, charas.p1, charas.p2);
|
||||
const s11 = lookup(aff, t, charas.p1, charas.s11) + saddles.p1.intersection(saddles.s11).size;
|
||||
const s12 = lookup(aff, t, charas.p1, charas.s12) + saddles.p1.intersection(saddles.s12).size;
|
||||
const s21 = lookup(aff, t, charas.p2, charas.s21) + saddles.p2.intersection(saddles.s21).size;
|
||||
const s22 = lookup(aff, t, charas.p2, charas.s22) + saddles.p2.intersection(saddles.s22).size;
|
||||
return {
|
||||
p1: lookup(aff, t, charas.p1) + pp + s11 + s12,
|
||||
s11,
|
||||
s12,
|
||||
p2: lookup(aff, t, charas.p2) + pp + s21 + s22,
|
||||
s21,
|
||||
s22,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user