jardiacaj/finem_imperii

View on GitHub
turn/demography.py

Summary

Maintainability
A
55 mins
Test Coverage
import random

from django.db import transaction
from django.db.models import F

import world.initialization
from parallelism import parallel
from world.models.buildings import Building
from world.models.geography import World, Settlement


def worldwide_population_changes(world: World):
    for tile in world.tile_set.all():
        for settlement in tile.settlement_set.all():
            do_settlement_population_changes(settlement)


def do_settlement_population_changes(settlement: Settlement):
    settlement.update_population()
    amount_to_generate = 0

    if settlement.population < 50:
        amount_to_generate += 5

    if (
            settlement.population < settlement.population_default and
            settlement.get_hunger_percentage() < 3
    ):
        amount_to_generate += int(settlement.population * 0.05)

    residences = settlement.building_set.filter(
        type=Building.RESIDENCE).all()
    for i in range(amount_to_generate):
        world.initialization.generate_npc(i, residences, settlement)
    if amount_to_generate > 0:
        settlement.update_population()


def worldwide_food_consumption(world: World):
    parallel(
        do_settlement_food_consumption,
        Settlement.objects.filter(tile__world=world)[:]
    )


@transaction.atomic
def do_settlement_food_consumption(settlement: Settlement):
    mouths = settlement.population
    granary = settlement.get_default_granary()
    bushels_to_consume = min(
        mouths,
        granary.population_consumable_bushels()
    )
    granary.consume_bushels(bushels_to_consume)

    hunger = mouths - bushels_to_consume
    if hunger > 0 and settlement.npc_set.exists():
        for npc in random.sample(
                list(settlement.npc_set.all()),
                min(hunger, settlement.npc_set.count())
        ):
            npc.hunger += 1
            npc.save()

    if hunger == 0 and settlement.npc_set.filter(hunger__gt=0).exists():
        settlement.npc_set.filter(hunger__gt=0).update(
            hunger=F('hunger')-1
        )

    for npc in settlement.npc_set.filter(hunger__gt=3):
        if random.getrandbits(3) == 0:
            npc.take_hit()
        if npc.hunger > 5:
            npc.take_hit()

    settlement.update_population()