mirror of
https://github.com/Acamaeda/The-Modding-Tree.git
synced 2024-11-24 01:11:46 +00:00
Merge branch '2.3.6-dev' into 2.3.6-dev
This commit is contained in:
commit
cf69924b5f
9 changed files with 48 additions and 29 deletions
|
@ -1,5 +1,12 @@
|
||||||
# The Modding Tree changelog:
|
# The Modding Tree changelog:
|
||||||
|
|
||||||
|
## v2.3.6 -
|
||||||
|
- Performance improvements.
|
||||||
|
- Fixed tooltips overlapping with the top display.
|
||||||
|
- Added support for bulk challenge completions.
|
||||||
|
- "Best" is updated automatically.
|
||||||
|
- Fixed keeping Decimal values on reset.
|
||||||
|
|
||||||
## v2.3.5 - 12/21/20
|
## v2.3.5 - 12/21/20
|
||||||
- Added resetTime, which tracks the time since a layer prestiged or was reset.
|
- Added resetTime, which tracks the time since a layer prestiged or was reset.
|
||||||
- A layer node will be highlighted red if one of its subtabs is highlighted red.
|
- A layer node will be highlighted red if one of its subtabs is highlighted red.
|
||||||
|
@ -8,7 +15,7 @@
|
||||||
- Other minor fixes.
|
- Other minor fixes.
|
||||||
|
|
||||||
## v2.3.4 - 12/16/20
|
## v2.3.4 - 12/16/20
|
||||||
- Added an node image feature.
|
- Added a node image feature.
|
||||||
- Resource display now always shows the amount of the currency the layer's gain is based on.
|
- Resource display now always shows the amount of the currency the layer's gain is based on.
|
||||||
- Added spacing between tree nodes.
|
- Added spacing between tree nodes.
|
||||||
- Another attempt to fix tooltip flickering.
|
- Another attempt to fix tooltip flickering.
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="treeOverlay" v-if="!(gameEnded && !player.keepGoing)" class="treeOverlay" onscroll="resizeCanvas()" v-bind:class="{ fullWidth: (player.tab == 'none' || player.navTab == 'none'), col: (player.tab !== 'none' && player.navTab !== 'none'), left: (player.tab !== 'none' && player.navTab !== 'none')}">
|
<div id="treeOverlay" v-if="!(gameEnded && !player.keepGoing)" class="treeOverlay" onscroll="resizeCanvas()" v-bind:class="{ fullWidth: (player.tab == 'none' || player.navTab == 'none'), col: (player.tab !== 'none' && player.navTab !== 'none'), left: (player.tab !== 'none' && player.navTab !== 'none')}">
|
||||||
<div id="version" onclick="showTab('changelog-tab')" class="overlayThing" style="margin-right: 13px">{{VERSION.withoutName}}</div>
|
<div id="version" onclick="showTab('changelog-tab')" class="overlayThing" style="margin-right: 13px">{{(VERSION.withoutName)}}</div>
|
||||||
<button v-if= "player.navTab == 'none' && (tmp[player.tab].row == 'side' || tmp[player.tab].row == 'otherside')" class="other-back overlayThing" onclick="goBack()">←</button>
|
<button v-if= "player.navTab == 'none' && (tmp[player.tab].row == 'side' || tmp[player.tab].row == 'otherside')" class="other-back overlayThing" onclick="goBack()">←</button>
|
||||||
<img id="optionWheel" class="overlayThing" v-if="player.tab!='options-tab'" src="options_wheel.png" onclick="showTab('options-tab')"></img>
|
<img id="optionWheel" class="overlayThing" v-if="player.tab!='options-tab'" src="options_wheel.png" onclick="showTab('options-tab')"></img>
|
||||||
<div id="info" v-if="player.tab!='info-tab'" class="overlayThing" onclick="showTab('info-tab')"><br>i</div>
|
<div id="info" v-if="player.tab!='info-tab'" class="overlayThing" onclick="showTab('info-tab')"><br>i</div>
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!(gameEnded && !player.keepGoing)" id="treeTab" style="z-index: 0" onscroll="resizeCanvas()" v-bind:class="{ fullWidth: (player.tab == 'none' || player.navTab == 'none'), col: (player.tab !== 'none' && player.navTab !== 'none'), left: (player.tab !== 'none' && player.navTab !== 'none')}">
|
<div v-if="!(gameEnded && !player.keepGoing)" id="treeTab" v-bind:style="{'z-index': (tmp.scrolled ? '999999999999' : '0')}" onscroll="resizeCanvas()" v-bind:class="{ fullWidth: (player.tab == 'none' || player.navTab == 'none'), col: (player.tab !== 'none' && player.navTab !== 'none'), left: (player.tab !== 'none' && player.navTab !== 'none')}">
|
||||||
<br><br><br><br>
|
<br><br><br><br>
|
||||||
<overlay-head id="fakeHead" style="visibility: hidden;">
|
<overlay-head id="fakeHead" style="visibility: hidden;">
|
||||||
</overlay-head>
|
</overlay-head>
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
<layer-tab :layer="player.navTab == 'none' ? player.tab : player.navTab" :key="'left'"></layer-tab>
|
<layer-tab :layer="player.navTab == 'none' ? player.tab : player.navTab" :key="'left'"></layer-tab>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Popups -->
|
<!-- Popups -->
|
||||||
<div class="popup-container">
|
<div class="popup-container">
|
||||||
<transition-group name="fade">
|
<transition-group name="fade">
|
||||||
|
|
|
@ -34,7 +34,8 @@ Individual Challenges can have these features:
|
||||||
- goalDescription: A description of the win condition for the challenge. It can also be a function that returns updating text.
|
- goalDescription: A description of the win condition for the challenge. It can also be a function that returns updating text.
|
||||||
Can use basic HTML. (Optional if using the old goal system)
|
Can use basic HTML. (Optional if using the old goal system)
|
||||||
|
|
||||||
- canComplete(): A function that returns true if you meet the win condition for the challenge. (Optional if using the old goal system)
|
- canComplete(): A function that returns true if you meet the win condition for the challenge. Returning a number will allow bulk completing the challenge.
|
||||||
|
(Optional if using the old goal system)
|
||||||
|
|
||||||
- rewardDescription: A description of the reward's effect. *You will also have to implement the effect where it is applied.* It can also be a function that returns updating text. Can use basic HTML.
|
- rewardDescription: A description of the reward's effect. *You will also have to implement the effect where it is applied.* It can also be a function that returns updating text. Can use basic HTML.
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!(gameEnded && !player.keepGoing)" id="treeTab" style="z-index: 0" onscroll="resizeCanvas()"
|
<div v-if="!(gameEnded && !player.keepGoing)" id="treeTab" v-bind:style="{'z-index': (tmp.scrolled ? '999999999999' : '0')}" onscroll="resizeCanvas()"
|
||||||
v-bind:class="{ fullWidth: (player.tab == 'none' || player.navTab == 'none'), col: (player.tab !== 'none' && player.navTab !== 'none'), left: (player.tab !== 'none' && player.navTab !== 'none')}">
|
v-bind:class="{ fullWidth: (player.tab == 'none' || player.navTab == 'none'), col: (player.tab !== 'none' && player.navTab !== 'none'), left: (player.tab !== 'none' && player.navTab !== 'none')}">
|
||||||
<br><br><br><br>
|
<br><br><br><br>
|
||||||
<overlay-head id="fakeHead" style="visibility: hidden;">
|
<overlay-head id="fakeHead" style="visibility: hidden;">
|
||||||
|
|
|
@ -17,7 +17,7 @@ addLayer("c", {
|
||||||
color: "#4BDC13",
|
color: "#4BDC13",
|
||||||
requires: new Decimal(10), // Can be a function that takes requirement increases into account
|
requires: new Decimal(10), // Can be a function that takes requirement increases into account
|
||||||
resource: "lollipops", // Name of prestige currency
|
resource: "lollipops", // Name of prestige currency
|
||||||
baseResource: "candies", // Name of resource prestige is based on
|
baseResource: "points", // Name of resource prestige is based on
|
||||||
baseAmount() {return player.points}, // Get the current amount of baseResource
|
baseAmount() {return player.points}, // Get the current amount of baseResource
|
||||||
type: "normal", // normal: cost to gain currency depends on amount gained. static: cost depends on how much you already have
|
type: "normal", // normal: cost to gain currency depends on amount gained. static: cost depends on how much you already have
|
||||||
exponent: 0.5, // Prestige currency exponent
|
exponent: 0.5, // Prestige currency exponent
|
||||||
|
@ -83,11 +83,10 @@ addLayer("c", {
|
||||||
completionLimit: 3,
|
completionLimit: 3,
|
||||||
challengeDescription() {return "Makes the game 0% harder<br>"+challengeCompletions(this.layer, this.id) + "/" + this.completionLimit + " completions"},
|
challengeDescription() {return "Makes the game 0% harder<br>"+challengeCompletions(this.layer, this.id) + "/" + this.completionLimit + " completions"},
|
||||||
unlocked() { return player[this.layer].best.gt(0) },
|
unlocked() { return player[this.layer].best.gt(0) },
|
||||||
goalDescription: 'Have 20 lollipops I guess',
|
goalDescription: 'Have 20 points I guess',
|
||||||
goal: new Decimal("20"),
|
canComplete() {
|
||||||
currencyDisplayName: "lollipops", // Use if using a nonstandard currency
|
return player.points.gte(20)
|
||||||
currencyInternalName: "points", // Use if using a nonstandard currency
|
},
|
||||||
currencyLayer: this.layer, // Leave empty if not in a layer
|
|
||||||
rewardEffect() {
|
rewardEffect() {
|
||||||
let ret = player[this.layer].points.add(1).tetrate(0.02)
|
let ret = player[this.layer].points.add(1).tetrate(0.02)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -108,7 +107,7 @@ addLayer("c", {
|
||||||
unlocked() { return player[this.layer].unlocked }, // The upgrade is only visible when this is true
|
unlocked() { return player[this.layer].unlocked }, // The upgrade is only visible when this is true
|
||||||
},
|
},
|
||||||
12: {
|
12: {
|
||||||
description: "Candy generation is faster based on your unspent Lollipops.",
|
description: "Point generation is faster based on your unspent Lollipops.",
|
||||||
cost: new Decimal(1),
|
cost: new Decimal(1),
|
||||||
unlocked() { return (hasUpgrade(this.layer, 11))},
|
unlocked() { return (hasUpgrade(this.layer, 11))},
|
||||||
effect() { // Calculate bonuses from the upgrade. Can return a single value or an object with multiple values
|
effect() { // Calculate bonuses from the upgrade. Can return a single value or an object with multiple values
|
||||||
|
@ -200,7 +199,7 @@ addLayer("c", {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
doReset(resettingLayer){ // Triggers when this layer is being reset, along with the layer doing the resetting. Not triggered by lower layers resetting, but is by layers on the same row.
|
doReset(resettingLayer){ // Triggers when this layer is being reset, along with the layer doing the resetting. Not triggered by lower layers resetting, but is by layers on the same row.
|
||||||
if(layers[resettingLayer].row > this.row) layerDataReset(this.layer) // This is actually the default behavior
|
if(layers[resettingLayer].row > this.row) layerDataReset(this.layer, ["points"]) // This is actually the default behavior
|
||||||
},
|
},
|
||||||
layerShown() {return true}, // Condition for when layer appears on the tree
|
layerShown() {return true}, // Condition for when layer appears on the tree
|
||||||
automate() {
|
automate() {
|
||||||
|
@ -358,6 +357,7 @@ addLayer("c", {
|
||||||
tooltip() { // Optional, tooltip displays when the layer is unlocked
|
tooltip() { // Optional, tooltip displays when the layer is unlocked
|
||||||
let tooltip = formatWhole(player[this.layer].points) + " " + this.resource
|
let tooltip = formatWhole(player[this.layer].points) + " " + this.resource
|
||||||
if (player[this.layer].buyables[11].gt(0)) tooltip += "\n" + formatWhole(player[this.layer].buyables[11]) + " Exhancers"
|
if (player[this.layer].buyables[11].gt(0)) tooltip += "\n" + formatWhole(player[this.layer].buyables[11]) + " Exhancers"
|
||||||
|
tooltip += "\nmomomo\m oo\nommom\nyeyeyeye"
|
||||||
return tooltip
|
return tooltip
|
||||||
},
|
},
|
||||||
shouldNotify() { // Optional, layer will be highlighted on the tree if true.
|
shouldNotify() { // Optional, layer will be highlighted on the tree if true.
|
||||||
|
@ -380,7 +380,7 @@ addLayer("f", {
|
||||||
color: "#FE0102",
|
color: "#FE0102",
|
||||||
requires() {return new Decimal(10)},
|
requires() {return new Decimal(10)},
|
||||||
resource: "farm points",
|
resource: "farm points",
|
||||||
baseResource: "candies",
|
baseResource: "points",
|
||||||
baseAmount() {return player.points},
|
baseAmount() {return player.points},
|
||||||
type: "static",
|
type: "static",
|
||||||
exponent: 0.5,
|
exponent: 0.5,
|
||||||
|
@ -393,7 +393,7 @@ addLayer("f", {
|
||||||
branches: ["c"], // When this layer appears, a branch will appear from this layer to any layers here. Each entry can be a pair consisting of a layer id and a color.
|
branches: ["c"], // When this layer appears, a branch will appear from this layer to any layers here. Each entry can be a pair consisting of a layer id and a color.
|
||||||
|
|
||||||
tooltipLocked() { // Optional, tooltip displays when the layer is locked
|
tooltipLocked() { // Optional, tooltip displays when the layer is locked
|
||||||
return ("This weird farmer dinosaur will only see you if you have at least " + this.requires() + " candies. You only have " + formatWhole(player.points))
|
return ("This weird farmer dinosaur will only see you if you have at least " + this.requires() + " points. You only have " + formatWhole(player.points))
|
||||||
},
|
},
|
||||||
midsection: [
|
midsection: [
|
||||||
"blank", ['display-image', 'https://images.beano.com/store/24ab3094eb95e5373bca1ccd6f330d4406db8d1f517fc4170b32e146f80d?auto=compress%2Cformat&dpr=1&w=390'],
|
"blank", ['display-image', 'https://images.beano.com/store/24ab3094eb95e5373bca1ccd6f330d4406db8d1f517fc4170b32e146f80d?auto=compress%2Cformat&dpr=1&w=390'],
|
||||||
|
@ -401,8 +401,8 @@ addLayer("f", {
|
||||||
],
|
],
|
||||||
// The following are only currently used for "custom" Prestige type:
|
// The following are only currently used for "custom" Prestige type:
|
||||||
prestigeButtonText() { //Is secretly HTML
|
prestigeButtonText() { //Is secretly HTML
|
||||||
if (!this.canBuyMax()) return "Hi! I'm a <u>weird dinosaur</u> and I'll give you a Farm Point in exchange for all of your candies and lollipops! (At least " + formatWhole(tmp[this.layer].nextAt) + " candies)"
|
if (!this.canBuyMax()) return "Hi! I'm a <u>weird dinosaur</u> and I'll give you a Farm Point in exchange for all of your points and lollipops! (At least " + formatWhole(tmp[this.layer].nextAt) + " points)"
|
||||||
if (this.canBuyMax()) return "Hi! I'm a <u>weird dinosaur</u> and I'll give you <b>" + formatWhole(tmp[this.layer].resetGain) + "</b> Farm Points in exchange for all of your candies and lollipops! (You'll get another one at " + formatWhole(tmp[layer].nextAtDisp) + " candies)"
|
if (this.canBuyMax()) return "Hi! I'm a <u>weird dinosaur</u> and I'll give you <b>" + formatWhole(tmp[this.layer].resetGain) + "</b> Farm Points in exchange for all of your points and lollipops! (You'll get another one at " + formatWhole(tmp[layer].nextAtDisp) + " points)"
|
||||||
},
|
},
|
||||||
getResetGain() {
|
getResetGain() {
|
||||||
return getResetGain(this.layer, useType = "static")
|
return getResetGain(this.layer, useType = "static")
|
||||||
|
@ -514,3 +514,8 @@ addLayer("a", {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addLayer('qq', {row: 2})
|
||||||
|
addLayer('rr', {row: 3})
|
||||||
|
addLayer('ss', {row: 4})
|
||||||
|
addLayer('tt', {row: 5})
|
|
@ -218,7 +218,7 @@ function loadVue() {
|
||||||
Vue.component('main-display', {
|
Vue.component('main-display', {
|
||||||
props: ['layer'],
|
props: ['layer'],
|
||||||
template: `
|
template: `
|
||||||
<div><span v-if="player[layer].points.lt('1e1000')">You have </span><h2 v-bind:style="{'color': tmp[layer].color, 'text-shadow': '0px 0px 10px' + tmp[layer].color}">{{formatWhole(player[layer].points)}}</h2> {{tmp[layer].resource}}<span v-if="tmp[layer].effectDescription">, <span v-html="tmp[layer].effectDescription"></span></span><br><br></div>
|
<div><span v-if="player[layer].points.lt('1e1000')">You have </span><h2 v-bind:style="{'color': tmp[layer].color, 'text-shadow': '0px 0px 10px ' + tmp[layer].color}">{{formatWhole(player[layer].points)}}</h2> {{tmp[layer].resource}}<span v-if="tmp[layer].effectDescription">, <span v-html="tmp[layer].effectDescription"></span></span><br><br></div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
18
js/game.js
18
js/game.js
|
@ -1,6 +1,7 @@
|
||||||
var player;
|
var player;
|
||||||
var needCanvasUpdate = true;
|
var needCanvasUpdate = true;
|
||||||
var gameEnded = false;
|
var gameEnded = false;
|
||||||
|
var scrolled = false;
|
||||||
|
|
||||||
// Don't change this
|
// Don't change this
|
||||||
const TMT_VERSION = {
|
const TMT_VERSION = {
|
||||||
|
@ -101,11 +102,9 @@ function shouldNotify(layer){
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tmp[layer].shouldNotify){
|
|
||||||
return tmp[layer].shouldNotify
|
return tmp[layer].shouldNotify
|
||||||
}
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function canReset(layer)
|
function canReset(layer)
|
||||||
|
@ -290,13 +289,16 @@ function canCompleteChallenge(layer, x)
|
||||||
function completeChallenge(layer, x) {
|
function completeChallenge(layer, x) {
|
||||||
var x = player[layer].activeChallenge
|
var x = player[layer].activeChallenge
|
||||||
if (!x) return
|
if (!x) return
|
||||||
if (! canCompleteChallenge(layer, x)){
|
|
||||||
|
let completions = canCompleteChallenge(layer, x)
|
||||||
|
if (!completions){
|
||||||
player[layer].activeChallenge = null
|
player[layer].activeChallenge = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (player[layer].challenges[x] < tmp[layer].challenges[x].completionLimit) {
|
if (player[layer].challenges[x] < tmp[layer].challenges[x].completionLimit) {
|
||||||
needCanvasUpdate = true
|
needCanvasUpdate = true
|
||||||
player[layer].challenges[x] += 1
|
player[layer].challenges[x] += completions
|
||||||
|
player[layer].challenges[x] = Math.min(player[layer].challenges[x], tmp[layer].challenges[x].completionLimit)
|
||||||
if (layers[layer].challenges[x].onComplete) run(layers[layer].challenges[x].onComplete, layers[layer].challenges[x])
|
if (layers[layer].challenges[x].onComplete) run(layers[layer].challenges[x].onComplete, layers[layer].challenges[x])
|
||||||
}
|
}
|
||||||
player[layer].activeChallenge = null
|
player[layer].activeChallenge = null
|
||||||
|
@ -364,6 +366,7 @@ function gameLoop(diff) {
|
||||||
let layer = OTHER_LAYERS[row][item]
|
let layer = OTHER_LAYERS[row][item]
|
||||||
if (tmp[layer].autoPrestige && tmp[layer].canReset) doReset(layer);
|
if (tmp[layer].autoPrestige && tmp[layer].canReset) doReset(layer);
|
||||||
if (layers[layer].automate) layers[layer].automate();
|
if (layers[layer].automate) layers[layer].automate();
|
||||||
|
player[layer].best = player[layer].best.max(player[layer].points)
|
||||||
if (layers[layer].autoUpgrade) autobuyUpgrades(layer)
|
if (layers[layer].autoUpgrade) autobuyUpgrades(layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,6 +408,7 @@ var interval = setInterval(function() {
|
||||||
if (needCanvasUpdate){ resizeCanvas();
|
if (needCanvasUpdate){ resizeCanvas();
|
||||||
needCanvasUpdate = false;
|
needCanvasUpdate = false;
|
||||||
}
|
}
|
||||||
|
tmp.scrolled = document.getElementById('treeTab').scrollTop < 30
|
||||||
updateTemp();
|
updateTemp();
|
||||||
gameLoop(diff)
|
gameLoop(diff)
|
||||||
fixNaNs()
|
fixNaNs()
|
||||||
|
|
|
@ -21,7 +21,8 @@ function setupTemp() {
|
||||||
tmp = {}
|
tmp = {}
|
||||||
tmp.pointGen = {}
|
tmp.pointGen = {}
|
||||||
tmp.displayThings = []
|
tmp.displayThings = []
|
||||||
|
tmp.scrolled = 0
|
||||||
|
|
||||||
setupTempData(layers, tmp)
|
setupTempData(layers, tmp)
|
||||||
for (layer in layers){
|
for (layer in layers){
|
||||||
tmp[layer].resetGain = {}
|
tmp[layer].resetGain = {}
|
||||||
|
@ -103,7 +104,7 @@ function updateTempData(layerData, tmpData) {
|
||||||
else if ((!!layerData[item]) && (layerData[item].constructor === Object) || (typeof layerData[item] === "object") && traversableClasses.includes(layerData[item].constructor.name)){
|
else if ((!!layerData[item]) && (layerData[item].constructor === Object) || (typeof layerData[item] === "object") && traversableClasses.includes(layerData[item].constructor.name)){
|
||||||
updateTempData(layerData[item], tmpData[item])
|
updateTempData(layerData[item], tmpData[item])
|
||||||
}
|
}
|
||||||
else if (isFunction(layerData[item]) && !activeFunctions.includes(item)){
|
else if (isFunction(layerData[item]) && !isFunction(tmpData[item])){
|
||||||
let value = layerData[item]()
|
let value = layerData[item]()
|
||||||
if (value !== value || value === decimalNaN){
|
if (value !== value || value === decimalNaN){
|
||||||
if (NaNalert === true || confirm ("Invalid value found in tmp, named '" + item + "'. Please let the creator of this mod know! Would you like to try to auto-fix the save and keep going?")){
|
if (NaNalert === true || confirm ("Invalid value found in tmp, named '" + item + "'. Please let the creator of this mod know! Would you like to try to auto-fix the save and keep going?")){
|
||||||
|
|
|
@ -211,7 +211,8 @@ function goBack() {
|
||||||
|
|
||||||
function layOver(obj1, obj2) {
|
function layOver(obj1, obj2) {
|
||||||
for (let x in obj2) {
|
for (let x in obj2) {
|
||||||
if (obj2[x] instanceof Object) layOver(obj1[x], obj2[x]);
|
if (obj2[x] instanceof Decimal) obj1[x] = new Decimal(obj2[x])
|
||||||
|
else if (obj2[x] instanceof Object) layOver(obj1[x], obj2[x]);
|
||||||
else obj1[x] = obj2[x];
|
else obj1[x] = obj2[x];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue