├── .gitignore
├── icons
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
├── apple-touch-icon.png
├── android-chrome-192x192.png
├── browserconfig.xml
└── safari-pinned-tab.svg
├── package.json
├── manifest.json
├── sw.js
├── css
└── styles.css
├── app.js
└── index.html
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/favicon.ico
--------------------------------------------------------------------------------
/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/icons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #da532c
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pidgeygrinding",
3 | "description": "",
4 | "version": "0.0.1",
5 | "author": "Paul Irish",
6 | "dependencies": {
7 |
8 | },
9 | "engines": {
10 | "node": "4.1.1"
11 | },
12 | "devDependencies": {
13 | },
14 | "scripts": {
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "short_name": "Pidgey Grinding",
4 | "name": "Pidgey Grinding",
5 | "display": "standalone",
6 | "icons": [
7 | {
8 | "src": "./icons/android-chrome-192x192.png",
9 | "sizes": "192x192",
10 | "type": "image/png"
11 | }
12 | ],
13 | "theme_color": "#662f17",
14 | "background_color": "#662f17",
15 | "start_url": "./"
16 | }
17 |
--------------------------------------------------------------------------------
/sw.js:
--------------------------------------------------------------------------------
1 | var CACHE_NAME = 'sw-ex';
2 | var CACHE_VERSION = 4;
3 |
4 | var filesToCache = [
5 | './',
6 | './index.html',
7 | './css/styles.css',
8 | './app.js',
9 | './icons/android-chrome-192x192.png'
10 | ];
11 |
12 | self.oninstall = function(event) {
13 | event.waitUntil(
14 | caches.open(CACHE_NAME + '-v' + CACHE_VERSION).then(function(cache) {
15 | return cache.addAll(filesToCache);
16 | })
17 | );
18 | };
19 |
20 | self.onactivate = function(event) {
21 | var currentCacheName = CACHE_NAME + '-v' + CACHE_VERSION;
22 | caches.keys().then(function(cacheNames) {
23 | return Promise.all(
24 | cacheNames.map(function(cacheName) {
25 | if (cacheName.indexOf(CACHE_NAME) == -1) {
26 | return;
27 | }
28 |
29 | if (cacheName != currentCacheName) {
30 | return caches.delete(cacheName);
31 | }
32 | })
33 | );
34 | });
35 | };
36 |
37 | self.onfetch = function(event) {
38 | var request = event.request;
39 | event.respondWith(
40 | caches.match(request).then(function(response) {
41 | if (response) {
42 | return response;
43 | }
44 |
45 | return fetch(request).then(function(response) {
46 | var responseToCache = response.clone();
47 | caches.open(CACHE_NAME + '-v' + CACHE_VERSION).then(
48 | function(cache) {
49 | cache.put(request, responseToCache).catch(function(err) {
50 | console.warn(request.url + ': ' + err.message);
51 | });
52 | });
53 | return response;
54 | });
55 | })
56 | );
57 | };
58 |
59 |
60 | // Communicate via MessageChannel.
61 | self.addEventListener('message', function(event) {
62 | console.log(`Received message from main thread: ${event.data}`);
63 | event.ports[0].postMessage(`Got message! Sending direct message back - "${event.data}"`);
64 | });
65 |
66 | // Broadcast via postMessage.
67 | function sendMessage(message) {
68 | self.clients.matchAll().then(function(clients) {
69 | clients.map(function(client) {
70 | return client.postMessage(message);
71 | })
72 | });
73 | }
74 |
75 |
76 |
--------------------------------------------------------------------------------
/css/styles.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-family: "Open Sans", sans-serif;
3 | box-sizing: border-box;
4 | }
5 |
6 | html, body {
7 | margin: 0;
8 | height: 100%;
9 | }
10 |
11 | html {
12 | background-color: hsl(11, 26%, 24%);
13 | color: hsl(20, 16%, 93%);
14 | scroll-behavior: smooth;
15 | }
16 |
17 | @media all and (min-height: 850px) {
18 | body {
19 | background-image: url(../icons/android-chrome-192x192.png);
20 | background-position: bottom right;
21 | background-repeat: no-repeat;
22 | }
23 | }
24 |
25 |
26 | a,
27 | a:visited,
28 | a:active {
29 | text-decoration: none;
30 | color: hsl(36, 100%, 50%);
31 | }
32 |
33 | .container {
34 | display: flex;
35 | flex-direction: column;
36 | max-width: 600px;
37 | padding: 20px;
38 | margin: 0 auto;
39 | justify-content: space-between;
40 | }
41 |
42 | h1 {
43 | margin: 0 0 10px;
44 | text-align: center;
45 | font-family: "bangersregular", sans-serif;
46 | font-size: 60px;
47 | text-shadow: 2px 3px 3px black;
48 | }
49 |
50 | label {
51 | font-weight: bold;
52 | }
53 |
54 | .form {
55 | display: flex;
56 | flex-direction: column;
57 | max-width: 300px;
58 | min-width: 242px;
59 | margin: 0 auto;
60 | }
61 |
62 | input[type="number"],
63 | select {
64 | margin-top: 10px;
65 | border: none;
66 | padding: 10px;
67 | font-size: 20px;
68 | border-radius: 5px;
69 | box-shadow: 0 3px 0 0 #FF8F00;
70 | color: #662f17;
71 | background-color: white;
72 | }
73 |
74 | button {
75 | background-color: #ba6831;
76 | color: white;
77 | border: none;
78 | padding: 13px;
79 | margin: 0;
80 | border-radius: 5px;
81 | box-shadow: 0 3px 0 0 #924321;
82 | font-weight: bold;
83 | }
84 |
85 | button:hover {
86 | background-color: #924321;
87 | box-shadow: 0 3px 0 0 #662f17;
88 | }
89 |
90 | button:active {
91 | background-color: #ba6831;
92 | box-shadow: 0 3px 0 0 #924321;
93 | }
94 |
95 |
96 | input[type=number]::-webkit-inner-spin-button,
97 | input[type=number]::-webkit-outer-spin-button {
98 | -webkit-appearance: none;
99 | margin: 0;
100 | }
101 |
102 | #error {
103 | color: red;
104 | text-align: center;
105 | }
106 | #output {
107 | background: hsla(11,26%,13%,1);
108 | margin: 0 -20px;
109 | padding: 0 20px;
110 | border: 1px solid #FFC107;
111 | border-width: 2px 0;
112 | /* opacity: 0.2; */
113 | }
114 | #output b {
115 | color: #FF5722;
116 | }
117 |
118 | #footer {
119 | margin: 20px 0 0;
120 | padding: 20px;
121 | text-align: center;
122 | font-size: 80%;
123 | }
124 |
125 | #description {
126 | text-align: center;
127 | margin-top: 0;
128 | margin-bottom: 20px;
129 | }
130 |
131 | .input-wrapper {
132 | display: flex;
133 | flex-direction: row;
134 | justify-content: space-between;
135 | }
136 |
137 | .input-element {
138 | display: flex;
139 | flex-direction: column;
140 | flex: 1;
141 | max-width: 47.5%;
142 | }
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | if ('serviceWorker' in navigator) {
2 | navigator.serviceWorker.register('sw.js', { scope: './' }).then((reg) => {
3 | if (reg.installing) {
4 | console.log('Service worker installing');
5 | } else if(reg.waiting) {
6 | console.log('Service worker installed');
7 | } else if(reg.active) {
8 | console.log('Service worker active');
9 | }
10 | }).catch((error) => {
11 | console.log('Registration failed with ' + error); // Registration failed
12 | });
13 |
14 | // Communicate with the service worker using MessageChannel API.
15 | function sendMessage(message) {
16 | return new Promise((resolve, reject) => {
17 | const messageChannel = new MessageChannel();
18 | messageChannel.port1.onmessage = function(event) {
19 | resolve(`Direct message from SW: ${event.data}`);
20 | };
21 |
22 | navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2])
23 | });
24 | }
25 | }
26 |
27 |
28 | // bling.js
29 | var $ = window.$ = document.querySelector.bind(document);
30 | var $$ = window.$$ = document.querySelectorAll.bind(document);
31 | Node.prototype.on = window.on = function(name, fn) {
32 | this.addEventListener(name, fn);
33 | }
34 | NodeList.prototype.__proto__ = Array.prototype;
35 | NodeList.prototype.on = NodeList.prototype.addEventListener = (function(name, fn) {
36 | this.forEach(function(elem) {
37 | elem.on(name, fn);
38 | });
39 | });
40 |
41 |
42 | /**
43 | * Adapted from http://www.pidgeycalc.com/ by BaiChanKheo
44 | */
45 |
46 | var TIME_TO_EVOLVE = 30;
47 | var CANDIES_TO_EVOLVE = 12;
48 | var POKEMON_NAME = "Pidgey";
49 |
50 | // Listener for select changes
51 | $("#pokemon").on("change", function(e) {
52 | var elem = e.currentTarget;
53 | POKEMON_NAME = elem.options[elem.selectedIndex].text;
54 | CANDIES_TO_EVOLVE = +elem.options[elem.selectedIndex].value;
55 | $("#selected-pokemon").innerHTML = POKEMON_NAME;
56 | });
57 |
58 | $$("input").forEach(function(e){
59 | e.on("input", calculate);
60 | });
61 | $("select").on("change", calculate);
62 | //$('button').on('click', calculate);
63 | calculate();
64 |
65 | // Do this when submit is clicked
66 | function calculate() {
67 | // Clear output
68 | $("#output").innerHTML = "";
69 |
70 | // Get input amounts
71 | var pidgeys = parseInt($("#pidgey-amount").value, 10) || 0;
72 | var candies = parseInt($("#candy-amount").value, 10) || 0;
73 |
74 | if (pidgeys > 99999 || candies > 99999) {
75 | $("#error").innerHTML = "Too many " + POKEMON_NAME + "s or Candies!";
76 | } else {
77 | $("#error").innerHTML = "";
78 |
79 | // Counters
80 | var evolveCount = 0;
81 | var transferCount = 0;
82 |
83 | // How many can be evolved without transfers
84 | var canStillEvolve = true;
85 | while (canStillEvolve) {
86 | // Not enough candies to evolve or no Pidgeys
87 | if (Math.floor(candies / CANDIES_TO_EVOLVE) === 0 || pidgeys === 0) {
88 | canStillEvolve = false;
89 | } else {
90 | pidgeys--; // Evolve a Pidgey
91 | candies -= CANDIES_TO_EVOLVE; // Remove the candy
92 | candies++; // Gain 1 candy per evolution
93 | evolveCount++;
94 | if (pidgeys === 0) {
95 | break;
96 | }
97 | }
98 | }
99 |
100 | // Evolutions after transferring Pidgeys
101 | var shouldTransfer = true;
102 | while (shouldTransfer) {
103 | // Not enough to transfer and evolve or no Pidgeys left
104 | if ((candies + pidgeys) < (CANDIES_TO_EVOLVE + 1) || pidgeys === 0) {
105 | shouldTransfer = false;
106 | break;
107 | }
108 |
109 | // Keep transferring until enough candies
110 | while (candies < CANDIES_TO_EVOLVE) {
111 | transferCount++;
112 | pidgeys--;
113 | candies++;
114 | }
115 |
116 | // Evolve a Pidgey
117 | pidgeys--;
118 | candies -= CANDIES_TO_EVOLVE;
119 | candies++;
120 | evolveCount++;
121 | }
122 |
123 | var eggsToUse = Math.floor((evolveCount * TIME_TO_EVOLVE / 60) / 30);
124 | var xpToGain = (evolveCount * 1000).toLocaleString();
125 | var evolveTime = (evolveCount * TIME_TO_EVOLVE / 60);
126 |
127 | // Output
128 | var html = "";
129 | html += "
Transfer " + transferCount + " " + POKEMON_NAME + "s first.";
130 | html += "
Activate your Lucky Egg, then…"
131 | html += "
You can evolve " + evolveCount + " " + POKEMON_NAME + "s, gaining " + xpToGain + " XP.";
132 | html += "
Doing " + evolveCount + " evolutions (at ~30 sec each) takes " + evolveTime + " minutes.";
133 | html += "
Afterwards, you will have " + pidgeys + " " + POKEMON_NAME + "s and " + candies + " candies left over.";
134 |
135 | html += "
Lucky Egg Recommendation: ";
136 |
137 | if (eggsToUse > 0) {
138 | html += "Use " + eggsToUse + " Lucky Eggs
";
139 | } else {
140 | html += "Don't use any Lucky Eggs until you've found more " + POKEMON_NAME + "s!";
141 | }
142 |
143 | $("#output").innerHTML = html;
144 | }
145 | }
146 |
147 | // just some bullshit to get the output visible while keyboarding.
148 | $$("input").forEach(function(e){
149 | e.on("focus", function(){
150 | // set up a one-off resize handler
151 | window.addEventListener('resize', {
152 | handleEvent: function(evt){
153 | evt.currentTarget.removeEventListener(evt.type, this);
154 | scrollInputs();
155 | }
156 | })
157 | });
158 | });
159 |
160 | function scrollInputs(){
161 | setTimeout(function(){
162 | var topOfInputs = $('.input-element').getBoundingClientRect().top;
163 | window.scrollTo(0, window.scrollY + topOfInputs);
164 | }, 20);
165 | }
--------------------------------------------------------------------------------
/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
100 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pidgey Grinding - Calculator for boosting your Pokemon Go XP quick
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Pidgey Grinding
28 |
Max out your Lucky Egg XP gain in Pokémon Go
29 |
30 |
55 |
56 |
57 |
58 |
59 |
60 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------