made some changes to the UI, removed leaderboards. updated gamesaves
This commit is contained in:
@@ -241,7 +241,7 @@ function makeRoguelikeSegment(
|
||||
encounter.maxHealth
|
||||
+ encounter.damage * 18
|
||||
+ encounter.tankDamage * 10
|
||||
+ encounter.partyDamage * 12
|
||||
+ encounter.partyDamage * 18
|
||||
)
|
||||
const trashPool = [...pool.filter((encounter) => !encounter.isBoss)]
|
||||
.sort((left, right) => encounterThreat(left) - encounterThreat(right))
|
||||
@@ -331,7 +331,7 @@ export function CombatScreen({
|
||||
)
|
||||
const maxResource = gameClass.maxResource + (isRoguelike ? 0 : profile.gearStats.maxResourceBonus)
|
||||
const partyTemplate = useMemo(
|
||||
() => (dungeon.partySize === 10 ? RAID_PARTY : INITIAL_PARTY).map((member) => ({
|
||||
() => (dungeon.partySize >= 10 ? RAID_PARTY : INITIAL_PARTY).map((member) => ({
|
||||
...member,
|
||||
name: member.id === 'mira' ? profile.character.name : member.name,
|
||||
})),
|
||||
@@ -346,10 +346,10 @@ export function CombatScreen({
|
||||
const [encounterIndex, setEncounterIndex] = useState(initialEncounterIndex)
|
||||
const [enemyHealth, setEnemyHealth] = useState(encounters[initialEncounterIndex].maxHealth)
|
||||
const [cooldowns, setCooldowns] = useState<Record<string, number>>({})
|
||||
const [elapsedTicks, setElapsedTicks] = useState(0)
|
||||
const [, setElapsedTicks] = useState(0)
|
||||
const [status, setStatus] = useState<'playing' | 'won' | 'lost' | 'part-complete' | 'upgrade-choice'>('playing')
|
||||
const [paused, setPaused] = useState(false)
|
||||
const [targetGroup, setTargetGroup] = useState<0 | 1>(0)
|
||||
const [targetGroup, setTargetGroup] = useState<0 | 1 | 2>(0)
|
||||
const [log, setLog] = useState<CombatLogEntry[]>([
|
||||
{ id: 1, text: `${dungeon.name} begins.`, tone: 'system' },
|
||||
])
|
||||
@@ -373,6 +373,7 @@ export function CombatScreen({
|
||||
const nextFloatingTextId = useRef(1)
|
||||
const partyRef = useRef(partyTemplate)
|
||||
const enemyHealthRef = useRef(encounters[initialEncounterIndex].maxHealth)
|
||||
const elapsedTicksRef = useRef(0)
|
||||
const encounter = encounters[encounterIndex]
|
||||
const currentPart = getCurrentPart(encounterIndex)
|
||||
const firstEncounterIndex = (startPart - 1) * 3
|
||||
@@ -471,6 +472,7 @@ export function CombatScreen({
|
||||
setEncounterIndex(initialEncounterIndex)
|
||||
setEnemyHealth(nextEncounters[initialEncounterIndex].maxHealth)
|
||||
setCooldowns({})
|
||||
elapsedTicksRef.current = 0
|
||||
setElapsedTicks(0)
|
||||
setStatus('playing')
|
||||
setPaused(false)
|
||||
@@ -670,7 +672,7 @@ export function CombatScreen({
|
||||
}, [selectedId])
|
||||
|
||||
const selectDirectionalTarget = useCallback((action: InputAction) => {
|
||||
const columns = dungeon.partySize === 10 ? 5 : 3
|
||||
const columns = dungeon.partySize >= 10 ? 6 : 3
|
||||
const currentIndex = partyRef.current.findIndex((member) => member.id === selectedId)
|
||||
if (currentIndex < 0) {
|
||||
setSelectedId(partyRef.current[0].id)
|
||||
@@ -711,7 +713,7 @@ export function CombatScreen({
|
||||
}, [dungeon.partySize, selectedId])
|
||||
|
||||
const selectDirectTarget = useCallback((slot: number) => {
|
||||
const index = slot + (dungeon.partySize === 10 ? targetGroup * 5 : 0)
|
||||
const index = slot + (dungeon.partySize > 6 ? targetGroup * 6 : 0)
|
||||
const member = partyRef.current[index]
|
||||
if (member) setSelectedId(member.id)
|
||||
}, [dungeon.partySize, targetGroup])
|
||||
@@ -748,6 +750,7 @@ export function CombatScreen({
|
||||
setParty(recoveredParty)
|
||||
setEncounterIndex((current) => current + 1)
|
||||
setEnemyHealth(nextEncounter.maxHealth)
|
||||
elapsedTicksRef.current = 0
|
||||
setElapsedTicks(0)
|
||||
setCooldowns({})
|
||||
setResource((value) => clamp(value + Math.round(maxResource * 0.25), 0, maxResource))
|
||||
@@ -771,11 +774,12 @@ export function CombatScreen({
|
||||
return
|
||||
}
|
||||
if (action === 'toggleTargetGroup') {
|
||||
if (dungeon.partySize !== 10) return
|
||||
if (dungeon.partySize <= 6) return
|
||||
setTargetGroup((current) => {
|
||||
const next = current === 0 ? 1 : 0
|
||||
const groupCount = Math.max(1, Math.ceil(partyRef.current.length / 6))
|
||||
const next = ((current + 1) % groupCount) as 0 | 1 | 2
|
||||
const selectedIndex = partyRef.current.findIndex((member) => member.id === selectedId)
|
||||
const nextMember = partyRef.current[(selectedIndex < 0 ? 0 : selectedIndex % 5) + next * 5]
|
||||
const nextMember = partyRef.current[(selectedIndex < 0 ? 0 : selectedIndex % 6) + next * 6]
|
||||
if (nextMember) setSelectedId(nextMember.id)
|
||||
return next
|
||||
})
|
||||
@@ -798,7 +802,9 @@ export function CombatScreen({
|
||||
useEffect(() => {
|
||||
if (status !== 'playing' || paused) return
|
||||
const timer = window.setInterval(() => {
|
||||
setElapsedTicks((value) => value + 1)
|
||||
const nextElapsedTicks = elapsedTicksRef.current + 1
|
||||
elapsedTicksRef.current = nextElapsedTicks
|
||||
setElapsedTicks(nextElapsedTicks)
|
||||
setResource((value) => clamp(value + 2.4, 0, maxResource))
|
||||
setCooldowns((current) =>
|
||||
Object.fromEntries(
|
||||
@@ -820,19 +826,19 @@ export function CombatScreen({
|
||||
const primaryTarget = living[Math.floor(Math.random() * living.length)]
|
||||
const mechanics = (encounter as RoguelikeEncounter).roguelikeMechanics ?? []
|
||||
const useDefaultBossMechanics = encounter.isBoss && mechanics.length === 0
|
||||
const bossPulse = encounter.isBoss && elapsedTicks > 0 && elapsedTicks % 7 === 0
|
||||
const bossPulse = encounter.isBoss && nextElapsedTicks > 0 && nextElapsedTicks % 7 === 0
|
||||
&& (useDefaultBossMechanics || mechanics.includes('party-pulse'))
|
||||
const appliesDebuff = encounter.isBoss && elapsedTicks > 0 && elapsedTicks % 11 === 0
|
||||
const appliesDebuff = encounter.isBoss && nextElapsedTicks > 0 && nextElapsedTicks % 11 === 0
|
||||
&& (useDefaultBossMechanics || mechanics.includes('searing-mark'))
|
||||
const appliesMaxHealthCut = encounter.isBoss && elapsedTicks > 0 && elapsedTicks % 13 === 0
|
||||
const appliesMaxHealthCut = encounter.isBoss && nextElapsedTicks > 0 && nextElapsedTicks % 13 === 0
|
||||
&& mechanics.includes('max-health-cut')
|
||||
const appliesHealingReduction = encounter.isBoss && elapsedTicks > 0 && elapsedTicks % 9 === 0
|
||||
const appliesHealingReduction = encounter.isBoss && nextElapsedTicks > 0 && nextElapsedTicks % 9 === 0
|
||||
&& mechanics.includes('healing-reduction')
|
||||
const tankBuster = encounter.isBoss && elapsedTicks > 0 && elapsedTicks % 8 === 0
|
||||
const tankBuster = encounter.isBoss && nextElapsedTicks > 0 && nextElapsedTicks % 8 === 0
|
||||
&& mechanics.includes('tank-buster')
|
||||
const resourceDrain = encounter.isBoss && elapsedTicks > 0 && elapsedTicks % 10 === 0
|
||||
const resourceDrain = encounter.isBoss && nextElapsedTicks > 0 && nextElapsedTicks % 10 === 0
|
||||
&& mechanics.includes('resource-drain')
|
||||
const appliesPoison = encounter.isBoss && elapsedTicks > 0 && elapsedTicks % 12 === 0
|
||||
const appliesPoison = encounter.isBoss && nextElapsedTicks > 0 && nextElapsedTicks % 12 === 0
|
||||
&& mechanics.includes('ramping-poison')
|
||||
if (bossPulse) addLog(`${encounter.enemyName} unleashes party-wide damage.`, 'danger')
|
||||
if (appliesDebuff) addLog(`${primaryTarget.name} is afflicted by Searing Mark.`, 'danger')
|
||||
@@ -957,6 +963,7 @@ export function CombatScreen({
|
||||
setParty(recoveredParty)
|
||||
setEncounterIndex((value) => value + 1)
|
||||
setEnemyHealth(nextEncounter.maxHealth)
|
||||
elapsedTicksRef.current = 0
|
||||
setElapsedTicks(0)
|
||||
addLog(`${encounter.enemyName} defeated. ${nextEncounter.enemyName} approaches.`, 'system')
|
||||
}, TICK_MS)
|
||||
@@ -965,7 +972,6 @@ export function CombatScreen({
|
||||
addLog,
|
||||
addFloatingHeal,
|
||||
difficulty.damageMultiplier,
|
||||
elapsedTicks,
|
||||
encounter,
|
||||
encounterIndex,
|
||||
encounters,
|
||||
@@ -1123,7 +1129,7 @@ export function CombatScreen({
|
||||
<div className="bar mana-bar"><span style={{ width: `${(resource / maxResource) * 100}%` }} /></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`party-grid ${dungeon.partySize === 10 ? 'raid-party-grid' : ''}`}>
|
||||
<div className={`party-grid ${dungeon.partySize >= 10 ? 'raid-party-grid' : ''}`}>
|
||||
{party.map((member) => (
|
||||
<button
|
||||
className={`party-member ${selectedId === member.id ? 'selected' : ''} ${member.health <= 0 ? 'dead' : ''}`}
|
||||
@@ -1146,6 +1152,7 @@ export function CombatScreen({
|
||||
<div className="bar member-health">
|
||||
<span style={{ width: `${(member.health / effectiveMaxHealth(member)) * 100}%` }} />
|
||||
{member.shield > 0 && <i style={{ width: `${(member.shield / effectiveMaxHealth(member)) * 100}%` }} />}
|
||||
<em className="health-text">{Math.ceil(member.health)} / {effectiveMaxHealth(member)}</em>
|
||||
</div>
|
||||
<div className="floating-combat-texts" aria-hidden="true">
|
||||
{floatingTexts
|
||||
@@ -1395,6 +1402,7 @@ export function CombatScreen({
|
||||
setParty(recoveredParty)
|
||||
setEncounterIndex(nextIndex)
|
||||
setEnemyHealth(nextEncounter.maxHealth)
|
||||
elapsedTicksRef.current = 0
|
||||
setElapsedTicks(0)
|
||||
setStatus('playing')
|
||||
addLog(`Proceeding to ${sectionName} ${currentPart + 1}. ${nextEncounter.enemyName} approaches.`, 'system')
|
||||
|
||||
Reference in New Issue
Block a user