125 lines
5.1 KiB
Plaintext
125 lines
5.1 KiB
Plaintext
module horse/legacy
|
|
|
|
import std/num/decimal
|
|
import std/data/linearmap
|
|
import std/data/linearset
|
|
import horse/game-id
|
|
import horse/spark
|
|
import horse/prob/dist
|
|
|
|
// A legacy, or parent and grandparents.
|
|
pub struct legacy
|
|
uma: veteran
|
|
sub1: veteran
|
|
sub2: veteran
|
|
|
|
// A veteran, or the result of a completed career.
|
|
pub struct veteran
|
|
uma: uma-id
|
|
sparks: list<spark-id>
|
|
saddles: list<saddle-id>
|
|
|
|
// Get all saddles shared between two lists thereof.
|
|
pub fun shared-saddles(a: list<saddle-id>, b: list<saddle-id>): list<saddle-id>
|
|
val sa: linearSet<saddle-id> = a.foldl(linear-set(Nil)) fn(s, id) if id.is-valid then s.add(id) else s
|
|
val c: linearSet<saddle-id> = b.foldl(linear-set(Nil)) fn(s, id) if sa.member(id) then s.add(id) else s
|
|
c.list
|
|
|
|
// Get the individual affinity for a legacy.
|
|
// Any invalid ID is treated as giving 0.
|
|
pub fun parent-affinity(
|
|
trainee: uma-id,
|
|
legacy: legacy,
|
|
other-parent: uma-id,
|
|
?character-id: (uma-id) -> character-id,
|
|
?saddle-bonus: (list<saddle-id>) -> int,
|
|
?pair-affinity: (a: character-id, b: character-id) -> int,
|
|
?trio-affinity: (a: character-id, b: character-id, c: character-id) -> int
|
|
): int
|
|
val t = trainee.character-id
|
|
val p1 = legacy.uma.uma.character-id
|
|
val s1 = legacy.sub1.uma.character-id
|
|
val s2 = legacy.sub2.uma.character-id
|
|
val p2 = other-parent.character-id
|
|
pair-affinity(t, p1) + pair-affinity(p1, p2)
|
|
+ trio-affinity(t, p1, s1) + trio-affinity(t, p1, s2)
|
|
+ saddle-bonus(shared-saddles(legacy.uma.saddles, legacy.sub1.saddles)) + saddle-bonus(shared-saddles(legacy.uma.saddles, legacy.sub2.saddles))
|
|
|
|
// Get the individual affinities for a legacy's sub-legacies.
|
|
// The first value is the legacy for the `legacy.sub1` and the second is for
|
|
// `legacy.sub2`.
|
|
// Any invalid ID is treated as giving 0.
|
|
pub fun sub-affinity(
|
|
trainee: uma-id,
|
|
legacy: legacy,
|
|
?character-id: (uma-id) -> character-id,
|
|
?saddle-bonus: (list<saddle-id>) -> int,
|
|
?trio-affinity: (a: character-id, b: character-id, c: character-id) -> int
|
|
): (int, int)
|
|
val t = trainee.character-id
|
|
val p = legacy.uma.uma.character-id
|
|
val s1 = legacy.sub1.uma.character-id
|
|
val s2 = legacy.sub2.uma.character-id
|
|
val r1 = trio-affinity(t, p, s1) + saddle-bonus(shared-saddles(legacy.uma.saddles, legacy.sub1.saddles))
|
|
val r2 = trio-affinity(t, p, s2) + saddle-bonus(shared-saddles(legacy.uma.saddles, legacy.sub2.saddles))
|
|
(r1, r2)
|
|
|
|
// Associate each spark with its actual chance to activate given an individual
|
|
// affinity value and the possible effects when it does.
|
|
pub fun uma/inspiration(l: list<spark-id>, affinity: int, ?spark-type: (spark-id) -> spark-type, ?rarity: (spark-id) -> rarity, ?effects: (spark-id) -> list<list<spark-effect>>): list<(spark-id, decimal, list<list<spark-effect>>)>
|
|
val a = decimal(1 + affinity, -2)
|
|
l.map() fn(id) (id, min(id.base-proc * a, 1.decimal), id.effects)
|
|
|
|
// Get the complete list of effects that may occur in an inspiration event
|
|
// and the respective probability of activation.
|
|
// Duplicates, i.e. multiple veterans with the same spark, are preserved.
|
|
pub fun inspiration(
|
|
trainee: uma-id,
|
|
parent1: legacy,
|
|
parent2: legacy,
|
|
?character-id: (uma-id) -> character-id,
|
|
?saddle-bonus: (list<saddle-id>) -> int,
|
|
?pair-affinity: (a: character-id, b: character-id) -> int,
|
|
?trio-affinity: (a: character-id, b: character-id, c: character-id) -> int,
|
|
?spark-type: (spark-id) -> spark-type,
|
|
?rarity: (spark-id) -> rarity,
|
|
?effects: (spark-id) -> list<list<spark-effect>>
|
|
): list<(spark-id, decimal, list<list<spark-effect>>)>
|
|
val p1a = parent-affinity(trainee, parent1, parent2.uma.uma)
|
|
val p2a = parent-affinity(trainee, parent2, parent1.uma.uma)
|
|
val (s11a, s12a) = sub-affinity(trainee, parent1)
|
|
val (s21a, s22a) = sub-affinity(trainee, parent2)
|
|
[
|
|
inspiration(parent1.uma.sparks, p1a),
|
|
inspiration(parent1.sub1.sparks, s11a),
|
|
inspiration(parent1.sub2.sparks, s12a),
|
|
inspiration(parent2.uma.sparks, p2a),
|
|
inspiration(parent2.sub1.sparks, s21a),
|
|
inspiration(parent2.sub2.sparks, s22a),
|
|
].concat
|
|
|
|
// Reduce a spark effect list to the skill it is able to give.
|
|
pub fun skills(l: list<list<spark-effect>>): maybe<skill-id>
|
|
val r: linearSet<skill-id> = l.head(Nil).foldl(linear-set(Nil)) fn(s, eff)
|
|
match eff
|
|
Skill-Hint(id, _) -> s + id
|
|
_ -> s
|
|
r.list.head
|
|
|
|
// Reduce a spark effect list to the aptitude it is able to give.
|
|
pub fun aptitudes(l: list<list<spark-effect>>): maybe<aptitude>
|
|
val r: linearSet<aptitude> = l.head(Nil).foldl(linear-set(Nil)) fn(s, eff)
|
|
match eff
|
|
Aptitude-Up(apt) -> s + apt
|
|
_ -> s
|
|
r.list.head
|
|
|
|
// Get the overall chance of each count of sparks, including zero, providing a
|
|
// given type of effect activating in a single inspiration event.
|
|
pub fun inspiration-gives(l: list<(spark-id, decimal, list<list<spark-effect>>)>, f: (list<list<spark-effect>>) -> maybe<a>, ?a/(==): (a, a) -> bool): linearMap<a, list<decimal>>
|
|
val m: linearMap<_, list<decimal>> = l.foldl(LinearMap(Nil)) fn(m, (_, p, eff))
|
|
match f(eff)
|
|
Nothing -> m
|
|
Just(a) -> m.map/update(a, [p]) fn(cur, pp) pp.append(cur)
|
|
m.map() fn(_, v) poisson-binomial(v)
|