From 1d62aab2c10020a3c4a23af89bacea5b3b7a20db Mon Sep 17 00:00:00 2001 From: Andrei Andreev Date: Mon, 26 Nov 2018 01:46:50 +0300 Subject: [PATCH] Add time study tree scaffolding --- index.html | 4 +- .../components/eternity/time-studies-tab.js | 4 - .../eternity/time-studies/time-studies-tab.js | 239 +++++++++ javascripts/components/hint-text.js | 2 +- javascripts/core/extensions.js | 12 +- javascripts/core/timestudies.js | 486 ++++++++++++++++++ stylesheets/time-studies.css | 37 ++ stylesheets/timestudies.css | 14 - 8 files changed, 776 insertions(+), 22 deletions(-) delete mode 100644 javascripts/components/eternity/time-studies-tab.js create mode 100644 javascripts/components/eternity/time-studies/time-studies-tab.js create mode 100644 stylesheets/time-studies.css delete mode 100644 stylesheets/timestudies.css diff --git a/index.html b/index.html index 415e686f8..899a3b894 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ - + @@ -965,7 +965,7 @@ - + diff --git a/javascripts/components/eternity/time-studies-tab.js b/javascripts/components/eternity/time-studies-tab.js deleted file mode 100644 index ececf6448..000000000 --- a/javascripts/components/eternity/time-studies-tab.js +++ /dev/null @@ -1,4 +0,0 @@ -Vue.component("time-studies-tab", { - template: - `
Time studies
` -}); \ No newline at end of file diff --git a/javascripts/components/eternity/time-studies/time-studies-tab.js b/javascripts/components/eternity/time-studies/time-studies-tab.js new file mode 100644 index 000000000..f9c788823 --- /dev/null +++ b/javascripts/components/eternity/time-studies/time-studies-tab.js @@ -0,0 +1,239 @@ +const remMixin = { + methods: { + rem(value) { + return value + "rem"; + } + } +}; + +Vue.component("time-studies-tab", { + mixins: [remMixin], + data: function() { + const layout = TimeStudyTreeLayout.instance; + return { + width: this.rem(layout.width), + height: this.rem(layout.height), + studies: layout.studies, + connections: layout.connections + }; + }, + computed: { + tabStyleObject: function() { + return { + width: this.width, + height: this.height + }; + } + }, + template: + `
+ + + + +
` +}); + +Vue.component("time-study", { + mixins: [remMixin], + props: { + setup: Object + }, + computed: { + styleObject: function() { + return { + top: this.rem(this.setup.top), + left: this.rem(this.setup.left) + }; + } + }, + template: + `
+ {{setup.study._id}} +
` +}); + +Vue.component("time-study-connection", { + mixins: [remMixin], + props: { + setup: Object + }, + template: + `` +}); + +class TimeStudyRow { + constructor(layout, items) { + this.layout = layout; + this.items = items; + } + + get width() { + const itemCount = this.items.length; + const layout = this.layout; + return itemCount * layout.itemWidth + (itemCount - 1) * layout.spacing; + } + + itemPosition(column, treeLayout) { + const layout = this.layout; + const treeWidth = treeLayout.width; + const rowLeft = (treeWidth - this.width) / 2; + return rowLeft + column * layout.itemWidth + column * layout.spacing; + } +} + +class TimeStudyRowLayout { + constructor(props) { + this.itemWidth = props.itemWidth; + this.itemHeight = props.itemHeight; + this.spacing = props.spacing; + } +} + +class TimeStudySetup { + constructor(props) { + this.study = props.study; + this.row = props.row; + this.column = props.column; + } + + setPosition(layout) { + this.top = layout.itemPosition(this.row); + const row = layout.rows[this.row]; + this.left = row.itemPosition(this.column, layout); + this.width = row.layout.itemWidth; + this.height = row.layout.itemHeight; + } +} + +class TimeStudyConnectionSetup { + constructor(from, to) { + this.from = from; + this.to = to; + } + + /** + * @param {TimeStudySetup[]} studies + */ + setPosition(studies) { + const from = studies.find(study => study.study === this.from); + const to = studies.find(study => study.study === this.to); + this.x1 = from.left + from.width / 2; + this.y1 = from.top + from.height / 2; + this.x2 = to.left + to.width / 2; + this.y2 = to.top + to.height / 2; + } +} + +class TimeStudyTreeLayout { + constructor() { + this.spacing = 4; + + const normalRowLayout = new TimeStudyRowLayout({ + itemWidth: 17, + itemHeight: 8, + spacing: 3 + }); + const normalRow = (...items) => new TimeStudyRow(normalRowLayout, items); + + const TS = id => TimeStudy(id); + const EC = id => TimeStudy.eternityChallenge(id); + + /** + * @type {TimeStudyRow[]} + */ + this.rows = [ + normalRow(null, TS(11), null), + normalRow(TS(21), TS(22)), + normalRow(TS(33), TS(31), TS(32), null), + normalRow(TS(41), TS(42)), + normalRow(null, TS(51), EC(5)), + normalRow(null, TS(61), TS(62)), + normalRow(TS(71), TS(72), TS(73)), + normalRow(TS(81), TS(82), TS(83)), + normalRow(TS(91), TS(92), TS(93)), + normalRow(TS(101), TS(102), TS(103)), + normalRow(EC(7), TS(111), null), + normalRow(TS(121), TS(122), TS(123)), + normalRow(EC(6), TS(131), TS(132), TS(133), EC(8)), + normalRow(TS(141), TS(142), TS(143)), + normalRow(null, EC(9), TS(151), null, EC(4)), + normalRow(TS(161), TS(162)), + normalRow(TS(171)), + normalRow(EC(1), EC(2), EC(3)), + normalRow(TS(181)), + normalRow(EC(10)), + normalRow(TS(191), TS(192), TS(193)), + normalRow(TS(201)), + normalRow(TS(211), TS(212), TS(213), TS(214)), + normalRow(TS(221), TS(222), TS(223), TS(224), TS(225), TS(226), TS(227), TS(228)), + normalRow(TS(231), TS(232), TS(233), TS(234)), + normalRow(EC(11), EC(12)), + normalRow(TimeStudy.dilation), + normalRow(TimeStudy.timeDimension(5), TimeStudy.timeDimension(6)), + normalRow(TimeStudy.timeDimension(7), TimeStudy.timeDimension(8)), + normalRow(TimeStudy.reality), + ]; + + /** + * @type {TimeStudySetup[]} + */ + this.studies = []; + for (let rowIndex = 0; rowIndex < this.rows.length; rowIndex++) { + const row = this.rows[rowIndex]; + for (let columnIndex = 0; columnIndex < row.items.length; columnIndex++) { + const study = row.items[columnIndex]; + if (study === null) continue; + this.studies.push(new TimeStudySetup({ + study: study, + row: rowIndex, + column: columnIndex + })); + } + } + + /** + * @type {TimeStudyConnectionSetup[]} + */ + this.connections = TimeStudy.allConnections + .map(c => new TimeStudyConnectionSetup(c.from, c.to)); + + this.width = this.rows.map(row => row.width).max(); + const heightNoSpacing = this.rows.map(r => r.layout.itemHeight).sum(); + this.height = heightNoSpacing + (this.rows.length - 1) * this.spacing; + + for (let study of this.studies) { + study.setPosition(this); + } + + for (let connection of this.connections) { + connection.setPosition(this.studies); + } + } + + itemPosition(row) { + const rows = this.rows.slice(0, row); + const heightNoSpacing = rows.map(r => r.layout.itemHeight).sum(); + return heightNoSpacing + rows.length * this.spacing; + } + + static get instance() { + if (this._instance === undefined) { + this._instance = new TimeStudyTreeLayout(); + } + return this._instance; + } +} \ No newline at end of file diff --git a/javascripts/components/hint-text.js b/javascripts/components/hint-text.js index 802a64d13..3ba7dcd7e 100644 --- a/javascripts/components/hint-text.js +++ b/javascripts/components/hint-text.js @@ -5,5 +5,5 @@ Vue.component("hint-text", { } }, template: - `
` + `
` }); \ No newline at end of file diff --git a/javascripts/core/extensions.js b/javascripts/core/extensions.js index 66e489f0d..fd6d74798 100644 --- a/javascripts/core/extensions.js +++ b/javascripts/core/extensions.js @@ -138,4 +138,14 @@ Array.prototype.last = function(predicate) { /** * @type {number[]} */ -Array.dimensionTiers = Array.range(1, 8); \ No newline at end of file +Array.dimensionTiers = Array.range(1, 8); + +Array.prototype.sum = function() { + if (this.length === 0) return 0; + return this.reduce(Number.sumReducer); +}; + +Array.prototype.max = function() { + if (this.length === 0) return 0; + return this.reduce((a, b) => Math.max(a, b)); +}; \ No newline at end of file diff --git a/javascripts/core/timestudies.js b/javascripts/core/timestudies.js index 1a7717fca..d5a262030 100644 --- a/javascripts/core/timestudies.js +++ b/javascripts/core/timestudies.js @@ -573,3 +573,489 @@ $(document).ready(function() { } }); }); + +const TimeStudyType = { + NORMAL: 0, + EC: 1, + DILATION: 2 +}; + +const TimeStudyPath = { + NORMAL: 0, + INFINITY: 1, + TIME: 2, + ACTIVE: 3, + PASSIVE: 4, + IDLE: 5, + LIGHT: 6, + DARK: 7 +}; + +class TimeStudyInfo { + constructor(props) { + this._id = props.id; + this._cost = props.cost; + this.type = TimeStudyType.NORMAL; + this.incomingConnections = []; + } + + get id() { + return this._id; + } + + get cost() { + return this._cost; + } + + get isBought() { + return player.timestudy.studies.includes(this._id); + } +} + +TimeStudyInfo.studies = function() { + const allProps = [ + { + id: 11, + cost: 1 + }, + { + id: 21, + cost: 1 + }, + { + id: 22, + cost: 1 + }, + { + id: 31, + cost: 1 + }, + { + id: 32, + cost: 1 + }, + { + id: 33, + cost: 1 + }, + { + id: 41, + cost: 1 + }, + { + id: 42, + cost: 1 + }, + { + id: 51, + cost: 1 + }, + { + id: 61, + cost: 1 + }, + { + id: 62, + cost: 1 + }, + { + id: 71, + cost: 1 + }, + { + id: 72, + cost: 1 + }, + { + id: 73, + cost: 1 + }, + { + id: 81, + cost: 1 + }, + { + id: 82, + cost: 1 + }, + { + id: 83, + cost: 1 + }, + { + id: 91, + cost: 1 + }, + { + id: 92, + cost: 1 + }, + { + id: 93, + cost: 1 + }, + { + id: 101, + cost: 1 + }, + { + id: 102, + cost: 1 + }, + { + id: 103, + cost: 1 + }, + { + id: 111, + cost: 1 + }, + { + id: 121, + cost: 1 + }, + { + id: 122, + cost: 1 + }, + { + id: 123, + cost: 1 + }, + { + id: 131, + cost: 1 + }, + { + id: 132, + cost: 1 + }, + { + id: 133, + cost: 1 + }, + { + id: 141, + cost: 1 + }, + { + id: 142, + cost: 1 + }, + { + id: 143, + cost: 1 + }, + { + id: 151, + cost: 1 + }, + { + id: 161, + cost: 1 + }, + { + id: 162, + cost: 1 + }, + { + id: 171, + cost: 1 + }, + { + id: 181, + cost: 1 + }, + { + id: 191, + cost: 1 + }, + { + id: 192, + cost: 1 + }, + { + id: 193, + cost: 1 + }, + { + id: 201, + cost: 1 + }, + { + id: 211, + cost: 1 + }, + { + id: 212, + cost: 1 + }, + { + id: 213, + cost: 1 + }, + { + id: 214, + cost: 1 + }, + { + id: 221, + cost: 1 + }, + { + id: 222, + cost: 1 + }, + { + id: 223, + cost: 1 + }, + { + id: 224, + cost: 1 + }, + { + id: 225, + cost: 1 + }, + { + id: 226, + cost: 1 + }, + { + id: 227, + cost: 1 + }, + { + id: 228, + cost: 1 + }, + { + id: 231, + cost: 1 + }, + { + id: 232, + cost: 1 + }, + { + id: 233, + cost: 1 + }, + { + id: 234, + cost: 1 + }, + ]; + + const studies = []; + for (let props of allProps) { + studies[props.id] = new TimeStudyInfo(props); + } + + return studies; +}(); + +/** + * @returns {TimeStudyInfo} + */ +function TimeStudy(id) { + return TimeStudyInfo.studies[id]; +} + +class ECTimeStudyInfo { + constructor(props) { + this._id = props.id; + this.type = TimeStudyType.EC; + this.incomingConnections = []; + } + + get isBought() { + return player.eternityChallUnlocked === this._id; + } +} + +ECTimeStudyInfo.studies = Array.range(1, 12).map(id => new ECTimeStudyInfo({ id: id })); + +TimeStudy.eternityChallenge = function(id) { + return ECTimeStudyInfo.studies[id - 1]; +}; + +class DilationTimeStudy { + constructor(props) { + this._id = props.id; + this.type = TimeStudyType.DILATION; + this.incomingConnections = []; + } + + get isBought() { + return player.dilation.studies.includes(this._id); + } +} + +TimeStudy.dilation = new DilationTimeStudy({ id: 1 }); + +DilationTimeStudy.tdStudies = Array.range(5, 4).map(tier => new DilationTimeStudy({ id: tier - 3 })); + +TimeStudy.timeDimension = function(tier) { + return DilationTimeStudy.tdStudies[tier - 5]; +}; + +TimeStudy.reality = new DilationTimeStudy({ id: 6 }); + +class TimeStudyConnection { + constructor(from, to, override) { + this._from = from; + this._to = to; + this._override = override; + } + + get from() { + return this._from; + } + + get to() { + return this._to; + } + + get isOverridden() { + return this._override !== undefined && this._override(); + } + + get isSatisfied() { + return this.isOverridden || this._from.isBought; + } +} + +/** + * @type {TimeStudyConnection[]} + */ +TimeStudy.allConnections = function() { + const TS = id => TimeStudy(id); + const EC = id => TimeStudy.eternityChallenge(id); + const connections = [ + [TS(11), TS(21)], + [TS(11), TS(22)], + + [TS(21), TS(31)], + [TS(21), TS(33)], + [TS(22), TS(32)], + + [TS(31), TS(41)], + [TS(32), TS(42)], + + [TS(41), TS(51)], + [TS(42), TS(51)], + [TS(42), EC(5)], + + [TS(51), TS(61)], + [EC(5), TS(62)], + + [TS(61), TS(71)], + [TS(61), TS(72)], + [TS(61), TS(73)], + + [TS(71), TS(81)], + [TS(72), TS(82)], + [TS(73), TS(83)], + + [TS(81), TS(91)], + [TS(82), TS(92)], + [TS(83), TS(93)], + + [TS(91), TS(101)], + [TS(92), TS(102)], + [TS(93), TS(103)], + + [TS(101), TS(111)], + [TS(102), TS(111)], + [TS(103), TS(111)], + + [TS(111), EC(7)], + + [TS(111), TS(121)], + [TS(111), TS(122)], + [TS(111), TS(123)], + + [TS(121), TS(131)], + [TS(122), TS(132)], + [TS(123), TS(133)], + [TS(121), EC(6)], + [TS(123), EC(8)], + + [TS(131), TS(141)], + [TS(132), TS(142)], + [TS(133), TS(143)], + + [TS(141), TS(151)], + [TS(142), TS(151)], + [TS(143), TS(151)], + [TS(143), EC(4)], + + [TS(151), EC(9)], + + [TS(151), TS(161)], + [TS(151), TS(162)], + + [TS(161), TS(171)], + [TS(162), TS(171)], + + [TS(171), EC(1)], + [TS(171), EC(2)], + [TS(171), EC(3)], + + [EC(1), TS(181)], + [EC(2), TS(181)], + [EC(3), TS(181)], + + [TS(181), EC(10)], + + [EC(10), TS(191)], + [EC(10), TS(192)], + [EC(10), TS(193)], + + [TS(192), TS(201)], + + [TS(191), TS(211)], + [TS(191), TS(212)], + [TS(193), TS(213)], + [TS(193), TS(214)], + + [TS(211), TS(221)], + [TS(211), TS(222)], + [TS(212), TS(223)], + [TS(212), TS(224)], + [TS(213), TS(225)], + [TS(213), TS(226)], + [TS(214), TS(227)], + [TS(214), TS(228)], + + [TS(221), TS(231)], + [TS(222), TS(231)], + [TS(223), TS(232)], + [TS(224), TS(232)], + [TS(225), TS(233)], + [TS(226), TS(233)], + [TS(227), TS(234)], + [TS(228), TS(234)], + + [TS(231), EC(11)], + [TS(232), EC(11)], + [TS(233), EC(12)], + [TS(234), EC(12)], + + [EC(11), TimeStudy.dilation], + [EC(12), TimeStudy.dilation], + + [TimeStudy.dilation, TimeStudy.timeDimension(5)], + [TimeStudy.timeDimension(5), TimeStudy.timeDimension(6)], + [TimeStudy.timeDimension(6), TimeStudy.timeDimension(7)], + [TimeStudy.timeDimension(7), TimeStudy.timeDimension(8)], + [TimeStudy.timeDimension(8), TimeStudy.reality] + ] + .map(props => new TimeStudyConnection(props[0], props[1], props[2])); + for (let connection of connections) { + connection.to.incomingConnections.push(connection); + } + return connections; +}(); diff --git a/stylesheets/time-studies.css b/stylesheets/time-studies.css new file mode 100644 index 000000000..94a433ffa --- /dev/null +++ b/stylesheets/time-studies.css @@ -0,0 +1,37 @@ +.l-time-studies-tab { + align-self: center; + position: relative; + margin: 0 -1000%; +} + +.l-time-study { + position: absolute; + z-index: 1; +} + +.l-time-study-connection { + position: absolute; + left: 0; + top: 0; + z-index: 0; +} + +.o-time-study { + color: #b341e0; + background: black; + border: .1rem solid #b341e0; + font-weight: bold; + font-family: Typewriter, serif; + width: 17rem; + height: 8rem; + transition-duration: 0.2s; + cursor: pointer; + border-radius: .4rem; + font-size: 1.05rem; + animation: studyGlowIn 7s infinite; +} + +.o-time-study-connection { + stroke-width: 1rem; + stroke: #444444; +} \ No newline at end of file diff --git a/stylesheets/timestudies.css b/stylesheets/timestudies.css deleted file mode 100644 index 574736482..000000000 --- a/stylesheets/timestudies.css +++ /dev/null @@ -1,14 +0,0 @@ -.o-time-study { - color: #b341e0; - background: black; - border: .1rem solid #b341e0; - font-weight: bold; - font-family: Typewriter, serif; - width: 17rem; - height: 8rem; - transition-duration: 0.2s; - cursor: pointer; - border-radius: .4rem; - font-size: 1.05rem; - animation: studyGlowIn 7s infinite; -} \ No newline at end of file