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

Generate data for all Safari Zones #170

Merged
merged 12 commits into from
Dec 9, 2023
1,490 changes: 658 additions & 832 deletions bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion data/Safari/overview_description.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Safari is an area available in Kanto ([[Towns/Safari Zone]]) and Kalos ([[Friend Safari]]) where the player may spend Quest Points to try and catch unique Pokémon. To unlock this area the player must first have the Safari Ticket.
Safari is an area available in Kanto ([[Towns/Safari Zone]]) and Kalos ([[Towns/Friend Safari]]) where the player may spend Quest Points to try and catch unique Pokémon. To unlock this area the player must first have the Safari Ticket.

The Pokémon can randomly spawn both on water and grass tiles, and also as sprites that can show up in both these environments. In Kanto, some Pokémon, like in the original games, only appear here.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
## Location
[Kalos](#!Towns/Friend_Safari)

## Encounter List
Each day, 5 Pokémon will get randomly chosen, based on the player's trainer ID, which can be checked with the Safari Ranger NPC. Only those Pokémon that **cannot gain EVs in any other place** may show up and only if the player has captured them previously. If the player hasn't, then the Pokémon will show up as a silhouette and cannot be encountered. Even if all daily Pokémon are currently unavailable to the player, Friend Safari has a list of Pokémon that always show up, no matter what. These Pokémon have a lower encounter rate (5 times less likely to appear) in comparison to the 5 daily ones:
Each day, 5 Pokémon will get randomly chosen, based on the player's trainer ID, which can be checked with the Safari Ranger NPC. Only those Pokémon that **cannot gain EVs in any other place** may show up and only if the player has captured them previously. If the player hasn't, then the Pokémon will show up as a silhouette and cannot be encountered. Even if all daily Pokémon are currently unavailable to the player, Friend Safari has a list of Pokémon that always show up, no matter what. These Pokémon have a lower encounter rate (5 times less likely to appear) in comparison to the 5 daily ones:
11 changes: 5 additions & 6 deletions pages/Friend Safari/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@
<th class="text-center">Environment</th>
</tr>
</thead>
<tbody data-bind="foreach: Wiki.pokemon.getFriendSafariDefaultEncounters().flat()">
<tbody data-bind="foreach: SafariPokemonList.list[GameConstants.Region.kalos]().filter(p => !p.requireCaught)">
<tr>
<td class="align-middle">
<img width="48px" class="me-1" data-bind="attr: {src: './pokeclicker/docs/assets/images/pokemon/' + pokemonMap[$data].id + '.png'}"/>
<a href="#!" class="text-decoration-none" data-bind="text: $data, attr: {href: `#!Pokemon/${$data}` }"></a>
<img width="48px" class="me-1" data-bind="attr: {src: './pokeclicker/docs/assets/images/pokemon/' + pokemonMap[$data.name].id + '.png'}"/>
<a href="#!" class="text-decoration-none" data-bind="text: $data.name, attr: {href: `#!Pokemon/${$data.name}` }"></a>
</td>
<td class="align-middle">
2
<td class="align-middle" data-bind="text: $data.weight">
</td>
<td class="align-middle">
<knockout data-bind="text: Wiki.pokemon.getFriendSafariEncounterLocations($data)"></knockout>
<knockout data-bind="text: $data.environments.map(env => SafariEnvironments[env]).join(', ')"></knockout>
</td>
</tr>
</tbody>
Expand Down
44 changes: 24 additions & 20 deletions pages/Pokémon/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -334,14 +334,17 @@ <h4 class="accordion-header">
<div class="accordion-body" data-bind="foreach: Object.entries($data[PokemonLocationType.Safari])">
<h5 data-bind="text: GameConstants.camelCaseToString(GameConstants.Region[$data[0]])"></h5>
<p data-bind="foreach: Object.entries($data[1])">
<span class="badge text-bg-secondary" data-bind="with: { chance: $data[1], requireCaught: SafariPokemonList.list[$parent[0]]().find(p => p.name == Wiki.pageName())?.requireCaught }">
<knockout data-bind="text: `Chance ${$data.chance}%${$data.requireCaught ? ' 🔒' : ''}`, tooltip: {
title: $data.requireCaught ? `${Wiki.pageName()} will become available in the Safari Zone after being obtained elsewhere.` : '',
html: true,
placement: 'bottom',
trigger: 'hover'
}"></knockout>
</span>
<knockout data-bind="with: { chance: $data[1], requireCaught: SafariPokemonList.list[$parent[0]]().find(p => p.name == Wiki.pageName())?.requireCaught }">
<a class="badge text-bg-secondary" data-bind="text: `Chance ${$data.chance}%${$data.requireCaught ? ' 🔒' : ''}`,
attr: { href: `#!Towns/${Object.values(TownList).find(t => t.region == $parents[1][0] && t.content.filter(c => c instanceof SafariTownContent).length).name}` },
tooltip: {
title: $data.requireCaught ? `${Wiki.pageName()} will become available in the Safari Zone after being obtained elsewhere.` : '',
html: true,
placement: 'bottom',
trigger: 'hover'
}">
</a>
</knockout>
</p>
</div>
</div>
Expand All @@ -351,7 +354,7 @@ <h5 data-bind="text: GameConstants.camelCaseToString(GameConstants.Region[$data[
<!--
FRIEND SAFARI
-->
<!-- ko if: Wiki.pokemon.getFriendSafariDefaultEncounters().flat().includes(Wiki.pageName()) ||
<!-- ko if: SafariPokemonList.list[GameConstants.Region.kalos]().find(p => p.name == Wiki.pageName()) ||
PokemonHelper.isObtainableAndNotEvable(Wiki.pageName()) && (PokemonHelper.calcNativeRegion(Wiki.pageName()) <= GameConstants.MAX_AVAILABLE_REGION) -->
<div class="accordion-item">
<h4 class="accordion-header">
Expand All @@ -362,17 +365,18 @@ <h4 class="accordion-header">
</h4>
<div id="obtain-method-friend-safari" class="accordion-collapse collapse">
<div class="accordion-body">
<h5>Kalos</h5>
<p>
<span class="badge text-bg-secondary" data-bind="using: !Wiki.pokemon.getFriendSafariDefaultEncounters().flat().includes(Wiki.pageName()), as: 'requireCaught'">
<knockout data-bind="text: `In ${Wiki.pokemon.getFriendSafariEncounterLocations(Wiki.pageName())}${requireCaught ? ' 🔒' : ''}`, tooltip: {
title: requireCaught ? `${Wiki.pageName()} will become available in the Friend Safari after being obtained elsewhere.` : '',
html: true,
placement: 'bottom',
trigger: 'hover'
}"></knockout>
</span>
</p>
<h5 data-bind="">Kalos</h5>
<knockout data-bind="using: !(SafariPokemonList.list[GameConstants.Region.kalos]().find(p => p.name == Wiki.pageName())?.requireCaught == false), as: 'requireCaught'">
<a class="badge text-bg-secondary" data-bind="text: `In ${SafariPokemonList.getEnvironmentByPokemonType(Wiki.pageName()).map(env => SafariEnvironments[env]).join(', ')}${requireCaught ? ' 🔒' : ''}`,
attr: { href: `#!Towns/Friend Safari` },
tooltip: {
title: requireCaught ? `${Wiki.pageName()} will become available in the Friend Safari after being obtained elsewhere.` : '',
html: true,
placement: 'bottom',
trigger: 'hover'
}">
</a>
</knockout>
</div>
</div>
</div>
Expand Down
22 changes: 0 additions & 22 deletions pages/Safari/overview.html
Original file line number Diff line number Diff line change
@@ -1,22 +0,0 @@
<div data-bind="foreach: Object.keys(SafariItemController.list)" class="table-responsive">
<h4 data-bind="text: Wiki.gameHelper.getRegionName($data)"></h4>
<table class="table table-hover table-striped table-bordered no-data-tables">
<thead class="thead-dark">
<tr>
<th>Item</th>
<th>Chance</th>
<th>Requirement</th>
</tr>
</thead>
<tbody data-bind="foreach: SafariItemController.list[$data]">
<tr>
<td class="align-middle">
<img width="32px" class="me-1" data-bind="attr: { src: `pokeclicker/docs/${BagHandler.image($data.item)}` }"/>
<knockout data-bind="text: BagHandler.displayName($data.item)"></knockout>
</td>
<td class="align-middle" data-bind="text: `${$data.weight*100/SafariItemController.list[$parent].reduce((acc, cur) => { return acc + cur.weight }, 0)}%`"></td>
<td class="align-middle" data-bind="html: $data.requirement ? Wiki.gameHelper.requirementHints($data.requirement.requirements).join('<br />') : 'N/A'"></td>
</tr>
</tbody>
</table>
</div>
101 changes: 101 additions & 0 deletions pages/Towns/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,106 @@ <h3 data-bind="text: $data.name"></h3>
</div>
</div>
<!-- /ko -->
<!-- ko if: $data.content.filter(c => c instanceof SafariTownContent).length -->
<div class="mt-3">
<h2>Safari Encounters</h2>
<table class="table table-bordered table-striped table-hover text-center">
<thead>
<tr>
<th class="text-center">Pokémon</th>
<th class="text-center">Sprite</th>
<th class="text-center">Weight</th>
<th class="text-center">Environment</th>
<th class="text-center">Requirement</th>
</tr>
</thead>
<tbody data-bind="foreach: SafariPokemonList.list[$data.region]().filter(p => !p.requireCaught || !p.showUncaught)">
<tr>
<td class="align-middle">
<img width="48px" class="me-1" data-bind="attr: {src: './pokeclicker/docs/assets/images/pokemon/' + pokemonMap[$data.name].id + '.png'}"/>
<a href="#!" class="text-decoration-none" data-bind="text: $data.name, attr: {href: `#!Pokemon/${$data.name}` }"></a>
</td>
<td class="align-middle">
<div data-bind="style: {
backgroundImage: `url(./pokeclicker/docs/assets/images/dynamic-background/pokemon/${Math.floor(pokemonList.find(p => p.name == $data.name).id).toString().padStart(3, '0')}.png)`,
backgroundSize: '192px',
height: '48px',
width: '48px',
margin: 'auto',
}"></div>
</td>
<td class="align-middle" data-bind="text: $data.weight">
</td>
<td class="align-middle">
<knockout data-bind="text: $data.environments.map(env => SafariEnvironments[env]).join(', ')"></knockout>
</td>
<td class="align-middle" data-bind="text: $data.requireCaught ? 'Must be caught elsewhere first.' : 'N/A'"></td>
</tr>
</tbody>
</table>

<!-- ko if: $data.region == GameConstants.Region.kalos -->
<h2 class="mt-3">Pool of Daily Encounters</h2>
<table class="table table-bordered table-striped table-hover text-center">
<thead>
<tr>
<th class="text-center">Pokémon</th>
<th class="text-center">Sprite</th>
<th class="text-center">Weight</th>
<th class="text-center">Environment</th>
<th class="text-center">Requirement</th>
</tr>
</thead>
<tbody data-bind="foreach: pokemonList.filter(p => PokemonHelper.isObtainableAndNotEvable(p.name) && (PokemonHelper.calcNativeRegion(p.name) <= GameConstants.MAX_AVAILABLE_REGION))">
<tr>
<td class="align-middle">
<img width="48px" class="me-1" data-bind="attr: {src: './pokeclicker/docs/assets/images/pokemon/' + pokemonMap[$data.name].id + '.png'}"/>
<a href="#!" class="text-decoration-none" data-bind="text: $data.name, attr: {href: `#!Pokemon/${$data.name}` }"></a>
</td>
<td class="align-middle">
<div data-bind="style: {
backgroundImage: `url(./pokeclicker/docs/assets/images/dynamic-background/pokemon/${Math.floor(pokemonList.find(p => p.name == $data.name).id).toString().padStart(3, '0')}.png)`,
backgroundSize: '192px',
height: '48px',
width: '48px',
margin: 'auto',
}"></div>
</td>
<td class="align-middle">
10
</td>
<td class="align-middle">
<knockout data-bind="text: SafariPokemonList.getEnvironmentByPokemonType($data.name).map(env => SafariEnvironments[env]).join(', ')"></knockout>
</td>
<td class="align-middle">
Must be caught elsewhere first
</td>
</tr>
</tbody>
</table>
<!-- /ko -->

<h2 class="mt-3">Safari Items</h2>
<table class="table table-hover table-striped table-bordered no-data-tables text-center">
<thead class="thead-dark">
<tr>
<th class="text-center">Item</th>
<th class="text-center">Chance</th>
<th class="text-center">Requirement</th>
</tr>
</thead>
<tbody data-bind="foreach: SafariItemController.list[$data.region]">
<tr>
<td class="align-middle">
<img width="32px" class="me-1" data-bind="attr: { src: `pokeclicker/docs/${BagHandler.image($data.item)}` }"/>
<knockout data-bind="text: BagHandler.displayName($data.item)"></knockout>
</td>
<td class="align-middle" data-bind="text: `${Math.round($data.weight*100/SafariItemController.list[$parent.region].reduce((acc, cur) => { return acc + cur.weight }, 0) * 100)/100}%`"></td>
<td class="align-middle" data-bind="html: $data.requirement ? Wiki.gameHelper.requirementHints($data.requirement.requirements).join('<br />') : 'N/A'"></td>
</tr>
</tbody>
</table>
</div>
<!-- /ko -->
<!-- /ko -->
</div>
2 changes: 1 addition & 1 deletion scripts/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ App.game.keyItems.initialize();
App.game.underground.initialize();
App.game.specialEvents.initialize();
QuestLineHelper.loadQuestLines();
SafariPokemonList.generateKantoSafariList();
BattleFrontierRunner.stage(100);
BattleFrontierBattle.generateNewEnemy();

Expand All @@ -63,6 +62,7 @@ DailyDeal.generateDeals(5, now);
BerryDeal.generateDeals(now);
GemDeal.generateDeals();
ShardDeal.generateDeals();
SafariPokemonList.generateSafariLists(); // This needs to be after anything that generates shopmon due to Friend Safari calcs

// Farm Simulator
App.game.farming.plotList.forEach((p) => p.isUnlocked = true); // All plots unlocked
Expand Down
35 changes: 0 additions & 35 deletions scripts/pages/pokemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,45 +56,10 @@ const getAllAvailableShadowPokemon = () => {
.map(d => Wiki.dungeons.getDungeonShadowPokemon(d)).flat();
};

const getFriendSafariDefaultEncounters = () => {
// These are not surfaced by the game code, consolidating to a single location here
return [
// Grass
[
'Shuckle',
'Stunfisk',
'Magmar',
'Maractus',
'Klefki',
'Breloom',
'Woobat',
'Golurk',
'Marowak',
],
// Water
[
'Lapras',
]
];
}

const getFriendSafariEncounterLocations = (pokemonName) => {
const defaultEncounters = getFriendSafariDefaultEncounters();
for (let env of GameHelper.enumNumbers(SafariEnvironments)) {
if (defaultEncounters[env].includes(pokemonName)) {
return SafariEnvironments[env];
}
}

return `${SafariPokemonList.getEnvironmentByPokemonType(pokemonName).map(env => SafariEnvironments[env]).join(", ")}`;
}

module.exports = {
getBreedingAttackBonus,
calcEggSteps,
getEfficiency,
getBestVitamins,
getAllAvailableShadowPokemon,
getFriendSafariDefaultEncounters,
getFriendSafariEncounterLocations,
}
2 changes: 1 addition & 1 deletion scripts/typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ const searchOptions = [
type: 'Towns',
page: '',
},
...Object.values(TownList).filter(t => !(t instanceof DungeonTown) && !['Safari Zone', 'Friend Safari'].includes(t.name) && t.region <= GameConstants.MAX_AVAILABLE_REGION).map(t => ({
...Object.values(TownList).filter(t => !(t instanceof DungeonTown) && t.region <= GameConstants.MAX_AVAILABLE_REGION).map(t => ({
display: t.name,
type: 'Towns',
page: t.name,
Expand Down