zenno: tooltips on skills

This commit is contained in:
2026-05-25 15:30:32 -04:00
parent a89ef8fc4c
commit 7b45b8761b
3 changed files with 248 additions and 7 deletions

View File

@@ -57,6 +57,24 @@ export interface Skill {
icon_id: number;
}
export enum DurationScale {
Direct = 1,
FrontDistance = 2,
RemainingHP = 3,
IncrementPass = 4,
MidSideBlock = 5,
RemainingHP2 = 7,
}
export const DURATION_SCALE_NAME: Readonly<Record<DurationScale, string>> = {
[DurationScale.Direct]: '',
[DurationScale.FrontDistance]: 'scaling with distance from the front',
[DurationScale.RemainingHP]: 'scaling with remaining HP',
[DurationScale.IncrementPass]: 'increasing with each pass while active',
[DurationScale.MidSideBlock]: 'scaling with mid-race phase blocked side time',
[DurationScale.RemainingHP2]: 'scaling with remaining HP',
} as const;
/**
* Conditions and results of skill activation.
*/
@@ -77,7 +95,7 @@ export interface Activation {
/**
* Special skill duration scaling mode.
*/
dur_scale: 1 | 2 | 3 | 4 | 5 | 7;
dur_scale: DurationScale;
/**
* Skill cooldown in ten thousandths of a second.
* A value of 5000000 indicates that the cooldown is forever.
@@ -90,6 +108,159 @@ export interface Activation {
abilities: Ability[];
}
export function tenThousandths(v: number): string {
const q = v / 10000;
if (v % 10000 === 0) {
return q.toString();
}
const s = q.toFixed(4);
const j = /\.?0+$/.exec(s);
return s.substring(0, j?.index ?? undefined);
}
function plusBonus(v: number): string {
const s = tenThousandths(v);
return v < 0 ? s : '+' + s;
}
export enum AbilityType {
Speed = 1,
Stamina = 2,
Power = 3,
Guts = 4,
Wit = 5,
GreatEscape = 6,
Vision = 8,
HP = 9,
GateDelay = 10,
Frenzy = 13,
AddGateDelay = 14,
CurrentSpeed = 21,
TargetSpeed = 27,
LaneSpeed = 28,
Accel = 31,
LaneChange = 35,
}
export const ABILITY_TYPE_FORMAT: Readonly<Record<AbilityType, (v: number) => string>> = {
[AbilityType.Speed]: (v) => 'Speed ' + plusBonus(v),
[AbilityType.Stamina]: (v) => 'Stamina ' + plusBonus(v),
[AbilityType.Power]: (v) => 'Power ' + plusBonus(v),
[AbilityType.Guts]: (v) => 'Guts ' + plusBonus(v),
[AbilityType.Wit]: (v) => 'Wit ' + plusBonus(v),
[AbilityType.GreatEscape]: () => 'Enable Great Escape',
[AbilityType.Vision]: (v) => plusBonus(v) + 'm Vision',
[AbilityType.HP]: (v) => (v > 0 ? tenThousandths(v * 100) + '% Recovery' : tenThousandths(v * 100) + '% HP Drain'),
[AbilityType.GateDelay]: (v) => tenThousandths(v) + '× Gate Delay',
[AbilityType.Frenzy]: (v) => tenThousandths(v) + 's Frenzy',
[AbilityType.AddGateDelay]: (v) => plusBonus(v) + 's Gate Delay',
[AbilityType.CurrentSpeed]: (v) => plusBonus(v) + ' m/s Current Speed',
[AbilityType.TargetSpeed]: (v) => plusBonus(v) + ' m/s Target Speed',
[AbilityType.LaneSpeed]: (v) => plusBonus(v) + ' CW/s Lane Change Speed',
[AbilityType.Accel]: (v) => plusBonus(v) + ' m/s² Acceleration',
[AbilityType.LaneChange]: (v) => 'Target Lane = ' + tenThousandths(v) + ' CW',
} as const;
export enum AbilityValueUsage {
Direct = 1,
SkillCount = 2,
TeamSpeed = 3,
TeamStamina = 4,
TeamPower = 5,
TeamGuts = 6,
TeamWit = 7,
Random1 = 8,
Random2 = 9,
Climax = 10,
MaxStat = 13,
GreenCount = 14,
DistAdd = 19,
MidRaceSideBlock = 20,
Speed1 = 22,
Speed2 = 23,
ArcPotential = 24,
MaxLead = 25,
}
export const ABILITY_SCALE_NAME: Readonly<Record<AbilityValueUsage, string>> = {
[AbilityValueUsage.Direct]: '',
[AbilityValueUsage.SkillCount]: 'scaling with the number of skills',
[AbilityValueUsage.TeamSpeed]: 'scaling with team Speed',
[AbilityValueUsage.TeamStamina]: 'scaling with team Stamina',
[AbilityValueUsage.TeamPower]: 'scaling with team Power',
[AbilityValueUsage.TeamGuts]: 'scaling with team Guts',
[AbilityValueUsage.TeamWit]: 'scaling with team Wit',
[AbilityValueUsage.Random1]: 'with a random 0× to 0.04× multiplier',
[AbilityValueUsage.Random2]: 'with a random 0× to 0.04× mulitplier',
[AbilityValueUsage.Climax]: 'scaling with the number of races won in training',
[AbilityValueUsage.MaxStat]: 'scaling with the highest raw stat',
[AbilityValueUsage.GreenCount]: 'scaling with the number of Passive skills activated',
[AbilityValueUsage.DistAdd]: 'plus extra when far from the lead',
[AbilityValueUsage.MidRaceSideBlock]: 'scaling with mid-race phase blocked side time',
[AbilityValueUsage.Speed1]: 'scaling with overall speed',
[AbilityValueUsage.Speed2]: 'scaling with overall speed',
[AbilityValueUsage.ArcPotential]: "scaling with L'Arc global potential",
[AbilityValueUsage.MaxLead]: 'scaling with the longest lead obtained in the first ⅔',
};
export enum Target {
Self = 1,
Sympathizers = 2,
InView = 4,
Frontmost = 7,
Ahead = 9,
Behind = 10,
AllTeammates = 11,
Style = 18,
RushingAhead = 19,
RushingBehind = 20,
RushingStyle = 21,
Character = 22,
Triggering = 23,
}
function targetn(v: number, n: string, one?: string): string {
switch (v) {
case 1:
return one != null ? one : `to ${n}`;
case 18:
return `to all ${n}`;
default:
return `to ${v} others ${n}`;
}
}
function stylename(v: number, infix: string): string {
switch (v) {
case 1:
return `to ${infix} Front Runners`;
case 2:
return `to ${infix} Pace Chasers`;
case 3:
return `to ${infix} Late Surgers`;
case 4:
return `to ${infix} End Closers`;
default:
return `to all running unknown style ${v}`;
}
}
export const TARGET_FORMAT: Readonly<Record<Target, (v?: number) => string>> = {
[Target.Self]: () => '',
[Target.Sympathizers]: () => 'to others with Sympathy',
[Target.InView]: (v) => targetn(v!, 'in view'),
[Target.Frontmost]: (v) => targetn(v!, 'at the front', 'the frontmost'),
[Target.Ahead]: (v) => targetn(v!, 'ahead'),
[Target.Behind]: (v) => targetn(v!, 'behind'),
[Target.AllTeammates]: () => 'to all teammates',
[Target.Style]: (v) => stylename(v!, 'all'),
[Target.RushingAhead]: (v) => targetn(v!, 'rushing ahead'),
[Target.RushingBehind]: (v) => targetn(v!, 'rushing behind'),
[Target.RushingStyle]: (v) => stylename(v!, 'all rushing'),
[Target.Character]: (v) => `to character ${v}`,
[Target.Triggering]: () => 'to whosoever triggered this skill',
} as const;
/**
* Effects applied when a skill activates.
*/
@@ -97,11 +268,11 @@ export interface Ability {
/**
* Race mechanic affected by the ability.
*/
type: 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 13 | 21 | 27 | 28 | 31 | 35;
type: AbilityType;
/**
* Special scaling type of the skill value.
*/
value_usage: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 19 | 20 | 22 | 23 | 24 | 25;
value_usage: AbilityValueUsage;
/**
* Amount that the skill modifies the race mechanic in ten thousandths of
* whatever is the appropriate unit.
@@ -110,7 +281,7 @@ export interface Ability {
/**
* Selector for horses targeted by the ability.
*/
target: 1 | 2 | 4 | 7 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23;
target: Target;
/**
* Argument value for the ability target, when appropriate.
*/