Feast 2.0!
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

391 lignes
9.2 KiB

  1. <template>
  2. <div class="combat-layout">
  3. <div @wheel="horizWheelLeft" class="stat-column" id="left-stats">
  4. <Statblock @selectAlly="right = combatant" @select="left = combatant" class="left-stats" :data-active="combatant === left" :data-active-ally="combatant === right" v-for="(combatant, index) in combatants.filter(c => c.side == Side.Heroes && !c.digested).slice().reverse()" v-bind:key="'left-stat-' + index" :subject="combatant" />
  5. </div>
  6. <div @wheel="horizWheelRight" class="stat-column" id="right-stats">
  7. <Statblock @selectAlly="left = combatant" @select="right = combatant" class="right-stats" :data-active="combatant === right" :data-active-ally="combatant === left" v-for="(combatant, index) in combatants.filter(c => c.side == Side.Monsters && !c.digested)" v-bind:key="'right-stat-' + index" :subject="combatant" />
  8. </div>
  9. <div id="log">
  10. </div>
  11. <div class="left-fader">
  12. </div>
  13. <div class="left-actions">
  14. <div class="vert-display">
  15. <i class="action-label fas fa-users" v-if="left.validGroupActions(combatants).length > 0"></i>
  16. <ActionButton @described="described" @executed="executedLeft" v-for="action in left.validGroupActions(combatants)" :key="'right' + action.name" :action="action" :user="left" :target="right" :combatants="combatants" />
  17. <i class="action-label fas fa-user-friends" v-if="left.validActions(right).length > 0"></i>
  18. <ActionButton @described="described" @executed="executedLeft" v-for="action in left.validActions(right)" :key="'left' + action.name" :action="action" :user="left" :target="right" :combatants="combatants" />
  19. <i class="action-label fas fa-user" v-if="left.validActions(left).length > 0"></i>
  20. <ActionButton @described="described" @executed="executedLeft" v-for="action in left.validActions(left)" :key="'left' + action.name" :action="action" :user="left" :target="left" :combatants="combatants" />
  21. </div>
  22. <div>{{actionDescription}}</div>
  23. </div>
  24. <div class="right-fader">
  25. </div>
  26. <div class="right-actions">
  27. <div class="vert-display">
  28. <i class="action-label fas fa-users" v-if="right.validGroupActions(combatants).length > 0"></i>
  29. <ActionButton @described="described" @executed="executedRight" v-for="action in right.validGroupActions(combatants)" :key="'right' + action.name" :action="action" :user="right" :target="left" :combatants="combatants" />
  30. <i class="action-label fas fa-user-friends" v-if="right.validActions(left).length > 0"></i>
  31. <ActionButton @described="described" @executed="executedRight" v-for="action in right.validActions(left)" :key="'right' + action.name" :action="action" :user="right" :target="left" :combatants="combatants" />
  32. <i class="action-label fas fa-user" v-if="right.validActions(right).length > 0"></i>
  33. <ActionButton @described="described" @executed="executedRight" v-for="action in right.validActions(right)" :key="'right' + action.name" :action="action" :user="right" :target="right" :combatants="combatants" />
  34. </div>
  35. </div>
  36. <div id="action-desc">
  37. </div>
  38. </div>
  39. </template>
  40. <script lang="ts">
  41. import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator'
  42. import { Creature, POV } from '@/game/entity'
  43. import { LogEntry } from '@/game/interface'
  44. import Statblock from './Statblock.vue'
  45. import ActionButton from './ActionButton.vue'
  46. import { Side } from '@/game/combat'
  47. @Component(
  48. {
  49. components: { Statblock, ActionButton },
  50. methods: {
  51. horizWheelLeft (event: MouseWheelEvent) {
  52. const target = this.$el.querySelector("#left-stats")
  53. console.log(target)
  54. if (target !== null) {
  55. target.scrollBy({ top: 0, left: event.deltaY, behavior: 'smooth' })
  56. }
  57. },
  58. horizWheelRight (event: MouseWheelEvent) {
  59. const target = this.$el.querySelector("#right-stats")
  60. console.log(target)
  61. if (target !== null) {
  62. target.scrollBy({ top: 0, left: -event.deltaY, behavior: 'smooth' })
  63. }
  64. }
  65. }
  66. }
  67. )
  68. export default class Combat extends Vue {
  69. @Prop({ type: Creature, required: true })
  70. left!: Creature
  71. @Prop({ type: Creature, required: true })
  72. right!: Creature
  73. @Prop()
  74. combatants!: Array<Creature>
  75. Side = Side
  76. actionDescription = ''
  77. mounted () {
  78. const left = this.$el.querySelector("#left-stats")
  79. if (left !== null) {
  80. left.scrollTo(left.getBoundingClientRect().width * 2, 0)
  81. }
  82. }
  83. @Emit("executedLeft")
  84. executedLeft (entry: LogEntry) {
  85. const log = document.querySelector("#log")
  86. if (log !== null) {
  87. const holder = document.createElement("div")
  88. entry.render().forEach(element => {
  89. holder.appendChild(element)
  90. })
  91. holder.classList.add("left-move")
  92. log.appendChild(holder)
  93. log.scrollTo({ top: log.scrollHeight, left: 0 })
  94. }
  95. }
  96. @Emit("executedRight")
  97. executedRight (entry: LogEntry) {
  98. const log = document.querySelector("#log")
  99. if (log !== null) {
  100. const holder = document.createElement("div")
  101. entry.render().forEach(element => {
  102. holder.appendChild(element)
  103. })
  104. holder.classList.add("right-move")
  105. log.appendChild(holder)
  106. log.scrollTo({ top: log.scrollHeight, left: 0 })
  107. }
  108. }
  109. @Emit("described")
  110. described (entry: LogEntry) {
  111. const actionDesc = document.querySelector("#action-desc")
  112. if (actionDesc !== null) {
  113. const holder = document.createElement("div")
  114. entry.render().forEach(element => {
  115. holder.appendChild(element)
  116. })
  117. actionDesc.innerHTML = ''
  118. actionDesc.appendChild(holder)
  119. }
  120. }
  121. }
  122. </script>
  123. <!-- Add "scoped" attribute to limit CSS to this component only -->
  124. <style scoped>
  125. .combat-layout {
  126. display: grid;
  127. grid-template-rows: fit-content(40%) 10% [main-row-start] 1fr 20% [main-row-end] ;
  128. grid-template-columns: 20% [main-col-start] 1fr 1fr [main-col-end] 20%;
  129. width: 100%;
  130. height: 100%;
  131. flex: 10;
  132. overflow: hidden;
  133. }
  134. #log {
  135. grid-area: main-row-start / main-col-start / main-row-end / main-col-end;
  136. overflow-y: scroll;
  137. font-size: 12pt;
  138. width: 100%;
  139. max-height: 100%;
  140. align-self: flex-start;
  141. }
  142. #left-stats,
  143. #right-stats {
  144. display: flex;
  145. }
  146. #left-stats {
  147. flex-direction: row;
  148. }
  149. #right-stats {
  150. flex-direction: row;
  151. }
  152. #left-stats {
  153. grid-area: 1 / 1 / 2 / 3
  154. }
  155. #right-stats {
  156. grid-area: 1 / 3 / 2 / 5;
  157. }
  158. .stat-column {
  159. overflow-x: scroll;
  160. overflow-y: auto;
  161. }
  162. .left-fader {
  163. grid-area: 2 / 1 / 4 / 2;
  164. }
  165. .right-fader {
  166. grid-area: 2 / 4 / 4 / 5;
  167. }
  168. .left-fader,
  169. .right-fader {
  170. z-index: 1;
  171. pointer-events: none;
  172. background: linear-gradient(to bottom, #111, #00000000 10%, #00000000 90%, #111 100%);
  173. height: 100%;
  174. width: 100%;
  175. }
  176. .left-actions {
  177. grid-area: 2 / 1 / 4 / 2;
  178. }
  179. .right-actions {
  180. grid-area: 2 / 4 / 4 / 5;
  181. }
  182. .left-actions,
  183. .right-actions {
  184. overflow-y: hidden;
  185. display: flex;
  186. flex-direction: column;
  187. height: 100%;
  188. width: 100%;
  189. }
  190. #action-desc {
  191. grid-area: 2 / main-col-start / main-row-start / main-col-end;
  192. padding: 8pt;
  193. text-align: center;
  194. font-size: 16px;
  195. }
  196. h3 {
  197. margin: 40px 0 0;
  198. }
  199. ul {
  200. list-style-type: none;
  201. padding: 0;
  202. }
  203. li {
  204. display: inline-block;
  205. margin: 0 10px;
  206. }
  207. a {
  208. color: #42b983;
  209. }
  210. .horiz-display {
  211. display: flex;
  212. justify-content: center;
  213. }
  214. .vert-display {
  215. display: flex;
  216. flex-direction: column;
  217. align-items: center;
  218. flex-wrap: nowrap;
  219. justify-content: start;
  220. height: 100%;
  221. overflow-y: auto;
  222. padding: 64px 0 64px;
  223. }
  224. .statblock:hover {
  225. background: #444;
  226. }
  227. .statblock:hover[data-active] {
  228. background: #666;
  229. }
  230. .statblock:hover[data-active-ally] {
  231. background: #966;
  232. }
  233. .action-label {
  234. font-size: 200%;
  235. }
  236. </style>
  237. <style>
  238. .log-damage {
  239. font-weight: bold;
  240. }
  241. .damage-instance {
  242. white-space: nowrap;
  243. }
  244. #log > div {
  245. color: #888;
  246. padding-top: 4pt;
  247. padding-bottom: 4pt;
  248. }
  249. div.left-move,
  250. div.right-move {
  251. color: #888;
  252. }
  253. div.left-move {
  254. text-align: start;
  255. margin-right: 25%;
  256. margin-left: 2%;
  257. }
  258. div.right-move {
  259. text-align: end;
  260. margin-left: 25%;
  261. margin-right: 2%;
  262. }
  263. #log img {
  264. width: 75%;
  265. }
  266. #log > div.left-move:nth-last-child(7) {
  267. padding-top: 8pt;
  268. color: #988;
  269. }
  270. #log > div.left-move:nth-last-child(6) {
  271. padding-top: 12pt;
  272. color: #a88;
  273. }
  274. #log > div.left-move:nth-last-child(5) {
  275. padding-top: 16pt;
  276. color: #b88;
  277. }
  278. #log > div.left-move:nth-last-child(4) {
  279. padding-top: 20pt;
  280. color: #c88;
  281. }
  282. #log > div.left-move:nth-last-child(3) {
  283. padding-top: 24pt;
  284. color: #d88;
  285. }
  286. #log > div.left-move:nth-last-child(2) {
  287. padding-top: 28pt;
  288. color: #e88;
  289. }
  290. #log > div.left-move:nth-last-child(1) {
  291. padding-top: 32pt;
  292. color: #f88;
  293. }
  294. #log > div.right-move:nth-last-child(7) {
  295. padding-top: 8pt;
  296. color: #988;
  297. }
  298. #log > div.right-move:nth-last-child(6) {
  299. padding-top: 12pt;
  300. color: #a88;
  301. }
  302. #log > div.right-move:nth-last-child(5) {
  303. padding-top: 16pt;
  304. color: #b88;
  305. }
  306. #log > div.right-move:nth-last-child(4) {
  307. padding-top: 20pt;
  308. color: #c88;
  309. }
  310. #log > div.right-move:nth-last-child(3) {
  311. padding-top: 24pt;
  312. color: #d88;
  313. }
  314. #log > div.right-move:nth-last-child(2) {
  315. padding-top: 28pt;
  316. color: #e88;
  317. }
  318. #log > div.right-move:nth-last-child(1) {
  319. padding-top: 32pt;
  320. color: #f88;
  321. }
  322. .left-selector,
  323. .right-selector {
  324. display: flex;
  325. flex-wrap: wrap;
  326. }
  327. .combatant-picker {
  328. flex: 1 1;
  329. }
  330. </style>