Relationships
What it is
This API reads the player’s relationship scores and tells you when one changes.
Reference
Scores run from -100 to 100.
Relationships scores and change event
Use GetDisposition or All() to read the scores, SetDisposition to set one, Has to check whether the player has one, and RelationshipChanged to hear when a score changes.
public static class Relationships
{
public static List<RelationshipValue> All();
public static float GetDisposition(string id);
public static bool SetDisposition(string id, float value);
public static bool Has(string id);
public static bool IsAvailable { get; }
public static event Action<RelationshipChange> RelationshipChanged;
}
| Method | Returns | What it does |
|---|---|---|
All() | List<RelationshipValue> | Every relationship the framework tracks. |
GetDisposition(id) | float | The score, or 0 if the player does not have it. |
SetDisposition(id, value) | bool | Sets the score and its target, so the score does not drift back. The score runs from -100 to 100. It is false when the id is unknown, when a save or load is running, when the value is not a finite number, when the value is outside -100 to 100 (the value is refused, not clamped), or when no relationship is loaded. It raises RelationshipChanged. |
Has(id) | bool | It is true when the player has it. |
| Property | Type | What it means |
|---|---|---|
IsAvailable | bool | It is false when the change event is off. |
| Event | Gives you | When it fires |
|---|---|---|
RelationshipChanged | RelationshipChange | It fires when the game’s daily check or SetDisposition changes a score. |
RelationshipValue one relationship
Relationships.All() gives you one of these for each relationship the framework tracks. Disposition is the score now, and Target is the score it moves toward.
public sealed class RelationshipValue
{
public string Id { get; }
public string Name { get; }
public float Disposition { get; }
public float Target { get; }
public bool Enabled { get; }
}
| Property | Type | What it means |
|---|---|---|
Id | string | The relationship’s internal name in the game files. |
Name | string | The name the game shows the player. |
Disposition | float | The current score. |
Target | float | The score it moves toward. |
Enabled | bool | It is true when the player has it. |
RelationshipChange a score change
Relationships.RelationshipChanged hands you one of these when the game’s daily check changes a score. Previous and Current are the scores before and after.
public sealed class RelationshipChange
{
public string Id { get; }
public string Name { get; }
public float Previous { get; }
public float Current { get; }
}
| Property | Type | What it means |
|---|---|---|
Id | string | The relationship’s internal name in the game files. |
Name | string | The name the game shows the player. |
Previous | float | The score before the change. |
Current | float | The score after the change. |
Putting it together
Logs any relationship that drops below zero.
using ObenseuerCore;
[ModInfo("example.moodwatch", "Mood Watch", "0.1.0")]
[ModDependency("obenseuer.moddingframework", "0.11.0")]
public sealed class MoodWatch : FrameworkMod
{
protected override void OnLoad()
{
Relationships.RelationshipChanged += change =>
{
if (change.Previous >= 0 && change.Current < 0)
Log.Info(change.Name + " dropped below zero, from " + change.Previous + " to " + change.Current);
};
Events.WhenReady(() =>
{
if (!Relationships.IsAvailable) Log.Info("Relationship change events are off, so no changes will be reported.");
foreach (RelationshipValue relationship in Relationships.All())
{
if (!relationship.Enabled) continue;
Log.Info(relationship.Name + ": " + relationship.Disposition + ", moving toward " + relationship.Target);
}
});
}
}
| Step | What it does |
|---|---|
Relationships.IsAvailable | false means no changes are reported. |
relationship.Enabled | Skips relationships the player lacks. |
Things to know
RelationshipChangeddoes not fire on add, remove or save load.
Limits
- Scores are per player, not per NPC.
- You can’t set scores or targets, because the framework has nothing safe to call.
Details
Target: Obenseuer 0.5.08 (buildid 25969064), Unity 6000.0.77f1 Mono, BepInEx 6 Unity.Mono (be.788, the tested build) or BepInEx 5 (5.4.23 or later). Logs go to BepInEx\logs\obenseuer.moddingframework.npcs.log.
Relationships use feature group obenseuer.moddingframework.npcs.relationship.
When you can call it
- Call from the main thread, not a thread you started.
- It is safe to call at any time. Empty reads return
0,false,nullor an empty list. - If a handler throws, the error is logged and the other handlers still run.
- Don’t change scenes or NPCs from a handler.
Under the hood
How the framework reads the game, for modders who want to dig deeper.
Relationship.CheckDateAndTriggerraisesRelationshipChanged, only when the score changed.- Scores live on
Relationshipassets. No game method setsRelationshipController.RelationshipInfo.dispositionordispositionTarget.