Android build v1.1.15

This commit is contained in:
Warren H
2026-07-04 12:43:59 -04:00
parent a849cd2c69
commit 99e97e5208
47 changed files with 8470 additions and 1610 deletions
+162
View File
@@ -0,0 +1,162 @@
import type {
Iwt2ArenaEvent,
Iwt2ArenaIndicator,
Iwt2EntityId,
Iwt2GroundHazardState,
Iwt2PartyEntityState,
Iwt2Vec2,
} from './types'
import {
applyPartyDamageInShape,
createCircleIndicator,
} from './mechanics'
const MAX_FIRE_PUDDLES = 8
const FIRE_PUDDLE_TICK_SECONDS = 0.55
const FIRE_PUDDLE_FADE_SECONDS = 0.8
const FIRE_PUDDLE_MERGE_DISTANCE = 28
export function addFirePuddle({
damage,
duration,
hazards,
nextHazardId,
position,
radius,
sourceId,
time,
}: {
damage: number
duration: number
hazards: Iwt2GroundHazardState[]
nextHazardId: number
position: Iwt2Vec2
radius: number
sourceId: Iwt2EntityId
time: number
}): { hazards: Iwt2GroundHazardState[], nextHazardId: number } {
const overlappingIndex = hazards.findIndex((hazard) => (
hazard.hazardKind === 'firePuddle'
&& hazard.remainingSeconds > hazard.fadeSeconds
&& Math.hypot(hazard.position.x - position.x, hazard.position.y - position.y) <= FIRE_PUDDLE_MERGE_DISTANCE
))
if (overlappingIndex >= 0) {
return {
hazards: hazards.map((hazard, index) => index === overlappingIndex
? {
...hazard,
damage: Math.max(hazard.damage, damage),
position: {
x: (hazard.position.x + position.x) / 2,
y: (hazard.position.y + position.y) / 2,
},
radius: Math.max(hazard.radius, radius),
remainingSeconds: Math.max(hazard.remainingSeconds, duration),
}
: hazard),
nextHazardId,
}
}
const nextHazard: Iwt2GroundHazardState = {
id: `fire-puddle-${nextHazardId}`,
kind: 'groundHazard',
hazardKind: 'firePuddle',
sourceId,
position: { ...position },
radius,
damage,
remainingSeconds: duration,
fadeSeconds: FIRE_PUDDLE_FADE_SECONDS,
nextDamageAt: time + 0.12,
}
return {
hazards: capFirePuddles([...hazards, nextHazard]),
nextHazardId: nextHazardId + 1,
}
}
export function tickGroundHazards({
dt,
hazards,
party,
time,
}: {
dt: number
hazards: Iwt2GroundHazardState[]
party: Iwt2PartyEntityState[]
time: number
}): {
hazards: Iwt2GroundHazardState[]
party: Iwt2PartyEntityState[]
events: Iwt2ArenaEvent[]
} {
const events: Iwt2ArenaEvent[] = []
let nextParty = party
const nextHazards: Iwt2GroundHazardState[] = []
for (const hazard of hazards) {
const remainingSeconds = hazard.remainingSeconds - dt
if (remainingSeconds <= 0) continue
let nextDamageAt = hazard.nextDamageAt
if (time >= hazard.nextDamageAt) {
const result = applyPartyDamageInShape(
nextParty,
{
kind: 'circle',
position: hazard.position,
radius: hazard.radius,
},
{
damage: hazard.damage,
sourceId: hazard.sourceId,
time,
},
)
nextParty = result.party
events.push(...result.events)
nextDamageAt = time + FIRE_PUDDLE_TICK_SECONDS
}
nextHazards.push({
...hazard,
nextDamageAt,
remainingSeconds,
})
}
return {
events,
hazards: nextHazards,
party: nextParty,
}
}
export function createHazardIndicators(hazards: Iwt2GroundHazardState[]): Iwt2ArenaIndicator[] {
return hazards.map((hazard) => createCircleIndicator({
color: '#ff7a2f',
id: `${hazard.id}:indicator`,
mechanicId: 'fire-puddle',
phase: hazard.remainingSeconds <= hazard.fadeSeconds ? 'recover' : 'active',
position: hazard.position,
radius: hazard.radius,
sourceId: hazard.sourceId,
}))
}
function capFirePuddles(hazards: Iwt2GroundHazardState[]): Iwt2GroundHazardState[] {
let activePuddles = 0
let oldestActivePuddleIndex = -1
for (let index = 0; index < hazards.length; index += 1) {
const hazard = hazards[index]
if (hazard.hazardKind !== 'firePuddle' || hazard.remainingSeconds <= hazard.fadeSeconds) continue
activePuddles += 1
if (oldestActivePuddleIndex < 0) oldestActivePuddleIndex = index
}
if (activePuddles <= MAX_FIRE_PUDDLES || oldestActivePuddleIndex < 0) return hazards
return hazards.map((hazard, index) => index === oldestActivePuddleIndex
? { ...hazard, remainingSeconds: Math.min(hazard.remainingSeconds, hazard.fadeSeconds) }
: hazard)
}