@gamepark/greylune 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/dist/Constants.d.ts +23 -0
  2. package/dist/Constants.d.ts.map +1 -0
  3. package/dist/Constants.js +17 -0
  4. package/dist/Constants.js.map +1 -0
  5. package/dist/GreyluneOptions.d.ts +11 -0
  6. package/dist/GreyluneOptions.d.ts.map +1 -0
  7. package/dist/GreyluneOptions.js +8 -0
  8. package/dist/GreyluneOptions.js.map +1 -0
  9. package/dist/GreyluneRules.d.ts +123 -0
  10. package/dist/GreyluneRules.d.ts.map +1 -0
  11. package/dist/GreyluneRules.js +122 -0
  12. package/dist/GreyluneRules.js.map +1 -0
  13. package/dist/GreyluneSetup.d.ts +18 -0
  14. package/dist/GreyluneSetup.d.ts.map +1 -0
  15. package/dist/GreyluneSetup.js +88 -0
  16. package/dist/GreyluneSetup.js.map +1 -0
  17. package/dist/Memory.d.ts +22 -0
  18. package/dist/Memory.d.ts.map +1 -0
  19. package/dist/Memory.js +23 -0
  20. package/dist/Memory.js.map +1 -0
  21. package/dist/PlayerColor.d.ts +7 -0
  22. package/dist/PlayerColor.d.ts.map +1 -0
  23. package/dist/PlayerColor.js +8 -0
  24. package/dist/PlayerColor.js.map +1 -0
  25. package/dist/Season.d.ts +7 -0
  26. package/dist/Season.d.ts.map +1 -0
  27. package/dist/Season.js +8 -0
  28. package/dist/Season.js.map +1 -0
  29. package/dist/Year.d.ts +8 -0
  30. package/dist/Year.d.ts.map +1 -0
  31. package/dist/Year.js +10 -0
  32. package/dist/Year.js.map +1 -0
  33. package/dist/ai/Evaluation.d.ts +118 -0
  34. package/dist/ai/Evaluation.d.ts.map +1 -0
  35. package/dist/ai/Evaluation.js +1069 -0
  36. package/dist/ai/Evaluation.js.map +1 -0
  37. package/dist/ai/GreyluneAI.d.ts +20 -0
  38. package/dist/ai/GreyluneAI.d.ts.map +1 -0
  39. package/dist/ai/GreyluneAI.js +113 -0
  40. package/dist/ai/GreyluneAI.js.map +1 -0
  41. package/dist/ai/Model.d.ts +38 -0
  42. package/dist/ai/Model.d.ts.map +1 -0
  43. package/dist/ai/Model.js +105 -0
  44. package/dist/ai/Model.js.map +1 -0
  45. package/dist/ai/Simulation.d.ts +13 -0
  46. package/dist/ai/Simulation.d.ts.map +1 -0
  47. package/dist/ai/Simulation.js +20 -0
  48. package/dist/ai/Simulation.js.map +1 -0
  49. package/dist/index.d.ts +5 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +5 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/material/Area.d.ts +9 -0
  54. package/dist/material/Area.d.ts.map +1 -0
  55. package/dist/material/Area.js +10 -0
  56. package/dist/material/Area.js.map +1 -0
  57. package/dist/material/Distance.d.ts +8 -0
  58. package/dist/material/Distance.d.ts.map +1 -0
  59. package/dist/material/Distance.js +9 -0
  60. package/dist/material/Distance.js.map +1 -0
  61. package/dist/material/Effect.d.ts +103 -0
  62. package/dist/material/Effect.d.ts.map +1 -0
  63. package/dist/material/Effect.js +83 -0
  64. package/dist/material/Effect.js.map +1 -0
  65. package/dist/material/EncounterCard.d.ts +61 -0
  66. package/dist/material/EncounterCard.d.ts.map +1 -0
  67. package/dist/material/EncounterCard.js +214 -0
  68. package/dist/material/EncounterCard.js.map +1 -0
  69. package/dist/material/EventTile.d.ts +17 -0
  70. package/dist/material/EventTile.d.ts.map +1 -0
  71. package/dist/material/EventTile.js +52 -0
  72. package/dist/material/EventTile.js.map +1 -0
  73. package/dist/material/LocationType.d.ts +42 -0
  74. package/dist/material/LocationType.d.ts.map +1 -0
  75. package/dist/material/LocationType.js +43 -0
  76. package/dist/material/LocationType.js.map +1 -0
  77. package/dist/material/MaterialSource.d.ts +8 -0
  78. package/dist/material/MaterialSource.d.ts.map +1 -0
  79. package/dist/material/MaterialSource.js +2 -0
  80. package/dist/material/MaterialSource.js.map +1 -0
  81. package/dist/material/MaterialType.d.ts +23 -0
  82. package/dist/material/MaterialType.d.ts.map +1 -0
  83. package/dist/material/MaterialType.js +24 -0
  84. package/dist/material/MaterialType.js.map +1 -0
  85. package/dist/material/Period.d.ts +6 -0
  86. package/dist/material/Period.d.ts.map +1 -0
  87. package/dist/material/Period.js +7 -0
  88. package/dist/material/Period.js.map +1 -0
  89. package/dist/material/PlayerState.d.ts +34 -0
  90. package/dist/material/PlayerState.d.ts.map +1 -0
  91. package/dist/material/PlayerState.js +106 -0
  92. package/dist/material/PlayerState.js.map +1 -0
  93. package/dist/material/QuestTile.d.ts +21 -0
  94. package/dist/material/QuestTile.d.ts.map +1 -0
  95. package/dist/material/QuestTile.js +32 -0
  96. package/dist/material/QuestTile.js.map +1 -0
  97. package/dist/material/Reaction.d.ts +49 -0
  98. package/dist/material/Reaction.d.ts.map +1 -0
  99. package/dist/material/Reaction.js +37 -0
  100. package/dist/material/Reaction.js.map +1 -0
  101. package/dist/material/Tokens.d.ts +29 -0
  102. package/dist/material/Tokens.d.ts.map +1 -0
  103. package/dist/material/Tokens.js +46 -0
  104. package/dist/material/Tokens.js.map +1 -0
  105. package/dist/material/Village.d.ts +23 -0
  106. package/dist/material/Village.d.ts.map +1 -0
  107. package/dist/material/Village.js +29 -0
  108. package/dist/material/Village.js.map +1 -0
  109. package/dist/material/VillageCard.d.ts +90 -0
  110. package/dist/material/VillageCard.d.ts.map +1 -0
  111. package/dist/material/VillageCard.js +359 -0
  112. package/dist/material/VillageCard.js.map +1 -0
  113. package/dist/material/Villager.d.ts +8 -0
  114. package/dist/material/Villager.d.ts.map +1 -0
  115. package/dist/material/Villager.js +7 -0
  116. package/dist/material/Villager.js.map +1 -0
  117. package/dist/material/VpToken.d.ts +10 -0
  118. package/dist/material/VpToken.d.ts.map +1 -0
  119. package/dist/material/VpToken.js +9 -0
  120. package/dist/material/VpToken.js.map +1 -0
  121. package/dist/rules/ActivateCardRule.d.ts +43 -0
  122. package/dist/rules/ActivateCardRule.d.ts.map +1 -0
  123. package/dist/rules/ActivateCardRule.js +183 -0
  124. package/dist/rules/ActivateCardRule.js.map +1 -0
  125. package/dist/rules/AutumnRule.d.ts +9 -0
  126. package/dist/rules/AutumnRule.d.ts.map +1 -0
  127. package/dist/rules/AutumnRule.js +42 -0
  128. package/dist/rules/AutumnRule.js.map +1 -0
  129. package/dist/rules/BonusTokenRule.d.ts +10 -0
  130. package/dist/rules/BonusTokenRule.d.ts.map +1 -0
  131. package/dist/rules/BonusTokenRule.js +20 -0
  132. package/dist/rules/BonusTokenRule.js.map +1 -0
  133. package/dist/rules/ChooseOutcomeRule.d.ts +9 -0
  134. package/dist/rules/ChooseOutcomeRule.d.ts.map +1 -0
  135. package/dist/rules/ChooseOutcomeRule.js +18 -0
  136. package/dist/rules/ChooseOutcomeRule.js.map +1 -0
  137. package/dist/rules/ChooseSkillRule.d.ts +10 -0
  138. package/dist/rules/ChooseSkillRule.d.ts.map +1 -0
  139. package/dist/rules/ChooseSkillRule.js +20 -0
  140. package/dist/rules/ChooseSkillRule.js.map +1 -0
  141. package/dist/rules/CustomMoveType.d.ts +17 -0
  142. package/dist/rules/CustomMoveType.d.ts.map +1 -0
  143. package/dist/rules/CustomMoveType.js +18 -0
  144. package/dist/rules/CustomMoveType.js.map +1 -0
  145. package/dist/rules/DiscardItemRule.d.ts +9 -0
  146. package/dist/rules/DiscardItemRule.d.ts.map +1 -0
  147. package/dist/rules/DiscardItemRule.js +19 -0
  148. package/dist/rules/DiscardItemRule.js.map +1 -0
  149. package/dist/rules/EncounterRule.d.ts +26 -0
  150. package/dist/rules/EncounterRule.d.ts.map +1 -0
  151. package/dist/rules/EncounterRule.js +75 -0
  152. package/dist/rules/EncounterRule.js.map +1 -0
  153. package/dist/rules/EventRule.d.ts +13 -0
  154. package/dist/rules/EventRule.d.ts.map +1 -0
  155. package/dist/rules/EventRule.js +39 -0
  156. package/dist/rules/EventRule.js.map +1 -0
  157. package/dist/rules/FinalScoringRule.d.ts +18 -0
  158. package/dist/rules/FinalScoringRule.d.ts.map +1 -0
  159. package/dist/rules/FinalScoringRule.js +30 -0
  160. package/dist/rules/FinalScoringRule.js.map +1 -0
  161. package/dist/rules/GreyluneRule.d.ts +87 -0
  162. package/dist/rules/GreyluneRule.d.ts.map +1 -0
  163. package/dist/rules/GreyluneRule.js +432 -0
  164. package/dist/rules/GreyluneRule.js.map +1 -0
  165. package/dist/rules/PlaceVillagerRule.d.ts +10 -0
  166. package/dist/rules/PlaceVillagerRule.d.ts.map +1 -0
  167. package/dist/rules/PlaceVillagerRule.js +17 -0
  168. package/dist/rules/PlaceVillagerRule.js.map +1 -0
  169. package/dist/rules/ReactionRule.d.ts +17 -0
  170. package/dist/rules/ReactionRule.d.ts.map +1 -0
  171. package/dist/rules/ReactionRule.js +48 -0
  172. package/dist/rules/ReactionRule.js.map +1 -0
  173. package/dist/rules/ResolveEffectsRule.d.ts +12 -0
  174. package/dist/rules/ResolveEffectsRule.d.ts.map +1 -0
  175. package/dist/rules/ResolveEffectsRule.js +85 -0
  176. package/dist/rules/ResolveEffectsRule.js.map +1 -0
  177. package/dist/rules/ResolveEncounterRule.d.ts +19 -0
  178. package/dist/rules/ResolveEncounterRule.d.ts.map +1 -0
  179. package/dist/rules/ResolveEncounterRule.js +86 -0
  180. package/dist/rules/ResolveEncounterRule.js.map +1 -0
  181. package/dist/rules/ResolveQuestRule.d.ts +17 -0
  182. package/dist/rules/ResolveQuestRule.d.ts.map +1 -0
  183. package/dist/rules/ResolveQuestRule.js +64 -0
  184. package/dist/rules/ResolveQuestRule.js.map +1 -0
  185. package/dist/rules/RuleId.d.ts +27 -0
  186. package/dist/rules/RuleId.d.ts.map +1 -0
  187. package/dist/rules/RuleId.js +28 -0
  188. package/dist/rules/RuleId.js.map +1 -0
  189. package/dist/rules/SeasonRule.d.ts +11 -0
  190. package/dist/rules/SeasonRule.d.ts.map +1 -0
  191. package/dist/rules/SeasonRule.js +32 -0
  192. package/dist/rules/SeasonRule.js.map +1 -0
  193. package/dist/rules/SpecialActionRule.d.ts +15 -0
  194. package/dist/rules/SpecialActionRule.d.ts.map +1 -0
  195. package/dist/rules/SpecialActionRule.js +32 -0
  196. package/dist/rules/SpecialActionRule.js.map +1 -0
  197. package/dist/rules/SpringRule.d.ts +7 -0
  198. package/dist/rules/SpringRule.d.ts.map +1 -0
  199. package/dist/rules/SpringRule.js +16 -0
  200. package/dist/rules/SpringRule.js.map +1 -0
  201. package/dist/rules/StraightenCardRule.d.ts +9 -0
  202. package/dist/rules/StraightenCardRule.d.ts.map +1 -0
  203. package/dist/rules/StraightenCardRule.js +11 -0
  204. package/dist/rules/StraightenCardRule.js.map +1 -0
  205. package/dist/rules/SummerRule.d.ts +30 -0
  206. package/dist/rules/SummerRule.d.ts.map +1 -0
  207. package/dist/rules/SummerRule.js +140 -0
  208. package/dist/rules/SummerRule.js.map +1 -0
  209. package/dist/rules/TellStoryRule.d.ts +22 -0
  210. package/dist/rules/TellStoryRule.d.ts.map +1 -0
  211. package/dist/rules/TellStoryRule.js +72 -0
  212. package/dist/rules/TellStoryRule.js.map +1 -0
  213. package/dist/rules/TheFirstStepRule.d.ts +5 -0
  214. package/dist/rules/TheFirstStepRule.d.ts.map +1 -0
  215. package/dist/rules/TheFirstStepRule.js +7 -0
  216. package/dist/rules/TheFirstStepRule.js.map +1 -0
  217. package/dist/rules/TravelRule.d.ts +13 -0
  218. package/dist/rules/TravelRule.d.ts.map +1 -0
  219. package/dist/rules/TravelRule.js +41 -0
  220. package/dist/rules/TravelRule.js.map +1 -0
  221. package/dist/rules/UseItemRule.d.ts +6 -0
  222. package/dist/rules/UseItemRule.d.ts.map +1 -0
  223. package/dist/rules/UseItemRule.js +35 -0
  224. package/dist/rules/UseItemRule.js.map +1 -0
  225. package/dist/rules/WinterRule.d.ts +24 -0
  226. package/dist/rules/WinterRule.d.ts.map +1 -0
  227. package/dist/rules/WinterRule.js +112 -0
  228. package/dist/rules/WinterRule.js.map +1 -0
  229. package/package.json +39 -0
@@ -0,0 +1,39 @@
1
+ import { isCustomMoveType, isMoveItemType } from '@gamepark/rules-api';
2
+ import { eventTileData, isFestival } from '../material/EventTile';
3
+ import { LocationType } from '../material/LocationType';
4
+ import { MaterialType } from '../material/MaterialType';
5
+ import { CustomMoveType } from './CustomMoveType';
6
+ import { GreyluneRule } from './GreyluneRule';
7
+ export class EventRule extends GreyluneRule {
8
+ get newcomer() {
9
+ return this.myVillagers.location((location) => location.type === LocationType.EventSpace && location.x === undefined);
10
+ }
11
+ onRuleStart() {
12
+ const moves = this.getPlayerMoves();
13
+ if (moves.length > 1)
14
+ return [];
15
+ return moves.length ? moves : this.endOfAction();
16
+ }
17
+ getPlayerMoves() {
18
+ const tile = this.eventTile;
19
+ if (tile === undefined || !this.newcomer.length)
20
+ return [];
21
+ return this.eventOptions.map((option) => isFestival(tile) ? this.newcomer.moveItem({ ...this.eventSpace, x: option }) : this.customMove(CustomMoveType.TakeEventOption, option));
22
+ }
23
+ afterItemMove(move) {
24
+ if (!isMoveItemType(MaterialType.Villager)(move) || move.location.type !== LocationType.EventSpace)
25
+ return [];
26
+ return move.location.x === undefined ? [] : this.takeOption(move.location.x);
27
+ }
28
+ onCustomMove(move) {
29
+ if (isCustomMoveType(CustomMoveType.TakeEventOption)(move))
30
+ return this.takeOption(move.data);
31
+ return super.onCustomMove(move);
32
+ }
33
+ takeOption(option) {
34
+ const ability = eventTileData[this.eventTile].abilities[option];
35
+ this.pushGains(ability.gains ?? []);
36
+ return [...this.payRequirements(ability.requirements), ...this.endOfAction()];
37
+ }
38
+ }
39
+ //# sourceMappingURL=EventRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventRule.js","sourceRoot":"","sources":["../../src/rules/EventRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,gBAAgB,EAAE,cAAc,EAAY,MAAM,qBAAqB,CAAA;AAC5F,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAkC,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAe7E,MAAM,OAAO,SAAU,SAAQ,YAAY;IAEzC,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC,KAAK,SAAS,CAAC,CAAA;IACvH,CAAC;IAED,WAAW;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QACnC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,CAAA;QAE/B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAA;IAClD,CAAC;IAED,cAAc;QACZ,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAA;QAI3B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,EAAE,CAAA;QAC1D,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACtC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,eAAe,EAAE,MAAM,CAAC,CACvI,CAAA;IACH,CAAC;IAGD,aAAa,CAAC,IAAkD;QAC9D,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,CAAC,UAAU;YAAE,OAAO,EAAE,CAAA;QAC7G,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAC9E,CAAC;IAGD,YAAY,CAAC,IAAgB;QAC3B,IAAI,gBAAgB,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAc,CAAC,CAAA;QACvG,OAAO,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAEO,UAAU,CAAC,MAAc;QAC/B,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,SAAU,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QAChE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;QACnC,OAAO,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IAC/E,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import { MaterialRulesPart } from '@gamepark/rules-api';
2
+ import { LocationType } from '../material/LocationType';
3
+ import { MaterialSource } from '../material/MaterialSource';
4
+ import { MaterialType } from '../material/MaterialType';
5
+ import { PlayerColor } from '../PlayerColor';
6
+ import { GreyluneMove } from './GreyluneRule';
7
+ import { RuleId } from './RuleId';
8
+ type Count = {
9
+ rule: RuleId;
10
+ score: (source: MaterialSource, player: PlayerColor) => number;
11
+ };
12
+ export declare const finalScoring: Count[];
13
+ export declare class FinalScoringRule extends MaterialRulesPart<PlayerColor, MaterialType, LocationType, RuleId> {
14
+ onRuleStart(): GreyluneMove[];
15
+ }
16
+ export declare const scoreStillToCount: (source: MaterialSource, player: PlayerColor, rule?: RuleId) => number;
17
+ export {};
18
+ //# sourceMappingURL=FinalScoringRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FinalScoringRule.d.ts","sourceRoot":"","sources":["../../src/rules/FinalScoringRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAc,MAAM,gBAAgB,CAAA;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC,KAAK,KAAK,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,KAAK,MAAM,CAAA;CAAE,CAAA;AAG7F,eAAO,MAAM,YAAY,EAAE,KAAK,EAK/B,CAAA;AAUD,qBAAa,gBAAiB,SAAQ,iBAAiB,CAAC,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,CAAC;IACtG,WAAW,IAAI,YAAY,EAAE,CAU5B;CACF;AAQD,eAAO,MAAM,iBAAiB,WAAY,cAAc,UAAU,WAAW,SAAS,MAAM,KAAG,MAI9F,CAAA"}
@@ -0,0 +1,30 @@
1
+ import { MaterialRulesPart } from '@gamepark/rules-api';
2
+ import { companionsScore, itemsScore, playerVp, questScore, skillScore } from '../material/PlayerState';
3
+ import { scoreMoves } from './GreyluneRule';
4
+ import { RuleId } from './RuleId';
5
+ export const finalScoring = [
6
+ { rule: RuleId.QuestsScoring, score: questScore },
7
+ { rule: RuleId.CompanionsScoring, score: companionsScore },
8
+ { rule: RuleId.ItemsScoring, score: itemsScore },
9
+ { rule: RuleId.SkillsScoring, score: skillScore }
10
+ ];
11
+ export class FinalScoringRule extends MaterialRulesPart {
12
+ onRuleStart() {
13
+ const step = finalScoring.findIndex(({ rule }) => rule === this.game.rule?.id);
14
+ const next = finalScoring[step + 1];
15
+ return [
16
+ ...this.game.players.flatMap((player) => {
17
+ const points = finalScoring[step].score(this, player);
18
+ return points ? scoreMoves(this, player, playerVp(this, player) + points) : [];
19
+ }),
20
+ next ? this.startRule(next.rule) : this.endGame()
21
+ ];
22
+ }
23
+ }
24
+ export const scoreStillToCount = (source, player, rule) => {
25
+ if (rule === undefined)
26
+ return 0;
27
+ const step = Math.max(0, finalScoring.findIndex((count) => count.rule === rule));
28
+ return finalScoring.slice(step).reduce((total, { score }) => total + score(source, player), 0);
29
+ };
30
+ //# sourceMappingURL=FinalScoringRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FinalScoringRule.js","sourceRoot":"","sources":["../../src/rules/FinalScoringRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAIvD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEvG,OAAO,EAAgB,UAAU,EAAE,MAAM,gBAAgB,CAAA;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAKjC,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,EAAE,IAAI,EAAE,MAAM,CAAC,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE;IACjD,EAAE,IAAI,EAAE,MAAM,CAAC,iBAAiB,EAAE,KAAK,EAAE,eAAe,EAAE;IAC1D,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE;IAChD,EAAE,IAAI,EAAE,MAAM,CAAC,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE;CAClD,CAAA;AAUD,MAAM,OAAO,gBAAiB,SAAQ,iBAAkE;IACtG,WAAW;QACT,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAC9E,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QACnC,OAAO;YACL,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;gBACtC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;gBACrD,OAAO,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;YAChF,CAAC,CAAC;YACF,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE;SAClD,CAAA;IACH,CAAC;CACF;AAQD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAsB,EAAE,MAAmB,EAAE,IAAa,EAAU,EAAE;IACtG,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,CAAA;IAChC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAA;IAChF,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;AAChG,CAAC,CAAA"}
@@ -0,0 +1,87 @@
1
+ import { CustomMove, Location, Material, MaterialMove, PlayerTurnRule } from '@gamepark/rules-api';
2
+ import { PlayerColor } from '../PlayerColor';
3
+ import { Count, Gain, Requirement } from '../material/Effect';
4
+ import { EventTile } from '../material/EventTile';
5
+ import { LocationType } from '../material/LocationType';
6
+ import { MaterialType } from '../material/MaterialType';
7
+ import { MaterialSource } from '../material/MaterialSource';
8
+ import { ReactionEffect, TriggerType } from '../material/Reaction';
9
+ import { VillageCard } from '../material/VillageCard';
10
+ import { Season } from '../Season';
11
+ import { RuleId } from './RuleId';
12
+ export type GreyluneMove = MaterialMove<PlayerColor, MaterialType, LocationType, RuleId>;
13
+ export type GreyluneMaterial = Material<PlayerColor, MaterialType, LocationType>;
14
+ export type SkillMarker = MaterialType.StrengthMarker | MaterialType.MagicMarker;
15
+ export type CostReduction = {
16
+ force?: number;
17
+ villagers?: number;
18
+ coins?: number;
19
+ noSurcharge?: boolean;
20
+ itemVp?: number;
21
+ freeSealValue?: boolean;
22
+ };
23
+ export type ReactionChoice = {
24
+ card: number;
25
+ option: number;
26
+ };
27
+ export declare abstract class GreyluneRule extends PlayerTurnRule<PlayerColor, MaterialType, LocationType, RuleId> {
28
+ get villageCards(): GreyluneMaterial;
29
+ get encounterCards(): GreyluneMaterial;
30
+ get villagers(): GreyluneMaterial;
31
+ get myVillagers(): GreyluneMaterial;
32
+ get activeVillagers(): GreyluneMaterial;
33
+ get adventurer(): GreyluneMaterial;
34
+ playerCard(index: number): VillageCard;
35
+ get coins(): number;
36
+ get force(): number;
37
+ get magic(): number;
38
+ get season(): Season;
39
+ get hasStoryToTell(): boolean;
40
+ canReceive(gains?: Gain[]): boolean;
41
+ get temporaryForce(): number;
42
+ get temporaryMagic(): number;
43
+ get tileOfTheYear(): GreyluneMaterial;
44
+ get eventTile(): EventTile | undefined;
45
+ get eventSpace(): Location<PlayerColor, LocationType>;
46
+ get hasUsedEvent(): boolean;
47
+ get eventOptions(): number[];
48
+ get gains(): Gain[];
49
+ pushGains(gains: Gain[], first?: boolean): void;
50
+ endOfAction(): GreyluneMove[];
51
+ amount(count: Count): number;
52
+ gainMove(gain: Gain): GreyluneMove | undefined;
53
+ onCustomMove(move: CustomMove): GreyluneMove[];
54
+ private get money();
55
+ gainCoins(amount: number): GreyluneMove[];
56
+ payCoins(amount: number): GreyluneMove[];
57
+ gainVp(amount: number): GreyluneMove[];
58
+ gainSkill(marker: SkillMarker, amount: number): GreyluneMove[];
59
+ moveSkillMarker(marker: SkillMarker, amount: number): GreyluneMove[];
60
+ skillGained(marker: SkillMarker, amount: number): GreyluneMove[];
61
+ gainVillagers(amount: number): GreyluneMove[];
62
+ canPay(requirements?: Requirement[], reduction?: CostReduction): boolean;
63
+ private canPayOne;
64
+ payRequirements(requirements?: Requirement[]): GreyluneMove[];
65
+ coinCost(requirements?: Requirement[]): number;
66
+ private payOne;
67
+ spendVillagers(amount: number): GreyluneMove[];
68
+ get costReduction(): CostReduction;
69
+ reduceCost(reduction: CostReduction): void;
70
+ reactionChoices(triggers: TriggerType[]): ReactionChoice[];
71
+ private canReact;
72
+ get playerCards(): GreyluneMaterial;
73
+ potentialReduction(triggers: TriggerType[]): CostReduction;
74
+ resume(triggers?: TriggerType[]): GreyluneMove[];
75
+ openReactions(triggers: TriggerType[], next: RuleId): GreyluneMove[];
76
+ reactionEffect(card: number, option: number): ReactionEffect;
77
+ useReaction(card: number, option: number): GreyluneMove[];
78
+ private payReactionCost;
79
+ private applyReaction;
80
+ nextActivePlayer(): PlayerColor | undefined;
81
+ seasonRule(player: PlayerColor): RuleId;
82
+ endOfTurn(): GreyluneMove[];
83
+ forgetAction(): void;
84
+ }
85
+ export declare const vpTokenFor: (total: number) => number;
86
+ export declare const scoreMoves: (source: MaterialSource, player: PlayerColor, total: number) => GreyluneMove[];
87
+ //# sourceMappingURL=GreyluneRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GreyluneRule.d.ts","sourceRoot":"","sources":["../../src/rules/GreyluneRule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,432 @@
1
+ import { getEnumValues, isCustomMoveType, PlayerTurnRule } from '@gamepark/rules-api';
2
+ import { BONUS_TOKEN_SCORES, MAX_SKILL, SCORE_TRACK_SIZE } from '../Constants';
3
+ import { Memory } from '../Memory';
4
+ import { bonusToken, GainType, gathered, placeVillager, RequirementType, SEAL } from '../material/Effect';
5
+ import { encounterCardData } from '../material/EncounterCard';
6
+ import { eventTileData, isFestival } from '../material/EventTile';
7
+ import { LocationType } from '../material/LocationType';
8
+ import { MaterialType } from '../material/MaterialType';
9
+ import { activeVillagers, keepsPotions, playerCoins, playerForce, playerMagic, playerSeason, playerVp, scoreValue, vpTokenTotal } from '../material/PlayerState';
10
+ import { ReactionType, TriggerType } from '../material/Reaction';
11
+ import { coinUnits } from '../material/Tokens';
12
+ import { getVillagerPlayer } from '../material/Villager';
13
+ import { isPotion, villageCardData } from '../material/VillageCard';
14
+ import { getVpToken, getVpTokenValue, VpTokenValue } from '../material/VpToken';
15
+ import { Season } from '../Season';
16
+ import { isLastYear } from '../Year';
17
+ import { CustomMoveType } from './CustomMoveType';
18
+ import { RuleId } from './RuleId';
19
+ export class GreyluneRule extends PlayerTurnRule {
20
+ get villageCards() {
21
+ return this.material(MaterialType.VillageCard);
22
+ }
23
+ get encounterCards() {
24
+ return this.material(MaterialType.EncounterCard);
25
+ }
26
+ get villagers() {
27
+ return this.material(MaterialType.Villager);
28
+ }
29
+ get myVillagers() {
30
+ return this.villagers.id((villager) => getVillagerPlayer(villager) === this.player);
31
+ }
32
+ get activeVillagers() {
33
+ return activeVillagers(this, this.player);
34
+ }
35
+ get adventurer() {
36
+ return this.material(MaterialType.Adventurer).id(this.player);
37
+ }
38
+ playerCard(index) {
39
+ return this.villageCards.getItem(index).id.front;
40
+ }
41
+ get coins() {
42
+ return playerCoins(this, this.player);
43
+ }
44
+ get force() {
45
+ return playerForce(this, this.player);
46
+ }
47
+ get magic() {
48
+ return playerMagic(this, this.player);
49
+ }
50
+ get season() {
51
+ return playerSeason(this, this.player);
52
+ }
53
+ get hasStoryToTell() {
54
+ const untold = this.encounterCards.location(LocationType.UntoldStories).player(this.player);
55
+ if (untold.filter((item) => encounterCardData[item.id.front].story > 0).length)
56
+ return true;
57
+ return (untold.length > 0 &&
58
+ this.reactionChoices([TriggerType.TellStory]).some(({ card, option }) => this.reactionEffect(card, option).type === ReactionType.StoryValue3));
59
+ }
60
+ canReceive(gains = []) {
61
+ return !gains.some((gain) => gain.type === GainType.TellStory) || this.hasStoryToTell;
62
+ }
63
+ get temporaryForce() {
64
+ return this.remind(Memory.TemporaryForce) ?? 0;
65
+ }
66
+ get temporaryMagic() {
67
+ return this.remind(Memory.TemporaryMagic) ?? 0;
68
+ }
69
+ get tileOfTheYear() {
70
+ return this.material(MaterialType.EventTile).location(LocationType.EventPile).rotation(true);
71
+ }
72
+ get eventTile() {
73
+ return this.tileOfTheYear.getItem()?.id;
74
+ }
75
+ get eventSpace() {
76
+ return { type: LocationType.EventSpace, parent: this.tileOfTheYear.getIndex() };
77
+ }
78
+ get hasUsedEvent() {
79
+ return this.myVillagers.location(LocationType.EventSpace).length > 0;
80
+ }
81
+ get eventOptions() {
82
+ const tile = this.eventTile;
83
+ if (tile === undefined)
84
+ return [];
85
+ const taken = this.villagers.location(LocationType.EventSpace).getItems().map((item) => item.location.x);
86
+ return eventTileData[tile].abilities.flatMap((ability, option) => this.canPay(ability.requirements) && !(isFestival(tile) && taken.includes(option)) ? [option] : []);
87
+ }
88
+ get gains() {
89
+ return this.remind(Memory.Gains) ?? [];
90
+ }
91
+ pushGains(gains, first = false) {
92
+ if (gains.length)
93
+ this.memorize(Memory.Gains, first ? [...gains, ...this.gains] : [...this.gains, ...gains]);
94
+ }
95
+ endOfAction() {
96
+ return [this.startRule(RuleId.ResolveEffects)];
97
+ }
98
+ amount(count) {
99
+ return count === SEAL ? (this.remind(Memory.SealValue) ?? 0) : count;
100
+ }
101
+ gainMove(gain) {
102
+ switch (gain.type) {
103
+ case GainType.Coins:
104
+ return this.customMove(CustomMoveType.GainCoins, this.amount(gain.count));
105
+ case GainType.Vp:
106
+ return this.customMove(CustomMoveType.GainVp, this.amount(gain.count));
107
+ case GainType.Score:
108
+ return this.customMove(CustomMoveType.GainVp, scoreValue(this, this.player, gain.score));
109
+ default:
110
+ return undefined;
111
+ }
112
+ }
113
+ onCustomMove(move) {
114
+ if (isCustomMoveType(CustomMoveType.GainCoins)(move))
115
+ return [...this.gainCoins(move.data), ...this.resume()];
116
+ if (isCustomMoveType(CustomMoveType.GainVp)(move))
117
+ return [...this.gainVp(move.data), ...this.resume()];
118
+ return [];
119
+ }
120
+ get money() {
121
+ return this.material(MaterialType.Coin).location(LocationType.PlayerCoins).player(this.player).money(coinUnits);
122
+ }
123
+ gainCoins(amount) {
124
+ return this.money.addMoney(amount, { type: LocationType.PlayerCoins, player: this.player });
125
+ }
126
+ payCoins(amount) {
127
+ return this.money.removeMoney(amount, { type: LocationType.PlayerCoins, player: this.player });
128
+ }
129
+ gainVp(amount) {
130
+ const total = playerVp(this, this.player) + amount;
131
+ const tokens = this.material(MaterialType.BonusToken).location(LocationType.BonusTokens).player(this.player).length;
132
+ if (total >= BONUS_TOKEN_SCORES[0] && tokens === 3)
133
+ this.pushGains([bonusToken], true);
134
+ if (total >= BONUS_TOKEN_SCORES[1] && tokens >= 2)
135
+ this.pushGains([bonusToken], true);
136
+ return scoreMoves(this, this.player, total);
137
+ }
138
+ gainSkill(marker, amount) {
139
+ const moves = this.moveSkillMarker(marker, amount);
140
+ return moves.length ? [...moves, ...this.skillGained(marker, amount)] : [];
141
+ }
142
+ moveSkillMarker(marker, amount) {
143
+ const markers = this.material(marker).player(this.player);
144
+ const { location } = markers.getItem();
145
+ const x = Math.min(MAX_SKILL, Math.max(0, (location.x ?? 0) + amount));
146
+ return x === location.x ? [] : [markers.moveItem({ ...location, x })];
147
+ }
148
+ skillGained(marker, amount) {
149
+ this.memorize(Memory.CurrentGain, { type: marker === MaterialType.StrengthMarker ? GainType.Force : GainType.Magic, count: amount });
150
+ return this.resume([TriggerType.GainSkill]);
151
+ }
152
+ gainVillagers(amount) {
153
+ return this.villagers.location(LocationType.VillagerReserve).player(this.player).limit(amount).moveItems({
154
+ type: LocationType.ActiveVillagers,
155
+ player: this.player
156
+ });
157
+ }
158
+ canPay(requirements = [], reduction = this.costReduction) {
159
+ return gathered(requirements).every((requirement) => this.canPayOne(requirement, reduction));
160
+ }
161
+ canPayOne(requirement, reduction = this.costReduction) {
162
+ const count = requirement.count ?? 1;
163
+ switch (requirement.type) {
164
+ case RequirementType.Force:
165
+ return this.force + this.temporaryForce >= count;
166
+ case RequirementType.Magic:
167
+ return this.magic + this.temporaryMagic >= count;
168
+ case RequirementType.Skills:
169
+ return this.force + this.temporaryForce + this.magic + this.temporaryMagic >= count;
170
+ case RequirementType.SpendCoins:
171
+ return this.coins >= Math.max(0, count - (reduction.coins ?? 0));
172
+ case RequirementType.SpendForce:
173
+ return this.force >= Math.max(0, count - (reduction.force ?? 0));
174
+ case RequirementType.SpendMagic:
175
+ return this.magic >= count;
176
+ case RequirementType.SpendVillagers:
177
+ return this.activeVillagers.length >= Math.max(0, count - (reduction.villagers ?? 0));
178
+ case RequirementType.ReturnVillager:
179
+ return this.activeVillagers.length >= count;
180
+ case RequirementType.DiscardItem:
181
+ return this.material(MaterialType.VillageCard).location(LocationType.Items).player(this.player).length >= 1;
182
+ case RequirementType.TellStories:
183
+ return this.encounterCards.location(LocationType.UntoldStories).player(this.player).length >= count;
184
+ default:
185
+ return true;
186
+ }
187
+ }
188
+ payRequirements(requirements = []) {
189
+ return gathered(requirements).flatMap((requirement) => this.payOne(requirement));
190
+ }
191
+ coinCost(requirements = []) {
192
+ const reduction = this.costReduction;
193
+ return requirements.reduce((total, requirement) => {
194
+ if (requirement.type === RequirementType.SpendCoins)
195
+ return total + Math.max(0, (requirement.count ?? 1) - (reduction.coins ?? 0));
196
+ if (requirement.type === RequirementType.SealCoins)
197
+ return total + (this.remind(Memory.SealValue) ?? 0);
198
+ return total;
199
+ }, 0);
200
+ }
201
+ payOne(requirement) {
202
+ const count = requirement.count ?? 1;
203
+ const reduction = this.costReduction;
204
+ switch (requirement.type) {
205
+ case RequirementType.SpendCoins:
206
+ case RequirementType.SealCoins:
207
+ return this.payCoins(this.coinCost([requirement]));
208
+ case RequirementType.SpendForce:
209
+ return this.moveSkillMarker(MaterialType.StrengthMarker, -Math.max(0, count - (reduction.force ?? 0)));
210
+ case RequirementType.SpendMagic:
211
+ return this.moveSkillMarker(MaterialType.MagicMarker, -count);
212
+ case RequirementType.SpendVillagers:
213
+ return this.spendVillagers(Math.max(0, count - (reduction.villagers ?? 0)));
214
+ case RequirementType.ReturnVillager:
215
+ return this.activeVillagers.limit(count).moveItems({ type: LocationType.VillagerReserve, player: this.player });
216
+ default:
217
+ return [];
218
+ }
219
+ }
220
+ spendVillagers(amount) {
221
+ if (amount <= 0)
222
+ return [];
223
+ return this.activeVillagers.limit(amount).moveItems({ type: LocationType.Camp });
224
+ }
225
+ get costReduction() {
226
+ return this.remind(Memory.CostReduction) ?? {};
227
+ }
228
+ reduceCost(reduction) {
229
+ this.memorize(Memory.CostReduction, { ...this.costReduction, ...reduction });
230
+ }
231
+ reactionChoices(triggers) {
232
+ const choices = [];
233
+ for (const card of this.playerCards.getIndexes()) {
234
+ const reaction = villageCardData[this.playerCard(card)].reaction;
235
+ if (!reaction || !reaction.triggers.some((trigger) => triggers.includes(trigger)))
236
+ continue;
237
+ if (!this.canReact(card, reaction))
238
+ continue;
239
+ reaction.options.forEach((effect, option) => {
240
+ if (effect.trigger === undefined || triggers.includes(effect.trigger))
241
+ choices.push({ card, option });
242
+ });
243
+ }
244
+ return choices;
245
+ }
246
+ canReact(card, reaction) {
247
+ const item = this.villageCards.getItem(card);
248
+ for (const requirement of reaction.requirements) {
249
+ if (requirement.type === RequirementType.Tilt && item.location.rotation === true)
250
+ return false;
251
+ if (requirement.type === RequirementType.DiscardCard && item.location.rotation === true)
252
+ return false;
253
+ if (!this.canPayOne(requirement))
254
+ return false;
255
+ }
256
+ return !(reaction.triggers.includes(TriggerType.TiltCard) && this.remind(Memory.LastTilted) === card);
257
+ }
258
+ get playerCards() {
259
+ return this.villageCards.player(this.player).location((location) => location.type === LocationType.Items || location.type === LocationType.Companions);
260
+ }
261
+ potentialReduction(triggers) {
262
+ const reduction = { ...this.costReduction };
263
+ for (const card of new Set(this.reactionChoices(triggers).map((choice) => choice.card))) {
264
+ for (const option of villageCardData[this.playerCard(card)].reaction.options) {
265
+ switch (option.type) {
266
+ case ReactionType.ReduceForceCost:
267
+ reduction.force = (reduction.force ?? 0) + 1;
268
+ break;
269
+ case ReactionType.ReduceVillagerCost:
270
+ reduction.villagers = (reduction.villagers ?? 0) + 1;
271
+ break;
272
+ case ReactionType.CheaperItem:
273
+ reduction.coins = (reduction.coins ?? 0) + 1;
274
+ break;
275
+ case ReactionType.ChooseSealValue:
276
+ reduction.freeSealValue = true;
277
+ break;
278
+ }
279
+ }
280
+ }
281
+ return reduction;
282
+ }
283
+ resume(triggers = []) {
284
+ return this.openReactions(triggers, RuleId.ResolveEffects);
285
+ }
286
+ openReactions(triggers, next) {
287
+ if (!triggers.length || !this.reactionChoices(triggers).length)
288
+ return [this.startRule(next)];
289
+ this.memorize(Memory.Trigger, triggers);
290
+ this.memorize(Memory.Resume, next);
291
+ return [this.startRule(RuleId.Reaction)];
292
+ }
293
+ reactionEffect(card, option) {
294
+ return villageCardData[this.playerCard(card)].reaction.options[option];
295
+ }
296
+ useReaction(card, option) {
297
+ const tiltedBefore = this.remind(Memory.LastTilted);
298
+ return [...this.payReactionCost(card), ...this.applyReaction(card, option, tiltedBefore)];
299
+ }
300
+ payReactionCost(card) {
301
+ const front = this.playerCard(card);
302
+ const reaction = villageCardData[front].reaction;
303
+ const moves = [];
304
+ let tilted = false;
305
+ for (const requirement of reaction.requirements) {
306
+ switch (requirement.type) {
307
+ case RequirementType.Tilt:
308
+ moves.push(this.villageCards.index(card).rotateItem(true));
309
+ tilted = true;
310
+ break;
311
+ case RequirementType.DiscardCard:
312
+ if (isPotion(front) && keepsPotions(this, this.player)) {
313
+ moves.push(this.villageCards.index(card).rotateItem(true));
314
+ tilted = true;
315
+ }
316
+ else {
317
+ moves.push(this.villageCards.index(card).deleteItem());
318
+ }
319
+ break;
320
+ default:
321
+ moves.push(...this.payRequirements([requirement]));
322
+ }
323
+ }
324
+ if (tilted) {
325
+ this.memorize(Memory.LastTilted, card);
326
+ const triggers = this.remind(Memory.Trigger) ?? [];
327
+ if (!triggers.includes(TriggerType.TiltCard))
328
+ this.memorize(Memory.Trigger, [...triggers, TriggerType.TiltCard]);
329
+ }
330
+ return moves;
331
+ }
332
+ applyReaction(card, option, tiltedBefore) {
333
+ const effect = this.reactionEffect(card, option);
334
+ switch (effect.type) {
335
+ case ReactionType.ExtraTravel:
336
+ this.memorize(Memory.TravelDistance, (this.remind(Memory.TravelDistance) ?? 0) + effect.count);
337
+ return [];
338
+ case ReactionType.PlaceVillager:
339
+ this.pushGains([placeVillager], true);
340
+ return [];
341
+ case ReactionType.TemporarySkills:
342
+ if (effect.force)
343
+ this.memorize(Memory.TemporaryForce, this.temporaryForce + effect.force);
344
+ if (effect.magic)
345
+ this.memorize(Memory.TemporaryMagic, this.temporaryMagic + effect.magic);
346
+ return [];
347
+ case ReactionType.IgnoreCondition:
348
+ this.memorize(Memory.IgnoredConditions, (this.remind(Memory.IgnoredConditions) ?? 0) + 1);
349
+ return [];
350
+ case ReactionType.StoryValue3:
351
+ this.memorize(Memory.StoryBoost, (this.remind(Memory.StoryBoost) ?? 0) + 1);
352
+ return [];
353
+ case ReactionType.ReduceForceCost:
354
+ this.reduceCost({ force: (this.costReduction.force ?? 0) + 1 });
355
+ return [];
356
+ case ReactionType.ReduceVillagerCost:
357
+ this.reduceCost({ villagers: (this.costReduction.villagers ?? 0) + 1 });
358
+ return [];
359
+ case ReactionType.CheaperItem:
360
+ this.reduceCost({ coins: (this.costReduction.coins ?? 0) + 1, itemVp: (this.costReduction.itemVp ?? 0) + 1 });
361
+ return [];
362
+ case ReactionType.ExtraCoins:
363
+ return this.gainCoins(effect.count);
364
+ case ReactionType.NoSurcharge:
365
+ this.reduceCost({ noSurcharge: true });
366
+ return [];
367
+ case ReactionType.ChooseSealValue:
368
+ this.reduceCost({ freeSealValue: true });
369
+ return [];
370
+ case ReactionType.OtherSkill: {
371
+ const gain = this.remind(Memory.CurrentGain);
372
+ this.pushGains([{ type: gain?.type === GainType.Force ? GainType.Magic : GainType.Force, count: 1 }], true);
373
+ return [];
374
+ }
375
+ case ReactionType.StraightenTilted:
376
+ return tiltedBefore === undefined ? [] : [this.villageCards.index(tiltedBefore).rotateItem(false)];
377
+ }
378
+ }
379
+ nextActivePlayer() {
380
+ const players = this.game.players;
381
+ const start = players.indexOf(this.player);
382
+ for (let step = 1; step <= players.length; step++) {
383
+ const player = players[(start + step) % players.length];
384
+ if (playerSeason(this, player) !== Season.Autumn)
385
+ return player;
386
+ }
387
+ return undefined;
388
+ }
389
+ seasonRule(player) {
390
+ return playerSeason(this, player) === Season.Spring ? RuleId.Spring : RuleId.Summer;
391
+ }
392
+ endOfTurn() {
393
+ this.forgetAction();
394
+ const next = this.nextActivePlayer();
395
+ if (next !== undefined)
396
+ return [this.startPlayerTurn(this.seasonRule(next), next)];
397
+ return [this.startRule(isLastYear(this) ? RuleId.QuestsScoring : RuleId.Winter)];
398
+ }
399
+ forgetAction() {
400
+ for (const key of getEnumValues(Memory))
401
+ this.forget(key);
402
+ }
403
+ }
404
+ export const vpTokenFor = (total) => Math.min(100, Math.floor(total / SCORE_TRACK_SIZE) * SCORE_TRACK_SIZE);
405
+ export const scoreMoves = (source, player, total) => [
406
+ ...vpTokenMoves(source, player, total),
407
+ ...scoreMarkerMoves(source, player, total)
408
+ ];
409
+ const scoreMarkerMoves = (source, player, total) => {
410
+ const marker = source.material(MaterialType.ScoreMarker).id(player);
411
+ const x = total - vpTokenFor(total);
412
+ return marker.getItem()?.location.x === x ? [] : [marker.moveItem({ type: LocationType.ScoreTrack, x })];
413
+ };
414
+ const vpTokenMoves = (source, player, total) => {
415
+ const value = vpTokenFor(total);
416
+ const tokens = source.material(MaterialType.VpToken);
417
+ const held = tokens.location(LocationType.PlayerVpTokens).player(player).getItem();
418
+ const heldValue = held ? vpTokenTotal(held.id, held.location.rotation === true) : 0;
419
+ if (value === heldValue)
420
+ return [];
421
+ const moves = [];
422
+ const wanted = value >= 75 ? VpTokenValue.Vp75 : VpTokenValue.Vp25;
423
+ if (held && getVpTokenValue(held.id) !== wanted) {
424
+ moves.push(tokens.location(LocationType.PlayerVpTokens).player(player).deleteItem());
425
+ }
426
+ if (value === 0)
427
+ return moves;
428
+ const flipped = value === 50 || value === 100;
429
+ moves.push(tokens.id(getVpToken(player, wanted)).moveItem({ type: LocationType.PlayerVpTokens, player, rotation: flipped }));
430
+ return moves;
431
+ };
432
+ //# sourceMappingURL=GreyluneRule.js.map