Skip to content

Commit cd34440

Browse files
committed
Tidy up object, thing, and room modules with proper documentation
1 parent c572888 commit cd34440

File tree

3 files changed

+205
-28
lines changed

3 files changed

+205
-28
lines changed

yaifl-core/src/Yaifl/Object/Kind.hs

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
{-|
22
Module : Yaifl.Object.Kind
3-
Copyright : (c) Avery 2023-2024
3+
Copyright : (c) Avery 2023-2026
44
License : MIT
55
Maintainer : ppkfs@outlook.com
66
7-
A game object (a thing or a room).
7+
Game objects represent the fundamental building blocks of the game world,
8+
encompassing both things (portable objects) and rooms (environmental locations).
9+
10+
This module defines the core `Object` data structure and its supporting components:
11+
12+
- `Object`: The primary data structure combining identification, naming, and kind-specific behaviour
13+
- `ObjectKind`: Classification system for object kinds (distinct from Haskell types)
14+
- `Timestamp`: Creation and modification tracking for objects
15+
- `Name*` types: Linguistic properties controlling article usage and pluralisation
16+
- `IsObject`: Typeclass for thing/room classification
817
-}
918

1019
module Yaifl.Object.Kind (
11-
-- * Pointed sets
12-
Pointed(..)
1320
-- * Objects
1421
-- ** Components
1522
, NamePlurality(..)
@@ -28,28 +35,50 @@ import Yaifl.Prelude
2835
import Yaifl.Entity
2936
import Yaifl.WorldModel (WMText)
3037

31-
-- | If the object has a pluralised name.
38+
-- | Whether the object's name changes when pluralised.
39+
-- `SingularNamed` objects like "key" become "keys" when plural.
40+
-- `PluralNamed` objects like "sheep" remain "sheep" when plural.
3241
data NamePlurality = SingularNamed | PluralNamed
3342
deriving stock (Show, Eq, Ord, Bounded, Enum, Generic, Read)
3443

35-
-- | If the object should have an indefinite article or not.
44+
-- | Whether the object's name is a proper noun or common noun.
45+
-- `Proper` names (e.g., "John", "London") don't use articles.
46+
-- `Improper` names (e.g., "key", "door") may use indefinite articles.
3647
data NameProperness = Improper | Proper
3748
deriving stock (Show, Eq, Ord, Bounded, Enum, Generic, Read)
3849

39-
-- | If the object should have an indefinite article or not.
50+
-- | Whether the object's name is accessible to the command parser.
51+
-- `PrivatelyNamed` objects cannot be referred to by their given name in commands.
52+
-- They can only be referenced via their `understandAs` properties.
53+
-- `PubliclyNamed` objects can be referred to directly by their name in commands.
4054
data NamePrivacy = PrivatelyNamed | PubliclyNamed
4155
deriving stock (Show, Eq, Ord, Bounded, Enum, Generic, Read)
4256

43-
-- | See also `Yaifl.Metadata.typeDAG`. An object type is just a string that has some relations to other types.
44-
-- there is no data or polymorphism connected to a type, so it's very possible to call something a supporter without
45-
-- having some supporter properties.
57+
-- | A classification type for game objects, representing their role or category in the game world.
58+
-- ObjectKinds form a directed acyclic graph (see `Yaifl.Metadata.typeDAG`) where relationships
59+
-- between types are explicitly defined rather than implied through inheritance or polymorphism.
60+
--
61+
-- This design allows flexible classification: an object can be classified as a "supporter" without
62+
-- requiring any specific data structure or behavioural implementation. The type system is purely
63+
-- descriptive, enabling runtime type checking and hierarchical organisation without code coupling.
64+
--
65+
-- Examples of object kinds include: "container", "supporter", "door", "person", "scenery".
66+
--
67+
-- The `ObjectKind` is a simple wrapper around `Text` for type safety and to enable specific
68+
-- instances and operations related to the type system.
4669
newtype ObjectKind = ObjectKind
4770
{ unObjectKind :: Text
4871
} deriving stock (Eq, Show)
4972
deriving newtype (Read, Ord, IsString, Monoid, Semigroup)
5073

51-
-- | A `Timestamp` is used to date events that modify, add, or remove objects.
52-
-- Currently these aren't...used for anything.
74+
-- | A `Timestamp` tracks when objects are created or modified.
75+
-- Timestamps do not necessarily correspond to game turns, but rather to state update ticks.
76+
-- If an object's timestamp is older than the current game state, it indicates the object
77+
-- may be out of date and should be refreshed.
78+
--
79+
-- Currently implemented but not actively used in game logic, this field provides
80+
-- infrastructure for potential future features such as object aging, undo functionality,
81+
-- or temporal queries.
5382
newtype Timestamp = Timestamp
5483
{ unTimestamp :: Int
5584
} deriving stock (Show, Read, Generic)
@@ -69,7 +98,7 @@ data Object wm objData objSpecifics = Object
6998
, objectType :: ObjectKind
7099
, creationTime :: Timestamp
71100
, modifiedTime :: Timestamp
72-
, specifics :: objSpecifics -- ^ A @vanilla@ object has no specific additional information; this is a @Pointed@ constraint.
101+
, specifics :: objSpecifics -- ^ Kind-specific data (e.g., door mechanics, container contents)
73102
, objectData :: objData -- ^ `ThingData`, `RoomData`, or `Either ThingData RoomData`.
74103
} deriving stock (Generic)
75104

@@ -91,7 +120,7 @@ objectEquals = (. getEntity) . (==) . getEntity
91120
instance Eq (Object wm d s) where
92121
(==) = objectEquals
93122

94-
-- | Maybe I'll need this instance for something or other?
123+
-- | Order objects by creation time for chronological sorting.
95124
instance Ord (Object wm d s) where
96125
compare = (. creationTime) . compare . creationTime
97126

@@ -113,7 +142,13 @@ instance Bitraversable (Object wm) where
113142
s' = g (specifics o)
114143
in (\d s -> o & #objectData .~ d & #specifics .~ s) <$> d' <*> s'
115144

116-
-- | If something is a thing or a room.
145+
-- | Typeclass for determining whether an object is a thing or a room.
146+
-- This provides a uniform interface for thing/room classification across
147+
-- different object representations.
148+
--
149+
-- The classification follows the convention established in `Yaifl.Entity`:
150+
-- positive entity IDs represent `Yaifl.Thing.Kind.Thing`s, while negative
151+
-- entity IDs represent `Yaifl.Room.Kind.Room`s.
117152
class IsObject o where
118153
isThing :: o -> Bool
119154

yaifl-core/src/Yaifl/Room/Kind.hs

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,55 @@
1+
{-|
2+
Module : Yaifl.Room.Kind
3+
Copyright : (c) Avery 2023-2026
4+
License : MIT
5+
Maintainer : ppkfs@outlook.com
6+
7+
Rooms represent environmental locations in the game world that contain objects,
8+
provide spatial context, and define the game's geography.
9+
10+
This module defines the `Room` type and its associated data structures:
11+
12+
- `Room`: The core room type wrapping `Object` with room-specific data
13+
- `RoomData`: Comprehensive properties for room behaviour and state
14+
- `Connection`: Room-to-room connections with direction and explicitness (author-created vs implied)
15+
- `MapConnections`: Direction-based connection mapping
16+
- Functions for querying room properties and managing room state
17+
18+
See also:
19+
- `Yaifl.Object.Kind` for the base Object type
20+
- `Yaifl.Enclosing.Kind` for enclosing functionality
21+
- `Yaifl.Tag` for the tagging system used by `tagRoomEntity`
22+
- `Yaifl.Metadata` for game state management used by `updateFirstRoom`
23+
-}
24+
125
module Yaifl.Room.Kind
2-
( ConnectionExplicitness(..)
26+
( -- * Connection types
27+
ConnectionExplicitness(..)
328
, Connection(..)
429
, MapConnections(..)
5-
-- ** Rooms
30+
31+
-- * Room components
632
, ContainingRegion(..)
733
, Darkness(..)
834
, RoomData(..)
935
, IsVisited(..)
1036
, blankRoomData
37+
38+
-- * Room type
1139
, Room(..)
40+
41+
-- * Entity tagging
1242
, tagRoomEntity
43+
44+
-- * Default IDs
1345
, voidID
14-
, isNotVisited
46+
47+
-- * Room queries and utilities
48+
, roomIsVisited
1549
, roomIsLighted
50+
, roomConnections
51+
, roomRegion
52+
, roomEnclosing
1653
, isVoid
1754
, updateFirstRoom
1855

@@ -98,6 +135,12 @@ makeFieldLabelsNoPrefix ''RoomData
98135
makeFieldLabelsNoPrefix ''Connection
99136

100137
-- | An `Object` with `RoomData`.
138+
-- | A room object with room-specific data and behaviour.
139+
--
140+
-- Wraps an `Object` (from `Yaifl.Object.Kind`) with `RoomData`, providing access to room properties
141+
-- such as connections, darkness, visitation state, and regional containment through the
142+
-- `HasField` instance. Maintains compatibility with the object system via
143+
-- `HasEntity` and `IsObject` instances.
101144
newtype Room wm = Room (Object wm (RoomData wm) (WMObjSpecifics wm))
102145
deriving newtype (Eq, Ord, Generic)
103146

@@ -110,14 +153,18 @@ instance Display (Room wm) where
110153
instance HasEntity (Room wm) where
111154
getEntity (Room a) = objectId a
112155

113-
-- | A place where new `Yaifl.Model.Objects.Thing`s are placed by default, to avoid having locations be `Maybe`.
156+
-- | The Void room ID used as a default placement location.
157+
-- The Void (Entity -1) serves as a fallback to avoid `Maybe` locations
158+
-- when objects need a default container. Objects in The Void are not
159+
-- considered part of the active game world and may be removed at any time.
114160
voidID :: TaggedEntity RoomTag
115161
voidID = unsafeTagEntity $ Entity (-1)
116162

117163
instance Taggable (Room wm) EnclosingTag
118164
instance Taggable (Room wm) RoomTag
119165

120-
-- | Tag a room entity.
166+
-- | Tag a room with its entity for type-safe references.
167+
-- Uses the room's object ID to create a tagged entity reference.
121168
tagRoomEntity ::
122169
Room wm
123170
-> TaggedEntity RoomTag
@@ -126,24 +173,47 @@ tagRoomEntity r = tagEntity r (r ^. #objectId)
126173
instance IsObject (Room wm) where
127174
isThing = const False
128175

129-
isNotVisited ::
130-
RoomData wm
176+
-- | Check if a room has been visited.
177+
roomIsVisited ::
178+
Room wm
131179
-> Bool
132-
isNotVisited = (/= Visited) . isVisited
180+
roomIsVisited = (== Visited) . view (#objectData % #isVisited)
133181

182+
-- | Check if a room is currently lighted.
134183
roomIsLighted ::
135184
Room wm
136185
-> Bool
137186
roomIsLighted = (== Lighted) . view (#objectData % #darkness)
138187

188+
-- | Check if an object is the void ID (default placement location).
139189
isVoid ::
140190
HasEntity a
141191
=> a
142192
-> Bool
143193
isVoid = (unTagEntity voidID ==) . getEntity
144194

195+
-- | Update the first room in metadata to the given room.
196+
-- This sets the default starting location for the player.
145197
updateFirstRoom ::
146198
State Metadata :> es
147199
=> Room wm
148200
-> Eff es ()
149-
updateFirstRoom e = #firstRoom .= tagRoomEntity e
201+
updateFirstRoom e = #firstRoom .= tagRoomEntity e
202+
203+
-- | Get the connections from a room to other rooms.
204+
roomConnections ::
205+
Room wm
206+
-> MapConnections wm
207+
roomConnections = view (#objectData % #mapConnections)
208+
209+
-- | Get the region containing a room.
210+
roomRegion ::
211+
Room wm
212+
-> ContainingRegion
213+
roomRegion = view (#objectData % #containingRegion)
214+
215+
-- | Get the enclosing data for a room.
216+
roomEnclosing ::
217+
Room wm
218+
-> Enclosing
219+
roomEnclosing = view (#objectData % #enclosing)

0 commit comments

Comments
 (0)