aboutsummaryrefslogtreecommitdiff
path: root/src/scalevalapokalypsi/Model/Area.scala
blob: 96392bac9804b74db62c5d54e7487f9de8c6f6ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package scalevalapokalypsi.Model

import scala.collection.mutable.Map
import scalevalapokalypsi.Model.Entities.*

/** The class `Area` represents locations in a text adventure game world. A game
  * world consists of areas. In general, an “area” can be pretty much anything:
  * a room, a building, an acre of forest, or something completely different.
  * What different areas have in common is that players can be located in them
  * and that they can have exits leading to other, neighboring areas. An area
  * also has a name and a description.
  *
  * @param name the name of the area
  * @param description a basic description of the area (typically not including
  *                    information about items)
  */
class Area(val name: String, var description: String):

	private val neighbors = Map[String, Area]()
	private val items: Map[String, Item] = Map()
	private val entities: Map[String, Entity] = Map()

	/** Returns the area that can be reached from this area by moving in the
	  * given direction. The result is returned in an `Option`; `None` is
	  * returned if there is no exit in the given direction.
	  */
	def neighbor(direction: String): Option[Area] =
		this.neighbors.get(direction)

	def getNeighborNames: Iterable[String] = this.neighbors.keys
	def getItemNames: Iterable[String] = this.items.keys
	def getEntityNames: Iterable[String] = this.entities.values.map(_.name)
	def getEntities: Iterable[Entity] = this.entities.values
	def getEntity(name: String): Option[Entity] = this.entities.get(name)

	/** Makes all entities in this area observe the given event.
	  *
	  * @param event the event to observe.
	  */
	def observeEvent(event: Event): Unit =
		this.getEntities.foreach(_.observe(event))

	/** Tells whether this area has a neighbor in the given direction.
	 *
	 * @param direction the direction to check
	 * @return whether there is a neighbor in the direction
	 */
	def hasNeighbor(direction: String): Boolean =
		this.neighbors.contains(direction)

	/** Adds an exit from this area to the given area. The neighboring area is
	  * reached by moving in the specified direction from this area. */
	def setNeighbor(direction: String, neighbor: Area) =
		this.neighbors += direction -> neighbor

	/** Adds exits from this area to the given areas. Calling this method is
	  * equivalent to calling the `setNeighbor` method on each of the given
	  * direction–area pairs.
	  *
	  * @param exits contains pairs consisting of a direction and the
	  *              neighboring area in that direction
	  * @see [[setNeighbor]]
	  */
	def setNeighbors(exits: Vector[(String, Area)]) =
		this.neighbors ++= exits

	/** Adds the specified item
	  *
	  * @param item the item to add
	  */
	def addItem(item: Item): Unit = this.items += item.name -> item

	/** Adds multiple items
	  *
	  * @param items a once iterable collection of items to add
	  */
	def addItems(items: IterableOnce[Item]) =
		items.iterator.foreach(i => this.items += i.name -> i)

	def hasItem(itemName: String) = this.items.contains(itemName)


	/** Removes the specified item if it exists.
	  *
	  * @param itemName the name of the item to remove
	  * @return an option containing the removed item
	  */
	def removeItem(itemName: String): Option[Item] =
		this.items.remove(itemName)

	/** Adds the specified entity to the area.
	  *
	  * @param entity the entity to add.
	  */
	def addEntity(entity: Entity): Unit =
		this.entities += entity.name.toLowerCase -> entity

	/** Removes the entity with the name `entityName`.
	  *
	  * @param entityName the name of the entity to remove
	  * @return an option containing the removed entity if it was in the area
	  */
	def removeEntity(entityName: String): Option[Entity] =
		this.entities.remove(entityName.toLowerCase())

	/** Returns a multi-line description of the area as a player sees it. This
	  * includes a basic description of the area as well as information about
	  * exits and items. If there are no items present, the return value has the
	  * form "DESCRIPTION\n\nExits available:
	  * DIRECTIONS SEPARATED BY SPACES". If there are one or more items present,
	  * the return value has the form "DESCRIPTION\nYou see here: ITEMS
	  * SEPARATED BY SPACES\n\nExits available: DIRECTIONS SEPARATED BY SPACES".
	  * The items and directions are listed in an arbitrary order.
	  */
	def fullDescription: String =
		val exitList = this.neighbors.keys.mkString(" ")
		val itemList = this.items.keys.mkString(" ")
		val entityList = this.getEntityNames.mkString(" ")
		val itemDescription =
			if this.items.nonEmpty then
				s"\nYou see here: ${itemList}"
			else ""
		val entityDescription =
			if this.entities.nonEmpty then
				s"\nThere are entities: ${entityList}"
			else ""
		(this.description +
			itemDescription +
			entityDescription +
			s"\n\nExits available: $exitList")


	/** Returns a single-line description of the area for debugging purposes. */
	override def toString =
		this.name + ": " + this.description.replaceAll("\n", " ").take(150)

end Area