Skip to content

Commit

Permalink
improve obscurement rules after first QA round
Browse files Browse the repository at this point in the history
  • Loading branch information
ThyWoof committed Jan 18, 2024
1 parent eb08c04 commit f2c566b
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 73 deletions.
22 changes: 18 additions & 4 deletions SolastaUnfinishedBusiness/Api/DatabaseHelper-RELEASE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ namespace SolastaUnfinishedBusiness.Api;

internal static partial class DatabaseHelper
{
internal static class FeatureDefinitionPerceptionAffinitys
{
internal static FeatureDefinitionPerceptionAffinity PerceptionAffinityConditionBlinded { get; } =
GetDefinition<FeatureDefinitionPerceptionAffinity>("PerceptionAffinityConditionBlinded");
}

internal static class ActionDefinitions
{
internal static ActionDefinition ActionSurge { get; } = GetDefinition<ActionDefinition>("ActionSurge");
Expand Down Expand Up @@ -316,6 +322,12 @@ internal static class ConditionDefinitions
internal static ConditionDefinition ConditionBlinded { get; } =
GetDefinition<ConditionDefinition>("ConditionBlinded");

internal static ConditionDefinition ConditionBlinded_Sunburst { get; } =
GetDefinition<ConditionDefinition>("ConditionBlinded_Sunburst");

internal static ConditionDefinition ConditionBlindedEndOfNextTurn { get; } =
GetDefinition<ConditionDefinition>("ConditionBlindedEndOfNextTurn");

internal static ConditionDefinition ConditionBlurred { get; } =
GetDefinition<ConditionDefinition>("ConditionBlurred");

Expand Down Expand Up @@ -1216,9 +1228,6 @@ internal static class FeatureDefinitionCombatAffinitys

internal static FeatureDefinitionCombatAffinity CombatAffinityStealthy { get; } =
GetDefinition<FeatureDefinitionCombatAffinity>("CombatAffinityStealthy");

internal static FeatureDefinitionCombatAffinity CombatAffinityVeil { get; } =
GetDefinition<FeatureDefinitionCombatAffinity>("CombatAffinityVeil");
}

internal static class FeatureDefinitionConditionAffinitys
Expand Down Expand Up @@ -1273,6 +1282,9 @@ internal static FeatureDefinitionConditionAffinity
internal static FeatureDefinitionConditionAffinity ConditionAffinityHinderedByFrostImmunity { get; } =
GetDefinition<FeatureDefinitionConditionAffinity>("ConditionAffinityHinderedByFrostImmunity");

internal static FeatureDefinitionConditionAffinity ConditionAffinityInvocationDevilsSight { get; } =
GetDefinition<FeatureDefinitionConditionAffinity>("ConditionAffinityInvocationDevilsSight");

internal static FeatureDefinitionConditionAffinity ConditionAffinityMindControlledImmunity { get; } =
GetDefinition<FeatureDefinitionConditionAffinity>("ConditionAffinityMindControlledImmunity");

Expand All @@ -1294,7 +1306,6 @@ internal static FeatureDefinitionConditionAffinity
internal static FeatureDefinitionConditionAffinity ConditionAffinityRestrainedmmunity { get; } =
GetDefinition<FeatureDefinitionConditionAffinity>("ConditionAffinityRestrainedmmunity");


internal static FeatureDefinitionConditionAffinity ConditionAffinityVeilImmunity { get; } =
GetDefinition<FeatureDefinitionConditionAffinity>("ConditionAffinityVeilImmunity");

Expand Down Expand Up @@ -1646,6 +1657,9 @@ internal static class FeatureDefinitionPowers
internal static FeatureDefinitionPower PowerCollegeLoreCuttingWords { get; } =
GetDefinition<FeatureDefinitionPower>("PowerCollegeLoreCuttingWords");

internal static FeatureDefinitionPower PowerDefilerDarkness { get; } =
GetDefinition<FeatureDefinitionPower>("PowerDefilerDarkness");

internal static FeatureDefinitionPower PowerDruidCircleBalanceBalanceOfPower { get; } =
GetDefinition<FeatureDefinitionPower>("PowerDruidCircleBalanceBalanceOfPower");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static bool IsWithinRange(this GameLocationCharacter source, GameLocation
return int3.Distance(source.LocationPosition, target.LocationPosition) <= range;
}

public static bool IsMagicEffectValidUnderObscurementOrMagicalDarkness(
public static bool IsMagicEffectValidUnderBlindness(
this GameLocationCharacter source,
IMagicEffect magicEffect,
GameLocationCharacter target)
Expand All @@ -45,8 +45,7 @@ public static bool IsMagicEffectValidUnderObscurementOrMagicalDarkness(
var rulesetSource = source.RulesetActor;
var rulesetTarget = target.RulesetActor;

if (!rulesetSource.IsUnderHeavyObscurementOrMagicalDarkness() &&
!rulesetTarget.IsUnderHeavyObscurementOrMagicalDarkness())
if (!rulesetSource.HasBlindness() && !rulesetTarget.HasBlindness())
{
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ public static bool MyIsCellPerceivedByCharacter(
var inRange = false;
var distance = DistanceCalculation.GetDistanceFromTwoPositions(sensor.LocationPosition, cellPosition);
var lightingState = sensor.ComputeLightingStateOnTargetPosition(cellPosition);
var nonMagicalDarkness =
target != null && target.RulesetCharacter.IsUnderHeavyObscurement();

var nonMagicalDarkness = target?.LightingState != LocationDefinitions.LightingState.Darkness;
var selectedSenseType = SenseMode.Type.None;
var selectedSenseRange = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,9 @@ internal static bool IsTemporarilyFlying(this RulesetActor actor)
);*/
}

internal static bool IsUnderHeavyObscurement(this RulesetActor character)
internal static bool HasBlindness(this RulesetActor character)
{
return character.HasConditionOfType(DatabaseHelper.ConditionDefinitions.ConditionHeavilyObscured.Name) ||
character.HasConditionOfType(DatabaseHelper.ConditionDefinitions.ConditionInStinkingCloud.Name) ||
character.HasConditionOfType(DatabaseHelper.ConditionDefinitions.ConditionSleetStorm.Name);
}

internal static bool IsUnderHeavyObscurementOrMagicalDarkness(this RulesetActor character)
{
return character.IsUnderHeavyObscurement() ||
character.HasConditionOfType(DatabaseHelper.ConditionDefinitions.ConditionDarkness.Name) ||
character.HasConditionOfType(DatabaseHelper.ConditionDefinitions.ConditionVeil.Name);
return character.HasConditionOfTypeOrSubType(DatabaseHelper.ConditionDefinitions.ConditionBlinded.Name);
}

internal static bool HasAnyConditionOfType(this RulesetActor actor, params string[] conditions)
Expand Down
1 change: 1 addition & 0 deletions SolastaUnfinishedBusiness/Displays/RulesDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ internal static void DisplayRules()
SrdAndHouseRulesContext.SwitchOfficialObscurementRules();
}

UI.Label();
UI.Label();
UI.Label();

Expand Down
172 changes: 123 additions & 49 deletions SolastaUnfinishedBusiness/Models/SrdAndHouseRulesContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.SpellDefinitions;
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.MonsterDefinitions;
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.FeatureDefinitionCombatAffinitys;
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.FeatureDefinitionConditionAffinitys;
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.FeatureDefinitionPowers;
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.FeatureDefinitionSenses;
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.CharacterClassDefinitions;
using static SolastaUnfinishedBusiness.Api.DatabaseHelper.ItemDefinitions;
Expand Down Expand Up @@ -77,13 +79,10 @@ internal static class SrdAndHouseRulesContext
.SetForbiddenActions(Id.AttackOpportunity)
.AddToDB();

private static readonly FeatureDefinitionConditionAffinity ConditionAffinityDarknessImmunity =
FeatureDefinitionConditionAffinityBuilder
.Create("ConditionAffinityDarknessImmunity")
.SetGuiPresentationNoContent(true)
.SetConditionType(ConditionDefinitions.ConditionDarkness)
.SetConditionAffinityType(ConditionAffinityType.Immunity)
.AddToDB();
private static readonly EffectForm FormBlinded = EffectFormBuilder
.Create()
.SetConditionForm(ConditionDefinitions.ConditionBlinded, ConditionForm.ConditionOperation.Add)
.Build();

private static SpellDefinition ConjureElementalInvisibleStalker { get; set; }

Expand Down Expand Up @@ -302,17 +301,11 @@ internal static void ApplyConditionBlindedShouldNotAllowOpportunityAttack()
{
if (Main.Settings.BlindedConditionDontAllowAttackOfOpportunity)
{
if (!ConditionDefinitions.ConditionBlinded.Features.Contains(ActionAffinityConditionBlind))
{
ConditionDefinitions.ConditionBlinded.Features.Add(ActionAffinityConditionBlind);
}
ConditionDefinitions.ConditionBlinded.Features.TryAdd(ActionAffinityConditionBlind);
}
else
{
if (ConditionDefinitions.ConditionBlinded.Features.Contains(ActionAffinityConditionBlind))
{
ConditionDefinitions.ConditionBlinded.Features.Remove(ActionAffinityConditionBlind);
}
ConditionDefinitions.ConditionBlinded.Features.Remove(ActionAffinityConditionBlind);
}
}

Expand Down Expand Up @@ -409,55 +402,136 @@ internal static void SwitchOfficialObscurementRules()
{
if (Main.Settings.UseOfficialLightingObscurementAndVisionRules)
{
foreach (var monster in DatabaseRepository.GetDatabase<MonsterDefinition>()
.Where(x => x.Features.Contains(
FeatureDefinitionConditionAffinitys.ConditionAffinityVeilImmunity)))
// reuse blinded condition as many depend on it as parent
ConditionDefinitions.ConditionBlinded.Features.SetRange(
CombatAffinityHeavilyObscured,
CombatAffinityHeavilyObscuredSelf,
FeatureDefinitionPerceptionAffinitys.PerceptionAffinityConditionBlinded);

if (Main.Settings.BlindedConditionDontAllowAttackOfOpportunity)
{
monster.Features.Add(ConditionAffinityDarknessImmunity);
ConditionDefinitions.ConditionBlinded.Features.Add(ActionAffinityConditionBlind);
}

// vanilla has this set as disadvantage so we flip it and update senses
ConditionDefinitions.ConditionBlinded.GuiPresentation.description =
"Rules/&ConditionBlindedExtendedDescription";

// >> ConditionVeil
// ConditionAffinityVeilImmunity
// PowerDefilerDarkness

ConditionAffinityVeilImmunity.conditionType =
ConditionDefinitions.ConditionBlinded.Name;

PowerDefilerDarkness.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionDefinitions.ConditionBlinded;

// >> ConditionDarkness
// ConditionAffinityInvocationDevilsSight
// Darkness

ConditionAffinityInvocationDevilsSight.conditionType =
ConditionDefinitions.ConditionBlinded.Name;

Darkness.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionDefinitions.ConditionBlinded;

// >> ConditionHeavilyObscured
// FogCloud

FogCloud.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionDefinitions.ConditionBlinded;

// >> ConditionInStinkingCloud
// StinkingCloud

StinkingCloud.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionDefinitions.ConditionBlinded;

// >> ConditionSleetStorm
// SleetStorm

SleetStorm.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionDefinitions.ConditionBlinded;

// Cloud Kill / Incendiary Cloud

CloudKill.EffectDescription.EffectForms.Add(FormBlinded);
IncendiaryCloud.EffectDescription.EffectForms.Add(FormBlinded);

// vanilla has this set as disadvantage so we flip it with nullified requirements
CombatAffinityHeavilyObscured.attackOnMeAdvantage = AdvantageType.Advantage;
(CombatAffinityHeavilyObscured.nullifiedBySenses, CombatAffinityHeavilyObscured.nullifiedBySelfSenses) =
(CombatAffinityHeavilyObscured.nullifiedBySelfSenses, CombatAffinityHeavilyObscured.nullifiedBySenses);

// vanilla reuses Heavily Obscured terms
ConditionDefinitions.ConditionDarkness.GuiPresentation.title =
"Tooltip/&LightingDarknessFormat";
ConditionDefinitions.ConditionDarkness.GuiPresentation.description =
"Rules/&ConditionHeavilyObscuredExtendedDescription";

ConditionDefinitions.ConditionDarkness.conditionType = ConditionType.Detrimental;
ConditionDefinitions.ConditionDarkness.possessive = false;
ConditionDefinitions.ConditionDarkness.Features.SetRange(
CombatAffinityHeavilyObscured,
CombatAffinityHeavilyObscuredSelf);

ConditionVeil.Features.SetRange(CombatAffinityHeavilyObscured, CombatAffinityHeavilyObscuredSelf);
// replace sight impaired from all non magical light and heavy obscurement effects
CloudKill.EffectDescription.EffectForms[2].TopologyForm.changeType = TopologyForm.Type.None;
FogCloud.EffectDescription.EffectForms[1].TopologyForm.changeType = TopologyForm.Type.None;
IncendiaryCloud.EffectDescription.EffectForms[2].TopologyForm.changeType = TopologyForm.Type.None;
InsectPlague.effectDescription.EffectForms[1].TopologyForm.changeType = TopologyForm.Type.SightBlocker;
SleetStorm.EffectDescription.EffectForms[5].TopologyForm.changeType = TopologyForm.Type.None;
StinkingCloud.EffectDescription.EffectForms[1].TopologyForm.changeType = TopologyForm.Type.None;
}
else
{
foreach (var monster in DatabaseRepository.GetDatabase<MonsterDefinition>()
.Where(x => x.Features.Contains(
FeatureDefinitionConditionAffinitys.ConditionAffinityVeilImmunity)))
{
monster.Features.Remove(ConditionAffinityDarknessImmunity);
}
ConditionDefinitions.ConditionBlinded.GuiPresentation.description =
"Rules/&ConditionBlindedExtendedDescription";

// >> ConditionVeil
// ConditionAffinityVeilImmunity
// PowerDefilerDarkness

ConditionAffinityVeilImmunity.conditionType =
ConditionVeil.Name;

PowerDefilerDarkness.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionVeil;

// >> ConditionDarkness
// ConditionAffinityInvocationDevilsSight
// Darkness

ConditionAffinityInvocationDevilsSight.conditionType =
ConditionDefinitions.ConditionDarkness.Name;

Darkness.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionDefinitions.ConditionDarkness;

// >> ConditionHeavilyObscured
// FogCloud

FogCloud.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionHeavilyObscured;

// >> ConditionInStinkingCloud
// StinkingCloud

StinkingCloud.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionInStinkingCloud;

// >> ConditionSleetStorm
// SleetStorm

SleetStorm.EffectDescription.EffectForms[1].ConditionForm.ConditionDefinition =
ConditionSleetStorm;

// Cloud Kill / Incendiary Cloud

CloudKill.EffectDescription.EffectForms.Remove(FormBlinded);
IncendiaryCloud.EffectDescription.EffectForms.Remove(FormBlinded);

// vanilla has this set as disadvantage so we flip it with nullified requirements
CombatAffinityHeavilyObscured.attackOnMeAdvantage = AdvantageType.Disadvantage;
(CombatAffinityHeavilyObscured.nullifiedBySelfSenses, CombatAffinityHeavilyObscured.nullifiedBySenses) =
(CombatAffinityHeavilyObscured.nullifiedBySenses, CombatAffinityHeavilyObscured.nullifiedBySelfSenses);

ConditionDefinitions.ConditionDarkness.GuiPresentation.title =
"Rules/&ConditionHeavilyObscuredTitle";
ConditionDefinitions.ConditionDarkness.GuiPresentation.description =
"Rules/&ConditionHeavilyObscuredDescription";

ConditionDefinitions.ConditionDarkness.conditionType = ConditionType.Neutral;
ConditionDefinitions.ConditionDarkness.possessive = true;
ConditionDefinitions.ConditionDarkness.Features.SetRange(CombatAffinityVeil);

ConditionVeil.Features.SetRange(CombatAffinityVeil);
// add sight impaired from all non magical light and heavy obscurement effects
CloudKill.EffectDescription.EffectForms[2].TopologyForm.changeType = TopologyForm.Type.SightImpaired;
FogCloud.EffectDescription.EffectForms[1].TopologyForm.changeType = TopologyForm.Type.SightImpaired;
IncendiaryCloud.EffectDescription.EffectForms[2].TopologyForm.changeType = TopologyForm.Type.SightImpaired;
InsectPlague.effectDescription.EffectForms[1].TopologyForm.changeType = TopologyForm.Type.SightImpaired;
SleetStorm.EffectDescription.EffectForms[5].TopologyForm.changeType = TopologyForm.Type.SightImpaired;
StinkingCloud.EffectDescription.EffectForms[1].TopologyForm.changeType = TopologyForm.Type.SightImpaired;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ public static bool Prefix(
{
// BEGIN PATCH
if (!Main.Settings.UseOfficialLightingObscurementAndVisionRules &&
!locationCharacter.IsMagicEffectValidUnderObscurementOrMagicalDarkness(
availableMagicEffect, context.character))
!locationCharacter.IsMagicEffectValidUnderBlindness(availableMagicEffect, context.character))
{
Main.Info($"{locationCharacter.Name} => {availableMagicEffect.Name} : OBSCUREMENT DISCARDED");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void Postfix(
if (__result &&
Main.Settings.UseOfficialLightingObscurementAndVisionRules &&
definition is IMagicEffect magicEffect &&
!actingCharacter.IsMagicEffectValidUnderObscurementOrMagicalDarkness(magicEffect, target))
!actingCharacter.IsMagicEffectValidUnderBlindness(magicEffect, target))
{
__instance.actionModifier.FailureFlags.Add("Failure/&FailureFlagNoPerceptionOfTargetDescription");
__result = false;
Expand Down

0 comments on commit f2c566b

Please sign in to comment.