"""neighborly.settlement
This module contains classes and helper functions for defining and modeling settlements.
"""
from __future__ import annotations
from typing import Any, Iterable, Optional
from neighborly.ecs import Component, GameObject
[docs]class District(Component):
"""A subsection of a settlement."""
__slots__ = (
"_name",
"_description",
"_settlement",
"_population",
"_residential_slots",
"_business_slots",
"_businesses",
"_residences",
)
_name: str
"""The name of the district."""
_description: str
"""A short description of the district."""
_settlement: GameObject
"""The settlement the district belongs to."""
_population: int
"""The number of characters that live in this district."""
_residential_slots: int
"""The number of residential slots the district can build on."""
_business_slots: int
"""The number of business slots the district can build on."""
_businesses: list[GameObject]
"""Businesses in this district."""
_residences: list[GameObject]
"""Residences in this district."""
def __init__(
self,
name: str,
description: str,
settlement: GameObject,
residential_slots: int,
business_slots: int,
) -> None:
super().__init__()
self._name = name
self._description = description
self._settlement = settlement
self._residential_slots = residential_slots
self._business_slots = business_slots
self._population = 0
self._businesses = []
self._residences = []
@property
def name(self) -> str:
"""The name of the settlement."""
return self._name
@name.setter
def name(self, value: str) -> None:
"""Set the name of the settlement"""
self._name = value
self._gameobject.name = value
@property
def description(self) -> str:
"""A short description of the district."""
return self._description
@description.setter
def description(self, value: str) -> None:
"""A short description of the district."""
self._description = value
@property
def population(self) -> int:
"""The number of characters that live in this district."""
return self._population
@population.setter
def population(self, value: int) -> None:
"""Set the number of characters that live in this district."""
self._population = value
@property
def settlement(self) -> GameObject:
"""The settlement the district belongs to."""
return self._settlement
@property
def residential_slots(self) -> int:
"""Get the number of slots remaining for residential buildings."""
return self._residential_slots
@property
def business_slots(self) -> int:
"""Get the number of slots remaining for businesses."""
return self._business_slots
@property
def businesses(self) -> Iterable[GameObject]:
"""Get all the businesses in the district."""
return self._businesses
@property
def residences(self) -> Iterable[GameObject]:
"""Get all the residential buildings in the district."""
return self._residences
[docs] def add_business(self, business: GameObject) -> None:
"""Add a business to this district.
Parameters
---------
business
The business to add.
"""
self._businesses.append(business)
self._business_slots -= 1
[docs] def remove_business(self, business: GameObject) -> bool:
"""Remove a business from this district.
Parameters
----------
business
The business to remove
Returns
-------
bool
True if the business was successfully removed, False otherwise.
"""
try:
self._businesses.remove(business)
self._business_slots += 1
return True
except ValueError:
# The business was not present
return False
[docs] def add_residence(self, residence: GameObject) -> None:
"""Add a residence to this district.
Parameters
---------
residence
The district to add.
"""
self._residences.append(residence)
self._residential_slots -= 1
[docs] def remove_residence(self, residence: GameObject) -> bool:
"""Remove a residence from this district.
Parameters
----------
residence
The residence to remove
Returns
-------
bool
True if the residence was successfully removed, False otherwise.
"""
try:
self._residences.remove(residence)
self._residential_slots += 1
return True
except ValueError:
# The residence was not present
return False
[docs] def to_dict(self) -> dict[str, Any]:
return {
"name": self.name,
"description": self._description,
"settlement": self._settlement.uid,
"residences": [r.uid for r in self.residences],
"businesses": [b.uid for b in self.businesses],
"population": self.population,
}
[docs]class Settlement(Component):
"""A town, city, or village where characters live."""
__slots__ = "_name", "_districts"
_districts: list[GameObject]
"""References to districts within this settlement."""
_name: str
"""The name of the settlement."""
def __init__(self, name: str, districts: Optional[list[GameObject]] = None) -> None:
super().__init__()
self._name = name
self._districts = districts.copy() if districts is not None else []
@property
def name(self) -> str:
"""The name of the settlement."""
return self._name
@name.setter
def name(self, value: str) -> None:
"""Set the name of the settlement"""
self._name = value
self._gameobject.name = value
@property
def population(self) -> int:
"""The total number of people living in the settlement."""
total_population: int = 0
for district in self._districts:
total_population += district.get_component(District).population
return total_population
@property
def districts(self) -> Iterable[GameObject]:
"""Return an iterable for this settlement's districts."""
return self._districts
[docs] def add_district(self, district: GameObject) -> None:
"""Add a district to this settlement.
Parameters
---------
district
The district to add.
"""
self._districts.append(district)
[docs] def remove_district(self, district: GameObject) -> bool:
"""Remove a district from this settlement.
Parameters
----------
district
The district to remove
Returns
-------
bool
True if the district was successfully removed, False otherwise.
"""
try:
self._districts.remove(district)
return True
except ValueError:
# The district was not present
return False
[docs] def to_dict(self) -> dict[str, Any]:
return {
"name": self.name,
"districts": [d.uid for d in self._districts],
"population": self.population,
}