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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
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 adventure: Adventure,
val name: String,
initialLocation: Area,
initialHP: Int = 100,
val maxHP: Int = 100,
val maxInventoryWeight: Int = 10
):
private var currentLocation: Area = initialLocation
private var quitCommandGiven = false // one-way flag
private var hp = initialHP
private var items: Map[String, (Int, Item)] = Map()
// 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: Vector[String] =
Vector("Esimerkkirivi laulettavaksi")
def isAlive = this.hp > 0
def takeDamage(amount: Int): Unit =
hp -= amount
val event = if this.isAlive then
Event(
Vector(this -> this.condition(0)).toMap,
this.condition(1)
)
else
this.adventure.removeEntity(this.name)
Event(
Vector(this ->
"Olet täysin menettänyt toimintakykysi. Kaadut elottomana maahan."
).toMap,
s"${this.name} kaatuu elottomana maahan."
)
this.location.observeEvent(event)
/** 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 observe(event: Event): Unit = ()
/** 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} lähtee $direction")
)
val self = Vector((this, s"Menet $direction."))
Some(Event(
(leaving ++ self).toMap,
s"$name saapuu tänne."
))
else None
def pickUp(itemName: String): Event =
this.currentLocation.removeItem(itemName) match
case Some(i) =>
val inventoryWeight = items.values.map(p => p(1).weight).sum
if inventoryWeight + i.weight > maxInventoryWeight then
Event(
Vector((
this,
s"Voimasi eivät riitä kannattelemaan esinettä ${i.name}, koska kannat liikaa"
)).toMap,
s""
)
else
if items.contains(i.name) then
val (current, _) = items(i.name)
this.items += i.name -> (current + 1, i)
else
this.items += i.name -> (1, i)
Event(
Vector((this, s"Poimit esineen ${i.name}")).toMap,
s"$name poimi esineen ${i.name}"
)
case None =>
Event(
immutable.Map.from(Vector((
this,
s"Täällä ei ole esinettä $itemName noukittavaksi."
))),
s"${this.name} yritti ottaa jotakin, mutta sai vain likaa käsilleen."
)
def removeItem(itemName: String): Boolean =
this.items.get(itemName).map((count, item) =>
if count > 1 then
this.items.remove(itemName)
else
this.items(itemName) = (count - 1, item)
assert(this.items(itemName)(0) == count - 1)
Some(true)
).isDefined
def drop(itemName: String): Event =
this.items.remove(itemName) match
case Some((current, item)) if current > 0 =>
if current - 1 == 0 then
this.items -= item.name
else
this.items += itemName -> (current - 1, item)
this.currentLocation.addItem(item)
Event(
immutable.Map.from(
Vector((this, s"Pudotit esineen $itemName"))
),
s"$name Pudotti esineen $itemName"
)
case Some((current, item)) =>
this.items.remove(item.name)
println(" [virhe] esineitä ei koskaan pitäisi olla nollaa")
Event(
Vector((this, "Sinulla ei ole tuota esinettä.")).toMap,
""
)
case None => Event(
Vector((this, "Sinulla ei ole tätä esinettä!")).toMap,
s"$name yritti tonkia repustaan esineen $itemName mutta ei löytänyt sitä."
)
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.items.contains(itemName)
def useItem(itemName: String): Event =
val item: Option[Item] = this.items.get(itemName).map(_(1))
val event: Option[Event] = item.flatMap(_.use(this))
event.getOrElse(
Event(Vector(this -> "Sinulla ei ole tuota esinettä.").toMap, "")
)
/** Returns a brief description of the player’s state, for debugging purposes. */
override def toString = s"${this.name} at ${this.location.name}"
def inventory: Event =
if this.items.isEmpty then
Event(
immutable.Map.from(Vector((this, s"Sinulla ei ole esineitä"))),
s"")
else
var inventoryList = List[String]()
for (name, (count, item)) <- this.items do
inventoryList = inventoryList :+ s"$name $count (${item.description})"
Event(
immutable.Map.from(Vector((this, s"Kannat repussasi:\n" + inventoryList.mkString("\n")))),
s"")
end Entity
|