Android build v1.1.2
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import { memo, type ElementType, type ReactNode } from 'react'
|
||||
import type { ControllerIconStyle } from '../input'
|
||||
import type { PartyMember } from '../game'
|
||||
import {
|
||||
effectiveMaxHealth,
|
||||
formatEffectTime,
|
||||
memberHotEffects,
|
||||
} from '../combat/rules'
|
||||
import { ControllerBindingLabel } from './ControllerIcons'
|
||||
|
||||
export type FloatingCombatText = {
|
||||
id: number
|
||||
memberId: string
|
||||
value: number
|
||||
}
|
||||
|
||||
type MemberEffectMode = 'full' | 'compact' | 'timed-basic'
|
||||
|
||||
const MemberEffects = memo(function MemberEffects({
|
||||
member,
|
||||
mode,
|
||||
}: {
|
||||
member: PartyMember
|
||||
mode: MemberEffectMode
|
||||
}) {
|
||||
if (mode === 'compact') {
|
||||
return (
|
||||
<div className="member-effects">
|
||||
{memberHotEffects(member).map((effect) => (
|
||||
<span className="buff" key={effect.id}>{effect.label}</span>
|
||||
))}
|
||||
{member.shield > 0 && <span className="buff">Shield {Math.ceil(member.shield)}</span>}
|
||||
{member.debuff && <span className="debuff">{member.debuff}</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (mode === 'timed-basic') {
|
||||
return (
|
||||
<div className="member-effects">
|
||||
{member.hotTicks > 0 && <span className="buff">Renew {formatEffectTime(member.hotTicks)}</span>}
|
||||
{member.shield > 0 && <span className="buff">Shield {Math.ceil(member.shield)}</span>}
|
||||
{member.debuff && member.debuffTicks && <span className="debuff">{member.debuff} {formatEffectTime(member.debuffTicks)}</span>}
|
||||
{(member.poisonStacks ?? 0) > 0 && <span className="debuff">Poison {member.poisonStacks}</span>}
|
||||
{(member.maxHealthPenaltyTicks ?? 0) > 0 && <span className="debuff">Max HP -25% {formatEffectTime(member.maxHealthPenaltyTicks ?? 0)}</span>}
|
||||
{(member.healingReductionTicks ?? 0) > 0 && <span className="debuff">Healing -25% {formatEffectTime(member.healingReductionTicks ?? 0)}</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="member-effects">
|
||||
{memberHotEffects(member).map((effect) => (
|
||||
<span className="buff" key={effect.id}>{effect.label} {formatEffectTime(effect.ticks)}</span>
|
||||
))}
|
||||
{member.shield > 0 && <span className="buff">Shield {Math.ceil(member.shield)}</span>}
|
||||
{(member.damageReductionTicks ?? 0) > 0 && <span className="buff">Barkskin {formatEffectTime(member.damageReductionTicks ?? 0)}</span>}
|
||||
{(member.bounceHeals ?? []).map((effect) => (
|
||||
<span className="buff" key={effect.id}>{effect.label} {effect.charges}</span>
|
||||
))}
|
||||
{member.debuff && member.debuffTicks && <span className="debuff">{member.debuff} {formatEffectTime(member.debuffTicks)}</span>}
|
||||
{(member.poisonStacks ?? 0) > 0 && <span className="debuff">Poison {member.poisonStacks}</span>}
|
||||
{(member.maxHealthPenaltyTicks ?? 0) > 0 && <span className="debuff">Max HP -25% {formatEffectTime(member.maxHealthPenaltyTicks ?? 0)}</span>}
|
||||
{(member.healingReductionTicks ?? 0) > 0 && <span className="debuff">Healing -25% {formatEffectTime(member.healingReductionTicks ?? 0)}</span>}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export const PartyMemberFrame = memo(function PartyMemberFrame({
|
||||
as,
|
||||
member,
|
||||
selected = false,
|
||||
baseClassName = 'party-member',
|
||||
selectedClassName = 'selected',
|
||||
deadClassName = 'dead',
|
||||
effectMode = 'full',
|
||||
floatingTexts = [],
|
||||
showTargetMarker = false,
|
||||
showHeaderHealth = true,
|
||||
showHealthText = false,
|
||||
targetBinding,
|
||||
controllerIconStyle,
|
||||
onSelect,
|
||||
children,
|
||||
}: {
|
||||
as?: ElementType
|
||||
member: PartyMember
|
||||
selected?: boolean
|
||||
baseClassName?: string
|
||||
selectedClassName?: string
|
||||
deadClassName?: string
|
||||
effectMode?: MemberEffectMode
|
||||
floatingTexts?: FloatingCombatText[]
|
||||
showTargetMarker?: boolean
|
||||
showHeaderHealth?: boolean
|
||||
showHealthText?: boolean
|
||||
targetBinding?: string | null
|
||||
controllerIconStyle?: ControllerIconStyle
|
||||
onSelect?: (id: string) => void
|
||||
children?: ReactNode
|
||||
}) {
|
||||
const Component = as ?? (onSelect ? 'button' : 'div')
|
||||
const maxHealth = effectiveMaxHealth(member)
|
||||
const className = [
|
||||
baseClassName,
|
||||
selected ? selectedClassName : '',
|
||||
member.health <= 0 ? deadClassName : '',
|
||||
].filter(Boolean).join(' ')
|
||||
const action = targetBinding ? {
|
||||
binding: targetBinding,
|
||||
iconStyle: controllerIconStyle ?? 'xbox',
|
||||
} : null
|
||||
|
||||
return (
|
||||
<Component
|
||||
className={className}
|
||||
data-party-member-id={member.id}
|
||||
onClick={onSelect ? () => onSelect(member.id) : undefined}
|
||||
aria-pressed={onSelect ? selected : undefined}
|
||||
type={Component === 'button' ? 'button' : undefined}
|
||||
>
|
||||
{showTargetMarker && (
|
||||
<span className="target-marker" aria-hidden="true">
|
||||
<i />
|
||||
Target
|
||||
</span>
|
||||
)}
|
||||
<div className="member-header">
|
||||
<span className={`role role-${member.role.toLowerCase()}`}>{member.role[0]}</span>
|
||||
<strong>{member.name}</strong>
|
||||
{showHeaderHealth && <small>{Math.ceil(member.health)} / {maxHealth}</small>}
|
||||
</div>
|
||||
<div className="bar member-health">
|
||||
<span style={{ width: `${(member.health / maxHealth) * 100}%` }} />
|
||||
{member.shield > 0 && <i style={{ width: `${(member.shield / maxHealth) * 100}%` }} />}
|
||||
{showHealthText && <em className="health-text">{Math.floor(member.health)} / {maxHealth}</em>}
|
||||
</div>
|
||||
<div className="floating-combat-texts" aria-hidden="true">
|
||||
{floatingTexts.map((entry) => <span className="floating-heal" key={entry.id}>+{entry.value}</span>)}
|
||||
</div>
|
||||
{action && (
|
||||
<div className="member-target-key">
|
||||
<ControllerBindingLabel
|
||||
binding={action.binding}
|
||||
iconStyle={action.iconStyle}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<MemberEffects member={member} mode={effectMode} />
|
||||
{children}
|
||||
</Component>
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user