Android build v1.1.20
This commit is contained in:
@@ -56,9 +56,13 @@ const INITIAL_PARTY: InitialPartyMember[] = [
|
||||
{ id: 'warrior', classId: 'warrior', aiRole: 'melee', x: 515, y: 310, preferredOffset: { x: -18, y: 64 }, decisionOffset: 0.24 },
|
||||
]
|
||||
|
||||
export function createInitialIwt2ArenaState(bossId: Iwt2BossId = 'bulldrome', bossIds?: Iwt2BossId[]): Iwt2ArenaState {
|
||||
export function createInitialIwt2ArenaState(
|
||||
bossId: Iwt2BossId = 'bulldrome',
|
||||
bossIds?: Iwt2BossId[],
|
||||
bossHealthScale = 1,
|
||||
): Iwt2ArenaState {
|
||||
const initialBossIds = bossIds?.length ? bossIds.slice(0, 2) : chooseInitialBossIds(bossId)
|
||||
const bosses = initialBossIds.map((id, index) => createBossEntity(id, index))
|
||||
const bosses = initialBossIds.map((id, index) => createBossEntity(id, index, bossHealthScale))
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
time: 0,
|
||||
@@ -84,9 +88,10 @@ function chooseInitialBossIds(primaryBossId: Iwt2BossId): Iwt2BossId[] {
|
||||
return [primaryBossId, random]
|
||||
}
|
||||
|
||||
function createBossEntity(bossId: Iwt2BossId, index: number): Iwt2BossEntityState {
|
||||
function createBossEntity(bossId: Iwt2BossId, index: number, healthScale: number): Iwt2BossEntityState {
|
||||
const bossMetadata = IWT2_BOSS_METADATA[bossId]
|
||||
const position = initialBossPosition(index)
|
||||
const maxHealth = Math.max(1, Math.round(bossMetadata.maxHealth * Math.max(0.01, healthScale)))
|
||||
return {
|
||||
id: bossId,
|
||||
kind: 'boss',
|
||||
@@ -95,8 +100,8 @@ function createBossEntity(bossId: Iwt2BossId, index: number): Iwt2BossEntityStat
|
||||
velocity: { x: 0, y: 0 },
|
||||
facing: { x: -1, y: 0 },
|
||||
radius: bossMetadata.radius,
|
||||
health: bossMetadata.maxHealth,
|
||||
maxHealth: bossMetadata.maxHealth,
|
||||
health: maxHealth,
|
||||
maxHealth,
|
||||
meleeCooldownRemaining: 0.6 + index * 0.25,
|
||||
chargeCooldownRemaining: initialBossSpecialCooldown(bossId) + index * 0.7,
|
||||
chargeCount: 0,
|
||||
|
||||
@@ -54,8 +54,12 @@ export type Iwt2ArenaState = Iwt2CoreArenaState & {
|
||||
telegraphs: Iwt2ArenaTelegraph[]
|
||||
}
|
||||
|
||||
export function createInitialIwt2ArenaState(bossId?: Iwt2BossId, bossIds?: Iwt2BossId[]): Iwt2ArenaState {
|
||||
return decorateArenaState(createCoreIwt2ArenaState(bossId, bossIds))
|
||||
export function createInitialIwt2ArenaState(
|
||||
bossId?: Iwt2BossId,
|
||||
bossIds?: Iwt2BossId[],
|
||||
bossHealthScale?: number,
|
||||
): Iwt2ArenaState {
|
||||
return decorateArenaState(createCoreIwt2ArenaState(bossId, bossIds, bossHealthScale))
|
||||
}
|
||||
|
||||
export function tickIwt2Arena(state: Iwt2ArenaState, input: Iwt2ArenaInput, dt: number): Iwt2ArenaState {
|
||||
|
||||
@@ -14,11 +14,12 @@ import {
|
||||
withFallbackFacing,
|
||||
} from './vector'
|
||||
|
||||
const CENTER_LEASH_BOSS_IDS = new Set(['great-jaggi', 'khezu'])
|
||||
const NO_CENTER_LEASH_BOSS_IDS = new Set<string>()
|
||||
const CENTER_LEASH_START_DISTANCE = 230
|
||||
const CENTER_LEASH_WALL_MARGIN = 96
|
||||
const CENTER_LEASH_EXTRA_DISTANCE = 36
|
||||
const PARTY_ARRIVAL_RADIUS = 3.5
|
||||
const PARTY_SAFE_DESTINATION_PADDING = 34
|
||||
|
||||
export function tickPartyMember(
|
||||
member: Iwt2PartyEntityState,
|
||||
@@ -128,24 +129,29 @@ function getPartyDesiredPosition(
|
||||
const anchor = attackTarget?.position ?? getPrimaryBoss(state).position
|
||||
const centerLeash = getTankCenterLeashPosition(member, state)
|
||||
if (centerLeash) return centerLeash
|
||||
return {
|
||||
return clampPartyDestination({
|
||||
x: anchor.x + member.preferredOffset.x + drift.x,
|
||||
y: anchor.y + member.preferredOffset.y + drift.y,
|
||||
}
|
||||
}, member, state)
|
||||
}
|
||||
|
||||
function clampPartyDestination(
|
||||
position: Iwt2Vec2,
|
||||
member: Iwt2PartyEntityState,
|
||||
state: Iwt2ArenaState,
|
||||
): Iwt2Vec2 {
|
||||
return clampVec2ToArena(position, member.radius + PARTY_SAFE_DESTINATION_PADDING, state.bounds)
|
||||
}
|
||||
|
||||
function getTankCenterLeashPosition(
|
||||
member: Iwt2PartyEntityState,
|
||||
state: Iwt2ArenaState,
|
||||
): Iwt2Vec2 | null {
|
||||
const boss = getPrimaryBoss(state)
|
||||
if (member.aiRole !== 'tank' || !CENTER_LEASH_BOSS_IDS.has(boss.bossId)) return null
|
||||
if (member.aiRole !== 'tank') return null
|
||||
const boss = getCenterLeashBoss(member, state)
|
||||
if (!boss) return null
|
||||
|
||||
const center = arenaCenter(state)
|
||||
const bossCenterDistance = distanceVec2(boss.position, center)
|
||||
const nearWall = isBossNearWall(boss, state)
|
||||
if (!nearWall && bossCenterDistance < CENTER_LEASH_START_DISTANCE) return null
|
||||
|
||||
const bossMetadata = IWT2_BOSS_METADATA[boss.bossId]
|
||||
const towardCenter = withFallbackFacing(subtractVec2(center, boss.position), {
|
||||
x: boss.position.x < center.x ? 1 : -1,
|
||||
@@ -159,6 +165,21 @@ function getTankCenterLeashPosition(
|
||||
)
|
||||
}
|
||||
|
||||
function getCenterLeashBoss(
|
||||
member: Iwt2PartyEntityState,
|
||||
state: Iwt2ArenaState,
|
||||
): Iwt2ArenaState['boss'] | null {
|
||||
const center = arenaCenter(state)
|
||||
const candidates = state.bosses.filter((boss) => {
|
||||
if (boss.health <= 0 || NO_CENTER_LEASH_BOSS_IDS.has(boss.bossId)) return false
|
||||
return isBossNearWall(boss, state) || distanceVec2(boss.position, center) >= CENTER_LEASH_START_DISTANCE
|
||||
})
|
||||
if (candidates.length === 0) return null
|
||||
return candidates.reduce((best, boss) => (
|
||||
distanceVec2(member.position, boss.position) < distanceVec2(member.position, best.position) ? boss : best
|
||||
), candidates[0])
|
||||
}
|
||||
|
||||
function arenaCenter(state: Iwt2ArenaState): Iwt2Vec2 {
|
||||
return {
|
||||
x: state.bounds.width * 0.5,
|
||||
|
||||
Reference in New Issue
Block a user