Skip to content

Commit

Permalink
MORE DOCS AAIIEEE
Browse files Browse the repository at this point in the history
  • Loading branch information
SlashScreen committed Jun 24, 2024
1 parent 7535e9b commit 4a570f7
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 25 deletions.
44 changes: 44 additions & 0 deletions docs/user guide/npcs.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,46 @@
# NPCs

Skelerealms' NPCs are easily the most complex (and bug-prone - please report any bugs) part of the entire framework. They bring together a number of other complex systems (AI Modules, GOAP, Schedules, Covens, Navigation, Perception) into one entity. You can skip this entire systme and roll your own if you want to. NPCs are a blank slate, and don't do much on their own: their behavior is defined entirely by AI Modules and other systems.

The component itself offers a number of flags and settings that may define its behavior:

## Flags

`essential`, `ghost`, `invulnerable`, `unique`, and `affects_stealth_meter` don't actually do anything by default. They are here because they are often used in your own implementation of gameplay mechanics.

Interactive, however, determines whther you can interact with this NPC or not, say, to start dialogue.

## AI

A few AI settings are here as well, although they are only here to be used by AI Modules.

- `relationships`: Determines relationships this NPC has with other NPCs, think a father and daughter, a boss and employee, etc.
- `threatening_enemy_types`: The names of components other entities it sees must have for it to determine whether it's a threat or not. It doesn't make much sense for an invisible `Marker` to be a threat, does it?
- `npc_opoinions`: Any opinions it has of any particulat entity, in the shape of `ref_id -> opinion`. For example, an NPC called `biggest_bts_fan` may have an opinion value of 100 of the NPC `jimin`, bringing the opinion calculations up.
- `loyalty`: This determines the "allegiance" on an NPC during opinion calculations; that is, whether the opinion should be weighted more towards the opinions of the NPC's covens or its own loyalties, or no wieght at all. This is only used if the `opinion_mode` is set to `Average`. See "Opinion Calculation".
- `opinion_mode`: How this NPC generates opinions. See "Opinion Calculatin" for details.


## Opinion Calculation

An NPC can determine its own opinion of another NPC. This is used to influence dialogue choices, whether this NPC should attack another NPC, that sort of thing.

When an NPC calculates an opinion it has on another NPC, influencing its behavior toward the NPC, it has a lot of different things to consider. Opinions are drawn from two sources:

- Its own opinions defined in `npc_opinions`
- Opinions that each coven the NPC has has regarding each coven the target entity has

How these opinions factor into the final opinion depends on `opinion_mode`:

- `Minimum`: The calculated opinion is the minimum of all opinions gathered. This is the default.
- `Maximum`: The calculated opinion is the maximum of all opinions gathered.
- `Average`: The calculated opinion is the weighted average of all the opinions gathered, deduplicated. The weight is determined by `loyalty_mode`.


## Simulation Level

The NPCs have 3 simulation levels to keep down processing power for lots of agents:

- FULL: Full simulation
- GRANULAR: Partial simulation, only handles schedules and inter-scene navigation
- NONE: The NPC will not do anything.
5 changes: 5 additions & 0 deletions docs/user guide/schedules.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
# Schedules

Skelerealms comes with a schedule/NPC routines system. It's used by adding a `Schedule` node underneath an `NPCComponent`, and adding a number of `ScheduleEvent`s underneath.

`ScheduleEvents` are nodes that can influence what an NPC does at different times of day, and are roughly equivalent to Creation Engine's "AI Packages" feature, but limited to the "routines" aspect of the feature. This class is meant to be inherited with your own functionality. For an example of how this is done, see the built-in `SandboxSchedule`. The `SandboxSchedule` is perhaps confusingly named, but it is used for NPCs idle behaviors during a set time - for example, milling about in their house during the evening. The "Sandbox" name is inherited from Creation Kit's name for the same idea.

Most of the properties are documented or self-explanatory. For them to be considered, the current time of day must be between the times described in `from` and `to`. The timestamps can be adjusted to inform to what degree the timestamps must be matched, so NPCs can, for example, do a schedulke every day, or only on certain days. `ScheduleConditions` can also be added to only allow events to happen if certain conditions are met - for example, only having certain behavior happen when a quest is complete.
23 changes: 23 additions & 0 deletions docs/user guide/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

Skelerealms offers a few tools to help with your development.

## Components

Components will tell you if any other components they depend on are absent, using the ditor warnings feature.

## Node Bundles

If you want to compose a set of AI Modules, Loot table items, etc. the `NodeBundle` class aims to help with that. All it does is take all of its children and reparent them to be siblings of itself, and then removes itself afterwards. Since some systems rely on a tree's structure to determine functionality, this is handy for having a scene you can drag in while making an entity, helping for composability. Simply make a scene with a NodeBundle as a root and all your items below it, and it will flatten out during runtime.

## SKWorldEntity

The premiere way to spawn unique entities into the world is by using an SKWorldEntity. Put your entity in, and do with it as you wish.

There is a work-in-progress tool you can use to create entities based on an archetype (see [entities](entities.md)). You can add paths to each archetype you want to use in the project settings, and then create new ones using the menu in the inspector. It's not perfect, but it will get better support once instancing scenes directly within code gets supported (an active PR).

You can sync the position of any unique entity by hitting the button in the inspector. This will edit the attached entity to make its position the **global** position of the World Entity node, and set its world to the current edited world (Internally, this is determined to be the name of the root node of the currently edited scene).

## Doors

The easiest way to allow the player to move between scenes is the Door. Add a door into the scene. Whenever any entity with a `TeleportComponent` interacts with the door, they will be teleported to the door's other side. To set up a door, do as follows:

1. Create a Door node, and position it. You can also add any colliders or whatever you use to determine when to interact with something, as well as your mesh instance.
2. Create a resource in the `instance` field, and save it to disk somewhere. press the "Sync position" button to sync the door resource.
3. Create a new door in a different (or the same) scene, and repeat the process. Grab the resource of the door you already have, (or, if you already have a door resource you'd like to link to, grab that instead), and drag it into the `destination_instance` field. You must do this on both sides (a bit tedious, but it allows for more flexible/non-euclidean door layouts).
4. You now have a door.

At any time, once you have a `destination_instance`, you can press the "Jump to destination" button to navigate the editor's camera to the other side of the door, opening the destination scene in the editor if necessary (providing that the destination world is in the proper folder).
2 changes: 1 addition & 1 deletion scripts/components/npc_component.gd
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ extends SKEntityComponent
@export var affects_stealth_meter:bool = true
## Whether you can interact with this NPC.
@export var interactive:bool = true
@export_category("AI")
## NPC relationships.
@export var relationships:Array[Relationship]
@export_category("AI")
## Component types that the AI will looks for to determine threats.
@export var threatening_enemy_types = [
"NPCComponent",
Expand Down
4 changes: 4 additions & 0 deletions scripts/entities/entity_component.gd
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ func gather_debug_info() -> String:
return ""


func _to_string() -> String:
return gather_febug_info()


## Prints a rich text message to the console prepended with the entity name. Used for easier debugging.
func printe(text:String) -> void:
if parent_entity:
Expand Down
20 changes: 0 additions & 20 deletions scripts/schedules/quest_condition.gd

This file was deleted.

4 changes: 3 additions & 1 deletion scripts/schedules/schedule.gd
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
class_name Schedule
extends Node


## Keeps track of the schedule.
## Schedules are roughly analagous to Creation Kit's "AI packages", although limited to time slots.
## It is made up of [ScheduleEvent]s.
## To adjust NPC behavior under circumastances outside of keeping a schedule, see [GOAPComponent] and [ScheduleCondition].


@export var events:Array[ScheduleEvent]
@onready var events:Array[ScheduleEvent] = get_children()


func find_schedule_activity_for_current_time() -> Option:
Expand Down
14 changes: 11 additions & 3 deletions scripts/schedules/schedule_event.gd
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
class_name ScheduleEvent
extends Resource
extends Node


## These are the different schedule events that can occupy a schedule.


@export var name:String
## From what time?
@export var from:Timestamp
## To what time?
@export var to:Timestamp
## Anmy condition that needs be checked first.
@export var condition:ScheduleCondition
## Schedule priotity.
@export var priority:float


## Get the location this event is at
## Get the location this event is at.
func get_event_location() -> NavPoint:
return null


## Wthether this entity is "at" the event.
func satisfied_at_location(e:SKEntity) -> bool:
return true


## What to do when the event has begun.
func on_event_started() -> void:
return


## What to do when the event has ended.
func on_event_ended() -> void:
return

0 comments on commit 4a570f7

Please sign in to comment.