Android build v1.1.15
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
import type {
|
||||
Iwt2ArenaBounds,
|
||||
Iwt2ArenaCircleIndicator,
|
||||
Iwt2ArenaConeIndicator,
|
||||
Iwt2ArenaDonutIndicator,
|
||||
Iwt2ArenaEvent,
|
||||
Iwt2ArenaEventType,
|
||||
Iwt2ArenaIndicator,
|
||||
Iwt2ArenaIndicatorPhase,
|
||||
Iwt2ArenaLaneIndicator,
|
||||
Iwt2EntityId,
|
||||
Iwt2PartyEntityState,
|
||||
Iwt2Vec2,
|
||||
} from './types'
|
||||
import { circleIntersectsSegment } from './collision'
|
||||
import {
|
||||
addVec2,
|
||||
clampVec2ToArena,
|
||||
distanceVec2,
|
||||
normalizeVec2,
|
||||
scaleVec2,
|
||||
subtractVec2,
|
||||
} from './vector'
|
||||
|
||||
export type Iwt2LinearMovementPlan = {
|
||||
direction: Iwt2Vec2
|
||||
end: Iwt2Vec2
|
||||
}
|
||||
|
||||
export type Iwt2PartyDamageEffect = {
|
||||
sourceId: Iwt2EntityId
|
||||
time: number
|
||||
damage: number
|
||||
damageEventType?: Iwt2ArenaEventType
|
||||
stunSeconds?: number
|
||||
knockdownSeconds?: number
|
||||
statusEventType?: Iwt2ArenaEventType
|
||||
excludedEntityIds?: Iwt2EntityId[]
|
||||
}
|
||||
|
||||
export type Iwt2LaneHitShape = {
|
||||
kind: 'lane'
|
||||
start: Iwt2Vec2
|
||||
end: Iwt2Vec2
|
||||
width: number
|
||||
}
|
||||
|
||||
export type Iwt2CircleHitShape = {
|
||||
kind: 'circle'
|
||||
position: Iwt2Vec2
|
||||
radius: number
|
||||
}
|
||||
|
||||
export type Iwt2HitShape = Iwt2LaneHitShape | Iwt2CircleHitShape
|
||||
|
||||
export function createArenaEvent(
|
||||
id: number,
|
||||
time: number,
|
||||
type: Iwt2ArenaEventType,
|
||||
sourceId: Iwt2EntityId,
|
||||
targetId?: Iwt2EntityId,
|
||||
value?: number,
|
||||
): Iwt2ArenaEvent {
|
||||
return { id, time, type, sourceId, targetId, value }
|
||||
}
|
||||
|
||||
export function createLinearMovementPlan({
|
||||
bounds,
|
||||
from,
|
||||
length,
|
||||
radius,
|
||||
target,
|
||||
}: {
|
||||
bounds: Iwt2ArenaBounds
|
||||
from: Iwt2Vec2
|
||||
length: number
|
||||
radius: number
|
||||
target: Iwt2Vec2
|
||||
}): Iwt2LinearMovementPlan {
|
||||
const direction = normalizeVec2(subtractVec2(target, from))
|
||||
const rawEnd = addVec2(from, scaleVec2(direction, length))
|
||||
return {
|
||||
direction,
|
||||
end: clampVec2ToArena(rawEnd, radius, bounds),
|
||||
}
|
||||
}
|
||||
|
||||
export function applyPartyDamageInShape(
|
||||
party: Iwt2PartyEntityState[],
|
||||
shape: Iwt2HitShape,
|
||||
effect: Iwt2PartyDamageEffect,
|
||||
): {
|
||||
party: Iwt2PartyEntityState[]
|
||||
hitEntityIds: Iwt2EntityId[]
|
||||
events: Iwt2ArenaEvent[]
|
||||
} {
|
||||
const events: Iwt2ArenaEvent[] = []
|
||||
const excluded = new Set(effect.excludedEntityIds ?? [])
|
||||
const hitEntityIds: Iwt2EntityId[] = []
|
||||
const stunSeconds = effect.stunSeconds ?? 0
|
||||
const knockdownSeconds = effect.knockdownSeconds ?? stunSeconds
|
||||
const nextParty = party.map((member) => {
|
||||
if (member.health <= 0 || excluded.has(member.id) || !partyMemberIntersectsShape(member, shape)) {
|
||||
return member
|
||||
}
|
||||
|
||||
hitEntityIds.push(member.id)
|
||||
const shieldAbsorbed = Math.min(member.shield, effect.damage)
|
||||
const healthDamage = effect.damage - shieldAbsorbed
|
||||
const nextShield = member.shield - shieldAbsorbed
|
||||
const nextHealth = Math.max(0, member.health - healthDamage)
|
||||
events.push(createArenaEvent(
|
||||
0,
|
||||
effect.time,
|
||||
effect.damageEventType ?? 'partyDamaged',
|
||||
effect.sourceId,
|
||||
member.id,
|
||||
effect.damage,
|
||||
))
|
||||
if (stunSeconds > 0 || knockdownSeconds > 0) {
|
||||
events.push(createArenaEvent(
|
||||
0,
|
||||
effect.time,
|
||||
effect.statusEventType ?? 'partyStunned',
|
||||
effect.sourceId,
|
||||
member.id,
|
||||
Math.max(stunSeconds, knockdownSeconds),
|
||||
))
|
||||
}
|
||||
if (member.health > 0 && nextHealth <= 0) {
|
||||
events.push(createArenaEvent(0, effect.time, 'entityDefeated', effect.sourceId, member.id))
|
||||
}
|
||||
|
||||
return {
|
||||
...member,
|
||||
health: nextHealth,
|
||||
shield: nextShield,
|
||||
status: {
|
||||
...member.status,
|
||||
stunnedSeconds: Math.max(member.status.stunnedSeconds, stunSeconds),
|
||||
knockedDownSeconds: Math.max(member.status.knockedDownSeconds, knockdownSeconds),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
return { party: nextParty, hitEntityIds, events }
|
||||
}
|
||||
|
||||
export function partyMemberIntersectsShape(member: Iwt2PartyEntityState, shape: Iwt2HitShape): boolean {
|
||||
if (shape.kind === 'lane') {
|
||||
return circleIntersectsSegment(
|
||||
{ position: member.position, radius: member.radius },
|
||||
shape.start,
|
||||
shape.end,
|
||||
shape.width,
|
||||
)
|
||||
}
|
||||
return distanceVec2(member.position, shape.position) <= shape.radius + member.radius
|
||||
}
|
||||
|
||||
export function createLaneIndicator({
|
||||
color,
|
||||
end,
|
||||
id,
|
||||
mechanicId,
|
||||
phase,
|
||||
sourceId,
|
||||
start,
|
||||
width,
|
||||
}: {
|
||||
color: string
|
||||
end: Iwt2Vec2
|
||||
id: string
|
||||
mechanicId: string
|
||||
phase: Iwt2ArenaIndicatorPhase
|
||||
sourceId: Iwt2EntityId
|
||||
start: Iwt2Vec2
|
||||
width: number
|
||||
}): Iwt2ArenaLaneIndicator {
|
||||
return {
|
||||
color,
|
||||
end: { ...end },
|
||||
fillAlpha: phase === 'active' ? 0.18 : 0.11,
|
||||
id,
|
||||
kind: 'lane',
|
||||
lineAlpha: phase === 'active' ? 0.8 : 0.45,
|
||||
mechanicId,
|
||||
phase,
|
||||
sourceId,
|
||||
start: { ...start },
|
||||
width,
|
||||
}
|
||||
}
|
||||
|
||||
export function createCircleIndicator({
|
||||
color,
|
||||
id,
|
||||
mechanicId,
|
||||
phase,
|
||||
position,
|
||||
radius,
|
||||
sourceId,
|
||||
}: {
|
||||
color: string
|
||||
id: string
|
||||
mechanicId: string
|
||||
phase: Iwt2ArenaIndicatorPhase
|
||||
position: Iwt2Vec2
|
||||
radius: number
|
||||
sourceId: Iwt2EntityId
|
||||
}): Iwt2ArenaCircleIndicator {
|
||||
return {
|
||||
color,
|
||||
fillAlpha: phase === 'active' ? 0.18 : 0.12,
|
||||
id,
|
||||
kind: 'circle',
|
||||
lineAlpha: phase === 'active' ? 0.75 : 0.55,
|
||||
mechanicId,
|
||||
phase,
|
||||
position: { ...position },
|
||||
radius,
|
||||
sourceId,
|
||||
}
|
||||
}
|
||||
|
||||
export function createConeIndicator({
|
||||
angleRadians,
|
||||
color,
|
||||
direction,
|
||||
id,
|
||||
mechanicId,
|
||||
origin,
|
||||
phase,
|
||||
range,
|
||||
sourceId,
|
||||
}: {
|
||||
angleRadians: number
|
||||
color: string
|
||||
direction: Iwt2Vec2
|
||||
id: string
|
||||
mechanicId: string
|
||||
origin: Iwt2Vec2
|
||||
phase: Iwt2ArenaIndicatorPhase
|
||||
range: number
|
||||
sourceId: Iwt2EntityId
|
||||
}): Iwt2ArenaConeIndicator {
|
||||
return {
|
||||
angleRadians,
|
||||
color,
|
||||
direction: normalizeVec2(direction),
|
||||
fillAlpha: phase === 'active' ? 0.18 : 0.1,
|
||||
id,
|
||||
kind: 'cone',
|
||||
lineAlpha: phase === 'active' ? 0.72 : 0.48,
|
||||
mechanicId,
|
||||
origin: { ...origin },
|
||||
phase,
|
||||
range,
|
||||
sourceId,
|
||||
}
|
||||
}
|
||||
|
||||
export function createDonutIndicator({
|
||||
color,
|
||||
id,
|
||||
innerRadius,
|
||||
mechanicId,
|
||||
outerRadius,
|
||||
phase,
|
||||
position,
|
||||
sourceId,
|
||||
}: {
|
||||
color: string
|
||||
id: string
|
||||
innerRadius: number
|
||||
mechanicId: string
|
||||
outerRadius: number
|
||||
phase: Iwt2ArenaIndicatorPhase
|
||||
position: Iwt2Vec2
|
||||
sourceId: Iwt2EntityId
|
||||
}): Iwt2ArenaDonutIndicator {
|
||||
return {
|
||||
color,
|
||||
fillAlpha: phase === 'active' ? 0.14 : 0.08,
|
||||
id,
|
||||
innerRadius,
|
||||
kind: 'donut',
|
||||
lineAlpha: phase === 'active' ? 0.76 : 0.5,
|
||||
mechanicId,
|
||||
outerRadius,
|
||||
phase,
|
||||
position: { ...position },
|
||||
sourceId,
|
||||
}
|
||||
}
|
||||
|
||||
export function indicatorPhaseFromAttack(
|
||||
windup: boolean,
|
||||
active: boolean,
|
||||
): Iwt2ArenaIndicatorPhase {
|
||||
if (active) return 'active'
|
||||
if (windup) return 'windup'
|
||||
return 'recover'
|
||||
}
|
||||
|
||||
export function isIndicatorActive(indicator: Iwt2ArenaIndicator): boolean {
|
||||
return indicator.phase === 'active'
|
||||
}
|
||||
Reference in New Issue
Block a user