# How PolicyManager Handles Social Policies in Unciv: A Complete Technical Guide

> Explore how Uncivs PolicyManager class manages social policies, culture, free slots, adoption, and civilization stats. Get a complete technical guide.

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

---

**The PolicyManager class in Unciv serves as the central brain for all social policy mechanics, tracking culture accumulation, managing free policy slots, validating adoption requirements against policy trees, and applying unique effects to civilization stats.**

Managing social policies is one of the core progression systems in Unciv, governed by the `PolicyManager` class located in [`core/src/com/unciv/logic/civilization/managers/PolicyManager.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/logic/civilization/managers/PolicyManager.kt). This component orchestrates the entire lifecycle of policies from culture accumulation through adoption to branch completion. Understanding how PolicyManager handles social policies is essential for anyone modifying civilization behavior or debugging policy-related mechanics.

## Core Data Structures in PolicyManager

The PolicyManager maintains several critical properties that persist across turns:

- **`storedCulture`**: Accumulated culture available to spend on new policies
- **`freePolicies`**: Count of free policy slots earned through great people or other effects
- **`adoptedPolicies`**: A `HashSet<String>` containing the names of all currently adopted policies
- **`numberOfAdoptedPolicies`**: Counter tracking how many policies were paid for with culture, used for cost scaling calculations
- **`policyUniques`**: A `UniqueMap` storing all uniques granted by adopted policies for fast lookup
- **`shouldOpenPolicyPicker`**: Boolean flag indicating when the UI should display the policy picker

These fields are defined in [`PolicyManager.kt`](https://github.com/yairm210/Unciv/blob/main/PolicyManager.kt) and serialize with the civilization's game state.

## Calculating Culture Costs

The cost of the next policy scales non-linearly based on how many policies a civilization has already purchased. The `getPolicyCultureCost()` method implements this formula:

```kotlin
fun getPolicyCultureCost(numberOfAdoptedPolicies: Int): Int {
    var policyCultureCost = 25 + (numberOfAdoptedPolicies * 6).toDouble().pow(1.7)
    // city-count modifier applied...
    // unique modifiers (LessPolicyCost, LessPolicyCostFromCities) applied...
    // difficulty & speed modifiers applied...
    return (policyCultureCost * (1 + cityModifier)).roundToInt() - (cost % 5)
}

```

The `getCultureNeededForNextPolicy()` method (lines 46-48 in [`PolicyManager.kt`](https://github.com/yairm210/Unciv/blob/main/PolicyManager.kt)) forwards the call using the current `numberOfAdoptedPolicies` counter. This ensures that each subsequent policy becomes progressively more expensive, modified by city count and special uniques.

## Validating Policy Adoption

Before a policy can be adopted, the `canAdoptPolicy()` method verifies that the civilization has either free slots available or sufficient `storedCulture`. The more detailed `isAdoptable(policy, checkEra = true)` check in [`PolicyManager.kt`](https://github.com/yairm210/Unciv/blob/main/PolicyManager.kt) validates five specific conditions:

1. The policy is not already present in `adoptedPolicies`
2. It is not a branch-completion policy (those are added automatically)
3. All prerequisite policies listed in `policy.requires` are adopted
4. The civilization's current era meets the policy's era requirement
5. "OnlyAvailable" and "Unavailable" uniques are respected

These checks reference policy data defined in [`core/src/com/unciv/models/ruleset/Policy.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/models/ruleset/Policy.kt).

## The Policy Adoption Process

The `adopt(policy, branchCompletion = false)` method manages the complete adoption workflow (lines 241-287 in [`PolicyManager.kt`](https://github.com/yairm210/Unciv/blob/main/PolicyManager.kt)):

**Resource Consumption**
If `freePolicies > 0`, the method decrements the free slot counter. Otherwise, it deducts the culture cost from `storedCulture` and increments `numberOfAdoptedPolicies`.

**Recording Adoption**
The policy name is added to `adoptedPolicies`, and its uniques are inserted into the `policyUniques` map for immediate effect.

**Branch Completion Handling**
When the last regular policy of a branch is adopted, the method recursively adopts the hidden *BranchComplete* policy (lines 60-62), granting the branch's completion bonus.

**Triggering Effects**
Any triggerable uniques on the policy fire via `UniqueTriggerActivation.triggerUnique`.

**State Refresh**
All cities update their stats, populations are reassigned, and the civilization's resource cache refreshes to reflect the new policy effects.

**UI Updates**
If `canAdoptPolicy()` returns false after adoption, `shouldOpenPolicyPicker` clears to close the picker.

## Removing Policies

The `removePolicy(policy, assumeWasFree = false)` method (lines 96-121) mirrors the adoption process in reverse:

- Deletes the policy from `adoptedPolicies`
- Decrements `numberOfAdoptedPolicies` unless `assumeWasFree` is true
- Clears the policy's uniques from `policyUniques`
- Removes the hidden *BranchComplete* policy if the branch becomes incomplete
- Updates city stats and resource caches

This supports undo operations and special events that require policy refunds.

## Branch Management and AI Integration

PolicyManager tracks branch states through several computed properties:

- **`branches`**: All policy branches available to the civilization
- **`adoptableBranches`**: Branches with at least one adoptable policy
- **`completedBranches`**: Branches where all policies including the completion bonus are adopted

The `priorityMap` scores each branch based on victory goals, civilization personality, and AI weighting, supporting the AI's policy selection logic. These helpers are defined around lines 46-78 in [`PolicyManager.kt`](https://github.com/yairm210/Unciv/blob/main/PolicyManager.kt).

## UI Integration

The PolicyManager drives the user interface through the `shouldShowPolicyPicker()` method (line 44), which returns `shouldOpenPolicyPicker`. The UI component in [`core/src/com/unciv/ui/screens/pickerscreens/PolicyPickerScreen.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/screens/pickerscreens/PolicyPickerScreen.kt) queries `adoptableBranches` from the manager to present available options to the player.

## Working with PolicyManager: Code Examples

Here are practical examples of interacting with the PolicyManager:

```kotlin
// Initialize manager references (normally handled by game engine)
val policyManager = civ.policyManager
policyManager.setTransients(civ)  // Registers adopted uniques

// Process turn-end culture
policyManager.endTurn(cultureEarnedThisTurn)

// Check if picker should appear
if (policyManager.shouldShowPolicyPicker()) {
    // Open PolicyPickerScreen
}

// Find and adopt a specific policy
val policy = policyManager.getPolicyByName("Scientific Theory")
if (policyManager.isAdoptable(policy)) {
    policyManager.adopt(policy)  // Consumes culture or free slot
}

// Calculate refund when removing policies
val refundMap = policyManager.getCultureRefundMap(
    sequenceOf(policy), refundPercentage = 100)

// Remove a policy (e.g., during undo)
policyManager.removePolicy(policy, assumeWasFree = false)

```

## Summary

- **PolicyManager** in [`PolicyManager.kt`](https://github.com/yairm210/Unciv/blob/main/PolicyManager.kt) is the authoritative source for all social policy state in Unciv, tracking culture, free slots, and adopted policies via `HashSet` and `UniqueMap` structures
- **Cost scaling** follows a non-linear formula based on `numberOfAdoptedPolicies` and city count, modified by policy uniques
- **Adoption validation** checks prerequisites, era requirements, and unique conditions through `isAdoptable()` before `adopt()` processes the transaction
- **Branch completion** occurs automatically when the last regular policy in a branch is adopted, triggering hidden completion policies
- **Removal logic** mirrors adoption, properly decrementing counters and cleaning up uniques when policies are refunded or undone

## Frequently Asked Questions

### How does PolicyManager calculate the culture cost for the next policy?

The `getPolicyCultureCost()` method uses the formula `25 + (numberOfAdoptedPolicies * 6)^1.7` as a base, then multiplies by city count modifiers and applies difficulty and speed adjustments. The `getCultureNeededForNextPolicy()` method returns this value to determine if adoption is possible.

### What happens when a policy branch is completed in Unciv?

When the last regular policy of a branch is adopted, the `adopt()` method recursively calls itself to add the hidden *BranchComplete* policy automatically. This grants the branch completion bonus and updates the `completedBranches` tracking.

### How does PolicyManager handle free policy slots?

The `freePolicies` counter tracks slots earned through great people or other effects. During `adopt()`, if `freePolicies > 0`, the method decrements this counter instead of deducting culture from `storedCulture`, and does not increment `numberOfAdoptedPolicies` for cost scaling purposes.

### Can policies be removed after adoption in Unciv?

Yes, the `removePolicy()` method supports policy removal for undo operations or special events. It reverses the adoption process by removing entries from `adoptedPolicies` and `policyUniques`, decrementing counters unless marked as free, and recalculating civilization stats to remove the policy's effects.