# How Diplomatic Relations Work in Unciv: Inside the DiplomacyManager Architecture

> Discover how Unciv manages diplomatic relations through its DiplomacyManager. Learn about relationship levels, opinion modifiers, and turn-based flags influencing trade and war.

- Repository: [Yair Morgenstern/Unciv](https://github.com/yairm210/Unciv)
- Tags: architecture
- Published: 2026-06-18

---

**Unciv models every bilateral relationship between civilizations using a `DiplomacyManager` class that tracks relationship levels, numeric opinion modifiers, and temporary turn-based flags to determine everything from trade access to war status.**

In the open-source Civilization V clone [yairm210/Unciv](https://github.com/yairm210/Unciv), diplomatic relations are not hardcoded states but dynamic data structures that persist across game turns. Understanding how diplomatic relations work in Unciv requires examining the three-layer system that stores opinion scores, temporary agreements, and the derived relationship status visible to players.

## The Core Architecture of Unciv Diplomatic Relations

Every `Civilization` object maintains a map of `DiplomacyManager` instances keyed by the other civilization's ID. When two civilizations first meet, the constructor at lines [80‑89](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L80-L89) in [`DiplomacyManager.kt`](https://github.com/yairm210/Unciv/blob/main/DiplomacyManager.kt) instantiates a reciprocal manager for both parties. Because the class implements `IsPartOfGameInfoSerialization` (line [64](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L64)), all diplomatic data survives save-game serialization.

## The Three Layers of Diplomatic State

The `DiplomacyManager` stores state across three distinct layers that collectively determine how diplomatic relations work in Unciv.

### 1. Relationship Levels (The Visible Status)

The **RelationshipLevel** enum (lines [34‑45](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L34-L45)) defines nine possible states ranging from `Ally` and `Friend` to `War`. The function `relationshipLevel()` (lines [378‑386](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L378-L386)) derives the current level by evaluating diplomatic modifiers, war status, and city-state influence thresholds. This enum drives the UI color coding and determines which diplomatic actions are available.

### 2. Diplomatic Modifiers (The Hidden Opinion Score)

Beneath the visible relationship level lies a mutable map `diplomaticModifiers: HashMap<String, Float>` that stores numeric opinion values. Positive modifiers improve relations; negative modifiers damage them. The method `opinionOfOtherCiv()` (lines [314‑320](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L314-L320)) sums these values to produce the raw score used by `relationshipLevel()`.

Modifiers are manipulated through `setModifier()` (lines [666‑674](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L666-L674)), which is invoked by high-level actions such as `signDeclarationOfFriendship()` (lines [697‑710](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L697-L710)) and `signDefensivePact()` (lines [745‑757](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L745-L757)).

### 3. Temporal Flags (Expiring Agreements)

Temporary diplomatic states are stored in `flagsCountdown: HashMap<String, Int>`, which tracks turn-based expiration timers. The helper methods `hasFlag()` (lines [552‑553](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L552-L553)) and `setFlag()` (lines [554‑558](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L554-L558)) manage entries like `DiplomacyFlags.DeclarationOfFriendship` or `DiplomacyFlags.Denunciation`. These flags block or enable specific actions regardless of the underlying opinion score.

## City-State Diplomacy and the Influence System

For city-states, the standard modifier system is replaced by an **influence** mechanic. The `influence` field (lines [226‑227](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L226-L227)) stores a numeric value that determines the relationship through `relationshipIgnoreAfraid()` (lines [390‑403](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L390-L403)). Unlike major civilizations, city-states categorize relations as **Afraid**, **Neutral**, or **Friend** based strictly on influence thresholds, bypassing the diplomatic modifiers map entirely.

## Key Diplomatic Actions in Code

High-level diplomatic moves are methods on the `DiplomacyManager` that update all three state layers atomically:

- **`declareWar()`** (lines [28‑30](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L28-L30)): Sets the war flag and triggers relationship recalculation
- **`signDeclarationOfFriendship()`** (lines [697‑710](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L697-L710)): Adds a positive modifier and sets a 30-turn flag
- **`signDefensivePact()`** (lines [745‑757](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L745-L757)): Creates a mutual defense obligation with an expiration timer

## How the UI Interacts with Diplomatic Data

The player interface bridges the gap between internal state and visual feedback. In [`TechPolicyDiplomacyButtons.kt`](https://github.com/yairm210/Unciv/blob/main/TechPolicyDiplomacyButtons.kt) (lines [87‑89](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/ui/screens/worldscreen/TechPolicyDiplomacyButtons.kt#L87-L89)), the diplomacy button launches [`DiplomacyScreen.kt`](https://github.com/yairm210/Unciv/blob/main/DiplomacyScreen.kt), which aggregates data from [`MajorCivDiplomacyTable.kt`](https://github.com/yairm210/Unciv/blob/main/MajorCivDiplomacyTable.kt). This table queries the `DiplomacyManager` to render relationship labels and conditionally expose action buttons based on `canDeclareWar()` and similar guard methods.

## Code Examples: Working with Diplomatic Relations

Below are practical patterns for interacting with the diplomatic system in Unciv's Kotlin source:

```kotlin
// 1. Initialize diplomacy when two civilizations first meet
val diplomacy = DiplomacyManager(civA, civB)  // Constructor at lines 80-89
civA.diplomacyManagers[civB.civID] = diplomacy
civB.diplomacyManagers[civA.civID] = diplomacy

// 2. Query the current relationship level for UI display
val level = civA.getDiplomacyManager(civB)!!.relationshipLevel()
// Returns RelationshipLevel enum: Ally, Friend, Neutral, War, etc.

// 3. Modify opinion through diplomatic actions
civA.getDiplomacyManager(civB)!!.addModifier(
    DiplomaticModifiers.OpenBorders,  // Defined in enum at lines 104-112
    10f                               // +10 opinion points
)

// 4. Check prerequisites before declaring war
if (civA.getDiplomacyManager(civB)!!.canDeclareWar()) {
    civA.getDiplomacyManager(civB)!!.declareWar()
}

// 5. Establish temporary friendship (sets flag and modifier)
civA.getDiplomacyManager(civB)!!.signDeclarationOfFriendship()

// 6. Influence mechanics for city-states
civA.getDiplomacyManager(civB)!!.addInfluence(15f)
val influenceScore = civA.getDiplomacyManager(civB)!!.influence

```

## Summary

- **DiplomacyManager** is the central class in [`core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt) that stores all bilateral data.
- **Three data layers** drive relations: the `RelationshipLevel` enum (visible status), `diplomaticModifiers` (numeric opinion), and `flagsCountdown` (temporary agreements).
- **City-states** use an `influence` field rather than modifiers to determine relationship levels through `relationshipIgnoreAfraid()`.
- **Persistence** is guaranteed by implementing `IsPartOfGameInfoSerialization`, ensuring diplomatic states survive save/load cycles.
- **UI integration** occurs through [`DiplomacyScreen.kt`](https://github.com/yairm210/Unciv/blob/main/DiplomacyScreen.kt) and [`MajorCivDiplomacyTable.kt`](https://github.com/yairm210/Unciv/blob/main/MajorCivDiplomacyTable.kt), which read manager state to display options and colors.

## Frequently Asked Questions

### What determines the relationship level between civilizations in Unciv?

The `relationshipLevel()` function evaluates the sum of `diplomaticModifiers`, checks active war status, and applies city-state influence thresholds to return a `RelationshipLevel` enum value ranging from `Ally` to `War`. This calculation occurs in [`DiplomacyManager.kt`](https://github.com/yairm210/Unciv/blob/main/DiplomacyManager.kt) at lines [378‑386](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L378-L386).

### How does Unciv store temporary diplomatic agreements like peace treaties?

Temporary agreements are stored in the `flagsCountdown` map as `DiplomacyFlags` enum entries with integer turn counters. The `setFlag()` method schedules expiration, while `hasFlag()` checks active status, as implemented at lines [552‑558](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L552-L558).

### What is the difference between major civilization and city-state diplomacy in Unciv?

Major civilizations use the `diplomaticModifiers` map to accumulate opinion scores that determine relationship levels, while city-states rely on the `influence` float field. The `relationshipIgnoreAfraid()` method (lines [390‑403](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L390-L403)) handles city-state-specific logic that ignores standard modifiers.

### Where is the diplomatic data saved in Unciv?

All diplomatic data persists through the `DiplomacyManager` class implementing `IsPartOfGameInfoSerialization` (line [64](https://github.com/yairm210/Unciv/blob/master/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt#L64)). Each `Civilization` object serializes its `diplomacyManagers` map, ensuring that modifiers, flags, and influence values are preserved in save files.