diff --git a/changelog.js b/changelog.js index b17e4f8..0c30f57 100644 --- a/changelog.js +++ b/changelog.js @@ -20,6 +20,15 @@ along with this program. If not, see . function getChangeLog() { var text = ''; + text += '0.9.1 (2023-03-27):'; + text += '
• Added platinum infinity crops.'; + text += '
• New fish type added.'; + text += '
• Bees in infinity field now also give a slight boost to infinity mushrooms.'; + text += '
• Autumn now also makes mushrooms consume less seeds.'; + text += '
• Reordered how some resources are shown at the top, to line up resin/twigs, seeds/infinity seeds and spores/infinity spores.'; + text += '
• Various tweaks.'; // includes attempt at fix with mushroom priority heuristics for auto-plant and egg drop tweaks + text += '

'; + text += '0.9.0 (2023-03-23):'; text += '
• New infinity crop: golden mushroom.'; text += '
• Added ability to place fishes in the infinity pond, available once you have infinity mushrooms. Only a few fish types added in this first version of it.'; diff --git a/data.js b/data.js index ece9b94..fc0f62a 100644 --- a/data.js +++ b/data.js @@ -97,7 +97,7 @@ function getCropTypeHelp3(type, opt_have_fishes) { case CROPTYPE_STINGING: return ''; case CROPTYPE_BRASSICA: return 'Produces seeds, but has a limited lifespan. Produces more seeds than its initial cost over its lifespan.'; case CROPTYPE_MISTLETOE: return ''; - case CROPTYPE_BEE: return 'Boosts orthogonally neighboring flowers.'; + case CROPTYPE_BEE: return opt_have_fishes ? 'Boosts neighboring flowers. For the flower boost to mushrooms, also has a small effect based on tier.' : 'Boosts neighboring flowers.'; case CROPTYPE_CHALLENGE: return ''; case CROPTYPE_FERN2: return ''; case CROPTYPE_NUT: return ''; @@ -388,7 +388,7 @@ var infernal_mush_upgrade_base = Num.pow(Num(infernal_mush_tier_mul), Num(1.0 / // used for multiple possible aspects, such as production, boost if this is a flower, etc... // f is field, similar to in Crop.prototype.getProd -// result is change in-place and may be either Num or Res. Nothing is returned. +// result is changed in-place and may be either Num or Res. Nothing is returned. Crop.prototype.addSeasonBonus_ = function(result, season, f, breakdown) { // posmul is used: // Unlike other multipliers, this one does not affect negative production. This is a good thing in the crop's good season, but extra harsh in a bad season (e.g. winter) @@ -417,10 +417,12 @@ Crop.prototype.addSeasonBonus_ = function(result, season, f, breakdown) { if(season == 2 && this.type == CROPTYPE_MUSH) { var bonus = getAutumnMushroomBonus(); result.posmulInPlace(bonus); + var reduction = Num(1).sub(getAutumnMushroomConsumptionReduction()); + result.negmulInPlace(reduction); if(breakdown) breakdown.push([seasonNames[season], true, bonus, result.clone()]); } - // with ethereal upgrades, autumn also benefits mushrooms a bit, to catch up with other seasons ethereal upgrades + // with ethereal upgrades, autumn also benefits berries a bit, to catch up with other seasons ethereal upgrades if(season == 2 && (this.type == CROPTYPE_BERRY || this.type == CROPTYPE_PUMPKIN)) { var bonus = getAutumnBerryBonus(); result.posmulInPlace(bonus); @@ -2998,8 +3000,8 @@ var watercress_choice0 = registerChoiceUpgrade('brassica choice', upgrades[watercress_choice0].istreebasedupgrade = true; -var resin_choice0_resin_bonus = 0.2; -var resin_choice0_production_bonus = 0.2; +var resin_choice0_resin_bonus = 0.25; +var resin_choice0_production_bonus = 0.25; var resin_choice0 = registerChoiceUpgrade('resin choice', function() { @@ -6248,6 +6250,11 @@ function getAutumnMushroomBonus() { return bonus; } +// returns percentage to subtract, e.g. if this returns 0.3, then the consumption is 70% of the original consumption +function getAutumnMushroomConsumptionReduction() { + return new Num(0.5); +} + function getAutumnBerryBonus() { return getAutumnMushroomBonus().subr(bonus_season_autumn_mushroom).mulr(bonus_season_autumn_berry).addr(1); } @@ -7398,10 +7405,20 @@ Crop3.prototype.getProd = function(f, breakdown) { if(breakdown) breakdown.push(['goldfish', true, mul, result.clone()]); } + // octopus + if(this.type == CROPTYPE_MUSH && state.fishcount[octopus_0]) { + var num = state.fishcount[octopus_0]; + var mul = new Num(1 + octopus_0_bonus * num); + result.mulInPlace(mul); + if(breakdown) breakdown.push(['octopus', true, mul, result.clone()]); + } + // flower boost for mushroom: does not use getInfBoost, but depends on relative tier if(f && this.type == CROPTYPE_MUSH) { - var flowermul = new Num(1); - var num = 0; + var floweronlymul = new Num(1); + var flowerbeemul = new Num(1); + var num = 0; // flowers + var num2 = 0; // bees through flowers for(var dir = 0; dir < 4; dir++) { // get the neighbors N,E,S,W var x2 = f.x + (dir == 1 ? 1 : (dir == 3 ? -1 : 0)); @@ -7411,19 +7428,50 @@ Crop3.prototype.getProd = function(f, breakdown) { if(n.hasCrop() /*&& n.isFullGrown()*/ && crops3[n.cropIndex()].type == CROPTYPE_FLOWER) { var c2 = crops3[n.cropIndex()]; if(c2.tier >= this.tier - 1) { - var boost = Num(1); - if(c2.tier <= this.tier - 1) boost = Num(0.5); - if(c2.tier >= this.tier + 1) boost = Num(1.5); + var boost = new Num(1); + if(c2.tier <= this.tier - 1) boost = new Num(0.5); + if(c2.tier >= this.tier + 1) boost = new Num(1.5); if(boost.neqr(0)) { - flowermul.addInPlace(boost); + floweronlymul.addInPlace(boost); num++; - } + + var beeboost = new Num(1); + // bees neighboring the flower add another, albeit small, boost + for(var dir2 = 0; dir2 < 4; dir2++) { // get the neighbors N,E,S,W + var x3 = x2 + (dir2 == 1 ? 1 : (dir2 == 3 ? -1 : 0)); + var y3 = y2 + (dir2 == 2 ? 1 : (dir2 == 0 ? -1 : 0)); + if(x3 < 0 || x3 >= state.numw3 || y3 < 0 || y3 >= state.numh3) continue; + var n2 = state.field3[y3][x3]; + if(n2.hasCrop() /*&& n.isFullGrown()*/ && crops3[n2.cropIndex()].type == CROPTYPE_BEE) { + var c3 = crops3[n2.cropIndex()]; + if(c3.tier >= this.tier - 1) { + var boost2 = new Num(0.5); + if(c3.tier <= this.tier - 1) boost2 = new Num(0.25); + if(c3.tier >= this.tier + 1) boost2 = new Num(0.75); + if(boost2.neqr(0)) { + beeboost.addInPlace(boost2); + num2++; + } + } + } + } + boost.mulInPlace(beeboost); + flowerbeemul.addInPlace(boost); + } // end of 'boost.neqr(0)' for flower } } } if(num) { - result.mulInPlace(flowermul); - if(breakdown) breakdown.push(['flower tiers (' + num + ')', true, flowermul, result.clone()]); + // the below is same as doing just flowerbeemul, but, separately show flowers and bees in the breakdown, hence this mechanism + // NOTE: to understand the numbers: say there's one flower givin 100% boost (so doing x2), and one beehive giving 50% boost (so doing x1.5), + // then the breakdown will show +100% for flowers, +25% for bees (instead of +50%). Reason: bee gives 50% to flower's boost, so flower now gives 150% boost total (doing x2.5). + // therefore, you now get x2.5 instead of x2, which is 25% more. That's because all is expressed as bonus percentages to the mushroom, not to the flower. + // in case of multiple flowers/bees, this is all aggregated together. + var beeonlymul = flowerbeemul.div(floweronlymul); + result.mulInPlace(floweronlymul); + if(breakdown) breakdown.push(['flower tiers (' + num + ')', true, floweronlymul, result.clone()]); + result.mulInPlace(beeonlymul); + if(breakdown) breakdown.push(['bee tiers (' + num + ')', true, beeonlymul, result.clone()]); } } @@ -7596,6 +7644,7 @@ var brassica3_1 = registerBrassica3('bronze watercress', 1, Res({infseeds:25000} var brassica3_2 = registerBrassica3('silver watercress', 2, Res({infseeds:5e7}), Res({infseeds:5e7 * 4 / (3 * 24 * 3600)}), Num(0.05), 3 * 24 * 3600, metalifyPlantImages(images_watercress, metalheader2, 0)); var brassica3_3 = registerBrassica3('electrum watercress', 3, Res({infseeds:2e12}), Res({infseeds:2e12 * 2 / (24 * 3600)}), Num(0.05), 1 * 24 * 3600, metalifyPlantImages(images_watercress, metalheader3, 4)); var brassica3_4 = registerBrassica3('gold watercress', 4, Res({infseeds:100e15}), Res({infseeds:500e9}), Num(0.05), 5 * 24 * 3600, metalifyPlantImages(images_watercress, metalheader4, 0)); +var brassica3_5 = registerBrassica3('platinum watercress', 5, Res({infseeds:25e21}), Res({infseeds:100e15}), Num(0.05), 7 * 24 * 3600, metalifyPlantImages(images_watercress, metalheader5, 5, 6, 1, 1.045)); crop3_register_id = 300; var berry3_0 = registerBerry3('zinc blackberry', 0, Res({infseeds:400}), Res({infseeds:200 / (24 * 3600)}), Num(0.075), default_crop3_growtime, metalifyPlantImages(blackberry, metalheader0)); @@ -7605,21 +7654,25 @@ var berry3_2 = registerBerry3('silver blackberry', 2, Res({infseeds:2e9}), Res({ // more division since better flowers and beehives now var berry3_3 = registerBerry3('electrum blackberry', 3, Res({infseeds:100e12}), Res({infseeds:(100e12 / 32 / (24 * 3600))}), Num(0.2), default_crop3_growtime, metalifyPlantImages(blackberry, metalheader3, 4, 2)); var berry3_4 = registerBerry3('gold blackberry', 4, Res({infseeds:5e18}), Res({infseeds:50e9}), Num(0.4), default_crop3_growtime, metalifyPlantImages(blackberry, metalheader4, 2)); +var berry3_5 = registerBerry3('platinum blackberry', 5, Res({infseeds:500e21}), Res({infseeds:50e12}), Num(0.75), default_crop3_growtime, metalifyPlantImages(blackberry, metalheader5, 5, 1, undefined, 1.1)); crop3_register_id = 600; var mush3_4 = registerMushroom3('gold champignon', 4, Res({infseeds:500e18}), Res({infspores:1}), Num(0.5), default_crop3_growtime, metalifyPlantImages(champignon, metalheader4, 2)); +var mush3_5 = registerMushroom3('platinum champignon', 5, Res({infseeds:20e24}), Res({infspores:25}), Num(1), default_crop3_growtime, metalifyPlantImages(champignon, metalheader5, 6)); crop3_register_id = 900; var flower3_0 = registerFlower3('zinc anemone', 0, Res({infseeds:2500}), Num(0.5), Num(0.1), default_crop3_growtime, metalifyPlantImages(images_anemone, metalheader0, 1)); var flower3_1 = registerFlower3('bronze anemone', 1, Res({infseeds:2.5e6}), Num(1), Num(0.15), default_crop3_growtime, metalifyPlantImages(images_anemone, metalheader1)); -var flower3_2 = registerFlower3('silver anemone', 2, Res({infseeds:20e9}), Num(3), Num(0.2), default_crop3_growtime, metalifyPlantImages(images_anemone, metalheader2, 0)); +var flower3_2 = registerFlower3('silver anemone', 2, Res({infseeds:20e9}), Num(3), Num(0.2), default_crop3_growtime, metalifyPlantImages(images_anemone, metalheader2, 1, undefined, undefined, 0.9)); var flower3_3 = registerFlower3('electrum anemone', 3, Res({infseeds:1e15}), Num(12), Num(0.3), default_crop3_growtime, metalifyPlantImages(images_anemone, metalheader3, 4)); var flower3_4 = registerFlower3('gold anemone', 4, Res({infseeds:200e18}), Num(200), Num(0.6), default_crop3_growtime, metalifyPlantImages(images_anemone, metalheader4, 0)); +var flower3_5 = registerFlower3('platinum anemone', 5, Res({infseeds:20e24}), Num(2500), Num(1), default_crop3_growtime, metalifyPlantImages(images_anemone, metalheader5, 5)); crop3_register_id = 1200; var bee3_2 = registerBee3('silver bee nest', 2, Res({infseeds:200e9}), Num(4), Num(0.5), default_crop3_growtime, metalifyPlantImages(images_beenest, metalheader2, 0)); var bee3_3 = registerBee3('electrum bee nest', 3, Res({infseeds:10e15}), Num(32), Num(0.75), default_crop3_growtime, metalifyPlantImages(images_beenest, metalheader3, 4)); var bee3_4 = registerBee3('gold bee nest', 4, Res({infseeds:5e21}), Num(256), Num(1.5), default_crop3_growtime, metalifyPlantImages(images_beenest, metalheader4, 0)); +var bee3_5 = registerBee3('platinum bee nest', 5, Res({infseeds:500e24}), Num(2048), Num(4), default_crop3_growtime, metalifyPlantImages(images_beenest, metalheader5, 1, 5, 6, 1.05)); // Time that runestone, or crops next to it, cannot be deleted. Reason for this long no-deletion time: to not make it so that you want to change layout of infinity field all the time between basic field or infinity field focused depending on whether you get some actual production in basic field // the reason for 20 instead of 24 hours is to allow taking action slightly earlier next day, rather than longer @@ -7639,12 +7692,14 @@ function haveInfinityField() { //////////////////////////////////////////////////////////////////////////////// var fishtype_index = 0; -var FISHTYPE_GOLDFISH = fishtype_index++; // infinity field production bonus -var FISHTYPE_KOI = fishtype_index++; // infinity field to basic field bonus +var FISHTYPE_GOLDFISH = fishtype_index++; // infinity berry production bonus +var FISHTYPE_KOI = fishtype_index++; // runestone basic field boost bonus +var FISHTYPE_OCTOPUS = fishtype_index++; // infinity mushroom production bonus function getFishTypeName(type) { - if(type == FISHTYPE_GOLDFISH) return 'Goldfish'; - if(type == FISHTYPE_KOI) return 'Koi'; + if(type == FISHTYPE_GOLDFISH) return 'goldfish'; + if(type == FISHTYPE_KOI) return 'koi'; + if(type == FISHTYPE_OCTOPUS) return 'octopus'; return 'unknown'; } @@ -7725,14 +7780,24 @@ function registerKoi(name, tier, cost, effect_description, image, opt_tagline) { return index; } +function registerOctopus(name, tier, cost, effect_description, image, opt_tagline) { + var index = registerFish(name, FISHTYPE_OCTOPUS, tier, cost, effect_description, image, opt_tagline); + //var fish = fishes[index]; + return index; +} + fish_register_id = 100; var goldfish_0_bonus = 0.1; -var goldfish_0 = registerGoldfish('goldfish', 0, Res({infspores:5000}), 'Improves infinity seeds production by ' + Num(goldfish_0_bonus).toPercentString(), image_goldfish0); +var goldfish_0 = registerGoldfish('goldfish', 0, Res({infspores:5000}), 'Improves infinity berry production by ' + Num(goldfish_0_bonus).toPercentString(), image_goldfish0); fish_register_id = 200; var koi_0_bonus = 0.2; var koi_0 = registerKoi('koi', 0, Res({infspores:20000}), 'Improves runestone bonus by ' + Num(koi_0_bonus).toPercentString(), image_koi0); +fish_register_id = 300; +var octopus_0_bonus = 0.25; +var octopus_0 = registerOctopus('octopus', 0, Res({infspores:100000}), 'Improves infinity mushroom production by ' + Num(octopus_0_bonus).toPercentString(), image_octopus0); + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -8601,6 +8666,12 @@ registerPlantTypeMedal3(brassica3_4); registerPlantTypeMedal3(berry3_4); registerPlantTypeMedal3(flower3_4); registerPlantTypeMedal3(bee3_4); +registerPlantTypeMedal3(mush3_4); +registerPlantTypeMedal3(brassica3_5); +registerPlantTypeMedal3(berry3_5); +registerPlantTypeMedal3(flower3_5); +registerPlantTypeMedal3(bee3_5); +registerPlantTypeMedal3(mush3_5); diff --git a/game.js b/game.js index 0c28507..e65e2d5 100755 --- a/game.js +++ b/game.js @@ -1184,6 +1184,7 @@ function PreCell(x, y) { this.flowerneighbor = false; // how many flower neighbors of highest tier + // ideally heuristics are tier-independent, however there is a system for alternating whether flowers are upgraded next to berries and mushrooms and that needs to know the tiers this.bestflowers = 0; // set of relevant neighbor types brassica has, set in brassica cells, as bit flags: 1 = berry, 2 = mushroom, 4 = nuts @@ -1846,7 +1847,8 @@ function precomputeField_(prefield, opt_pretend) { var p = prefield[y][x]; var score_flower = 0; - var score_num = 0; + var score_num = 0; // num berries + var score_num_good = 0; // num berries with highest tier flower var score_mul = 1; var score_malus = 1; @@ -1871,12 +1873,15 @@ function precomputeField_(prefield, opt_pretend) { if(c2.type == CROPTYPE_FLOWER) score_flower += (1 + p.num_bee); if(c2.type == CROPTYPE_BRASSICA) score_mul *= ((state.cropcount[brassica_0] > 4) ? 1.25 : 2) * (have_brassica_fruit ? 3 : 1); if(c2.type == CROPTYPE_STINGING) score_mul++; - if((c2.type == CROPTYPE_BERRY || c2.type == CROPTYPE_PUMPKIN) && p2.bestflowers) score_num++; + if(c2.type == CROPTYPE_BERRY || c2.type == CROPTYPE_PUMPKIN) { + score_num++; + if(p2.bestflowers) score_num_good++; + } } } if(c.type == CROPTYPE_MUSH) { if(winter && !p.treeneighbor) score_malus *= 0.5; - p.score = (1 + score_flower) * score_mul * (score_num ? 1 : 0) * score_malus; + p.score = (1 + score_flower) * score_mul * (score_num ? 1 : 0) * (score_num_good ? 1.5 : 1) * score_malus; } } } @@ -2346,6 +2351,12 @@ function maybeUnlockInfinityCrops() { if(state.crops3[berry3_4].had) unlockInfinityCrop(flower3_4); if(state.crops3[flower3_4].had) unlockInfinityCrop(bee3_4); if(state.crops3[berry3_4].had) unlockInfinityCrop(mush3_4); + + if(state.crops3[berry3_4].had) unlockInfinityCrop(brassica3_5); + if(state.crops3[brassica3_5].had) unlockInfinityCrop(berry3_5); + if(state.crops3[berry3_5].had) unlockInfinityCrop(flower3_5); + if(state.crops3[flower3_5].had) unlockInfinityCrop(bee3_5); + if(state.crops3[berry3_5].had) unlockInfinityCrop(mush3_5); } // may only be called if the fishes feature in the infinity field is already unlocked (haveFishes() returns true) @@ -2353,6 +2364,8 @@ function maybeUnlockFishes() { var first_fish_unlocked = state.fishes[goldfish_0].unlocked; unlockFish(goldfish_0); unlockFish(koi_0); + //if(state.crops3[koi_0].had) unlockFish(octopus_0); + unlockFish(octopus_0); var first_fish_unlocked2 = state.fishes[goldfish_0].unlocked; if(!first_fish_unlocked && first_fish_unlocked2) showRegisteredHelpDialog(43); @@ -5211,7 +5224,7 @@ var update = function(opt_ignorePause) { if(g.seeds.lt(starter.seeds)) g.seeds = Num.max(g.seeds, starter.seeds); if(g.seeds.ltr(10)) g.seeds = Num.max(g.seeds, Num(10)); var presentres = new Res({seeds:g.seeds}); - if(basic) presentres = presentres.mulr(0.2); + if(basic) presentres = presentres.mulr(0.3); if(holidayEventActive() == 1) { showMessage('That present contained: ' + presentres.toString(), C_PRESENT, 38753631, 0.8, true); } else { @@ -5220,10 +5233,12 @@ var update = function(opt_ignorePause) { actualgain.addInPlace(presentres); } else if(effect == 2) { // spores - var g = computeFernGain().mulr(60 * 5); - if(g.spores.ltr(1)) g.spores = Num.max(g.spores, Num(1)); - var presentres = new Res({spores:g.spores}); - if(basic) presentres = presentres.mulr(0.2); + var g = computeFernGain().spores.mulr(60 * 5); + var g2 = state.c_res.spores.mulr(0.0035); // in case there is no spore production, e.g. no mushrooms, give something based on spores produced so far anyway + if(g.lt(g2)) g = g2; + if(basic) g = g.mulr(0.3); + if(g.ltr(1)) g = Num.max(g, Num(1)); + var presentres = new Res({spores:g}); if(holidayEventActive() == 1) { showMessage('That present contained: ' + presentres.toString(), C_PRESENT, 38753631, 0.8, true); } else { diff --git a/images_plants.js b/images_plants.js index 8637d70..7c8ccc1 100644 --- a/images_plants.js +++ b/images_plants.js @@ -1,6 +1,6 @@ /* Ethereal Farm -Copyright (C) 2020-2022 Lode Vandevenne +Copyright (C) 2020-2023 Lode Vandevenne This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -339,44 +339,62 @@ var image_missingfish = createFishImage( ........$$...... `); +var image_goldfish0 = createFishImage(` ++:#fb8a X:#fb8 O:#d96 +................ +.......+++...... +.......++++..... +.......+++++.... +......XXO+++...+ +....XZXOXOX+.+++ +...XZ0ZXOXOXO+++ +..XXXZXOXOXOO+.. +..XXOXOXOXOOO... +...OXOXOXOOOO+.. +....OOOOOO++.++. +......OOO.++.+++ +......++......++ +......+++....... +.......++....... +................ +`); + var image_koi0 = createFishImage(` ................ ................ ................ ................ ................ -......999......9 -..999999$$$9..99 -.909$$999999999. -9$9$$$99$$$9999. -9999999$$$$$9.99 -9..99.9........9 -....9..9........ +9......999...... +99..9$$$999999.. +.999999999$$909. +.9999$$$99$$$9$9 +99.9$$$$$9999999 +9........9.99..9 +........9..9.... ................ ................ ................ ................ `); - - -var image_goldfish0 = createFishImage(` -+:#fb8a X:#fb8 -................ -.......+++...... -.......++++..... -.......+++++.... -......XXX+++...+ -....XZXXXXX+.+++ -...XZ0ZXXXXXX+++ -..XXXZXXXXXXX+.. -..XXXXXXXXXXX... -...XXXXXXXXXX+.. -....XXXXXX++.++. -......XXX.++.+++ -......++......++ -......+++....... -.......++....... +var image_octopus0 = createFishImage(` +aa:#d33 +......999N...... +....99NNNNNN.... +...9NNNNNNNNN... +...9NNNNNNNNN... +..9NNNNNNNNNNN.. +..NN90NNNN90NM.. +..NN00NNNN00NM.. +..NNNNNNNNNNNM.. +...NNN0NN0NNM... +...NNNN00NNNM... +.NNNNNNNNNMMMNN. +.NM.NNNMMMNN.NM. +....NM.NN.NM.... +....NM.NM.NM.... +.......NM....... ................ `); @@ -6084,13 +6102,16 @@ function metalify_nonlincolor(v) { } // metalheader = metalheader0 for zinc, etc... They use the colors N,M,m,n (hue range hm) for the metal colors -// opt_effect and opt_effect2: operation done to make things more distinguishable if needed. Second can be given to apply two of the effects. +// opt_effect, opt_effect2, opt_effect3: operation done to make things more distinguishable if needed. Second can be given to apply two of the effects. // *) 0/undefined: no effect // *) 1: darken // *) 2: brighten // *) 3: shiny // *) 4: increase saturation slightly (to make electrum a bit more green) -function metalify(im, metalheader, opt_effect, opt_effect2) { +// *) 5: effect specifically for platinum infinity crops on the bright infinity field background, to have some contrast +// *) 6: subtle bottom right shadow, again to provide contrast for bright crops like the platinum ones against infinity field background +// opt_param: parameter used for the darken or brighten effect (shared also for opt_effect2 and opt_effect3), if not set a default value is used +function metalify(im, metalheader, opt_effect, opt_effect2, opt_effect3, opt_param) { var pal = generatePalette(metalheader); var m = []; m[0] = pal['0']; // black @@ -6122,17 +6143,19 @@ function metalify(im, metalheader, opt_effect, opt_effect2) { r = m[i][0] * f0 + m[i2][0] * f1; g = m[i][1] * f0 + m[i2][1] * f1; b = m[i][2] * f0 + m[i2][2] * f1; - if(opt_effect == 1 || opt_effect2 == 1) { - r *= 0.5; - g *= 0.5; - b *= 0.5; + if(opt_effect == 1 || opt_effect2 == 1 || opt_effect3 == 1) { + var amount = opt_param || 0.5; + r *= amount; + g *= amount; + b *= amount; } - if(opt_effect == 2 || opt_effect2 == 2) { - r = Math.min(r * 1.35, 255); - g = Math.min(g * 1.35, 255); - b = Math.min(b * 1.35, 255); + if(opt_effect == 2 || opt_effect2 == 2 || opt_effect3 == 2) { + var amount = opt_param || 1.35; + r = Math.min(r * amount, 255); + g = Math.min(g * amount, 255); + b = Math.min(b * amount, 255); } - if(opt_effect == 3 || opt_effect2 == 3) { + if(opt_effect == 3 || opt_effect2 == 3 || opt_effect3 == 3) { //l = (0.299 * r + 0.587 * g + 0.114 * b) / 255; var d = 1 - (x + y) / (w + h - 2); //d = Math.sin(d * 16) * 64; @@ -6144,7 +6167,7 @@ function metalify(im, metalheader, opt_effect, opt_effect2) { g = Math.min(Math.max(0, g + d), 255); b = Math.min(Math.max(0, b + d), 255); } - if(opt_effect == 4 || opt_effect2 == 4) { + if(opt_effect == 4 || opt_effect2 == 4 || opt_effect3 == 4) { var hsv = RGBtoHSV([r, g, b]); hsv[1] = Math.min(hsv[1] * 2, 255); var rgb = HSVtoRGB(hsv); @@ -6152,17 +6175,42 @@ function metalify(im, metalheader, opt_effect, opt_effect2) { g = rgb[1]; b = rgb[2]; } + if(opt_effect == 5 || opt_effect2 == 5 || opt_effect3 == 5) { + r /= 255; + g /= 255; + b /= 255; + r = r * r * r + 0.05; + g = g * g * g + 0.05; + b = b * b * b + 0.05; + r = Math.min(Math.max(0, r * 255), 255); + g = Math.min(Math.max(0, g * 255), 255); + b = Math.min(Math.max(0, b * 255), 255); + } + if(opt_effect == 6 || opt_effect2 == 6 || opt_effect3 == 6) { + if(a == 255) { + var touching_transparent = false; + //if(x > 0 && im[y][x - 1][3] == 0) touching_transparent = true; + //if(y > 0 && im[y - 1][x][3] == 0) touching_transparent = true; + if(x + 1 < w && im[y][x + 1][3] == 0) touching_transparent = true; + if(y + 1 < w && im[y + 1][x][3] == 0) touching_transparent = true; + if(touching_transparent) { + r *= 0.85; + g *= 0.85; + b *= 0.85; + } + } + } res[y][x] = [r, g, b, a]; } } return [res, w, h]; } -function metalifyPlantImages(images, metalheader, opt_effect, opt_effect2) { +function metalifyPlantImages(images, metalheader, opt_effect, opt_effect2, opt_effect3, opt_param) { var result = []; for(var i = 0; i < images.length; i++) { var im = images[i]; - result[i] = createCanvasImageFor(metalify(im[4], metalheader, opt_effect, opt_effect2)); + result[i] = createCanvasImageFor(metalify(im[4], metalheader, opt_effect, opt_effect2, opt_effect3, opt_param)); } return result; } diff --git a/main.js b/main.js index 23edf74..e3214de 100644 --- a/main.js +++ b/main.js @@ -25,7 +25,7 @@ along with this program. If not, see . // -sub: 0..any: does not change the numeric version code. if non-0, adds 'b', 'c'. ... to the version name. Should not affect savegame format. Cosmetic changes only. Version name including this part is appended to CSS URL query part to ensure no stale cached CSS file is used. var version_major = 0; // 0..61 var version_minor = 9; // 0..4095 -var version_patch = 0; // 0..63 +var version_patch = 1; // 0..63 var version_sub = 0; // 0=no suffix, 1=b, 2=c, ... var version = 262144 * (version_major + 2) + 64 * version_minor + version_patch; diff --git a/style_dark.css b/style_dark.css index 6cc6e07..03a5ab1 100644 --- a/style_dark.css +++ b/style_dark.css @@ -303,3 +303,10 @@ but it doesn't work on translucent background, so cannot use it here. So this mu .efNoOutline:focus { outline: unset; } + +.efHighlightResource { + /*border: 2px solid #5555;*/ + text-shadow: 0 0 0.1em #fbb, 0 0 0.1em #fbb, 0 0 0.1em #fbb, 0 0 0.1em #fbb; + border-color: #fbb !important; + border-width: 3px !important; +} diff --git a/style_dark2.css b/style_dark2.css index a876120..083c216 100644 --- a/style_dark2.css +++ b/style_dark2.css @@ -303,3 +303,10 @@ but it doesn't work on translucent background, so cannot use it here. So this mu .efNoOutline:focus { outline: unset; } + +.efHighlightResource { + /*border: 2px solid #5555;*/ + text-shadow: 0 0 0.1em #fbb, 0 0 0.1em #fbb, 0 0 0.1em #fbb, 0 0 0.1em #fbb; + border-color: #fbb !important; + border-width: 3px !important; +} diff --git a/style_light.css b/style_light.css index 6200d88..7d365a2 100644 --- a/style_light.css +++ b/style_light.css @@ -275,4 +275,11 @@ but it doesn't work on translucent background, so cannot use it here. So this mu outline: unset; } +.efHighlightResource { + /*border: 2px solid #5555;*/ + text-shadow: 0 0 0.1em #b44, 0 0 0.1em #b44, 0 0 0.1em #b44, 0 0 0.1em #b44; + border-color: #b44 !important; + border-width: 3px !important; +} + diff --git a/ui_amber.js b/ui_amber.js index 8b91f16..9f96cb9 100644 --- a/ui_amber.js +++ b/ui_amber.js @@ -1,6 +1,6 @@ /* Ethereal Farm -Copyright (C) 2020-2022 Lode Vandevenne +Copyright (C) 2020-2023 Lode Vandevenne This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -79,6 +79,7 @@ function updateAmberUI() { button.id = 'amber_prod'; if(state.amberprod) button.className = 'efButtonAmberActive'; else if(state.res.amber.lt(ambercost_prod)) button.className = 'efButtonCantAfford'; + else if(basicChallenge()) button.className = 'efButtonCantAfford'; if(!state.amberkeepseason) { button = makeAmberButton('Season hold this run', AMBER_KEEP_SEASON); diff --git a/ui_info.js b/ui_info.js index 338b6bd..c34d08e 100644 --- a/ui_info.js +++ b/ui_info.js @@ -418,7 +418,7 @@ function showResourceDialog(index) { var special = (index == 2 || index == 3 || index == 7); // if true, is resource that doesn't have income/s stat // computed here rather than inside of updatedialogfun to avoid it being too slow // NOTE: this means it doesn't get auto-updated though. - var breakdown = (index == 5) ? prodBreakdown3(index) : prodBreakdown(index); + var breakdown = (index == 5 || index == 8) ? prodBreakdown3(index) : prodBreakdown(index); if(breakdown == '') breakdown = ' • None yet'; var flex = dialog.content; var last = undefined; @@ -477,7 +477,7 @@ function showResourceDialog(index) { } // i = index of div, index = index of resource -function showResource(i, index) { +function showResource(i, index, highlight) { var name = resource_names[index]; var res = state.res.atIndex(index); var upcoming; @@ -496,6 +496,14 @@ function showResource(i, index) { var div = resourceDivs[i]; + if(highlight && !div.highlightClassAdded) { + div.classList.add('efHighlightResource'); + div.highlightClassAdded = true; + } else if(!highlight && div.highlightClassAdded) { + div.classList.remove('efHighlightResource'); + div.highlightClassAdded = false; + } + var res_gain; var res_gain_pos; var res_gain_hyp; @@ -610,7 +618,7 @@ function openTimeInfoDialog() { } } if(s == 2) { - result += '• +' + getAutumnMushroomBonus().subr(1).toPercentString() + ' bonus to mushroom spores production, without increasing consumption
'; + result += '• +' + getAutumnMushroomBonus().subr(1).toPercentString() + ' bonus to mushroom spores production, ' + getAutumnMushroomConsumptionReduction().toPercentString() + ' less seed consumption
'; if(getAutumnBerryBonus().neqr(1)) { result += '• +' + getAutumnBerryBonus().subr(1).toPercentString() + ' bonus to berry seed production
'; } @@ -690,7 +698,9 @@ function updateResourceUI() { if(getSeason() != lastRenderedInfoSeasonBackground) { lastRenderedInfoSeasonBackground = getSeason(); for(var i = 0; i < resourceDivs.length; i++) { - resourceDivs[i].className = 'efInfo ' + season_styles[getSeason()];; + var div = resourceDivs[i]; + resourceDivs[i].className = 'efInfo ' + season_styles[getSeason()]; + if(div.highlightClassAdded) div.highlightClassAdded = false; } } @@ -760,17 +770,37 @@ function updateResourceUI() { var show_infseeds = haveInfinityField(); var show_infspores = haveInfinityField() && state.res.infspores.gtr(0); - - var i = 1; // index in resourceDivs - if(state.g_max_res.seeds.neqr(0)) showResource(i++, 0); - if(state.g_max_res.spores.neqr(0))showResource(i++, 1); - if(state.g_max_res.resin.neqr(0) || state.resin.neqr(0)) showResource(i++, 2); - if(state.g_max_res.twigs.neqr(0) || state.twigs.neqr(0) || state.upgrades2[upgrade2_mistletoe].count) showResource(i++, 3); - if(!show_infspores) if(state.g_max_res.essence.neqr(0)) showResource(i++, 7); - if(state.g_max_res.nuts.neqr(0)) showResource(i++, 4); - if(show_infseeds) showResource(i++, 5); - else if(state.g_max_res.amber.neqr(0)) showResource(i++, 6); - if(show_infspores) showResource(i++, 8); + // when a new resource is added but not at the end of the resource info chips, highlight it so the fact that there's a new resource is more visible. Stop highlighting after a while, measured by having earned an amount worth a couple of hours to a day of gameplay + var highlight_nuts = !show_infseeds && state.g_res.nuts.gtr(0) && state.g_res.nuts.ltr(5000); + var highlight_infseeds = !show_infspores && show_infseeds && state.g_res.infseeds.ltr(50); + var highlight_infspores = show_infspores && state.g_res.infspores.ltr(100000); + + var i = 1; // index in resourceDivs. 0 is the time. + if(!show_infseeds && !show_infspores) { + if(state.g_max_res.seeds.neqr(0)) showResource(i++, 0); + if(state.g_max_res.spores.neqr(0))showResource(i++, 1); + if(state.g_max_res.resin.neqr(0) || state.resin.neqr(0)) showResource(i++, 2); + if(state.g_max_res.nuts.neqr(0)) showResource(i++, 4, highlight_nuts); + if(state.g_max_res.amber.neqr(0)) showResource(i++, 6); + if(state.g_max_res.essence.neqr(0)) showResource(i++, 7); + if(state.g_max_res.twigs.neqr(0) || state.twigs.neqr(0) || state.upgrades2[upgrade2_mistletoe].count) showResource(i++, 3); + } else if(show_infseeds && !show_infspores) { + if(state.g_max_res.seeds.neqr(0)) showResource(i++, 0); + if(state.g_max_res.spores.neqr(0))showResource(i++, 1); + if(state.g_max_res.resin.neqr(0) || state.resin.neqr(0)) showResource(i++, 2); + if(state.g_max_res.nuts.neqr(0)) showResource(i++, 4, highlight_nuts); + showResource(i++, 5, highlight_infseeds); // infinity seeds + if(state.g_max_res.essence.neqr(0)) showResource(i++, 7); + if(state.g_max_res.twigs.neqr(0) || state.twigs.neqr(0) || state.upgrades2[upgrade2_mistletoe].count) showResource(i++, 3); + } else { // show infseeds and infspores + if(state.g_max_res.seeds.neqr(0)) showResource(i++, 0); + if(state.g_max_res.spores.neqr(0))showResource(i++, 1); + if(state.g_max_res.resin.neqr(0) || state.resin.neqr(0)) showResource(i++, 2); + if(state.g_max_res.nuts.neqr(0)) showResource(i++, 4, highlight_nuts); + showResource(i++, 5, highlight_infseeds); // infinity seeds + showResource(i++, 8, highlight_infspores); // infinity spores + if(state.g_max_res.twigs.neqr(0) || state.twigs.neqr(0) || state.upgrades2[upgrade2_mistletoe].count) showResource(i++, 3); + } } function initInfoUI() {