Split custom world generation into staged lightweight batches
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
import { resolveRoleCombatStats } from '../../data/attributeCombat';
|
||||
import { resolveCharacterAttributeProfile } from '../../data/attributeResolver';
|
||||
import { appendBuildBuffs, resolveCompanionOutgoingDamage, resolveMonsterOutgoingDamage, resolvePlayerOutgoingDamage, tickBuildBuffs } from '../../data/buildDamage';
|
||||
import {
|
||||
appendBuildBuffs,
|
||||
resolveCompanionOutgoingDamageResult,
|
||||
resolveMonsterOutgoingDamageResult,
|
||||
resolvePlayerOutgoingDamageResult,
|
||||
tickBuildBuffs,
|
||||
} from '../../data/buildDamage';
|
||||
import {
|
||||
getSkillDelivery,
|
||||
} from '../../data/characterCombat';
|
||||
@@ -45,6 +52,7 @@ export type BattlePlanStep =
|
||||
selectedSkillId: string | null;
|
||||
appliedCooldowns: Record<string, number>;
|
||||
damage: number;
|
||||
criticalHit?: boolean;
|
||||
defeated: boolean;
|
||||
endsBattle: boolean;
|
||||
delivery: CombatDelivery;
|
||||
@@ -58,6 +66,7 @@ export type BattlePlanStep =
|
||||
selectedSkillId: string | null;
|
||||
appliedCooldowns: Record<string, number>;
|
||||
damage: number;
|
||||
criticalHit?: boolean;
|
||||
defeated: boolean;
|
||||
endsBattle: boolean;
|
||||
delivery: CombatDelivery;
|
||||
@@ -71,6 +80,7 @@ export type BattlePlanStep =
|
||||
targetCompanionNpcId?: string;
|
||||
targetX: number;
|
||||
damage: number;
|
||||
criticalHit?: boolean;
|
||||
endsBattle: boolean;
|
||||
selectedSkillId: string | null;
|
||||
npcCharacterId: string | null;
|
||||
@@ -165,7 +175,16 @@ function buildCombatTurnOrder(
|
||||
actorTimings.set(getCombatActorKey('player'), {
|
||||
actor: 'player',
|
||||
nextAt: 0,
|
||||
cadence: 1400 / Math.max((resolveCharacterAttributeProfile(playerCharacter, state.worldType, state.customWorldProfile)?.values.axis_b ?? 48) / 12, 1),
|
||||
cadence: 1400 / Math.max(
|
||||
resolveRoleCombatStats(
|
||||
resolveCharacterAttributeProfile(
|
||||
playerCharacter,
|
||||
state.worldType,
|
||||
state.customWorldProfile,
|
||||
),
|
||||
).turnSpeed,
|
||||
1,
|
||||
),
|
||||
});
|
||||
|
||||
state.companions
|
||||
@@ -177,7 +196,16 @@ function buildCombatTurnOrder(
|
||||
actor: 'companion',
|
||||
id: companion.npcId,
|
||||
nextAt: 0,
|
||||
cadence: 1400 / Math.max((resolveCharacterAttributeProfile(companionCharacter, state.worldType, state.customWorldProfile)?.values.axis_b ?? 48) / 12, 1),
|
||||
cadence: 1400 / Math.max(
|
||||
resolveRoleCombatStats(
|
||||
resolveCharacterAttributeProfile(
|
||||
companionCharacter,
|
||||
state.worldType,
|
||||
state.customWorldProfile,
|
||||
),
|
||||
).turnSpeed,
|
||||
1,
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -321,15 +349,28 @@ export function buildBattlePlan({
|
||||
resetStageMs: number;
|
||||
minTurnCount: number;
|
||||
}): BattlePlan {
|
||||
const targetMonster = getClosestMonster(state.playerX, state.sceneMonsters);
|
||||
const resolvedSceneMonsters =
|
||||
state.sceneMonsters.length > 0
|
||||
? state.sceneMonsters
|
||||
: (state.sceneHostileNpcs ?? []);
|
||||
const battleState: GameState = {
|
||||
...state,
|
||||
sceneMonsters: resolvedSceneMonsters,
|
||||
sceneHostileNpcs: resolvedSceneMonsters,
|
||||
};
|
||||
const targetMonster = getClosestMonster(
|
||||
battleState.playerX,
|
||||
battleState.sceneMonsters,
|
||||
);
|
||||
if (!targetMonster) {
|
||||
return {
|
||||
preparedState: state,
|
||||
preparedState: battleState,
|
||||
turns: [],
|
||||
finalState: {
|
||||
...state,
|
||||
...battleState,
|
||||
inBattle: false,
|
||||
sceneMonsters: [],
|
||||
sceneHostileNpcs: [],
|
||||
companions: resetCompanionCombatPresentation(state.companions),
|
||||
animationState: AnimationState.IDLE,
|
||||
playerActionMode: 'idle' as const,
|
||||
@@ -340,9 +381,16 @@ export function buildBattlePlan({
|
||||
}
|
||||
|
||||
const functionEffect = getFunctionEffect(option.functionId);
|
||||
const isNpcSpar = state.currentNpcBattleMode === 'spar';
|
||||
const isNpcSpar = battleState.currentNpcBattleMode === 'spar';
|
||||
const sequenceMs = Math.round(totalSequenceMs * (functionEffect.turnTimeMultiplier ?? 1));
|
||||
const turnOrder = buildCombatTurnOrder(state, character, sequenceMs, turnVisualMs, resetStageMs, minTurnCount);
|
||||
const turnOrder = buildCombatTurnOrder(
|
||||
battleState,
|
||||
character,
|
||||
sequenceMs,
|
||||
turnVisualMs,
|
||||
resetStageMs,
|
||||
minTurnCount,
|
||||
);
|
||||
const normalizedOption = normalizeSkillProbabilities(option, character);
|
||||
const npcBattleResources = new Map<string, {
|
||||
character: Character;
|
||||
@@ -350,7 +398,7 @@ export function buildBattlePlan({
|
||||
cooldowns: Record<string, number>;
|
||||
}>();
|
||||
|
||||
state.sceneMonsters.forEach(monster => {
|
||||
battleState.sceneMonsters.forEach(monster => {
|
||||
const npcCharacterId = monster.encounter?.characterId ?? null;
|
||||
const npcCharacter = npcCharacterId ? getCharacterById(npcCharacterId) : null;
|
||||
if (!npcCharacter) return;
|
||||
@@ -363,9 +411,16 @@ export function buildBattlePlan({
|
||||
});
|
||||
|
||||
let simulatedState: GameState = {
|
||||
...applyRecoveryEffectToState(state, character, option.functionId),
|
||||
companions: resetCompanionCombatPresentation(state.companions),
|
||||
sceneMonsters: resetCombatPresentation(state.sceneMonsters, state.playerX),
|
||||
...applyRecoveryEffectToState(battleState, character, option.functionId),
|
||||
companions: resetCompanionCombatPresentation(battleState.companions),
|
||||
sceneMonsters: resetCombatPresentation(
|
||||
battleState.sceneMonsters,
|
||||
battleState.playerX,
|
||||
),
|
||||
sceneHostileNpcs: resetCombatPresentation(
|
||||
battleState.sceneMonsters,
|
||||
battleState.playerX,
|
||||
),
|
||||
activeCombatEffects: [],
|
||||
playerActionMode: 'idle' as const,
|
||||
currentNpcBattleOutcome: null,
|
||||
@@ -373,7 +428,7 @@ export function buildBattlePlan({
|
||||
const preparedState = simulatedState;
|
||||
const turns: BattlePlanStep[] = [];
|
||||
|
||||
for (const turn of turnOrder) {
|
||||
for (const [turnIndex, turn] of turnOrder.entries()) {
|
||||
const currentTarget = getClosestMonster(simulatedState.playerX, simulatedState.sceneMonsters);
|
||||
if (!currentTarget) break;
|
||||
|
||||
@@ -398,14 +453,16 @@ export function buildBattlePlan({
|
||||
...cooledDown,
|
||||
[selectedSkill.id]: selectedSkill.cooldownTurns,
|
||||
};
|
||||
const damage = isNpcSpar
|
||||
? 1
|
||||
: resolvePlayerOutgoingDamage(
|
||||
const damageResult = isNpcSpar
|
||||
? null
|
||||
: resolvePlayerOutgoingDamageResult(
|
||||
simulatedState,
|
||||
character,
|
||||
selectedSkill.damage,
|
||||
functionEffect.damageMultiplier ?? 1,
|
||||
`${option.functionId}:player:${turnIndex}:${selectedSkill.id}:${currentTarget.id}`,
|
||||
);
|
||||
const damage = isNpcSpar ? 1 : damageResult!.damage;
|
||||
const wouldEndSpar = isNpcSpar && currentTarget.hp - damage <= 1;
|
||||
|
||||
const resolvedMonsters = simulatedState.sceneMonsters.map(monster =>
|
||||
@@ -460,6 +517,7 @@ export function buildBattlePlan({
|
||||
selectedSkillId: selectedSkill.id,
|
||||
appliedCooldowns,
|
||||
damage,
|
||||
criticalHit: damageResult?.isCritical ?? false,
|
||||
defeated,
|
||||
endsBattle: wouldEndSpar,
|
||||
delivery,
|
||||
@@ -513,15 +571,17 @@ export function buildBattlePlan({
|
||||
...cooledDown,
|
||||
[selectedSkill.id]: selectedSkill.cooldownTurns,
|
||||
};
|
||||
const damage = isNpcSpar
|
||||
? 1
|
||||
: resolveCompanionOutgoingDamage(
|
||||
const damageResult = isNpcSpar
|
||||
? null
|
||||
: resolveCompanionOutgoingDamageResult(
|
||||
companionCharacter,
|
||||
selectedSkill.damage,
|
||||
functionEffect.damageMultiplier ?? 1,
|
||||
state.worldType,
|
||||
state.customWorldProfile,
|
||||
`${option.functionId}:companion:${turnIndex}:${companion.npcId}:${selectedSkill.id}:${targetMonster.id}`,
|
||||
);
|
||||
const damage = isNpcSpar ? 1 : damageResult!.damage;
|
||||
const wouldEndSpar = isNpcSpar && targetMonster.hp - damage <= 1;
|
||||
|
||||
const resolvedMonsters = simulatedState.sceneMonsters.map(monster =>
|
||||
@@ -571,6 +631,7 @@ export function buildBattlePlan({
|
||||
selectedSkillId: selectedSkill.id,
|
||||
appliedCooldowns,
|
||||
damage,
|
||||
criticalHit: damageResult?.isCritical ?? false,
|
||||
defeated,
|
||||
endsBattle: wouldEndSpar,
|
||||
delivery,
|
||||
@@ -611,15 +672,17 @@ export function buildBattlePlan({
|
||||
if (selectedSkill) {
|
||||
const delivery = getSkillDelivery(selectedSkill);
|
||||
const strikeX = getSkillStrikeX(selectedSkill, originalMonsterX, targetX);
|
||||
const damage = isNpcSpar
|
||||
? 1
|
||||
: resolveCompanionOutgoingDamage(
|
||||
const damageResult = isNpcSpar
|
||||
? null
|
||||
: resolveCompanionOutgoingDamageResult(
|
||||
npcCombatant.character,
|
||||
selectedSkill.damage,
|
||||
functionEffect.incomingDamageMultiplier ?? 1,
|
||||
state.worldType,
|
||||
state.customWorldProfile,
|
||||
`${option.functionId}:monster-skill:${turnIndex}:${actingMonster.id}:${selectedSkill.id}:${randomTarget.kind}:${randomTarget.kind === 'companion' ? randomTarget.npcId : 'player'}`,
|
||||
);
|
||||
const damage = isNpcSpar ? 1 : damageResult!.damage;
|
||||
const wouldEndSpar = isNpcSpar && randomTarget.kind === 'player' && simulatedState.playerHp - damage <= 1;
|
||||
|
||||
npcBattleResources.set(actingMonster.id, {
|
||||
@@ -662,6 +725,7 @@ export function buildBattlePlan({
|
||||
targetCompanionNpcId: randomTarget.kind === 'companion' ? randomTarget.npcId : undefined,
|
||||
targetX,
|
||||
damage,
|
||||
criticalHit: damageResult?.isCritical ?? false,
|
||||
endsBattle: wouldEndSpar,
|
||||
selectedSkillId: selectedSkill.id,
|
||||
npcCharacterId: npcCombatant.character.id,
|
||||
@@ -672,15 +736,17 @@ export function buildBattlePlan({
|
||||
}
|
||||
|
||||
const strikeX = getMeleeStrikeX(originalMonsterX, targetX);
|
||||
const damage = isNpcSpar
|
||||
? 1
|
||||
: resolveMonsterOutgoingDamage(
|
||||
const damageResult = isNpcSpar
|
||||
? null
|
||||
: resolveMonsterOutgoingDamageResult(
|
||||
actingMonster,
|
||||
9,
|
||||
functionEffect.incomingDamageMultiplier ?? 1,
|
||||
state.worldType,
|
||||
state.customWorldProfile,
|
||||
`${option.functionId}:monster:${turnIndex}:${actingMonster.id}:${randomTarget.kind}:${randomTarget.kind === 'companion' ? randomTarget.npcId : 'player'}`,
|
||||
);
|
||||
const damage = isNpcSpar ? 1 : damageResult!.damage;
|
||||
const wouldEndSpar = isNpcSpar && randomTarget.kind === 'player' && simulatedState.playerHp - damage <= 1;
|
||||
|
||||
const damagedState = applyDamageToPartyTarget(simulatedState, randomTarget, damage);
|
||||
@@ -714,6 +780,7 @@ export function buildBattlePlan({
|
||||
targetCompanionNpcId: randomTarget.kind === 'companion' ? randomTarget.npcId : undefined,
|
||||
targetX,
|
||||
damage,
|
||||
criticalHit: damageResult?.isCritical ?? false,
|
||||
endsBattle: wouldEndSpar,
|
||||
selectedSkillId: null,
|
||||
npcCharacterId: null,
|
||||
@@ -735,6 +802,10 @@ export function buildBattlePlan({
|
||||
? false
|
||||
: simulatedState.sceneMonsters.length > 0,
|
||||
sceneMonsters: resetCombatPresentation(simulatedState.sceneMonsters, simulatedState.playerX),
|
||||
sceneHostileNpcs: resetCombatPresentation(
|
||||
simulatedState.sceneMonsters,
|
||||
simulatedState.playerX,
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user