Skip to content

Commit

Permalink
Added support for speed, mental-only actions, initiative modifieers, …
Browse files Browse the repository at this point in the history
…and ignored wounds for morphs
  • Loading branch information
Bathtor committed Jul 13, 2018
1 parent a7d238e commit 197f664
Show file tree
Hide file tree
Showing 15 changed files with 195 additions and 37 deletions.
2 changes: 1 addition & 1 deletion model/epmodel.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name := "EP Model Root"

organization in ThisBuild := "com.lkroll.ep"

version in ThisBuild := "1.8.3"
version in ThisBuild := "1.9.0"

scalaVersion in ThisBuild := "2.12.4"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,10 @@ object EPCharModel extends SheetModel {
val initiative = "initiative".editable(false).default(0);
//val initiativeFormula = number[Int]("initiative_formula").editable(false);
lazy val iniRoll = roll("ini_roll", Dice.d10 + initiative - woundsApplied - traumasApplied + miscInitiativeMod & RollOptions.Tracker);
val speed = "speed".default(1).validIn(0, 99, 1);
val mentalOnlyActions = "mental_only_actions".default(0).validIn(0, 99, 1);
val speed = "speed".editable(false).default(1);
val speedExtra = "speed_extra".default(1).validIn(0, 99, 1);
val mentalOnlyActions = "mental_only_actions".editable(false).default(0);
val mentalOnlyActionsExtra = "mental_only_actions_extra".default(0).validIn(0, 99, 1);
val damageBonus = "damage_bonus".editable(false).default(0);
val stress = "stress".default(0).validIn(0, 999, 1);
val trauma = "trauma".default(0).validIn(0, 99, 1);
Expand Down Expand Up @@ -168,6 +170,10 @@ object EPCharModel extends SheetModel {
val morphArmourEnergy = "morph_armour_energy".editable(false).default(0);
val morphArmourKinetic = "morph_armour_kinetic".editable(false).default(0);
val morphSkillBoni = "morph_skill_boni".editable(false).default("");
val morphSpeed = "morph_speed".editable(false).default(1);
val morphMOA = "morph_moa".editable(false).default(0);
val morphIniBonus = "morph_ini_bonus".editable(false).default(0);
val morphIgnoredWounds = "morph_ignored_wounds".editable(false).default(0);

// skills
lazy val activeSkills = ActiveSkillSection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ object EPTranslation extends SheetI18N {
val dr = abbr("dr", "death-rating");
val init = abbr("init", "initiative");
val spd = abbr("spd", "speed");
val spdExtra = abbr("spd-extra", "speed-extra");
val moa = abbr("moa", "mental-only-actions");
val moaExtra = abbr("moa-extra", "mental-only-actions-extra");
val db = abbr("db", "damage-bonus");
val mentalHealth = text("mental-health");
val stress = text("stress");
Expand Down Expand Up @@ -199,6 +201,10 @@ object EPTranslation extends SheetI18N {
val morphSkillBoni = text("morph-skill-boni");
val morphVisibleAge = text("morph-visible-age");
val morphVisibleGender = text("morph-visible-gender");
val morphSpeed = abbr("morph-spd", "morph-speed");
val morphMOA = abbr("morph-moa", "morph-mental-only-actions");
val morphIniBonus = abbr("morph-ini-mod", "morph-initiative_modifier");
val morphIgnoredWounds = text("morph-ignored-wounds");

// gear
val gear = text("gear");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ object MorphSection extends RepeatingSection {
val aptitudeBoni = "aptitude_boni".default("");
val aptitudeMax = "aptitude_maximum".default("");
val skillBoni = "skill_boni".default("");
val speed = "speed".default(1);
val moa = "moa".default(0);
val iniBonus = "ini_bonus".default(0);
val ignoredWounds = "ignored_wounds".default(0);
}
10 changes: 10 additions & 0 deletions model/shared/src/main/scala/com/lkroll/ep/model/OldModels.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,14 @@ object OldModels {
val aptitudeMax = "aptitude_max".default(""); // this causes to roll20 to think there's a current aptitude field
}
}

object V8 extends SheetModel {
import FieldImplicitsLabels._
implicit val ctx = this.renderingContext;

override def version = "1.8.0";

val speed = "speed".default(1).validIn(0, 99, 1);
val mentalOnlyActions = "mental_only_actions".default(0).validIn(0, 99, 1);
}
}
6 changes: 3 additions & 3 deletions script/epapiscript.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ name := "EP API Script"

organization := "com.lkroll.ep"

version := "0.7.0"
version := "0.7.1"

scalaVersion := "2.12.4"

libraryDependencies += "com.lkroll.roll20" %%% "roll20-api-framework" % "0.8.+"
libraryDependencies += "com.lkroll.ep" %%% "epcompendium-core" % "2.1.2"
libraryDependencies += "com.lkroll.ep" %%% "ep-model" % "1.8.2"
libraryDependencies += "com.lkroll.ep" %%% "epcompendium-core" % "3.0.0"
libraryDependencies += "com.lkroll.ep" %%% "ep-model" % "1.9.0"
libraryDependencies += "com.lihaoyi" %%% "fastparse" % "1.+"
libraryDependencies += "org.rogach" %%% "scallop" % "3.1.+"
libraryDependencies += "org.scalactic" %%% "scalactic" % "3.0.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ package com.lkroll.ep.api.compendium
import com.lkroll.roll20.core._
import com.lkroll.roll20.api._
import com.lkroll.ep.compendium._
import com.lkroll.ep.compendium.Effect._
import com.lkroll.ep.compendium.utils.OptionPickler._
import com.lkroll.ep.model.{ EPCharModel => epmodel, MorphSection, ValueParsers, Aptitude, MorphType => ModelMorphType }
import APIImplicits._;
Expand Down Expand Up @@ -54,10 +55,37 @@ case class MorphModelImport(morph: MorphModel) extends Importable {
}
char.createRepeating(MorphSection.aptitudeBoni, rowId) <<= write(morph.aptitudeBonus);
char.createRepeating(MorphSection.aptitudeMax, rowId) <<= write(morph.aptitudeMax);
char.createRepeating(MorphSection.skillBoni, rowId) <<= write(morph.skillBonus);

var speed = 1;
var moa = 0;
var skillBoni = List.empty[String];
var iniBonus = 0;
var ignoredWounds = 0;
var notes = List.empty[String];
morph.otherEffects.foreach {
case SpeedMod(mod) => speed += mod
case MOAMod(mod) => moa += mod
case IniMod(mod) => iniBonus += mod
case _: AptitudeMod => notes ::= "Not importing AptitudeMod. Use Aptitude Boni field instead."
case s: SkillMod => skillBoni ::= s.text
case _: DurMod => notes ::= "Not importing DurMod. Use Durability field instead."
case IgnoreWounds(w) => ignoredWounds += w
case _: IgnoreTraumas => notes ::= "Not importing IgnoreTraumas."
case _: LucMod => notes ::= "Not importing LucMod."
case _: DamageEffect => notes ::= "Not importing DamageEffect."
case _: FreeForm => notes ::= "Not importing FreeForm."
}
char.createRepeating(MorphSection.speed, rowId) <<= speed;
char.createRepeating(MorphSection.moa, rowId) <<= moa;
char.createRepeating(MorphSection.skillBoni, rowId) <<= skillBoni.mkString(", ");
char.createRepeating(MorphSection.iniBonus, rowId) <<= iniBonus;
char.createRepeating(MorphSection.ignoredWounds, rowId) <<= ignoredWounds;

val notesS = if (notes.isEmpty) "" else notes.mkString(" [", ", ", "]");

morph.playerDecisions match {
case Some(s) => Left(s"TODO: $s")
case None => Left("Ok")
case Some(s) => Left(s"TODO: $s $notesS")
case None => Left("Ok" ++ notesS)
}
}
override def children: List[Importable] = morph.attacks.map(a => WeaponImport(a)).toList;
Expand Down Expand Up @@ -97,8 +125,33 @@ case class MorphInstanceImport(morph: MorphInstance) extends Importable {
}
char.createRepeating(MorphSection.aptitudeBoni, rowId) <<= write(morph.aptitudeBonus);
char.createRepeating(MorphSection.aptitudeMax, rowId) <<= write(morph.aptitudeMax);
char.createRepeating(MorphSection.skillBoni, rowId) <<= write(morph.skillBonus);
Left("Ok")
var speed = 1;
var moa = 0;
var skillBoni = List.empty[String];
var iniBonus = 0;
var ignoredWounds = 0;
var notes = List.empty[String];
morph.otherEffects.foreach {
case SpeedMod(mod) => speed += mod
case MOAMod(mod) => moa += mod
case IniMod(mod) => iniBonus += mod
case _: AptitudeMod => notes ::= "Not importing AptitudeMod. Use Aptitude Boni field instead."
case s: SkillMod => skillBoni ::= s.text
case _: DurMod => notes ::= "Not importing DurMod. Use Durability field instead."
case IgnoreWounds(w) => ignoredWounds += w
case _: IgnoreTraumas => notes ::= "Not importing IgnoreTraumas."
case _: LucMod => notes ::= "Not importing LucMod."
case _: DamageEffect => notes ::= "Not importing DamageEffect."
case _: FreeForm => notes ::= "Not importing FreeForm."
}
char.createRepeating(MorphSection.speed, rowId) <<= speed;
char.createRepeating(MorphSection.moa, rowId) <<= moa;
char.createRepeating(MorphSection.skillBoni, rowId) <<= skillBoni.mkString(", ");
char.createRepeating(MorphSection.iniBonus, rowId) <<= iniBonus;
char.createRepeating(MorphSection.ignoredWounds, rowId) <<= ignoredWounds;

val notesS = if (notes.isEmpty) "" else notes.mkString(" [", ", ", "]");
Left("Ok" ++ notesS)
}
override def children: List[Importable] = morph.attacks.map(a => WeaponImport(a)).toList;
}
Expand Down Expand Up @@ -150,15 +203,31 @@ object MorphInstanceExport extends Exportable {
toTryOr("").
flatMap(ValueParsers.skillsFrom(_)).
map(toCompendiumSkills(_));
val mSpeed = char.repeatingAt(rowId)(MorphSection.speed).map(_.apply()).getOrElse(1);
val mMOA = char.repeatingAt(rowId)(MorphSection.moa).map(_.apply()).getOrElse(0);
val mIni = char.repeatingAt(rowId)(MorphSection.iniBonus).map(_.apply()).getOrElse(0);
val mIgnoredWounds = char.repeatingAt(rowId)(MorphSection.ignoredWounds).map(_.apply()).getOrElse(0);

val r = for {
mAptBonus <- mAptBonusT;
mAptMax <- mAptMaxT;
mSkillBonus <- mSkillBonusT;
mType <- mTypeO.toTry("Invalid Morph Type")
} yield MorphInstance(mLabel, mModel, mType, mDescr, mGender, mAge, mLocation,
mImplants, mTraits, mMovement, mAptMax, mAptBonus, mSkillBonus,
Seq.empty, mDur, mArmour);
} yield {
val speedBonus: List[Effect] = if (mSpeed > 1) List(SpeedMod(mSpeed - 1)) else List.empty;
val moaBonus: List[Effect] = if (mMOA > 0) List(MOAMod(mMOA)) else List.empty;
val iniBonus: List[Effect] = if (mIni > 0) List(IniMod(mIni)) else List.empty;
val ignWounds: List[Effect] = if (mIgnoredWounds > 0) List(IgnoreWounds(mIgnoredWounds)) else List.empty;
val effects: List[Effect] = mSkillBonus.toList ++
speedBonus ++
moaBonus ++
iniBonus ++
ignWounds;

MorphInstance(mLabel, mModel, mType, mDescr, mGender, mAge, mLocation,
mImplants, mTraits, mMovement, mAptMax, mAptBonus, effects,
Seq.empty, mDur, mArmour)
};

r match {
case Success(d) => Left(d)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ package com.lkroll.ep.api

import scala.util.{ Try, Success, Failure }
import com.lkroll.ep.model.{ AptitudeValues => ModelAptitudes, SkillMod => ModelSkillMod, MorphType => ModelMorphType };
import com.lkroll.ep.compendium.{ AptitudeValues => CompendiumAptitudes, SkillMod => CompendiumSkillMod, MorphType => CompendiumMorphType }
import com.lkroll.ep.compendium.{ AptitudeValues => CompendiumAptitudes, MorphType => CompendiumMorphType, Effect }

package object compendium {
implicit class OptionOps[A](opt: Option[A]) {
Expand All @@ -49,10 +49,10 @@ package object compendium {
}
}

def toCompendiumSkills(apts: Seq[ModelSkillMod]): Seq[CompendiumSkillMod] = {
def toCompendiumSkills(apts: Seq[ModelSkillMod]): Seq[Effect.SkillMod] = {
apts.map {
case ModelSkillMod(skill, field, mod) =>
CompendiumSkillMod(skill, field, mod)
Effect.SkillMod(skill, field, mod)
}
}

Expand Down
2 changes: 1 addition & 1 deletion sheet/epsheet.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name := "EP Sheet Root"

organization in ThisBuild := "com.lkroll.ep"

version in ThisBuild := "1.8.3"
version in ThisBuild := "1.9.0"

scalaVersion in ThisBuild := "2.12.4"

Expand Down
20 changes: 20 additions & 0 deletions sheet/js/src/main/scala/com/lkroll/ep/sheet/EPUpdates.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,24 @@ object EPUpdates extends MinorVersionUpdateManager {
val calc = nop { _: Option[Unit] => EPWorkers.chatOutputCalc().map(_ => ()) }; // workaround for initialisation timing
List(calc)
}
forVersion("1.8.0") {
val speedUpdate = op(model.speed).update(oldSpeed => {
val extraSpeed = if (oldSpeed <= 1) { // if it's < 1 something is weird, but we shouldn't touch it
0 // just leave everything as it is...morphSpeed will be 1 and speedExtra 0 so it'd sum to 1 anyway
} else {
oldSpeed - 1; // since 1 is coming from morphSpeed
};
Seq(model.speedExtra <<= extraSpeed)
});
val moaUpdate = op(model.mentalOnlyActions).update(oldMOA => {
val extraMOA = if (oldMOA == 0) { // can't be < 0 since the input field doesn't allow that
0 // just leave everything as it is...morphMOA will be 0 and moaExtra 0 so it'd sum to 0 anyway
} else {
oldMOA // since 0 is coming from morphMOA
};
Seq(model.mentalOnlyActionsExtra <<= oldMOA)
});

List(speedUpdate, moaUpdate)
}
}
32 changes: 22 additions & 10 deletions sheet/js/src/main/scala/com/lkroll/ep/sheet/EPWorkers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,33 +60,45 @@ object EPWorkers extends SheetWorkerRoot {
case (base, tmp, morph, morphMax) => Seq(aptField <<= aptTotal(base, tmp, morph, morphMax));
}

val initCalc = op(intTotal, refTotal) update {
case (int, ref) => Seq(initiative <<= Math.ceil((int + ref).toFloat / 5.0f).toInt)
}
val initCalc = op(intTotal, refTotal, morphIniBonus) update {
case (int, ref, morph) => {
val baseIni = Math.ceil((int + ref).toFloat / 5.0f).toInt;
val ini = baseIni + morph;
Seq(initiative <<= ini)
}
};

val dbCalc = op(somTotal) update {
case (som) => Seq(damageBonus <<= som / 10) // this is round down, funnily
}
};

val spdCalc = bind(op(morphSpeed, speedExtra)) update {
case (morph, extra) => Seq(speed <<= (morph + extra))
};

val woundCalc = bind(op(wounds, woundsIgnored)) update {
case (curWounds, woundsIgn) => {
val woundsApl = Math.max(curWounds - woundsIgn, 0);
val moaCalc = bind(op(morphMOA, mentalOnlyActionsExtra)) update {
case (morph, extra) => Seq(mentalOnlyActions <<= (morph + extra))
};

val woundCalc = bind(op(wounds, woundsIgnored, morphIgnoredWounds)) update {
case (curWounds, woundsIgn, morph) => {
val woundsApl = Math.max(curWounds - woundsIgn - morph, 0);
val woundsModifier = woundsApl * 10;
Seq(woundsApplied <<= woundsApl, woundMod <<= woundsModifier)
}
}
};

val traumaCalc = bind(op(trauma, traumasIgnored)) update {
case (curTraumas, traumasIgn) => {
val traumasApl = Math.max(curTraumas - traumasIgn, 0);
val traumasMod = traumasApl * 10;
Seq(traumasApplied <<= traumasApl, traumaMod <<= traumasMod)
}
}
};

val museTraumaCalc = bind(op(museTrauma)) update {
case (tr) => Seq(museTraumaMod <<= tr * 10)
}
};

val willStatsCalc = op(wilTotal) update {
case (wil) => {
Expand Down
29 changes: 22 additions & 7 deletions sheet/js/src/main/scala/com/lkroll/ep/sheet/MorphWorkers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,19 @@ object MorphWorkers extends SheetWorker {
}
});

private val morphAttrsCalc: Tuple15[Boolean, String, String, String, String, Int, String, Int, Int, String, String, String, String, String, String] => UpdateDecision = {
case (active, name, tpe, gender, age, dur, mob, ae, ak, imp, traits, descr, aptB, aptMax, skillB) => if (active) {
private val morphAttrsCalc: Tuple19[Boolean, String, String, String, String, Int, String, Int, Int, String, String, String, String, String, String, Int, Int, Int, Int] => UpdateDecision = {
case (active, name, tpe, gender, age, dur, mob, ae, ak, imp, traits, descr, aptB, aptMax, skillB, spd, moa, iniB, ignWounds) => if (active) {
val rowId = Roll20.getActiveRepeatingField();
log(s"Current row: ${rowId}");
val updates = Seq(morphs.id <<= rowId, morphs.morphLocation <<= "ACTIVE",
currentMorph <<= rowId, morphType <<= tpe,
morphVisibleGender <<= gender, morphVisibleAge <<= age,
morphName <<= name, morphDescription <<= descr, morphTraits <<= traits,
morphImplants <<= imp, morphMobilitySystem <<= mob, morphDurability <<= dur,
morphArmourEnergy <<= ae, morphArmourKinetic <<= ak, morphSkillBoni <<= skillB) ++ morphAptBoni(aptB) ++ morphAptMax(aptMax);
morphArmourEnergy <<= ae, morphArmourKinetic <<= ak, morphSkillBoni <<= skillB,
morphSpeed <<= spd, morphMOA <<= moa, morphIniBonus <<= iniB,
morphIgnoredWounds <<= ignWounds) ++
morphAptBoni(aptB) ++ morphAptMax(aptMax);
(updates, ExecuteChain)
} else {
log("********** No updates, skipping chain **********")
Expand All @@ -111,17 +114,29 @@ object MorphWorkers extends SheetWorker {
val morphAttrs = bind(
op(morphs.active, morphs.morphName, morphs.morphType, morphs.visibleGender, morphs.visibleAge, morphs.durability, morphs.mobilitySystem,
morphs.armourEnergy, morphs.armourKinetic, morphs.implants, morphs.traits,
morphs.description, morphs.aptitudeBoni, morphs.aptitudeMax, morphs.skillBoni)).
update(morphAttrsCalc, EPWorkers.aptTotalsAll ++ List(EPWorkers.durStatsCalc, GearWorkers.armourTotalCalc, SkillWorkers.morphSkillBoniCalc, SkillWorkers.skillTotalCalc));
morphs.description, morphs.aptitudeBoni, morphs.aptitudeMax, morphs.skillBoni, morphs.speed, morphs.moa, morphs.iniBonus, morphs.ignoredWounds)).
update(morphAttrsCalc, EPWorkers.aptTotalsAll ++
List(EPWorkers.durStatsCalc, EPWorkers.initCalc, EPWorkers.woundCalc,
EPWorkers.spdCalc, EPWorkers.moaCalc, GearWorkers.armourTotalCalc,
SkillWorkers.morphSkillBoniCalc, SkillWorkers.skillTotalCalc));

private def resetMorphDefaults(extraUpdates: Seq[(FieldLike[Any], Any)] = Seq.empty) {
val updates = Seq(currentMorph, morphType,
morphName, morphDescription, morphTraits,
morphImplants, morphMobilitySystem, morphDurability,
morphArmourEnergy, morphArmourKinetic, morphSkillBoni).map({ case f: Field[Any] => (f -> f.resetValue) }) ++ morphAptBoni("") ++ morphAptMax("");
morphArmourEnergy, morphArmourKinetic, morphSkillBoni, morphSpeed,
morphMOA, morphIniBonus, morphIgnoredWounds).
map({ case f: Field[Any] => (f -> f.resetValue) }) ++ morphAptBoni("") ++ morphAptMax("");
val setF = setAttrs((extraUpdates ++ updates).toMap);
setF.onComplete {
case Success(_) => EPWorkers.aptTotalsAll.andThen(EPWorkers.durStatsCalc).andThen(SkillWorkers.morphSkillBoniCalc).andThen(SkillWorkers.skillTotalCalc)()
case Success(_) => EPWorkers.aptTotalsAll.
andThen(EPWorkers.durStatsCalc).
andThen(EPWorkers.initCalc).
andThen(EPWorkers.woundCalc).
andThen(EPWorkers.spdCalc).
andThen(EPWorkers.moaCalc).
andThen(SkillWorkers.morphSkillBoniCalc).
andThen(SkillWorkers.skillTotalCalc)()
case Failure(e) => error(e)
}
}
Expand Down
6 changes: 4 additions & 2 deletions sheet/jvm/src/main/scala/com/lkroll/ep/sheet/CoreTab.scala
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,10 @@ object CoreTab extends FieldGroup {
roll(char, "dur-roll", char.chatOutputEPRolls, EPDefaultTemplate(char.characterName, t.dur.fullLabel, char.epRoll, char.durTarget), (t.dur -> char.durability)),
(t.dr -> char.deathRating),
roll(char, "initiative-roll", char.chatOutputOther, EPIniTemplate(char.characterName, char.iniRoll), (t.init -> char.initiative)),
(t.spd -> dualMode(char.speed)),
(t.moa -> dualMode(char.mentalOnlyActions)),
(t.spd -> char.speed),
editOnly(t.spdExtra -> char.speedExtra),
(t.moa -> char.mentalOnlyActions),
editOnly(t.moaExtra -> char.mentalOnlyActionsExtra),
(t.db -> char.damageBonus));

val topRow = eprow(frow(
Expand Down
Loading

0 comments on commit 197f664

Please sign in to comment.