Release v0.1.2 2026-07-11

This commit is contained in:
Warren H
2026-07-11 00:12:57 -04:00
parent 6726c600e4
commit 076f6cf97c
16 changed files with 556 additions and 21 deletions
+39 -1
View File
@@ -1,5 +1,6 @@
import { BULL_CHARGE } from "./bossMechanics";
import { CINDER_BREATH } from "./bosses/cindermaw";
import { EMBER_MANTIS_SLASH } from "./bosses/emberMantis";
import { moveToward, pointOutsideCircle, pointOutsideLane, pointToSegmentDistance } from "./geometry";
import type { BossMotionState, MemberId, PartyMember, WorldPosition } from "./types";
@@ -122,6 +123,42 @@ export const avoidBreathBehavior: PartyBehavior = {
},
};
export const evadeSlashLanesBehavior: PartyBehavior = {
id: "evade-slash-lanes",
decide: ({ memberId, current, formationTarget, bossMotion }) => {
if (bossMotion.mode !== "mantis_line_telegraph" && bossMotion.mode !== "mantis_cross_telegraph") return null;
if (!bossMotion.slashLanes.length) return null;
const unsafe = (position: WorldPosition) => bossMotion.slashLanes.some((lane) =>
pointToSegmentDistance(position, lane.start, lane.end) < EMBER_MANTIS_SLASH.aiClearance,
);
if (!unsafe(current) && !unsafe(formationTarget)) return null;
const origin = unsafe(formationTarget) ? formationTarget : current;
const memberOffset = AI_MEMBER_IDS.indexOf(memberId) * (Math.PI / 4);
let best = current;
let bestScore = Number.NEGATIVE_INFINITY;
for (const radius of [2.2, 3.4]) {
for (let index = 0; index < 8; index += 1) {
const angle = memberOffset + (index / 8) * Math.PI * 2;
const candidate = clampToArena([
origin[0] + Math.sin(angle) * radius,
origin[1] + Math.cos(angle) * radius,
]);
const laneDistance = Math.min(...bossMotion.slashLanes.map((lane) =>
pointToSegmentDistance(candidate, lane.start, lane.end),
));
const travelPenalty = Math.hypot(candidate[0] - current[0], candidate[1] - current[1]) * 0.08;
const score = laneDistance - travelPenalty;
if (score > bestScore) {
best = candidate;
bestScore = score;
}
}
}
return { target: best, speed: EMBER_MANTIS_SLASH.aiEvadeSpeed };
},
};
export const avoidCircleHazardsBehavior: PartyBehavior = {
id: "avoid-circle-hazards",
decide: ({ memberId, current, formationTarget, bossMotion, time }) => {
@@ -143,7 +180,7 @@ export const avoidCircleHazardsBehavior: PartyBehavior = {
export const maintainFormationBehavior: PartyBehavior = {
id: "maintain-formation",
decide: ({ formationTarget, bossMotion, memberId }) => {
if (!["holding", "telegraph", "tethering", "venom_cast", "skyfall"].includes(bossMotion.mode)) return null;
if (!["holding", "telegraph", "tethering", "venom_cast", "skyfall", "mantis_sidestep", "mantis_recover"].includes(bossMotion.mode)) return null;
return { target: formationTarget, speed: MOVE_SPEEDS[memberId] };
},
};
@@ -152,6 +189,7 @@ export const DEFAULT_PARTY_BEHAVIORS: readonly PartyBehavior[] = [
breakTetherBehavior,
stackForPounceBehavior,
evadeChargeBehavior,
evadeSlashLanesBehavior,
avoidBreathBehavior,
avoidCircleHazardsBehavior,
maintainFormationBehavior,