Skip to content

Commit

Permalink
Merge pull request #37 from ShiJbey/development
Browse files Browse the repository at this point in the history
A few docs updates
  • Loading branch information
ShiJbey authored Nov 28, 2023
2 parents 11051f0 + e944669 commit 079f15b
Show file tree
Hide file tree
Showing 12 changed files with 398 additions and 87 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). However, all releases before 1.0.0 have breaking changes
between minor-version updates.

## [2.4.0] - Unreleased
## [2.4.1] - 2023-11-20

### Fixed

- List construction error when compiling all event considerations

## [2.4.0] - 2023-11-19

### Fixed

Expand Down
28 changes: 28 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Neighborly Documentation

Neighborly uses Sphinx to build the documentation from reStructured Text files. The latest version of the live docs can be found on [Read the Docs](https:/neighborly.readthedocs.io/en/latest/index.html).

The docs is made up of two parts:

1. Wiki pages that explain Neighborly's core concepts and abstractions
2. Documentation for the Python source code

## Building the docs

**Note:** All file paths provided below are relative to `neighborly/docs`

Whenever new source code is added, run the following command to have sphinx-autodoc generate the proper documentation pages. All these pages are stored in the `./source/api` folder to keep them separated from the hand-authored wiki pages.

```bash
sphinx-apidoc -o ./source/api ../src/neighborly
```

Finally, you can build the html files with the command below

```bash
# macOS/Linux
make html

# Windows
./make.bat html
```
58 changes: 58 additions & 0 deletions docs/source/design-tips.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.. _design-tips:

Design Tips and FAQ
===================

When should I use a new component vs. a new trait?
--------------------------------------------------

Create a custom component if there is GameObject-specific data that you need to track. Traits are helpful for flexibly authoring effects but cannot hold stateful information.

If you want the best of both components and traits, first create a custom component, then have the component add traits to GameObject within their :py:meth:`neighborly.ecs.Component.on_add` method. For example, in the code below, we have a ``Vampire`` component that tracks vampire-specific data and adds a ``vampirism`` trait that can define specific effects like making characters immortal or buffing existing traits. Assume we load the ``vampirism`` trait from an external data file.

.. code-block:: python
class Vampire(Component):
"""Tracks information about a vampire."""
__slots__ = ("humans_bled",)
humans_bled: int
"""The number of human's they have feasted on."""
def __init__(self):
super().__init__()
self.humans_bled = 0
def on_add(self):
add_trait(self.gameobject, "vampirism")
def remove_trait(self):
remove_trait(self.gameobject, "vampirism")
.. code-block:: yaml
vampirism:
display_name: Vampirism
description: This character is a vampire
effects:
# This effect makes them unable to die from old age because
# their life decay becomes zero
- type: StatBuff
stat: health_decay
amount: -5000
# This effect makes them more less friendly toward humans
- type: AddSocialRule
preconditions:
- type: TargetHasTrait
trait: human
effects:
- type: StatBuff
stat: reputation
amount: -15
When should I create new systems?
---------------------------------

Consider creating a new system when you want a simulation mechanic to happen or be checked during every timestep (tick) of the simulation. For instance, health stats are decayed every tick, and character pregnancies are implemented as a system with custom components to ensure that pregnancies take the proper amount of time.
120 changes: 77 additions & 43 deletions docs/source/effects-and-preconditions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,18 @@
Effects and Preconditions
=========================

``Effects`` are a class of objects that can perform modifications to a GameObject when applied and undo their modifications when removed. Effects are used with traits and social rules to make changes to characters and relationships.
When building our simulations, there may be times when we want traits or job roles to have side-effects on characters. For example, maybe we want:

``Preconditions`` are a class of objects that check GameObjects for certain conditions. If these conditions are met, they return true.
- Customer service jobs to gradually increase a character's sociability stat
- A ``flirtatious`` trait that makes other characters more likely attracted to the flirtatious character.
- Require characters to have a high enough ``cooking`` skill before they become the owner of a restaurant.
- Make characters with the ``shopaholic`` trait to frequent shopping locations.

All these scenarios are accomplished through using :py:class:`~neighborly.effects.base_types.Effect` and :py:class:`~neighborly.preconditions.base_types.Precondition` types.

:py:class:`~neighborly.effects.base_types.Effect` objects perform modifications to a GameObject when applied and undo their modifications when removed. Effects are used with traits and social rules to make changes to characters and relationships.

:py:class:`~neighborly.preconditions.base_types.Precondition` objects check GameObjects for certain conditions. If these conditions are met, they return true.

Using effects and preconditions
-------------------------------
Expand All @@ -14,72 +23,97 @@ Effects are specified within the ``effects`` section of traits. Each effect ``ty

The example below shows a trait with multiple effects. All effects are applied when a trait is attached. One of the effects adds a new location preference rule that accepts a list of preconditions. Like effects, precondition specifications require the user to provide a `type: ...`, and all other key-value pairs are used to parameterize an instance of that precondition type. Here we specify that this location preference only applies to places that serve alcohol.

Below is an example of a ``drinks_too_much`` trait definition as it would appear in a JSON data file.

.. code-block:: json
{
"drinks_too_much": {
"display_name": "Drinks too much",
"effects": [
{
"type": "StatBuff",
"stat": "health_decay",
"amount": 0.05,
"modifier_type": "FLAT"
},
{
"type": "AddLocationPreference",
"preconditions": [
{
"type": "HasTrait",
"trait": "serves_alcohol"
"type": "StatBuff",
"stat": "health_decay",
"amount": 0.05,
"modifier_type": "FLAT"
},
{
"type": "AddLocationPreference",
"preconditions": [
{
"type": "HasTrait",
"trait": "serves_alcohol"
}
],
"amount": 0.2
}
],
"amount": 0.2
}
]
}
}
Below is the same trait defined using YAML.

Built-in effects
----------------

Below are a list of all the currently built-in effect types. If users want to add more, they can create a new subclass of ``Effect`` and register their effect type using.

.. code-block:: python
sim.world.resource_manager.get_resource(EffectLibrary).add_effect_type(CustomEffect)
.. code-block:: yaml
- ``StatBuff``: Adds a modifier to a relationship's interaction_score stat
drinks_too_much:
display_name: Drinks too much
effects:
- type: StatBuff
stat: health_decay
amount: 0.05
modifier_type: FLAT # <-- This is optional (defaults to FLAT)
- type: AddLocationPreference
preconditions:
- type: HasTrait
trait: serves_alcohol
amount: 0.2
- Parameters:
- ``stat``: the ID of the stat to buff
- ``modifier_type``: "FLAT", "PERCENT_ADD", or "PERCENT_MULTIPLY"
- ``amount``: number
Finally, this is how this trait might be defined directly within Python.

- ``IncreaseSkill``: Permanently increases a skill stat
.. code-block:: python
- Parameters:
trait_lib = sim.world.resource_manager.get_resource(TraitLibrary)
- ``skill_name``: str
- ``amount``: number
trait_lib.add_definition_from_obj(
{
"definition_id": "drinks_too_much",
"display_name": "Drinks too much",
"effects": [
{
"type": "StatBuff",
"stat": "health_decay",
"amount": 0.05,
"modifier_type": "FLAT"
},
{
"type": "AddLocationPreference",
"preconditions": [
{
"type": "HasTrait",
"trait": "serves_alcohol"
}
],
"amount": 0.2
}
]
}
)
- ``AddLocationPreference``: Adds a location preference rule to the character
Built-in effects
----------------

- Parameters:
Below are a list of all the currently built-in effect types. If users want to add more, they can create a new subclass of ``Effect`` and register their effect type using.

- ``preconditions``: list of preconditions
- ``modifier_type``: "Flat", "PercentAdd", or "PercentMult"
- ``amount``: number
.. code-block:: python
- ``AddSocialRule``: Adds a social rule to the character
sim.world.resource_manager.get_resource(EffectLibrary).add_effect_type(CustomEffect)
- Parameters:
- ``preconditions``: list of preconditions
- ``effects``: list of effects
- :py:class:`neighborly.effects.effects.StatBuff`
- :py:class:`neighborly.effects.effects.IncreaseSkill`
- :py:class:`neighborly.effects.effects.AddSocialRule`
- :py:class:`neighborly.effects.effects.AddLocationPreference`

Defining new effects
--------------------
Expand Down
25 changes: 13 additions & 12 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,42 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to neighborly's documentation!
Welcome to Neighborly's documentation!
======================================

Neighborly is an extensible agent-based settlement simulation. It was built to be a tool for emergent narrative storytelling research. Neighborly generates a virtual settlement and simulates the individual lives of its residents over multiple generations. It models the characters' traits, statuses, relationships, occupations, life events, and more. Neighborly tracks all the life events (starting a new job, falling in love, turning into a demon, etc.), and these become the building blocks for creating emergent stories about characters and their legacies. The entire history of the settlement and its generations of characters is then made available for data analysis or as content for other applications such as games.
Neighborly is an agent-based settlement simulation for emergent narrative storytelling and data analysis. It simulates generations of characters living within a village/town/city with a particular focus on their relationships and life events (starting a new job, falling in love, turning into a demon, etc.). It combines social simulation elements, like relationship tracking, with RPG elements, such as character stats and skills, to generate backstories about characters and their families.
Neighborly simulates characters' traits, statuses, relationships, occupations, and life events and makes the entire simulated history available for data analysis and game development.

Neighborly's was inspired `Talk of the Town <https://github.com/james-owen-ryan/talktown>`_, another settlement simulation for emergent narrative storytelling research. It also draws inspiration from commercial world-simulation games like Caves of Qud, Dwarf Fortress*, Crusader Kings, RimWorld, and WorldBox. It aims to be an easily customizable simulation that can adapt to various narrative settings and support research or entertainment projects.
Neighborly's was inspired by `Talk of the Town <https://github.com/james-owen-ryan/talktown>`_ and aims to be a more customizable and user-friendly alternative to support research or entertainment projects. It also draws inspiration from commercial simulation-driven emergent narrative games like *Caves of Qud*, *Dwarf Fortress*, *Crusader Kings*, *RimWorld*, and *WorldBox*.

How to use this wiki
--------------------
How to use these docs
---------------------

This wiki explains the core building blocks of Neighborly and how to get started simulating your own procedurally generated settlements. If you're looking for a tutorial or would like to try Neighborly without downloading it, we recommend that people try this `Google Colab notebook <https://colab.research.google.com/drive/1WxZnCR8afekfBl-vI6WcIcS6OhRGdkam?usp=sharing>`_.
This wiki explains the core building blocks of Neighborly and how to get started simulating your own procedurally generated settlements. If you're looking for a tutorial or would like to try Neighborly without downloading it, here is a `Google Colab notebook <https://colab.research.google.com/drive/1WxZnCR8afekfBl-vI6WcIcS6OhRGdkam?usp=sharing>`_ that covers the basics of Neighborly.

Problems with the wiki
What if I find errors?
----------------------

If you notice any error within the wiki, please file an issue and state where the repository maintainers can find the error. Errors can be anything ranging from typos to sample code that doesn't work. Thank you for helping to make Neighborly a tool for people to learn and experiment with.
If you notice any errors with sample code or typos within the docs, please file a GitHub issue stating the issue. We appreciate your help in making Neighborly an accessible tool for learning and experimentation.

Installation
------------

Neighborly is available to download from PyPI. Please use the following command to install the latest release.
Neighborly is available to install from PyPI. Please use the following command to install the latest release.

.. code-block:: bash
python3 -m pip install neighborly
If you plan to use Neighborly as a dependency within a larger project. It is recommended that you specify the specific release in your ``pyproject.toml`` or ``requirements.txt`` files. For example, ``neighborly==2.*``. Neighborly's function and class interfaces may change drastically between releases, and this will prevent errors from appearing in your code if an updated version of Neighborly breaks something you rely on.
We recommend that users specify a specific Neighborly release in their ``pyproject.toml`` or ``requirements.txt`` files. For example, ``neighborly==2.*``. Neighborly's function and class interfaces may change drastically between releases, and this will prevent errors from appearing in your code if an updated version of Neighborly breaks something you rely on.

Neighborly's core content types
-------------------------------

Neighborly is a data-driven framework. So, before we can generate a settlement and simulate the characters' lives, we need to feed the simulation content that it can use. We refer to each piece of content as a content definition.
Neighborly is a data-driven. So, user's need to feed it a decent amount of data to get diverse and interesting results. However, Neighborly makes it easy for people to start simulating with a small amount of data and gradually add more. Below are the main content types that users can define.

- :ref:`settlements`: Different types of settlements that could be generated.
- :ref:`settlements`: The overall place where characters live and start businesses.
- :ref:`businesses`: Places where characters work.
- :ref:`traits`: Represent characters' personalities, relationship statuses, faction affiliations, etc.
- :ref:`relationships`: Track how characters feel about other characters.
Expand Down
Loading

0 comments on commit 079f15b

Please sign in to comment.