aboutsummaryrefslogtreecommitdiff
path: root/src/scalevalapokalypsi/Model/Entities/Entity.scala
blob: e7cd45c7e8379eb63bb90c46f55de438e5154d78 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package scalevalapokalypsi.Model.Entities

import scala.collection.mutable.{Buffer, Map}
import scalevalapokalypsi.Model.*

import scala.collection.immutable


/** An in-game entity.
  *
  * @param name the name of the entity
  * @param initialLocation the Area where the entity is instantiated
  */
class Entity(
	val name: String,
	initialLocation: Area,
	initialHP: Int = 100,
	val maxHP: Int = 100
):

	private var currentLocation: Area = initialLocation
	private var quitCommandGiven = false // one-way flag
	private val inventory: Map[String, Item] = Map()
	private var hp = initialHP

	// TODO: add logic for choosing from multiplu lines - can depend on HP etc.
	/** Gets a verse to sing when attacking against this entity.
	  *
	  * @return the verse to sing against this entity
	  */
	def getVerseAgainst: String = "Esimerkkirivi laulettavaksi"

	def takeDamage(amount: Int): Unit =
		hp -= amount
		if hp < 0 then
			println("Oh no, I died!")

	/** Returns a description of the physical condition of this entity,
	  * i.e. the damage it has taken.
	  *
	  * @return a pair of strings, both of which describe the condition of this
	  *         entity, the first of which is in first person and the second in
	  *         third person.
	  */
	def condition: (String, String) =
		if hp < maxHP * .25 then
			("Sinua heikottaa ja tunnet olevasi lähellä häviötä.",
				s"$name näyttää maansa myyneeltä.")
		else if hp < maxHP * .50 then
			("Sinnittelet yhä, mutta kuntosi on laskenut suuresti.",
				s"$name näyttää sinnittelevän yhä.")
		else if hp < maxHP * .75 then
			("Tunnet koettelemusten vaikutuksen, mutta et anna niiden lannistaa itseäsi",
				s"$name näyttää aavistuksen lannistuneelta.")
		else if hp < maxHP then
			("Olet voimissasi.", s"$name on yhä voimissaan.")
		else
			("Olet täysin kunnossa.", s"$name näyttää kuin vastasyntyneeltä.")

	/** Does nothing, except possibly in inherited classes. */
	def observeString(observation: String): Unit =
		println("    [debug] entity got observation string & discarded it")
	def observe(event: Event): Unit =
		println("    [debug] entity got observation event & discarded it")

	/** Returns the player’s current location. */
	def location = this.currentLocation

	/** Attempts to move the player in the given direction. This is successful
	  * if there is an exit from the player’s current location towards the
	  * direction name. Returns a description of the result: "You go DIRECTION."
	  * or "You can't go DIRECTION."
	  */
	def go(direction: String): Option[Event] =
		val destination = this.location.neighbor(direction)
		val oldEntities = this.location.getEntities.filter(_ != this)
		val newEntities = destination.map(_.getEntities)
		if destination.isDefined then
			val removeSuccess = this.currentLocation.removeEntity(this.name)
			assert(removeSuccess.isDefined) // Production - assertions off
			this.currentLocation = destination.getOrElse(this.currentLocation)
			destination.foreach(_.addEntity(this))

			val leaving = oldEntities.zip(
				Vector.fill
					(oldEntities.size)
						(s"${this.name} leaves this location.")
			)
			//val arriving = newEntities.map(n => n.zip(
			//	Vector.fill
			//		(n.size)
			//		(s"${this.name} arrives here.")
			//)).getOrElse(Vector())
			val self = Vector((this, s"You go $direction."))
			Some(Event(
				(leaving ++ self).toMap,
				s"$name arrives here."
			))
		else None

	def pickUp(itemName: String): Event =
		this.currentLocation.removeItem(itemName) match
			case Some(i) =>
				this.inventory += i.name -> i
				Event(
					immutable.Map.from(Vector((this, s"You pick up the ${i.name}"))),
					s"$name picks up the ${i.name}"
				)
			case None => Event(
				immutable.Map.from(Vector((this, s"There is no $itemName here to pick up."))),
				s"${this.name} tries to pick up something but gets just dirt in their hands."
			)

	def drop(itemName: String): Event =
		this.inventory.remove(itemName) match
			case Some(item) =>
				this.currentLocation.addItem(item)
				Event(
					immutable.Map.from(Vector((this, s"You drop the $itemName"))),
					s"$name drops the $itemName"
				)
			case None => Event(
				immutable.Map.from(Vector((this, "You don't have that!"))),
				s"$name reaches their backpack to drop $itemName but miserably fails to find it there."
			)

	def sayTo(entity: Entity, message: String): Event =
		if entity == this then this.ponder(message: String)
		else
			Event(
				immutable.Map.from(Vector(
					(this, s"Sanot niin henkilölle ${entity.name}."),
					(entity, s"${this.name}: “${message}”")
				)),
				s"Kuulet henkilön ${this.name} sanovan jotain henkilölle ${entity.name}"
			)

	def ponder(message: String): Event =
		Event(
			immutable.Map.from(Vector(
				(this, s"Mietit itseksesi: “$message”")
			)),
			s"${this.name} näyttää pohtivan jotain itsekseen."
		)

	def say(message: String): Event =
		Event(
			immutable.Map.from(Vector((this, "Sanot niin ääneen."))),
			s"$name: “$message”"
		)

	/** Causes the player to rest for a turn.
	 * Returns a description of what happened. */
	def rest(): Event =
		Event(
			immutable.Map.from(Vector((this, "Lepäät hetken."))),
			s"${this.name} levähtää."
		)

	/** Tells whether this entity can drop the specified item
	 * (if an action were to specify so).
	 *
	 * @param itemName the name to check
	 * @return whether this entity has this item and can drop it
	 */
	def canDrop(itemName: String): Boolean = this.inventory.contains(itemName)

	/** Returns a brief description of the player’s state, for debugging purposes. */
	override def toString = s"${this.name} at ${this.location.name}"

end Entity