Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Gem pages, Type-catch quest pages, requirements fix #220

Merged
merged 5 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 158 additions & 11 deletions bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -77325,8 +77325,8 @@ themes.options.sort((a, b) => (a.text).localeCompare(b.text));
// Suppress game notifications
Notifier.notify = () => {};

// Ensure weather never satisfies requirements so they are always shown
Weather.currentWeather = () => -1;
// Ensure requirements are never satisfied so they are always shown
Requirement.prototype.isCompleted = () => false;

// Not sure why but this was causing an error on load after the v0.10.22 update
SortModules = () => {};
Expand Down Expand Up @@ -77381,6 +77381,7 @@ GemDeals.generateDeals();
ShardDeal.generateDeals();
GenericDeal.generateDeals();
SafariPokemonList.generateSafariLists(); // This needs to be after anything that generates shopmon due to Friend Safari calcs
Weather.generateWeather(now);

// Farm Simulator
App.game.farming.plotList.forEach((p) => p.isUnlocked = true); // All plots unlocked
Expand Down Expand Up @@ -77757,11 +77758,12 @@ window.Wiki = {
shopMon: require('./pages/shopMon'),
dungeonTokens: require('./pages/dungeonTokens'),
oakItems: require('./pages/oakItems'),
gems: require('./pages/gems'),
getDealChains: require('./pages/dealChains').getDealChains,
...require('./navigation'),
}

},{"../pokeclicker/package.json":502,"./components":503,"./datatables":504,"./discord":505,"./game":506,"./gameHelper":507,"./markdown-renderer":514,"./navigation":515,"./notifications":516,"./pages/dealChains":517,"./pages/dreamOrbs":518,"./pages/dungeonTokens":519,"./pages/dungeons":520,"./pages/farm":521,"./pages/farmSimulator":522,"./pages/items":523,"./pages/oakItems":524,"./pages/pokemon":525,"./pages/shopMon":526,"./typeahead":528}],509:[function(require,module,exports){
},{"../pokeclicker/package.json":502,"./components":503,"./datatables":504,"./discord":505,"./game":506,"./gameHelper":507,"./markdown-renderer":514,"./navigation":515,"./notifications":516,"./pages/dealChains":517,"./pages/dreamOrbs":518,"./pages/dungeonTokens":519,"./pages/dungeons":520,"./pages/farm":521,"./pages/farmSimulator":522,"./pages/gems":523,"./pages/items":524,"./pages/oakItems":525,"./pages/pokemon":526,"./pages/shopMon":527,"./typeahead":529}],509:[function(require,module,exports){
const { md } = require('./markdown-renderer');

const getContent = (editor) => editor.value().split('\n').map(l => l.trimEnd()).join('\n');
Expand Down Expand Up @@ -78251,7 +78253,7 @@ module.exports = {
gotoPageClick,
};

},{"./datatables":504,"./markdown-editor":509,"./markdown-renderer":514,"./redirections":527}],516:[function(require,module,exports){
},{"./datatables":504,"./markdown-editor":509,"./markdown-renderer":514,"./redirections":528}],516:[function(require,module,exports){
const alert = (message, type = 'primary', timeout = 5e3) => {
const wrapper = document.createElement('div');
wrapper.classList.add('alert', `alert-${type}`, 'alert-dismissible', 'fade', 'show');
Expand Down Expand Up @@ -78523,7 +78525,7 @@ const highestRoute = (region, weather) => {
const GBMB = (DT* (catchChanceAV+.15))/(2);
const UB = (DT* (catchChanceAV+.1))/(1.75)
const UBMB = (DT* (catchChanceAV+.2))/(1.75);
routeArr.push( [Routes.getRoute(region,route.number).routeName, DT.toLocaleString(), +(PB). toFixed(2), +(PBMB). toFixed(2), +(GB). toFixed(2), +(GBMB). toFixed(2), +(UB). toFixed(2), +(UBMB). toFixed(2)] );
routeArr.push([Routes.getRoute(region,route.number).routeName, DT.toLocaleString(), +(PB).toFixed(2), +(PBMB).toFixed(2), +(GB).toFixed(2), +(GBMB).toFixed(2), +(UB).toFixed(2), +(UBMB).toFixed(2)])
})

var highestPB = routeArr.reduce((max, dt) => {
Expand Down Expand Up @@ -79296,6 +79298,146 @@ module.exports = {
}

},{}],523:[function(require,module,exports){
// routeAvgHp copied from PokemonFactory.generateWildPokemon
const routeAvgHp = (region, route) => {
const poke = [...new Set(Object.values(Routes.getRoute(region, route).pokemon).flat().map(p => p.pokemon ?? p).flat())];
const total = poke.map(p => pokemonMap[p].base.hitpoints).reduce((s, a) => s + a, 0);
return total / poke.length;
};

const getStandardEncounters = (route) => {
return Object.values(route.pokemon).flat().filter((p) => typeof p === 'string');
}

const maxRouteHp = (regionRoutes, routeName) => {
const route = regionRoutes.find((r) => r.routeName === routeName);
const allMons = getStandardEncounters(route);
const maxHpStat = Math.max(...allMons.map((p) => PokemonHelper.getPokemonByName(p).hitpoints));
return Math.round(PokemonFactory.routeHealth(route.number, route.region) * (0.9 + (maxHpStat / routeAvgHp(route.region, route.number)) / 10));
}

const maxGymHp = (gymName) => {
return Math.max(...GymList[gymName].pokemons.map((p) => p.maxHealth));
}

const gemsPerPokemon = (pokemonName, gemType) => {
const pokemon = PokemonHelper.getPokemonByName(pokemonName);
const targetType = PokemonType[gemType];
if (pokemon.type2 === PokemonType.None) {
return pokemon.type1 === targetType ? 2 : 0;
} else {
return (pokemon.type1 === targetType || pokemon.type2 === targetType) ? 1 : 0;
}
}

const gemsPerGymEncounter = (gymName, gemType) => {
const gym = GymList[gymName];
const totalMons = gym.pokemons.length;
const totalGemsOfType = gym.pokemons.reduce((acc, p) => acc + 5 * gemsPerPokemon(p.name, gemType), 0);
return totalGemsOfType / totalMons;
}

const gemsPerRouteEncounter = (route, gemType) => {
const allMons = getStandardEncounters(route);
const totalMons = allMons.length;
const totalGemsOfType = allMons.reduce((acc, p) => acc + gemsPerPokemon(p, gemType), 0);
return totalGemsOfType / totalMons;
}

const bestGemsPerRegion = (region, gemType) => {
const regionRoutes = Routes.regionRoutes.filter((r) => r.region == region);
const allRouteGems = regionRoutes.map((route) => ({
battleType: "Route",
name: route.routeName,
gemsPerEncounter: gemsPerRouteEncounter(route, gemType),
}));

const regionGyms = GameConstants.RegionGyms[region].filter((g) => !g.includes('Trial'));
const allGymGems = regionGyms.map((gym) => ({
battleType: "Gym",
name: gym,
gemsPerEncounter: gemsPerGymEncounter(gym, gemType),
}));

return allRouteGems.concat(allGymGems)
.filter((battle) => battle.gemsPerEncounter > 0)
.sort((a, b) => b.gemsPerEncounter - a.gemsPerEncounter)
.splice(0, 2)
.map((gemData) => {
gemData.maxHealth = gemData.battleType === "Route" ? maxRouteHp(regionRoutes, gemData.name) : maxGymHp(gemData.name);
return gemData;
});
}

const bestCaptureRoutesPerRegion = (region, type) => {
const regionRoutes = Routes.regionRoutes.filter((r) => r.region == region);
const currentWeather = Weather.regionalWeather[region]();
const today = GameHelper.today().getDay();
const allRegionRoutesTypeCatchChance = regionRoutes.map((route) => {
const normalEncounters = getStandardEncounters(route);
const specialEncounters = route.pokemon.special.flatMap((special) => {
if (special.req instanceof OneFromManyRequirement || special.req instanceof SpecialEventRandomRequirement) {
// OneFromMany is Santa Jynx only
return [];
}
if (special.req instanceof WeatherRequirement) {
return special.req.weather.includes(currentWeather) ? special.pokemon : [];
}
if (special.req instanceof DayOfWeekRequirement) {
return special.req.DayOfWeekNum === today ? special.pokemon : [];
}
if (special.req instanceof MultiRequirement) {
// This might not cover all permutations of requirements
if (special.req.requirements.find((req) => req instanceof SpecialEventRequirement)) return [];
const weatherReq = special.req.requirements.find((req) => req instanceof WeatherRequirement);
if (weatherReq) return weatherReq.weather.includes(currentWeather) ? special.pokemon : [];
const dayReq = special.req.requirements.find((req) => req instanceof DayOfWeekRequirement);
if (dayReq) return dayReq.DayOfWeekNum === today ? special.pokemon : [];
}
return special.pokemon
});

const allEncounters = normalEncounters.concat(specialEncounters);
const typeCatchChances = allEncounters.map((p) => {
const pokemon = PokemonHelper.getPokemonByName(p);
return (pokemon.type1 === type || pokemon.type2 === type) ? PokemonFactory.catchRateHelper(pokemon.catchRate, true) : 0;
});
return {
route: route,
catchChances: typeCatchChances,
};
});

const allRoutesWithType = allRegionRoutesTypeCatchChance.filter((route) => route.catchChances.some((chance) => chance > 0));
const allRoutesWithCatchBonuses = allRoutesWithType.map((route) => {
const encounters = route.catchChances.length;
return {
route: route.route,
pokeball: route.catchChances.reduce((a, b) => a + b, 0) / encounters,
ultraball: route.catchChances.map((chance) => chance > 0 ? chance + 10 : chance).reduce((a, b) => a + b, 0) / encounters,
ultraballMagicBall: route.catchChances.map((chance) => chance > 0 ? chance + 20 : chance).reduce((a, b) => a + b, 0) / encounters,
}
});
return allRoutesWithCatchBonuses
.sort((a, b) => b.ultraballMagicBall - a.ultraballMagicBall)
.splice(0, 2)
.map((route) => {
return {
...route,
weather: currentWeather,
today: today,
maxHealth: maxRouteHp(regionRoutes, route.route.routeName),
}
});
}


module.exports = {
bestGemsPerRegion,
bestCaptureRoutesPerRegion,
}

},{}],524:[function(require,module,exports){
const getItemName = (itemType, itemId) => {
switch (itemType) {
case ItemType.item:
Expand Down Expand Up @@ -79387,7 +79529,7 @@ module.exports = {
getItemCategoryAndPageFromObject,
};

},{}],524:[function(require,module,exports){
},{}],525:[function(require,module,exports){
const getOakItemBonus = (oakItem, level) => {
const bonus = oakItem.bonusList[level];
switch (oakItem.name) {
Expand Down Expand Up @@ -79461,7 +79603,7 @@ module.exports = {
getOakItemBonus,
getOakItemUpgradeReq,
};
},{}],525:[function(require,module,exports){
},{}],526:[function(require,module,exports){

const getBreedingAttackBonus = (vitaminsUsed, baseAttack) => {
const attackBonusPercent = (GameConstants.BREEDING_ATTACK_BONUS + vitaminsUsed[GameConstants.VitaminType.Calcium]) / 100;
Expand Down Expand Up @@ -79551,7 +79693,7 @@ module.exports = {
battleCafeToHumanReadableString,
}

},{}],526:[function(require,module,exports){
},{}],527:[function(require,module,exports){
function getShopItemsByCurrencyAndFilter(currency, itemFilter) {
var towns = Object.values(TownList).filter(t => t.region <= GameConstants.MAX_AVAILABLE_REGION);
var filteredTowns = [];
Expand Down Expand Up @@ -79597,7 +79739,7 @@ module.exports = {
getShopItems,
getUniqueItems,
};
},{}],527:[function(require,module,exports){
},{}],528:[function(require,module,exports){
const redirections = [
({type, name}) => {
if (type === 'Pokemon') {
Expand Down Expand Up @@ -79649,7 +79791,7 @@ module.exports = {
redirections
};

},{}],528:[function(require,module,exports){
},{}],529:[function(require,module,exports){
const { gotoPage } = require('./navigation');
const { getAvailablePokemon } = require('./pages/pokemon');

Expand Down Expand Up @@ -79712,6 +79854,11 @@ const searchOptions = [
type: 'Gems',
page: t,
})),
...GameHelper.enumStrings(PokemonType).filter(t => t != 'None').map(t => ({
display: `${t} Catch Type Quests`,
type: 'Catch Type Quests',
page: t,
})),
// Berries
{
display: 'Berries',
Expand Down Expand Up @@ -80119,4 +80266,4 @@ module.exports = {
searchOptions,
};

},{"./navigation":515,"./pages/pokemon":525}]},{},[508]);
},{"./navigation":515,"./pages/pokemon":526}]},{},[508]);
5 changes: 5 additions & 0 deletions data/Catch Type Quests/overview_description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"Capture or Hatch X-type Pokémon" quests are random repeatable quests that can be completed for [[Quest Points]].

These quests can be completed by filtering the [[Hatchery]] to the specific type, and by going to [[Routes]] that have a large number of that type.

The best routes to farm can be found by choosing a type below
75 changes: 75 additions & 0 deletions pages/Catch Type Quests/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<div>
<!-- ko ifnot: PokemonType[Wiki.pageName()] >= 0 -->
<h3>Pokémon type not found...</h3>
<!-- /ko -->
<!-- ko if: PokemonType[Wiki.pageName()] >= 0 -->
<div data-bind="with: Wiki.pageName()">
<h3 data-bind="text: `Best locations for completing Capture ${$data}-type Pokémon quests`"></h3>
<p>The top two locations from each Region are listed below, if they exist.</p>
<p>Current weather and day of week are taken into account for Route encounters, but other requirements (such as previously caught) are assumed to be met.</p>
<p>The number shown is the chance that any single encounter on that route will be a successful catch of the desired type, while using the equipment specified.</p>
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered">
<thead class="thead-dark">
<tr>
<th class="align-middle">Region</th>
<th class="align-middle">Current Weather</th>
<th class="align-middle">Location</th>
<th class="align-middle" style="text-align: right;">Maximum HP</th>
<th class="align-middle" style="text-align: right; width: 15%;">
<img width="24" class="me-1" src="./pokeclicker/docs/assets/images/pokeball/Pokeball.svg" data-bind="tooltip: {
title: 'Poké Ball',
trigger: 'hover'
}">
</th>
<th class="align-middle" style="text-align: right; width: 15%;">
<img width="24" class="me-1" src="./pokeclicker/docs/assets/images/pokeball/Pokeball.svg" data-bind="tooltip: {
title: 'Poké Ball',
trigger: 'hover'
}"> +
<img width="32" class="me-1" src="./images/Magic_Ball.png" data-bind="tooltip: {
title: 'Magic Ball (Level 5)',
trigger: 'hover'
}">
or&nbsp;
<img width="24" class="me-1" src="./pokeclicker/docs/assets/images/pokeball/Ultraball.svg" data-bind="tooltip: {
title: 'Ultra Ball',
trigger: 'hover'
}">
</th>
<th class="align-middle" style="text-align: right; width: 15%;">
<img width="24" class="me-1" src="./pokeclicker/docs/assets/images/pokeball/Ultraball.svg" data-bind="tooltip: {
title: 'Ultra Ball',
trigger: 'hover'
}"> +
<img width="32" class="me-1" src="./images/Magic_Ball.png" data-bind="tooltip: {
title: 'Magic Ball (Level 5)',
trigger: 'hover'
}">
</th>
</tr>
</thead>
<tbody
data-bind="foreach: { data: GameHelper.enumNumbers(GameConstants.Region).filter((r) => r <= GameConstants.MAX_AVAILABLE_REGION && r != GameConstants.Region.none), as: 'region' }">
<!-- ko foreach: Wiki.gems.bestCaptureRoutesPerRegion(region, PokemonType[$parent]) -->
<tr>
<td data-bind="text: GameConstants.camelCaseToString(GameConstants.Region[region]), attr: { 'data-sort': region }"></td>
<td class="align-middle text-center tight" style="box-shadow: none; border: none;" data-bind="style: { 'background-color': Weather.weatherConditions[$data.weather].color, display: 'flex', width: 'auto' }">
<img data-bind="attr: { src: `./pokeclicker/docs/assets/images/weather/${WeatherType[$data.weather]}.png` }"
width="24px">
<ko data-bind="text: GameConstants.humanifyString(WeatherType[$data.weather])"></ko>
</td>
<td><a class="text-nowrap" style="text-decoration: none;" data-bind="text: $data.route.routeName.replace(), attr: { href: `#!Routes/${$data.route.routeName}` }"></a></td>
<td class="text-nowrap" style="text-align: right;" data-bind="text: `${$data.maxHealth.toLocaleString()} ❤️`, attr: { 'data-sort' : $data.maxHealth }"></td>
<td style="text-align: right;" data-bind="text: `${($data.pokeball / 100).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, attr: { 'data-sort': $data.pokeball }"></td>
<td style="text-align: right;" data-bind="text: `${($data.ultraball / 100).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, attr: { 'data-sort': $data.ultraball }"></td>
<td style="text-align: right;" data-bind="text: `${($data.ultraballMagicBall / 100).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, attr: { 'data-sort': $data.ultraballMagicBall }"></td>
</tr>
<!-- /ko -->
</tbody>
</table>
</div>
<p>Refresh if the weather in the regions above are out of sync with your game.</p>
</div>
<!-- /ko -->
</div>
7 changes: 7 additions & 0 deletions pages/Catch Type Quests/overview.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div style="max-width: 900px;">
<!-- ko foreach: GameHelper.enumNumbers(PokemonType).filter(t => t >= 0) -->
<span class="type-icon badge m-1" data-bind="style:{ background: GameConstants.TypeColor[$data] }">
<a style="text-decoration: none; font-size: 0.875rem; color: #f5f5f5;" data-bind="text: PokemonType[$data], attr: { href: `#!Catch Type Quests/${PokemonType[$data]}` }"></a>
</span>
<!-- /ko -->
</div>
Loading
Loading