Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions src/Core/Interpolation/DialogueInterpolator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,15 @@ private string InterpolatePlayerLances(InterpolateType interpolateType, CastDef

// Continue with interpolation
if (unitKey.StartsWith(DialogueInterpolationConstants.TeamPilot_Random)) {
// Rebind if the referenced pilot is dead or ejected, keep trying until a live one is found
int textRebindAttempts = 0;
int maxTextRebindAttempts = MissionControl.Instance.CurrentContract.Lances.GetLanceUnits(TeamUtils.GetTeamGuid("Player1")).Length + 1;
while (unit != null && unit.IsDead && PilotCastInterpolator.Instance.BoundAbstractActors.ContainsKey(unitKey) && textRebindAttempts < maxTextRebindAttempts) {
textRebindAttempts++;
PilotCastInterpolator.Instance.RebindDeadUnit(unitKey);
unit = GetBoundUnit(unitKey);
}

if (unitDataKey == "DisplayName") {
if (PilotCastInterpolator.Instance.DynamicCastDefs.ContainsKey(unitKey)) {
string castDefId = PilotCastInterpolator.Instance.DynamicCastDefs[unitKey];
Expand Down Expand Up @@ -667,21 +676,38 @@ public void HandleDeadActorFromDialogueContent(ref CastDef castDef) {
// Handle bound units
if (bindingKey != null) {
AbstractActor unit = DialogueInterpolator.Instance.GetBoundUnit(bindingKey);
while (unit != null && unit.IsDead) {
int rebindAttempts = 0;
int maxRebindAttempts = MissionControl.Instance.CurrentContract.Lances.GetLanceUnits(TeamUtils.GetTeamGuid("Player1")).Length + 1;
while (unit != null && unit.IsDead && rebindAttempts < maxRebindAttempts) {
rebindAttempts++;
string reboundCastDefID = PilotCastInterpolator.Instance.RebindDeadUnit(bindingKey);
Main.LogDebug($"[Interpolate.HandleDeadActorFromDialogueContent] Unit '{unit.UnitName} with pilot '{unit.GetPilot().Name}' is dead (or ejected). Rebinding all castdefs and references for unit key '{reboundCastDefID}'");
CastDef reboundCastDef = UnityGameInstance.Instance.Game.DataManager.CastDefs.Get(reboundCastDefID);

castDef = reboundCastDef;
unit = GetBoundUnit(bindingKey == DialogueInterpolationConstants.Commander ? DialogueInterpolationConstants.Darius : bindingKey);
}

if (rebindAttempts >= maxRebindAttempts) {
Main.Logger.LogWarning($"[HandleDeadActorFromDialogueContent] Exhausted rebind attempts for '{bindingKey}'. Falling back to Darius.");
castDef = RuntimeCastFactory.GetCastDef(CustomCastDef.castDef_Darius);
}
} else { // Attempt to see if a unit exists against the castDef pilot (PureRandom units)
AbstractActor unit = GetSpeakerUnit(RuntimeCastFactory.GetPilotDefIDFromCastDefID(castDef.id));
while (unit != null && unit.IsDead) {
Contract contract = MissionControl.Instance.CurrentContract;
SpawnableUnit[] lanceConfigUnits = contract.Lances.GetLanceUnits(TeamUtils.GetTeamGuid("Player1"));
int randomPosition = UnityEngine.Random.Range(0, lanceConfigUnits.Length);
string pilotDefID = lanceConfigUnits[randomPosition].PilotId;
Contract pureRandomContract = MissionControl.Instance.CurrentContract;
SpawnableUnit[] pureRandomLanceConfigUnits = pureRandomContract.Lances.GetLanceUnits(TeamUtils.GetTeamGuid("Player1"));

// Shuffle positions to sample without replacement — guarantees finding a survivor if one exists
List<int> shuffledPositions = Enumerable.Range(0, pureRandomLanceConfigUnits.Length).ToList();
for (int i = shuffledPositions.Count - 1; i > 0; i--) {
int j = UnityEngine.Random.Range(0, i + 1);
(shuffledPositions[i], shuffledPositions[j]) = (shuffledPositions[j], shuffledPositions[i]);
}

int positionIndex = 0;
while (unit != null && unit.IsDead && positionIndex < shuffledPositions.Count) {
string pilotDefID = pureRandomLanceConfigUnits[shuffledPositions[positionIndex]].PilotId;
positionIndex++;

string pilotCastDefID = RuntimeCastFactory.GetCastDefIDFromPilotDefID(pilotDefID);
CastDef updatedCastDef = RuntimeCastFactory.GetCastDef(pilotCastDefID);
Expand All @@ -706,6 +732,11 @@ public void HandleDeadActorFromDialogueContent(ref CastDef castDef) {
unit = null;
}
}

if (positionIndex >= shuffledPositions.Count && unit != null && unit.IsDead) {
Main.Logger.LogWarning($"[HandleDeadActorFromDialogueContent] Exhausted PureRandom rebind attempts. Falling back to Darius.");
castDef = RuntimeCastFactory.GetCastDef(CustomCastDef.castDef_Darius);
}
}
}
}
Expand Down
27 changes: 23 additions & 4 deletions src/Core/Interpolation/PilotCastInterpolator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ private string HandleFallback(int pilotPosition, string selectedCastDefID) {
if (IsBindableRandomCastDefID(selectedCastDefID)) {
string bindingKey = GetBindingKey(selectedCastDefID);
PilotCastInterpolator.Instance.DynamicCastDefs[bindingKey] = fallbackCastDefID;
PilotCastInterpolator.Instance.BoundAbstractActorsFullIndex.Remove(bindingKey);
}

return fallbackCastDefID;
Expand Down Expand Up @@ -170,9 +171,27 @@ private void BindAbstractActorToBindingKey() {
List<AbstractActor> units = lance.GetLanceUnits();

foreach (KeyValuePair<string, int> entry in BoundAbstractActorsFullIndex) {
AbstractActor actor = units[entry.Value - 1];
// Main.LogDebug($"[PilotCastInterpolator.BindAbstractActorToBindingKey] Binding AbstractActor '{actor.UnitName}' with pilot '{actor.GetPilot().Name}' using '{entry.Key}:{entry.Value - 1}'");
BoundAbstractActors[entry.Key] = actor;
AbstractActor matchedActor = null;

// Primary: match by pilot identity (robust against other mods injecting temporary actors into the lance)
if (DynamicCastDefs.TryGetValue(entry.Key, out string castDefId)) {
string pilotDefId = RuntimeCastFactory.GetPilotDefIDFromCastDefID(castDefId);
matchedActor = units.FirstOrDefault(u =>
u.GetPilot().pilotDef.Description.Id.ToUpperFirst() == pilotDefId.ToUpperFirst());
}

// Fallback: index-based with bounds checking
if (matchedActor == null) {
int index = entry.Value - 1;
if (index >= 0 && index < units.Count) {
matchedActor = units[index];
}
}

if (matchedActor != null) {
// Main.LogDebug($"[PilotCastInterpolator.BindAbstractActorToBindingKey] Binding AbstractActor '{matchedActor.UnitName}' with pilot '{matchedActor.GetPilot().Name}' using '{entry.Key}'");
BoundAbstractActors[entry.Key] = matchedActor;
}
}

// Bind the commander if they are in combat
Expand Down Expand Up @@ -209,7 +228,7 @@ private string RebindDeadUnitCastDef(string bindKey) {
int pilotPosition = FindNonUsedPilotPosition("Player1", lanceConfigUnits);

if (!IsPilotPositionValid(pilotPosition)) {
return HandleFallback(pilotPosition, bindKey);
return HandleFallback(pilotPosition, GetDynamicCastDefIDFromBindKey(bindKey));
}

return BindCastDefAndActorIndex(pilotPosition, GetDynamicCastDefIDFromBindKey(bindKey), lanceConfigUnits, fullLanceConfigUnits);
Expand Down