Merge remote-tracking branch 'upstream/master' into kronos

This commit is contained in:
thepaperpilot 2021-05-17 21:32:24 -05:00
commit e42c7c3df5
28 changed files with 493 additions and 120 deletions

View file

@ -1,5 +1,23 @@
# The Modding Tree changelog:
# v2.5.8 - 5/17/21
- Added makeShinies, which creates a stationary particle in a random spot.
- Bars will visually update more quickly.
- Fixed a major particle-related issue.
- Fixed autoUpgrade.
- Fixed a minor visal issue with tree nodes.
# v2.5.7 - 5/15/21
- Added a particle system! Not only can it be used for visual effects, but particles can interact with the mouse. They could be used to create golden cookies or collectables, for example.
- Added marked feature to buyables, clickables, and challenges. By default, stars multi-completion challenges when maxed.
- Added 'deactivated' feature to layers, which disables many features.
- Improved number formatting slightly.
# v2.5.6 - 5/14/21
- You can now use non-numeric ids for upgrades, buyables, etc.
- Fixed an exploit that let you buy an extra buyable.
- Moved basic getter/setter functions to easyAccess.js.
# v2.5.5.2 - 5/12/21
- Fixed a major issue with buyables.
- Fixed a variety of tabFormat-related issues.
@ -371,11 +389,11 @@ which will break old things)
- Added a few minor features, and updated the docs with new information.
### v1.1.1:
### v1.1.1 - 9/30/20
- You can define hotkeys directly from layer config.
## v1.1: Enhanced Edition
## v1.1: Enhanced Edition - 9/30/20
- Added "Buyables", which can function like Space Buildings or Enhancers.
- Custom CSS can now be used on any component! Make the third argument an object with CSS
@ -383,5 +401,5 @@ parameters.
- Lots of minor good things.
## v1.0:
## v1.0 - 9/27/20
- First release.

View file

@ -18,9 +18,12 @@
<script src="js/game.js"></script>
<script src="js/utils.js"></script>
<script src="js/utils/easyAccess.js"></script>
<script src="js/technical/systemComponents.js"></script>
<script src="js/components.js"></script>
<script src="js/technical/canvas.js"></script>
<script src="js/technical/particleSystem.js"></script>
<script src="js/utils/NumberFormating.js"></script>
<script src="js/utils/options.js"></script>
<script src="js/utils/save.js"></script>
@ -28,7 +31,7 @@
</head>
<body onload="load()">
<body onload="load()" onmousemove="updateMouse(event)">
<div id="app">
<canvas id="treeCanvas" class="canvas" v-if="!(gameEnded && !player.keepGoing)"></canvas>
@ -110,6 +113,11 @@
</div>
</transition-group>
</div>
<div class="particle-container">
<div v-for="particle,index in particles">
<particle :data="particle" :index="index" v-bind:key="'b' + particle.id"></particle>
</div>
</div>
<div v-if="player.navTab !== 'none' && player.tab !== 'none' && !(gameEnded && !player.keepGoing)" onscroll="resizeCanvas()" style="background-color:var(--background)" v-bind:class="{ fullWidth: player.navTab == 'none' || !tmp.other.splitScreen || !readData(layoutInfo.showTree), col: player.navTab != 'none', right: player.navTab != 'none', fast: true, tab: true}">
<div v-for="layer in LAYERS">

View file

@ -37,7 +37,7 @@ While reading this documentation, the following key will be used when describing
- [Upgrades](upgrades.md): How to create upgrades for a layer.
- [Milestones](milestones.md): How to create milestones for a layer.
- [Buyables](buyables.md): Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings.
- [Buyables](buyables.md): Create rebuyable upgrades for your layer (with the option to make them respec-able). Can be used to make Enhancers or Space Buildings, for example.
- [Clickables](clickables.md): A more generalized variant of buyables, for any kind of thing that is sometimes clickable. Between these and Buyables, you can do just about anything.
- [Achievements](achievements.md): How to create achievements for a layer (or for the whole game).
@ -50,3 +50,4 @@ While reading this documentation, the following key will be used when describing
- [Grids][grids.md]: Create a group buttons that behave the same, but have their own data. Good for map tiles, an inventory grid, and more!
- [Infoboxes](infoboxes.md): Boxes containing text that can be shown or hidden.
- [Trees](trees-and-tree-customization.md): Make your own trees. You can make non-layer button nodes too!
- [Particle system](particles.md): Can be used to create particles for visual effects, but also interactable things like golden cookies or collectables.

View file

@ -21,7 +21,7 @@ achievements: {
}
```
Each achievement should have an id where the first digit is the row and the second digit is the column.
Usually, each achievement should have an id where the first digit is the row and the second digit is the column.
Individual achievement can have these features:

View file

@ -52,6 +52,8 @@ Features:
- purchaseLimit: **optional**. The limit on how many of the buyable can be bought. The default is no limit.
- marked: **optional** Adds a mark to the corner of the buyable. If it's "true" it will be a star, but it can also be an image URL.
- layer: **assigned automagically**. It's the same value as the name of this layer, so you can do `player[this.layer].points` or similar.
- id: **assigned automagically**. It's the "key" which the buyable was stored under, for convenient access. The buyable in the example's id is 11.

View file

@ -22,7 +22,7 @@ challenges: {
}
```
Each challenge should have an id where the first digit is the row and the second digit is the column.
Usually, each challenge should have an id where the first digit is the row and the second digit is the column.
Individual Challenges can have these features:
@ -58,6 +58,8 @@ Individual Challenges can have these features:
- style: **optional**. Applies CSS to this challenge, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).
- marked: **optional** Adds a mark to the corner of the challenge. If it's "true" it will be a star, but it can also be an image URL. By default, if the challenge has multiple completions, it will be starred at max completions.
- layer: **assigned automagically**. It's the same value as the name of this layer, so you can do player[this.layer].points or similar
- id: **assigned automagically**. It's the "key" which the challenge was stored under, for convenient access. The challenge in the example's id is 11.

View file

@ -42,6 +42,8 @@ Features:
- style: **optional**. Applies CSS to this clickable, in the form of an object where the keys are CSS attributes, and the values are the values for those attributes (both as strings).
- marked: **optional** Adds a mark to the corner of the clickable. If it's "true" it will be a star, but it can also be an image URL.
- layer: **assigned automagically**. It's the same value as the name of this layer, so you can do `player[this.layer].points` or similar.
- id: **assigned automagically**. It's the "key" which the clickable was stored under, for convenient access. The clickable in the example's id is 11.

View file

View file

@ -173,6 +173,8 @@ componentStyles: {
}
```
- deactivated: **optional**, if this is true, hasUpgrade, hasChallenge, hasAchievement, and hasMilestone will return false for things in the layer, and you will be unable to buy or click things on the layer. You will have to disable effects of buyables, the innate layer effect, and possibly other things yourself.
## Custom Prestige type
(All of these can also be used by other prestige types)

View file

@ -24,7 +24,7 @@ Here's a breakdown of what's in it:
- num: The mod's version number, displayed at the top right of the tree tab.
- name: The version's name, displayed alongside the number in the info tab.
- changelog is the HTML displayed in the changelog tab.
- changelog is the HTML displayed in the changelog tab. If this gets particularly long, it might be good to put in a separate file (be sure to add the file to index.html)
- doNotCallTheseFunctionsEveryTick is very important, if you are adding non-standard functions. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.

59
docs/particles.md Normal file
View file

@ -0,0 +1,59 @@
# Particles
Particles are free-floating elements that can move and have many different behaviors. They can also interact with the mouse.
To make particles, use `makeParticles(particle, amount)`. `particle` is a particle-defining object, with features as explained below. There is also `makeShinies`, which uses different defaults and creates stationary particles at a random location. There are also a few other useful things listed at the end.
```js
const myParticle {
image:"options_wheel.png",
spread: 20,
gravity: 2,
time: 3,
speed() { // Randomize speed a bit
return (Math.random() + 1.2) * 8
},
etc...
}
```
Features can be functions or constant. These features will be called when each particle is made, with an `id` argument, which is assigned based on which of the `amount` particles being spawned this is. **All of these are optional**, with a default value.
All distances are in pixels and angles are in degrees, with 0 being up and going clockwise.
- time: The amount of time, in seconds, that the particle will last. Default is 3.
- fadeOutTime: The amount of seconds that fading out at the end should take (part of the total lifetime). Default is 1.
- fadeInTime: The amount of seconds that fading in should take (part of the total lifetime). Default is 0.
- image: The image the particle should display. `""` will display no image. Default is a generic particle.
- text: Displays text on the particle. Can use basic HTML.
- style: Lets you apply other CSS styling to the particle.
- width, height: The dimensions of the particle. Default is 35 and 35.
- angle: The angle that the particle should face. Default is 0.
- dir: The angle that the particles should move in, before spread is factored in. Default is whatever angle is.
- spread: If there are several particles, they will be spread out by this many degrees, centered on dir. Default is 30.
- rotation: The amount that the (visual) angle of the particle should change by. Default is 0.
- speed: The starting speed of the particle. Default is 15.
- gravity: The amount the particle should accelerate downwards. Default is 0.
- x, y: The starting coordinates of the particle. Default is at the mouse position.
- offset: How far from the start each particle should appear. Default is 10.
- layer: When changing tabs, if leaving the `layer` tab, this particle will be erased.
Function features: These stay as functions and are for more advanced things. They are optional.
- update(): Called each tick. Lets you do more advanced visual and movement behaviors by changing other properties.
- onClick(), onMouseOver(), onMouseLeave(): Called when the particle is interacted with.
Other useful things that are not features of the particle object:
- clearParticles(check): Function to delete particles. With no check, it deletes all particles. Check is a function that takes a particle, and returns true if that particle should be deleted.
- You can use Vue.delete(particles, this.id) to make a particle delete itself.
- mouseX and mouseY are variables that track the mouse position.
- sin(x), cos(x): functions that do these operations, with x in degrees. (Instead of radians).

View file

@ -21,7 +21,7 @@ upgrades: {
}
```
Each upgrade should have an id where the first digit is the row and the second digit is the column.
Usually, upgrades should have an id where the first digit is the row and the second digit is the column.
Individual upgrades can have these features:

View file

@ -24,9 +24,11 @@
<script type="text/javascript" src="js/technical/displays.js"></script>
<script type="text/javascript" src="js/game.js"></script>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/utils/easyAccess.js"></script>
<script type="text/javascript" src="js/technical/systemComponents.js"></script>
<script type="text/javascript" src="js/components.js"></script>
<script type="text/javascript" src="js/technical/canvas.js"></script>
<script type="text/javascript" src="js/technical/particleSystem.js"></script>
<script type="text/javascript" src="js/utils/NumberFormatting.js"></script>
<script type="text/javascript" src="js/utils/options.js"></script>
<script type="text/javascript" src="js/utils/save.js"></script>
@ -45,7 +47,7 @@
</head>
<body onload="load()">
<body onload="load()" onmousemove="updateMouse(event)">
<div id="app">
<img :src="'https://thepaperpilot.tech/count/tag.svg?url=' + encodeURIComponent(window.location.href)" alt="Hits" style="display: none"/>
<canvas id="treeCanvas" class="canvas" v-if ="!(gameEnded && !player.keepGoing)"></canvas>
@ -127,6 +129,11 @@
</div>
</transition-group>
</div>
<div class="particle-container">
<div v-for="particle,index in particles">
<particle :data="particle" :index="index" v-bind:key="'b' + particle.id"></particle>
</div>
</div>
<perfect-scrollbar v-if="player.navTab !== 'none' && player.tab !== 'none' && !(gameEnded && !player.keepGoing)" onscroll="resizeCanvas()" style="background-color:var(--background)" v-bind:class="{ fullWidth: player.navTab === 'none' || !tmp.other.splitScreen || !readData(layoutInfo.showTree), right: player.navTab !== 'none', fast: true, tab: true}">
<div v-for="layer in LAYERS" >

View file

@ -300,7 +300,7 @@ addLayer("c", {
["main-display",
"prestige-button", "resource-display",
["blank", "5px"], // Height
["raw-html", function() {return "<button onclick='console.log(`yeet`)'>'HI'</button>"}],
["raw-html", function() {return "<button onclick='console.log(`yeet`); makeParticles(textParticle)'>'HI'</button>"}],
["display-text", "Name your points!"],
["text-input", "thingy"],
["display-text",
@ -376,6 +376,7 @@ addLayer("c", {
// Layer will automatically highlight if an upgrade is purchasable.
return (player.c.buyables[11] == 1)
},
marked: "discord.png",
resetDescription: "Melt your points into ",
})
@ -455,6 +456,7 @@ addLayer("f", {
player[this.layer].clickables[this.id] = "Maybe that's a bit too far..."
break;
case "Maybe that's a bit too far...":
makeParticles(coolParticle, 4)
player[this.layer].clickables[this.id] = "Borkened..."
break;
default:
@ -524,5 +526,71 @@ addLayer("a", {
onComplete() {console.log("Bork bork bork!")}
},
},
},
midsection: ["grid", "blank"],
grid: {
maxRows: 3,
rows: 2,
cols: 2,
getStartData(id) {
return id
},
getUnlocked(id) { // Default
return true
},
getCanClick(data, id) {
return player.points.eq(10)
},
getStyle(data, id) {
return {'background-color': '#'+ (data*1234%999999)}
},
onClick(data, id) { // Don't forget onHold
player[this.layer].grid[id]++
},
getTitle(data, id) {
return "Gridable #" + id
},
getDisplay(data, id) {
return data
},
},
},
)
const coolParticle = {
image:"options_wheel.png",
spread: 20,
gravity: 2,
time: 3,
rotation (id) {
return 20 * (id - 1.5) + (Math.random() - 0.5) * 10
},
dir() {
return (Math.random() - 0.5) * 10
},
speed() {
return (Math.random() + 1.2) * 8
},
onClick() {
console.log("yay")
},
onMouseOver() {
console.log("hi")
},
onMouseLeave() {
console.log("bye")
},
update() {
//this.width += 1
},
layer: 'f',
}
const textParticle = {
spread: 20,
gravity: 0,
time: 3,
speed: 0,
text: function() { return "<h1 style='color:yellow'>" + format(player.points)},
offset: 30,
fadeInTime: 1,
}

View file

@ -11,7 +11,7 @@ let modInfo = {
// Set your version in num and name
let VERSION = {
num: "2.5.5.2",
num: "2.5.8",
name: "Dreams Really Do Come True",
}

View file

@ -171,7 +171,9 @@ function loadVue() {
Reward: <span v-html="tmp[layer].challenges[data].rewardDescription"></span><br>
<span v-if="layers[layer].challenges[data].rewardDisplay!==undefined">Currently: <span v-html="(tmp[layer].challenges[data].rewardDisplay) ? (run(layers[layer].challenges[data].rewardDisplay, layers[layer].challenges[data])) : format(tmp[layer].challenges[data].rewardEffect)"></span></span>
</span>
</div>
<node-mark :layer='layer' :data='tmp[layer].challenges[data].marked' :offset="10"></node-mark></span>
</div>
`
});
@ -346,6 +348,8 @@ function loadVue() {
v-on:click="buyBuyable(layer, data)" @mousedown="start" @mouseleave="stop" @mouseup="stop" @touchstart="start" @touchend="stop" @touchcancel="stop">
<span v-if= "tmp[layer].buyables[data].title"><h2 v-html="tmp[layer].buyables[data].title"></h2><br></span>
<span v-bind:style="{'white-space': 'pre-line'}" v-html="run(layers[layer].buyables[data].display, layers[layer].buyables[data])"></span>
<node-mark :layer='layer' :data='tmp[layer].buyables[data].marked'></node-mark>
</button>
<br v-if="(tmp[layer].buyables[data].sellOne !== undefined && !(tmp[layer].buyables[data].canSellOne !== undefined && tmp[layer].buyables[data].canSellOne == false)) || (tmp[layer].buyables[data].sellAll && !(tmp[layer].buyables[data].canSellAll !== undefined && tmp[layer].buyables[data].canSellAll == false))">
<sell-one :layer="layer" :data="data" v-bind:style="tmp[layer].componentStyles['sell-one']" v-if="(tmp[layer].buyables[data].sellOne)&& !(tmp[layer].buyables[data].canSellOne !== undefined && tmp[layer].buyables[data].canSellOne == false)"></sell-one>
@ -408,17 +412,18 @@ function loadVue() {
Vue.component("clickable", {
props: ["layer", "data", "size"],
template: `
<button
<button
v-if="tmp[layer].clickables && tmp[layer].clickables[data]!== undefined && tmp[layer].clickables[data].unlocked !== false"
v-bind:class="{ upg: true, can: tmp[layer].clickables[data].canClick !== false, locked: tmp[layer].clickables[data].canClick === false, ...tmp[layer].clickables[data].class}"
v-bind:style="[tmp[layer].clickables[data].canClick !== false ? {'background-color': tmp[layer].clickables[data].color || tmp[layer].color} : { 'background-color': tmp[layer].clickables[data].style?.backgroundColor }, size ? {'height': size, 'width': size} : {}, tmp[layer].clickables[data].style]"
v-on="handlers">
<span v-if="tmp[layer].clickables[data].title">
<!--suppress HtmlUnknownTag -->
<h2 v-html="tmp[layer].clickables[data].title"></h2><br>
</span>
<!--suppress HtmlUnknownTag -->
<h2 v-html="tmp[layer].clickables[data].title"></h2><br>
</span>
<span v-bind:style="{'white-space': 'pre-line'}" v-html="run(layers[layer].clickables[data].display, layers[layer].clickables[data])"></span>
</button>
<node-mark :layer='layer' :data='tmp[layer].clickables[data].marked'></node-mark>
</button>
`,
data() {
const {layer, data} = this;
@ -660,6 +665,7 @@ function loadVue() {
Vue.component('info-tab', systemComponents['info-tab'])
Vue.component('options-tab', systemComponents['options-tab'])
Vue.component('tooltip', systemComponents['tooltip'])
Vue.component('particle', systemComponents['particle'])
Vue.component("sticky", {
@ -683,6 +689,7 @@ function loadVue() {
format,
formatWhole,
formatTime,
formatSmall,
focused,
getThemeName,
layerunlocked,
@ -705,10 +712,16 @@ function loadVue() {
challengeStyle,
challengeButtonText,
constructBarStyle,
constructParticleStyle,
VERSION,
LAYERS,
hotkeys,
activePopups,
particles,
mouseX,
mouseY,
shiftDown,
ctrlDown,
},
});
}

View file

@ -5,7 +5,7 @@ let gameEnded = false;
// Don't change this
const TMT_VERSION = {
tmtNum: "2.5.5.2",
tmtNum: "2.5.8",
tmtName: "Dreams Really Do Come True"
}
@ -105,11 +105,8 @@ function softcap(value, cap, power = 0.5) {
// Return true if the layer should be highlighted. By default checks for upgrades only.
function shouldNotify(layer) {
if (player.tab === layer || player.navTab === layer) {
return false;
}
for (let id in tmp[layer].upgrades) {
if (!isNaN(id)) {
if (isPlainObject(layers[layer].upgrades[id])) {
if (canAffordUpgrade(layer, id) && !hasUpgrade(layer, id) && tmp[layer].upgrades[id].unlocked) {
return true;
}
@ -391,6 +388,7 @@ function gameLoop(diff) {
if (gameEnded && !player.keepGoing) {
diff = 0;
player.tab = "gameEnded";
clearParticles();
}
if (maxTickLength) {
@ -438,7 +436,7 @@ function gameLoop(diff) {
if (layers[layer].automate) {
layers[layer].automate();
}
if (layers[layer].autoUpgrade) {
if (tmp[layer].autoUpgrade) {
autobuyUpgrades(layer);
}
}
@ -454,7 +452,7 @@ function gameLoop(diff) {
layers[layer].automate();
}
player[layer].best = player[layer].best.max(player[layer].points);
if (layers[layer].autoUpgrade) {
if (tmp[layer].autoUpgrade) {
autobuyUpgrades(layer);
}
}
@ -495,6 +493,7 @@ const interval = setInterval(function () {
ticking = true;
let now = Date.now();
let diff = (now - player.time) / 1e3;
let trueDiff = diff;
if (player.offTime !== undefined) {
if (player.offTime.remain > modInfo.offlineLimit * 3600) {
player.offTime.remain = modInfo.offlineLimit * 3600;
@ -523,7 +522,8 @@ const interval = setInterval(function () {
updateTabFormats()
gameLoop(diff);
fixNaNs();
adjustPopupTime(0.05);
adjustPopupTime(trueDiff);
updateParticles(trueDiff);
ticking = false;
}, 50);

View file

@ -52,9 +52,12 @@ function achievementStyle(layer, id){
function updateWidth() {
var screenWidth = window.innerWidth
var splitScreen = screenWidth >= 1024
if (player.forceOneTab) splitScreen = false
tmp.other.screenWidth = screenWidth
tmp.other.screenHeight = window.innerHeight
tmp.other.splitScreen = splitScreen
tmp.other.lastPoints = player.points
}

View file

@ -66,7 +66,7 @@ function setupLayer(layer){
if (layers[layer].upgrades){
setRowCol(layers[layer].upgrades)
for (thing in layers[layer].upgrades){
if (typeof layers[layer].upgrades[thing] === "object"){
if (isPlainObject(layers[layer].upgrades[thing])){
layers[layer].upgrades[thing].id = thing
layers[layer].upgrades[thing].layer = layer
if (layers[layer].upgrades[thing].unlocked === undefined)
@ -76,7 +76,7 @@ function setupLayer(layer){
}
if (layers[layer].milestones){
for (let thing in layers[layer].milestones){
if (typeof layers[layer].milestones[thing] === "object"){
if (isPlainObject(layers[layer].milestones[thing])){
layers[layer].milestones[thing].id = thing
layers[layer].milestones[thing].layer = layer
if (layers[layer].milestones[thing].unlocked === undefined)
@ -87,7 +87,7 @@ function setupLayer(layer){
if (layers[layer].achievements){
setRowCol(layers[layer].achievements)
for (thing in layers[layer].achievements){
if (typeof layers[layer].achievements[thing] === "object"){
if (isPlainObject(layers[layer].achievements[thing])){
layers[layer].achievements[thing].id = thing
layers[layer].achievements[thing].layer = layer
if (layers[layer].achievements[thing].unlocked === undefined)
@ -98,13 +98,15 @@ function setupLayer(layer){
if (layers[layer].challenges){
setRowCol(layers[layer].challenges)
for (thing in layers[layer].challenges){
if (typeof layers[layer].challenges[thing] === "object"){
if (isPlainObject(layers[layer].challenges[thing])){
layers[layer].challenges[thing].id = thing
layers[layer].challenges[thing].layer = layer
if (layers[layer].challenges[thing].unlocked === undefined)
layers[layer].challenges[thing].unlocked = true
if (layers[layer].challenges[thing].completionLimit === undefined)
layers[layer].challenges[thing].completionLimit = 1
else if (layers[layer].challenges[thing].marked === undefined)
layers[layer].challenges[thing].marked = function() {return maxedChallenge(this.layer, this.id)}
}
}
@ -113,7 +115,7 @@ function setupLayer(layer){
layers[layer].buyables.layer = layer
setRowCol(layers[layer].buyables)
for (thing in layers[layer].buyables){
if (typeof layers[layer].buyables[thing] === "object"){
if (isPlainObject(layers[layer].buyables[thing])){
layers[layer].buyables[thing].id = thing
layers[layer].buyables[thing].layer = layer
if (layers[layer].buyables[thing].unlocked === undefined) {
@ -129,7 +131,7 @@ function setupLayer(layer){
layers[layer].clickables.layer = layer
setRowCol(layers[layer].clickables)
for (thing in layers[layer].clickables){
if (typeof layers[layer].clickables[thing] === "object"){
if (isPlainObject(layers[layer].clickables[thing])){
layers[layer].clickables[thing].id = thing
layers[layer].clickables[thing].layer = layer
if (layers[layer].clickables[thing].unlocked === undefined)
@ -165,7 +167,6 @@ function setupLayer(layer){
layers[layer].grid.getCanClick = true
}
if (layers[layer].startData) {
let data = layers[layer].startData()
if (data.best !== undefined && data.showBest === undefined) layers[layer].showBest = true

View file

@ -0,0 +1,160 @@
var particles = {};
var particleID = 0;
var mouseX = 0;
var mouseY = 0;
function makeParticles(data, amount=1, type = "normal") {
for (let x = 0; x < amount; x++) {
let particle = newParticles[type]()
for (thing in data) {
switch(thing) {
case 'onClick': // Functions that should be copied over
case 'onMouseEnter':
case 'onMouseLeave':
case 'update':
particle[thing] = data[thing]
break;
default:
particle[thing]=run(data[thing], data, x)
}
}
if (data.dir === undefined) {
particle.dir = particle.angle
}
particle.dir = particle.dir + (particle.spread * (x- amount/2 + 0.5))
if(particle.offset) {
particle.x += particle.offset * sin(particle.dir)
particle.y += particle.offset * cos(particle.dir) * -1
}
particle.xVel = particle.speed * sin(particle.dir)
particle.yVel = particle.speed * cos(particle.dir) * -1
particle.fadeInTimer = particle.fadeInTime
Vue.set(particles, particle.id, particle)
}
}
// Makes a particle at a random location that stays still until it despawns
function makeShinies(data, amount=1) {
makeParticles(data, amount, "shiny")
}
function sin(x) {
return Math.sin(x*Math.PI/180)
}
function cos(x) {
return Math.cos(x*Math.PI/180)
}
function updateParticles(diff) {
for (p in particles) {
let particle = particles[p]
particle.time -= diff;
particle.fadeInTimer -= diff;
if (particle["time"] < 0) {
Vue.delete(particles, p);
}
else {
if (particle.update) run(particle.update, particle)
particle.angle += particle.rotation
particle.x += particle.xVel
particle.y += particle.yVel
particle.yVel += particle.gravity
}
}
}
const newParticles = {
normal() {
particleID++
return {
time: 3,
id: particleID,
x: mouseX,
y: mouseY,
width: 35,
height: 35,
image: "resources/genericParticle.png",
angle: 0,
spread: 30,
offset: 10,
speed: 15,
xVel: 0,
yVel: 0,
rotation: 0,
gravity: 0,
fadeOutTime: 1,
fadeInTimer: 0,
fadeInTime: 0,
}
},
shiny() {
particleID++
return {
time: 10,
id: particleID,
x: Math.random() * (tmp.other.screenWidth - 100) + 50,
y: Math.random() * (tmp.other.screenHeight - 100) + 50,
width: 50,
height: 50,
image: "resources/genericParticle.png",
angle: 0,
spread: 0,
offset: 0,
speed: 0,
xVel: 0,
yVel: 0,
rotation: 0,
gravity: 0,
fadeOutTime: 1,
fadeInTimer: 0,
fadeInTime: 0.5,
}
},
}
function updateMouse(event) {
mouseX = event.clientX
mouseY = event.clientY
}
function getOpacity(particle) {
if ((particle.time < particle.fadeOutTime) && particle.fadeOutTime)
return particle.time / particle.fadeOutTime
if (particle.fadeInTimer > 0)
return 1 - (particle.fadeInTimer / particle.fadeInTime)
return 1
}
function constructParticleStyle(particle){
return {
left: (particle.x - particle.height/2) + 'px',
top: (particle.y - particle.height/2) + 'px',
width: particle.width + 'px',
height: particle.height + 'px',
transform: "rotate(" + particle.angle + "deg)",
opacity: getOpacity(particle),
"pointer-events": (particle.onClick || particle.onHover) ? 'auto' : 'none',
"background-image": "url(" + particle.image + ")",
}
}
function clearParticles(check) {
if (!check) check = true
for (p in particles) {
if (run(check, particles[p], particles[p])){
Vue.delete(particles, p)
}
}
}

View file

@ -206,5 +206,14 @@ const systemComponents = {
<img v-else class='mark' style='position: absolute; left: -25px; top: -10px;' v-bind:src="data"></div>
</div>
`
}
},
'particle': {
props: ['data', 'index'],
template: `<div class='particle instant' v-bind:style="[constructParticleStyle(data), data.style]"
v-on:click="run(data.onClick, data)" v-on:mouseenter="run(data.onMouseOver, data)" v-on:mouseleave="run(data.onMouseLeave, data)" ><span v-html="data.text"></span>
</div>
`
},
}

View file

@ -46,6 +46,8 @@ function setupTemp() {
tmp.other = {
lastPoints: player.points || decimalZero,
oomps: decimalZero,
screenWidth: 0,
screenHeight: 0,
}
updateWidth()
@ -156,7 +158,7 @@ function updateClickableTemp(layer)
function setupBuyables(layer) {
for (id in layers[layer].buyables) {
if (!isNaN(id)) {
if (isPlainObject(layers[layer].buyables[id])) {
let b = layers[layer].buyables[id]
b.actualCostFunction = b.cost
b.cost = function(x) {

View file

@ -11,6 +11,9 @@ function respecBuyables(layer) {
function canAffordUpgrade(layer, id) {
let upg = tmp[layer].upgrades[id];
if (tmp[layer].deactivated) {
return false;
}
if (tmp[layer].upgrades[id].canAfford !== undefined) {
return tmp[layer].upgrades[id].canAfford;
}
@ -20,83 +23,9 @@ function canAffordUpgrade(layer, id) {
function canBuyBuyable(layer, id) {
let b = temp[layer].buyables[id]
return (b.unlocked && b.canAfford && player[layer].buyables[id].lt(b.purchaseLimit))
return (b.unlocked && run(b.canAfford, b) && player[layer].buyables[id].lt(b.purchaseLimit) && !tmp[layer].deactivated)
}
function hasUpgrade(layer, id) {
return (player[layer].upgrades.includes(toNumber(id)) || player[layer].upgrades.includes(id.toString()));
}
function hasMilestone(layer, id) {
return (player[layer].milestones.includes(toNumber(id)) || player[layer].milestones.includes(id.toString()));
}
function hasAchievement(layer, id) {
return (player[layer].achievements.includes(toNumber(id)) || player[layer].achievements.includes(id.toString()));
}
function hasChallenge(layer, id) {
return (player[layer].challenges[id]);
}
function maxedChallenge(layer, id) {
return (player[layer].challenges[id] >= tmp[layer].challenges[id].completionLimit);
}
function challengeCompletions(layer, id) {
return (player[layer].challenges[id]);
}
function getBuyableAmount(layer, id) {
return (player[layer].buyables[id]);
}
function setBuyableAmount(layer, id, amt) {
player[layer].buyables[id] = amt;
}
function getClickableState(layer, id) {
return (player[layer].clickables[id]);
}
function setClickableState(layer, id, state) {
player[layer].clickables[id] = state;
}
function getGridData(layer, id) {
return (player[layer].grid[id])
}
function setGridData(layer, id, data) {
player[layer].grid[id] = data
}
function upgradeEffect(layer, id) {
return (tmp[layer].upgrades[id].effect);
}
function challengeEffect(layer, id) {
return (tmp[layer].challenges[id].rewardEffect);
}
function buyableEffect(layer, id) {
return (tmp[layer].buyables[id].effect);
}
function clickableEffect(layer, id) {
return (tmp[layer].clickables[id].effect);
}
function achievementEffect(layer, id) {
return (tmp[layer].achievements[id].effect);
}
function gridEffect(layer, id) {
return (gridRun(layer, 'getEffect', player[layer].grid[id], id))
}
function canAffordPurchase(layer, thing, cost) {
if (thing.currencyInternalName) {
@ -180,7 +109,7 @@ function buyMaxBuyable(layer, id) {
if (!tmp[layer].buyables[id].unlocked) {
return;
}
if (!tmp[layer].buyables[id].canAfford) {
if (!tmp[layer].buyables[id].canBuy) {
return;
}
if (!layers[layer].buyables[id].buyMax) {
@ -207,7 +136,7 @@ function buyBuyable(layer, id) {
}
function clickClickable(layer, id) {
if (!player[layer].unlocked) {
if (!player[layer].unlocked || tmp[layer].deactivated) {
return;
}
if (tmp[layer].clickables[id].unlocked === false) {
@ -222,7 +151,7 @@ function clickClickable(layer, id) {
}
function clickGrid(layer, id) {
if (!player[layer].unlocked) return
if (!player[layer].unlocked || tmp[layer].deactivated) return
if (!run(layers[layer].grid.getUnlocked, layers[layer].grid, id)) return
if (!gridRun(layer, 'getCanClick', player[layer].grid[id], id)) return
@ -253,6 +182,9 @@ function showTab(name) {
if (LAYERS.includes(name) && !layerunlocked(name)) {
return;
}
if (player.tab !== name) {
clearParticles(function(p) { return p.layer === player.tab });
}
if (player.tab === name && isPlainObject(tmp[name].tabFormat)) {
player.subtabs[name].mainTabs = Object.keys(layers[name].tabFormat)[0];
}
@ -270,6 +202,9 @@ function showNavTab(name) {
if (LAYERS.includes(name) && !layerunlocked(name)) {
return;
}
if (player.navTab !== name) {
clearParticles(function(p) { return p.layer === player.navTab });
}
var toTreeTab = name == "tree"
player.navTab = name

View file

@ -6,7 +6,7 @@ function exponentialFormat(num, precision, mantissa = true) {
m = decimalOne;
e = e.add(1);
}
e = (e.gte(1e9) ? format(e, 1) : (e.gte(10000) ? commaFormat(e, 0) : e.toStringWithDecimalPlaces(0)))
e = (e.gte(1e9) ? format(e, 3) : (e.gte(10000) ? commaFormat(e, 0) : e.toStringWithDecimalPlaces(0)))
if (mantissa) {
return m.toStringWithDecimalPlaces(precision)+"e"+e;
} else {

71
js/utils/easyAccess.js Normal file
View file

@ -0,0 +1,71 @@
function hasUpgrade(layer, id) {
return ((player[layer].upgrades.includes(toNumber(id)) || player[layer].upgrades.includes(id.toString())) && !tmp[layer].deactivated)
}
function hasMilestone(layer, id) {
return ((player[layer].milestones.includes(toNumber(id)) || player[layer].milestones.includes(id.toString())) && !tmp[layer].deactivated)
}
function hasAchievement(layer, id) {
return ((player[layer].achievements.includes(toNumber(id)) || player[layer].achievements.includes(id.toString())) && !tmp[layer].deactivated)
}
function hasChallenge(layer, id) {
return ((player[layer].challenges[id]) && !tmp[layer].deactivated)
}
function maxedChallenge(layer, id) {
return ((player[layer].challenges[id] >= tmp[layer].challenges[id].completionLimit) && !tmp[layer].deactivated)
}
function challengeCompletions(layer, id) {
return (player[layer].challenges[id])
}
function getBuyableAmount(layer, id) {
return (player[layer].buyables[id])
}
function setBuyableAmount(layer, id, amt) {
player[layer].buyables[id] = amt
}
function getClickableState(layer, id) {
return (player[layer].clickables[id])
}
function setClickableState(layer, id, state) {
player[layer].clickables[id] = state
}
function getGridData(layer, id) {
return (player[layer].grid[id])
}
function setGridData(layer, id, data) {
player[layer].grid[id] = data
}
function upgradeEffect(layer, id) {
return (tmp[layer].upgrades[id].effect)
}
function challengeEffect(layer, id) {
return (tmp[layer].challenges[id].rewardEffect)
}
function buyableEffect(layer, id) {
return (tmp[layer].buyables[id].effect)
}
function clickableEffect(layer, id) {
return (tmp[layer].clickables[id].effect)
}
function achievementEffect(layer, id) {
return (tmp[layer].achievements[id].effect)
}
function gridEffect(layer, id) {
return (gridRun(layer, 'getEffect', player[layer].grid[id], id))
}

View file

@ -47,3 +47,11 @@
.redtext {
color: red;
}
.particle {
background-color: transparent;
display: block;
position:absolute;
z-index: 99999;
background-size:contain;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View file

@ -126,14 +126,12 @@ h1, h2, h3, b, input {
/*noinspection CssUnresolvedCustomProperty,CssUnusedSymbol*/
.resetNotify {
box-shadow: var(--hqProperty2a), 0 0 8px #ffffff;
z-index: 3
}
/*noinspection CssUnresolvedCustomProperty*/
.treeNode.can:hover {
transform: scale(1.15, 1.15);
box-shadow: var(--hqProperty2a), 0 0 20px var(--points);
z-index: 4
}
/*noinspection CssUnresolvedCustomProperty,CssUnusedSymbol*/
@ -141,7 +139,6 @@ h1, h2, h3, b, input {
transform: scale(1.05, 1.05);
border-color: rgba(0, 0, 0, 0.125);
box-shadow: var(--hqProperty2a), 0 0 20px #ff0000;
z-index: 3
}
/*noinspection CssUnusedSymbol*/
@ -212,7 +209,7 @@ h1, h2, h3, b, input {
overflow: hidden;
margin-left: -0.5px;
transition-property: clip-path;
transition-duration: .25s;
transition-duration: .2s;
transition-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
}
@ -281,6 +278,7 @@ h1, h2, h3, b, input {
border-radius: 5px;
border: 2px solid rgba(0, 0, 0, 0.125);
font-size: 10px;
position:relative;
}
.tile {
@ -489,6 +487,7 @@ ul {
/*noinspection CssUnusedSymbol*/
.hChallenge {
background-color: #bf8f8f;
position: relative;
border: 4px solid rgba(0, 0, 0, 0.125);
color: rgba(0, 0, 0, 0.5);
width: 300px;
@ -1206,7 +1205,8 @@ b, h3 {
border-bottom: 0.7em solid transparent;
border-left: 0.3em solid transparent;
font-size: 10px;
overflow:auto
overflow:auto;
pointer-events: none;
}
.star {
@ -1222,6 +1222,8 @@ b, h3 {
border-bottom: 0.7em solid #ffcc00;
border-left: 0.3em solid transparent;
font-size: 10px;
pointer-events: none;
}
.star:before, .star:after {