Feast 2.0!
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

115 lines
3.7 KiB

  1. import { Damage, Combatant, Stats, Action, Vigor, Side, GroupAction, VisibleStatus, ImplicitStatus, StatusEffect, DamageType } from './combat'
  2. import { Noun, Pronoun } from './language'
  3. import { LogEntry, LogLines } from './interface'
  4. import { Vore, VoreContainer, VoreType } from './vore'
  5. import { Item } from './items'
  6. import { PassAction } from './combat/actions'
  7. export class Creature extends Vore implements Combatant {
  8. actions: Array<Action> = [];
  9. containedIn: VoreContainer | null = null;
  10. desc = "Some creature";
  11. effects: Array<StatusEffect> = [];
  12. groupActions: Array<GroupAction> = [];
  13. items: Array<Item> = [];
  14. otherActions: Array<Action> = [];
  15. side: Side;
  16. title = "Lv. 1 Creature";
  17. constructor (name: Noun, kind: Noun, pronouns: Pronoun, stats: Stats, preyPrefs: Set<VoreType>, predPrefs: Set<VoreType>, mass: number) {
  18. super(name, kind, pronouns, stats, preyPrefs, predPrefs, mass)
  19. this.actions.push(new PassAction())
  20. this.side = Side.Heroes
  21. }
  22. applyEffect (effect: StatusEffect): LogEntry {
  23. this.effects.push(effect)
  24. return effect.onApply(this)
  25. }
  26. /**
  27. * Determines how much damage an attack would do
  28. */
  29. effectiveDamage (damage: Damage): Damage {
  30. const preDamage = this.effects.reduce((modifiedDamage: Damage, effect: StatusEffect) => {
  31. return effect.preDamage(this, modifiedDamage)
  32. }, damage)
  33. return super.effectiveDamage(preDamage)
  34. }
  35. resistanceTo (damageType: DamageType) {
  36. const base = super.resistanceTo(damageType)
  37. const modified = this.effects.reduce((resist, effect) => effect.modResistance(damageType, resist), base)
  38. return modified
  39. }
  40. executeAction (action: Action, target: Creature): LogEntry {
  41. const preActionResults = this.effects.map(effect => effect.preAction(this))
  42. const preReceiveActionResults = target.effects.map(effect => effect.preReceiveAction(target, this))
  43. const blocking = preActionResults.concat(preReceiveActionResults).filter(result => result.prevented)
  44. if (blocking.length > 0) {
  45. return new LogLines(...blocking.map(result => result.log))
  46. } else {
  47. return action.execute(this, target)
  48. }
  49. }
  50. removeEffect (effect: StatusEffect): LogEntry {
  51. this.effects = this.effects.filter(eff => eff !== effect)
  52. return effect.onRemove(this)
  53. }
  54. get status (): Array<VisibleStatus> {
  55. const results: Array<VisibleStatus> = []
  56. if (this.vigors[Vigor.Health] <= 0) {
  57. results.push(new ImplicitStatus('Dead', 'Out of health', 'fas fa-heart'))
  58. }
  59. if (this.vigors[Vigor.Stamina] <= 0) {
  60. results.push(new ImplicitStatus('Unconscious', 'Out of stamina', 'fas fa-bolt'))
  61. }
  62. if (this.vigors[Vigor.Resolve] <= 0) {
  63. results.push(new ImplicitStatus('Broken', 'Out of resolve', 'fas fa-brain'))
  64. }
  65. if (this.containedIn !== null) {
  66. results.push(new ImplicitStatus('Eaten', 'Devoured by ' + this.containedIn.owner.name, 'fas fa-drumstick-bite'))
  67. }
  68. this.effects.forEach(effect => {
  69. results.push(effect)
  70. })
  71. return results
  72. }
  73. validActions (target: Creature): Array<Action> {
  74. let choices = this.actions.concat(
  75. this.containers.flatMap(container => container.actions)
  76. ).concat(
  77. target.otherActions.concat(
  78. this.otherContainers.flatMap(container => container.actions).concat(
  79. this.items.flatMap(item => item.actions)
  80. )
  81. )
  82. )
  83. if (this.containedIn !== null) {
  84. choices = choices.concat(this.containedIn.actions)
  85. }
  86. return choices.filter(action => {
  87. return action.allowed(this, target)
  88. })
  89. }
  90. validGroupActions (targets: Array<Creature>): Array<GroupAction> {
  91. const choices = this.groupActions
  92. return choices.filter(action => {
  93. return targets.some(target => action.allowed(this, target))
  94. })
  95. }
  96. }