├── img
├── favicon.ico
├── favicon-152.png
└── pinned-tab-icon.svg
├── README.md
├── License.md
├── js
├── jquery.highlight.js
└── main.js
├── css
└── main.css
└── index.html
/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZKjellberg/sekiro-cheat-sheet/HEAD/img/favicon.ico
--------------------------------------------------------------------------------
/img/favicon-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZKjellberg/sekiro-cheat-sheet/HEAD/img/favicon-152.png
--------------------------------------------------------------------------------
/img/pinned-tab-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sekiro Cheat Sheet
2 |
3 | To view the cheat sheet [click here](https://zkjellberg.github.io/sekiro-cheat-sheet)
4 |
5 | ## Contribution Guide
6 |
7 | If you are interested in contributing to this guide, I welcome Pull Requests on GitHub.
8 |
9 | **NOTE: This guide is currently in its early phases and will be evolving quickly.**
10 |
11 | For some background on how the guide code is written, here is a sample item on the checklist:
12 |
13 | ```html
14 |
Continue left until you can enter a room with a Large Soul of a Nameless Soldier and a Raw Gem
15 | ```
16 |
17 | The **data-id** is a unique ID used to store the user's progress. For example, ***playthrough_13_20*** is the 20th task in zone 13. New data-ids must be used in ascending order, but you can place the new entries anywhere within a zone.
18 |
19 | The **class="f_gem f_misc"** field is used for the filtering system. This task provides the user with a gem and a consumable, so we use **f_gem** and **f_misc**. This is a feature from the Dark Souls guide and will be revamped as the walkthrough is built.
--------------------------------------------------------------------------------
/License.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Zachary Kjellberg
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/js/jquery.highlight.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Highlight plugin
3 | *
4 | * Based on highlight v3 by Johann Burkard
5 | * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
6 | *
7 | * Code a little bit refactored and cleaned (in my humble opinion).
8 | * Most important changes:
9 | * - has an option to highlight only entire words (wordsOnly - false by default),
10 | * - has an option to be case sensitive (caseSensitive - false by default)
11 | * - highlight element tag and class names can be specified in options
12 | *
13 | * Usage:
14 | * // wrap every occurrance of text 'lorem' in content
15 | * // with (default options)
16 | * $('#content').highlight('lorem');
17 | *
18 | * // search for and highlight more terms at once
19 | * // so you can save some time on traversing DOM
20 | * $('#content').highlight(['lorem', 'ipsum']);
21 | * $('#content').highlight('lorem ipsum');
22 | *
23 | * // search only for entire word 'lorem'
24 | * $('#content').highlight('lorem', { wordsOnly: true });
25 | *
26 | * // don't ignore case during search of term 'lorem'
27 | * $('#content').highlight('lorem', { caseSensitive: true });
28 | *
29 | * // wrap every occurrance of term 'ipsum' in content
30 | * // with
31 | * $('#content').highlight('ipsum', { element: 'em', className: 'important' });
32 | *
33 | * // remove default highlight
34 | * $('#content').unhighlight();
35 | *
36 | * // remove custom highlight
37 | * $('#content').unhighlight({ element: 'em', className: 'important' });
38 | *
39 | *
40 | * Copyright (c) 2009 Bartek Szopka
41 | *
42 | * Licensed under MIT license.
43 | *
44 | */
45 |
46 | jQuery.extend({
47 | highlight: function (node, re, nodeName, className) {
48 | if (node.nodeType === 3) {
49 | var match = node.data.match(re);
50 | if (match) {
51 | var highlight = document.createElement(nodeName || 'span');
52 | highlight.className = className || 'highlight';
53 | var wordNode = node.splitText(match.index);
54 | wordNode.splitText(match[0].length);
55 | var wordClone = wordNode.cloneNode(true);
56 | highlight.appendChild(wordClone);
57 | wordNode.parentNode.replaceChild(highlight, wordNode);
58 | return 1; //skip added node in parent
59 | }
60 | } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
61 | !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
62 | !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
63 | for (var i = 0; i < node.childNodes.length; i++) {
64 | i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
65 | }
66 | }
67 | return 0;
68 | }
69 | });
70 |
71 | jQuery.fn.unhighlight = function (options) {
72 | var settings = { className: 'highlight', element: 'span' };
73 | jQuery.extend(settings, options);
74 |
75 | return this.find(settings.element + "." + settings.className).each(function () {
76 | var parent = this.parentNode;
77 | parent.replaceChild(this.firstChild, this);
78 | parent.normalize();
79 | }).end();
80 | };
81 |
82 | jQuery.fn.highlight = function (words, options) {
83 | var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
84 | jQuery.extend(settings, options);
85 |
86 | if (words.constructor === String) {
87 | words = [words];
88 | }
89 | words = jQuery.grep(words, function(word, i){
90 | return word != '';
91 | });
92 | words = jQuery.map(words, function(word, i) {
93 | return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
94 | });
95 | if (words.length == 0) { return this; };
96 |
97 | var flag = settings.caseSensitive ? "" : "i";
98 | var pattern = "(" + words.join("|") + ")";
99 | if (settings.wordsOnly) {
100 | pattern = "\\b" + pattern + "\\b";
101 | }
102 | var re = new RegExp(pattern, flag);
103 |
104 | return this.each(function () {
105 | jQuery.highlight(this, re, settings.element, settings.className);
106 | });
107 | };
108 |
109 |
--------------------------------------------------------------------------------
/css/main.css:
--------------------------------------------------------------------------------
1 | .in_progress,
2 | .done {
3 | color: #C60;
4 | border: 1px solid;
5 | border-radius: 3px;
6 | padding: .1em 0.4em;
7 | font-weight: normal;
8 | margin-left: .2em;
9 | vertical-align: middle;
10 | font-size: 0.9em;
11 | }
12 | .done { color: #009933; }
13 |
14 | @media print {
15 | body { color: #000; }
16 | .navbar, #intro, input[type="checkbox"], .done, .in_progress { display: none; }
17 | a { color: #000; text-decoration: underline; }
18 | a[href]:after { content: none !important; }
19 | .tab-content > .tab-pane, .pill-content > .pill-pane { display: block; }
20 | .tab-pane { page-break-after: always; }
21 | }
22 |
23 | ul {
24 | list-style-type: none;
25 | padding-left: 22px;
26 | }
27 | ul li ul {
28 | padding-top: 0;
29 | }
30 | h3 {
31 | margin-bottom: 0;
32 | }
33 | .checkbox label,
34 | .radio label {
35 | padding-left: 24px;
36 | }
37 | .checkbox input[type=checkbox],
38 | .checkbox-inline input[type=checkbox],
39 | .radio input[type=radio],
40 | .radio-inline input[type=radio] {
41 | margin-left: -24px;
42 | }
43 |
44 | .table_of_contents {
45 | margin-left: 0;
46 | padding: 0;
47 | line-height: 1.8;
48 | }
49 |
50 | .highlight {
51 | background-color: rgb(255, 246, 18);
52 | }
53 |
54 | .hiddenfile {
55 | width: 0px;
56 | height: 0px;
57 | overflow: hidden;
58 | }
59 |
60 | .btn.fadingbutton {
61 | border-bottom-right-radius: 0;
62 | border-bottom-left-radius: 0;
63 | border-bottom: 0;
64 | position: fixed;
65 | display: none;
66 | z-index: 1;
67 | bottom: 0;
68 | /* The "Paper" bootstrap theme modifies the transition properties;
69 | reset them to the default value to prevent ruining the fadeIn() */
70 | -webkit-transition: all 0s ease 0s;
71 | -o-transition: all 0s ease 0s;
72 | transition: all 0s ease 0s;
73 | }
74 | .fadingbutton.back-to-top {
75 | border-top-right-radius: 0;
76 | border-right: 0;
77 | right: 0;
78 | }
79 | .fadingbutton.togglehide {
80 | border-top-left-radius: 0;
81 | border-left: 0;
82 | left: 0;
83 | }
84 |
85 | .btn-collapse {
86 | padding: 4px 10px 1px;
87 | margin-right: 10px;
88 | vertical-align: top;
89 | }
90 |
91 | .btn:focus, .btn.active:focus {
92 | outline: none;
93 | outline: 0;
94 | }
95 |
96 | /* Icon when the collapsible content is shown */
97 | .btn-collapse:after {
98 | font-family: 'Glyphicons Halflings';
99 | content:"\e082";
100 | }
101 | /* Icon when the collapsible content is hidden */
102 | .btn-collapse.collapsed:after {
103 | content:"\e081";
104 | }
105 |
106 | h1 {
107 | margin-top: 0;
108 | margin-bottom: 20px;
109 | }
110 |
111 | body.hide_completed .completed {
112 | display: none !important;
113 | }
114 |
115 | input[type="checkbox"]:checked + .item_content {
116 | text-decoration: line-through;
117 | }
118 |
119 | input[type="checkbox"] ~ .glyphicon-eye-close,
120 | input[type="checkbox"] ~ * > .glyphicon-eye-close,
121 | input[type="checkbox"]:checked ~ .glyphicon-eye-open,
122 | input[type="checkbox"]:checked ~ * > .glyphicon-eye-open {
123 | display: none;
124 | }
125 | input[type="checkbox"] ~ .glyphicon-eye-open,
126 | input[type="checkbox"] ~ * > .glyphicon-eye-open,
127 | input[type="checkbox"]:checked ~ .glyphicon-eye-close,
128 | input[type="checkbox"]:checked ~ * > .glyphicon-eye-close {
129 | display: inline-block;
130 | }
131 |
132 | textarea#profileText {
133 | height: 15em;
134 | resize: vertical;
135 | }
136 |
137 | /* Work around what seems to be a bootstrap bug affecting the hover border on the right side of the add profile button */
138 | .input-group-btn:last-child>.btn:focus,
139 | .input-group-btn:last-child>.btn:hover {
140 | z-index: 3;
141 | }
142 |
143 | /* Decorators for NG+/NG++ entries */
144 | .s_ng\+ .item_content:before {
145 | content: "[NG+: ";
146 | }
147 | .s_ng\+\+ .item_content:before {
148 | content: "[NG++: ";
149 | }
150 | .s_ng\+ .item_content:after,
151 | .s_ng\+\+ .item_content:after {
152 | content: "]";
153 | }
154 |
155 | /* Styling for checklist filter categories and toggles */
156 | .btn-group.btn-group-vertical > .btn-group:not(:first-child) > .btn-group-vertical {
157 | left: 0;
158 | top: 100%;
159 | display: none;
160 | position: absolute;
161 | }
162 | .btn-group.btn-group-vertical:hover > .btn-group:not(:first-child) > .btn-group-vertical {
163 | display: block;
164 | }
165 | .btn-group.btn-group-vertical > .btn-group:first-child > .btn-group-vertical.open > .btn {
166 | z-index: 1;
167 | }
168 | .btn-group.btn-group-vertical > .btn-group:not(:first-child) > .btn-group-vertical > .btn {
169 | z-index: 3;
170 | text-align: left;
171 | }
172 | .btn-group.btn-group-vertical > .btn-group:not(:first-child) > .btn-group-vertical > .btn:hover {
173 | z-index: 4;
174 | }
175 | .btn-group.btn-group-vertical:not(:last-child) > .btn-group:first-child > .btn-group-vertical > .btn {
176 | border-top-right-radius: 0;
177 | border-bottom-right-radius: 0;
178 | }
179 | .btn-group.btn-group-vertical:not(:first-child) > .btn-group:first-child > .btn-group-vertical > .btn,
180 | .btn-group.btn-group-vertical > .btn-group:not(:first-child) > .btn-group-vertical > .btn:first-child {
181 | border-top-left-radius: 0;
182 | }
183 | .btn-group.btn-group-vertical:not(:first-child) > .btn-group:first-child > .btn-group-vertical > .btn,
184 | .btn-group.btn-group-vertical:first-child:hover > .btn-group:first-child > .btn-group-vertical > .btn {
185 | border-bottom-left-radius: 0;
186 | }
187 |
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | var profilesKey = 'sekiro_profiles';
2 |
3 | (function($) {
4 | 'use strict';
5 |
6 | var themes = {
7 | "Standard" : "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css",
8 | "Cosmo" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/cosmo/bootstrap.min.css",
9 | "Cyborg" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/cyborg/bootstrap.min.css",
10 | "Darkly" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/darkly/bootstrap.min.css",
11 | "Flatly" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/flatly/bootstrap.min.css",
12 | "Journal" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/journal/bootstrap.min.css",
13 | "Lumen" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/lumen/bootstrap.min.css",
14 | "Paper" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/paper/bootstrap.min.css",
15 | "Readable" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/readable/bootstrap.min.css",
16 | "Sandstone" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/sandstone/bootstrap.min.css",
17 | "Simplex" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/simplex/bootstrap.min.css",
18 | "Slate" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/slate/bootstrap.min.css",
19 | "Spacelab" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/spacelab/bootstrap.min.css",
20 | "Superhero" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/superhero/bootstrap.min.css",
21 | "United" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/united/bootstrap.min.css",
22 | "Yeti" : "https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/yeti/bootstrap.min.css"
23 | };
24 |
25 | var profiles = $.jStorage.get(profilesKey, {});
26 |
27 | /// assure default values are set
28 | /// necessary 'cause we're abusing local storage to store JSON data
29 | /// done in a more verbose way to be easier to understand
30 | if (!('current' in profiles)) profiles.current = 'Default Profile';
31 | if (!(profilesKey in profiles)) profiles[profilesKey] = {};
32 | initializeProfile(profiles.current);
33 |
34 | jQuery(document).ready(function($) {
35 | // Get the right style going...
36 | themeSetup(buildThemeSelection());
37 |
38 | $('ul li[data-id]').each(function() {
39 | addCheckbox(this);
40 | });
41 |
42 | // Open external links in new tab
43 | $("a[href^='http']").attr('target','_blank');
44 |
45 | populateProfiles();
46 |
47 | $('.checkbox input[type="checkbox"]').click(function() {
48 | var id = $(this).attr('id');
49 | var isChecked = profiles[profilesKey][profiles.current].checklistData[id] = $(this).prop('checked');
50 | if (isChecked === true) {
51 | $('[data-id="'+id+'"] label').addClass('completed');
52 | } else {
53 | $('[data-id="'+id+'"] label').removeClass('completed');
54 | }
55 | $.jStorage.set(profilesKey, profiles);
56 | calculateTotals();
57 | });
58 |
59 | // Theme callback
60 | $('#themes').change(function(event) {
61 | var stylesheet = $('#themes').val();
62 | themeSetup(stylesheet);
63 | $.jStorage.set("style", stylesheet);
64 | });
65 |
66 | $('#profiles').change(function(event) {
67 | profiles.current = $(this).val();
68 | $.jStorage.set(profilesKey, profiles);
69 |
70 | $('li .checkbox .completed').show();
71 |
72 | populateChecklists();
73 |
74 | restoreState(profiles.current);
75 |
76 | calculateTotals();
77 | });
78 |
79 | $('#profileAdd').click(function() {
80 | $('#profileModalTitle').html('Add Profile');
81 | $('#profileModalName').val('');
82 | $('#profileModalAdd').show();
83 | $('#profileModalUpdate').hide();
84 | $('#profileModalDelete').hide();
85 | $('#profileModal').modal('show');
86 | });
87 |
88 | $('#profileEdit').click(function() {
89 | $('#profileModalTitle').html('Edit Profile');
90 | $('#profileModalName').val(profiles.current);
91 | $('#profileModalAdd').hide();
92 | $('#profileModalUpdate').show();
93 | if (canDelete()) {
94 | $('#profileModalDelete').show();
95 | } else {
96 | $('#profileModalDelete').hide();
97 | }
98 | $('#profileModal').modal('show');
99 | });
100 |
101 | $('#profileModalAdd').click(function(event) {
102 | event.preventDefault();
103 | var profile = $.trim($('#profileModalName').val());
104 | if (profile.length > 0) {
105 | initializeProfile(profile);
106 |
107 | profiles.current = profile;
108 | $.jStorage.set(profilesKey, profiles);
109 | populateProfiles();
110 | populateChecklists();
111 | restoreState(profiles.current);
112 | }
113 | });
114 |
115 | $('#profileModalUpdate').click(function(event) {
116 | event.preventDefault();
117 | var newName = $.trim($('#profileModalName').val());
118 | if (newName.length > 0 && newName != profiles.current) {
119 | profiles[profilesKey][newName] = profiles[profilesKey][profiles.current];
120 | delete profiles[profilesKey][profiles.current];
121 | profiles.current = newName;
122 | $.jStorage.set(profilesKey, profiles);
123 | populateProfiles();
124 | }
125 | $('#profileModal').modal('hide');
126 | });
127 |
128 | $('#profileModalDelete').click(function(event) {
129 | event.preventDefault();
130 | if (!canDelete()) {
131 | return;
132 | }
133 | if (!confirm('Are you sure?')) {
134 | return;
135 | }
136 | delete profiles[profilesKey][profiles.current];
137 | profiles.current = getFirstProfile();
138 | $.jStorage.set(profilesKey, profiles);
139 | populateProfiles();
140 | populateChecklists();
141 | restoreState(profiles.current);
142 | $('#profileModal').modal('hide');
143 | });
144 |
145 | $('#profileNG\\+').click(function() {
146 | $('#NG\\+Modal').modal('show');
147 | });
148 |
149 | $('#NG\\+ModalYes').click(function(event) {
150 | event.preventDefault();
151 | if (!confirm('Are you sure you wish to begin the next journey?')) {
152 | return;
153 | }
154 | $('[id^="playthrough_"], [id^="crow_"]').filter(':checked').each(function(){
155 | profiles[profilesKey][profiles.current].checklistData[this.id] = false;
156 | });
157 | $.each(profiles[profilesKey][profiles.current].hidden_categories, function(f){
158 | profiles[profilesKey][profiles.current].hidden_categories[f] = false;
159 | });
160 | if (profiles[profilesKey][profiles.current].journey < 3) {
161 | profiles[profilesKey][profiles.current].journey++;
162 | }
163 | $.jStorage.set(profilesKey, profiles);
164 | populateChecklists();
165 | restoreState(profiles.current);
166 | $('#NG\\+Modal').modal('hide');
167 | });
168 |
169 | $('#profileExport').click(function(){
170 | var filename = 'profiles.json';
171 | var text = JSON.stringify(profiles);
172 | if (window.Blob && window.navigator.msSaveBlob) {
173 | // Microsoft browsers (https://docs.microsoft.com/en-us/microsoft-edge/dev-guide/html5/file-api/blob)
174 | var blob = new window.Blob([text]);
175 | window.navigator.msSaveBlob(blob, filename);
176 | } else {
177 | // All other modern browsers
178 | var element = document.createElement('a');
179 | element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
180 | element.setAttribute('download', filename);
181 | element.style.display = 'none';
182 | document.body.appendChild(element);
183 | element.click();
184 | document.body.removeChild(element);
185 | }
186 | });
187 |
188 | $('#profileImport').click(function(){
189 | $('#fileInput').trigger('click');
190 | });
191 | /* Will reject if an incorrect file or no file is selected */
192 | $('input#fileInput').change(function(){
193 | var fileInput = document.getElementById('fileInput');
194 | if(!fileInput.files || !fileInput.files[0] || !/\.json$/.test(fileInput.files[0].name)){
195 | alert("Bad input file. File should end in .json")
196 | return;
197 | }
198 | var fr = new FileReader();
199 | fr.readAsText(fileInput.files[0]);
200 | fr.onload = dataLoadCallback;
201 | });
202 |
203 | /*
204 | * Import & Export using textarea instead of files
205 | */
206 | $('#profileExportText').click(function(){
207 | document.getElementById("profileText").value = JSON.stringify(profiles);
208 | document.getElementById("profileText").select();
209 | document.execCommand("copy");
210 | });
211 |
212 | $('#profileImportText').click(function(){
213 | if (!confirm('Are you sure you want to import profile data?')) {
214 | return;
215 | }
216 | try {
217 | var jsonProfileData = JSON.parse(document.getElementById("profileText").value);
218 | profiles = jsonProfileData;
219 | $.jStorage.set(profilesKey, profiles);
220 | populateProfiles();
221 | populateChecklists();
222 | $('#profiles').trigger("change");
223 | location.reload();
224 | } catch(e) {
225 | alert(e); // error in the above string (in this case, yes)!
226 | }
227 | });
228 |
229 | $("#toggleHideCompleted").change(function() {
230 | // Store information about the old scroll position
231 | var oldPos = $(window).scrollTop();
232 | var labels = $('ul>li>div>label:visible:not(.completed)');
233 | var oldOff = labels.map(function(){return $(this).offset().top});
234 |
235 | var hidden = !$(this).is(':checked');
236 |
237 | $('body').toggleClass('hide_completed', !hidden);
238 |
239 | profiles[profilesKey][profiles.current].hide_completed = !hidden;
240 | $.jStorage.set(profilesKey, profiles);
241 |
242 | // Try to find a reasonable new scroll position
243 | for (var a=0; aoldPos) break;
244 | for (var b=0; boldPos+$(window).height()) break;
245 | if (!oldOff.length || $('h2:visible').last().offset().top>oldPos) $('html, body').scrollTop(oldPos);
246 | else if (a==b) $('html, body').scrollTop(Math.round(labels.eq(b).offset().top)-Math.round($(window).height()/2));
247 | else {var c = Math.round((a+b)/2); $('html, body').scrollTop(oldPos+Math.round(labels.eq(c).offset().top)-Math.round(oldOff[c]));}
248 | });
249 |
250 | $('[data-ng-toggle]').change(function() {
251 | var journey = $(this).data('ng-toggle');
252 |
253 | profiles[profilesKey][profiles.current].journey = +journey
254 | $.jStorage.set(profilesKey, profiles);
255 |
256 | toggleFilteredClasses('h_ng\\+');
257 | toggleFilteredClasses('s_ng\\+');
258 | toggleFilteredClasses('s_ng\\+\\+');
259 |
260 | calculateTotals();
261 | });
262 |
263 | $('[data-item-toggle]').change(function() {
264 | var type = $(this).data('item-toggle');
265 | var to_hide = $(this).is(':checked');
266 | var item_toggles = $(this).closest('.btn-group.btn-group-vertical').find('[data-item-toggle]');
267 |
268 | profiles[profilesKey][profiles.current].hidden_categories[type] = to_hide;
269 | $.jStorage.set(profilesKey, profiles);
270 |
271 | toggleFilteredClasses(type);
272 | toggleFilteredClasses('f_none');
273 |
274 | // Mark parent category as hidden if and only if all items in it are hidden
275 | if (to_hide === (item_toggles.length === item_toggles.filter(':checked').length)) {
276 | $(this).closest('.btn-group.btn-group-vertical').find('[data-category-toggle]').not(function(){return this.checked === to_hide}).click();
277 | }
278 | // Apply partial highlight to the parent category if at least one item in it is hidden
279 | $(this).closest('.btn-group.btn-group-vertical').find('.btn-group-vertical').toggleClass('open', item_toggles.filter(':checked').length > 0);
280 |
281 | calculateTotals();
282 | });
283 |
284 | $('[data-category-toggle]').change(function() {
285 | var to_hide = $(this).is(':checked');
286 | var item_toggles = $(this).closest('.btn-group.btn-group-vertical').find('[data-item-toggle]');
287 |
288 | // Change all child items to the same state as the category
289 | if (to_hide || (item_toggles.length === item_toggles.filter(':checked').length)) {
290 | item_toggles.not(function(){return this.checked === to_hide}).click();
291 | }
292 | });
293 |
294 | calculateTotals();
295 |
296 | });
297 |
298 | function initializeProfile(profile_name) {
299 | if (!(profile_name in profiles[profilesKey])) profiles[profilesKey][profile_name] = {};
300 | if (!('checklistData' in profiles[profilesKey][profile_name]))
301 | profiles[profilesKey][profile_name].checklistData = {};
302 | if (!('collapsed' in profiles[profilesKey][profile_name]))
303 | profiles[profilesKey][profile_name].collapsed = {};
304 | if (!('current_tab' in profiles[profilesKey][profile_name]))
305 | profiles[profilesKey][profile_name].current_tab = '#tabPlaythrough';
306 | if (!('hide_completed' in profiles[profilesKey][profile_name]))
307 | profiles[profilesKey][profile_name].hide_completed = false;
308 | if (!('journey' in profiles[profilesKey][profile_name]))
309 | profiles[profilesKey][profile_name].journey = 1;
310 | if (!('hidden_categories' in profiles[profilesKey][profile_name]))
311 | profiles[profilesKey][profile_name].hidden_categories = {
312 | f_boss: false,
313 | f_npc: false,
314 | f_estus: false,
315 | f_bone: false,
316 | f_tome: false,
317 | f_coal: false,
318 | f_ash: false,
319 | f_gest: false,
320 | f_sorc: false,
321 | f_pyro: false,
322 | f_mirac: false,
323 | f_ring: false,
324 | f_weap: false,
325 | f_arm: false,
326 | f_tit: false,
327 | f_gem: false,
328 | f_cov: false,
329 | f_misc: false
330 | };
331 | }
332 |
333 | /// restore all saved state, except for the current tab
334 | /// used on page load or when switching profiles
335 | function restoreState(profile_name) {
336 | $('a[href$="_col"]').each(function() {
337 | var value = profiles[profilesKey][profile_name].collapsed[$(this).attr('href')];
338 | var active = $(this).hasClass('collapsed');
339 |
340 | // interesting note: this condition is the same as (value ^ active),
341 | // but there's no logical xor in JS as far as I know; also, this is more readable
342 | if ((value && !active) || (!value && active)) {
343 | $($(this).attr('href')).collapse('toggle');
344 | }
345 | });
346 |
347 | var $button = $("#toggleHideCompleted");
348 | var hide_completed_state = profiles[profilesKey][profile_name].hide_completed;
349 | var button_active = $button.is(':checked');
350 | if ((hide_completed_state && !button_active) || (!hide_completed_state && button_active)) {
351 | $button.click();
352 | }
353 |
354 | $('[data-ng-toggle="' + profiles[profilesKey][profile_name].journey + '"]').click().change();
355 | $.each(profiles[profilesKey][profile_name].hidden_categories, function(key, value) {
356 | var $el = $('[data-item-toggle="' + key + '"]');
357 | var active = $el.is(':checked');
358 |
359 | if ((value && !active) || (!value && active)) {
360 | $el.click();
361 | }
362 | });
363 | }
364 |
365 | // Setup ("bootstrap", haha) styling
366 | function themeSetup(stylesheet) {
367 | if(stylesheet === null || stylesheet === undefined) { // if we didn't get a param, then
368 | stylesheet = $.jStorage.get("style") || "Standard"; // fall back on "light" if cookie not set
369 | }
370 | $("#bootstrap").attr("href", themes[stylesheet]);
371 | }
372 |
373 | function buildThemeSelection() {
374 | var style = $.jStorage.get("style") || "Standard";
375 | var themeSelect = $("#themes");
376 | $.each(themes, function(key, value){
377 | themeSelect.append(
378 | $('').val(key).html(key + " Theme")
379 | );
380 | });
381 | themeSelect.val(style);
382 | return style;
383 | }
384 |
385 | function dataLoadCallback(arg){
386 | var jsonProfileData = JSON.parse(arg.currentTarget.result);
387 | profiles = jsonProfileData;
388 | $.jStorage.set(profilesKey, profiles);
389 | populateProfiles();
390 | populateChecklists();
391 | $('#profiles').trigger("change");
392 | location.reload();
393 | }
394 |
395 | function populateProfiles() {
396 | $('#profiles').empty();
397 | $.each(profiles[profilesKey], function(index, value) {
398 | $('#profiles').append($("").attr('value', index).text(index));
399 | });
400 | $('#profiles').val(profiles.current);
401 | }
402 |
403 | function populateChecklists() {
404 | $('.checkbox input[type="checkbox"]')
405 | .prop('checked', false)
406 | .closest('label')
407 | .removeClass('completed')
408 | .closest('li').show();
409 |
410 | $.each(profiles[profilesKey][profiles.current].checklistData, function(index, value) {
411 | $('#' + index)
412 | .prop('checked', value)
413 | .closest('label')
414 | .toggleClass('completed', value);
415 | });
416 |
417 | calculateTotals();
418 | }
419 |
420 | function calculateTotals() {
421 | $('[id$="_overall_total"]').each(function(index) {
422 | var type = this.id.match(/(.*)_overall_total/)[1];
423 | var overallCount = 0, overallChecked = 0;
424 | $('[id^="' + type + '_totals_"]').each(function(index) {
425 | var regex = new RegExp(type + '_totals_(.*)');
426 | var regexFilter = new RegExp('^playthrough_(.*)');
427 | var i = parseInt(this.id.match(regex)[1]);
428 | var count = 0, checked = 0;
429 | for (var j = 1; ; j++) {
430 | var checkbox = $('#' + type + '_' + i + '_' + j);
431 | if (checkbox.length === 0) {
432 | break;
433 | }
434 | if (checkbox.is(':hidden') && checkbox.prop('id').match(regexFilter) && canFilter(checkbox.closest('li'))) {
435 | continue;
436 | }
437 | count++;
438 | overallCount++;
439 | if (checkbox.prop('checked')) {
440 | checked++;
441 | overallChecked++;
442 | }
443 | }
444 | if (checked === count) {
445 | this.innerHTML = $('#' + type + '_nav_totals_' + i)[0].innerHTML = 'DONE';
446 | $(this).removeClass('in_progress').addClass('done');
447 | $(this).parent('h3').addClass('completed');// Hide heading for completed category
448 | $($('#' + type + '_nav_totals_' + i)[0]).removeClass('in_progress').addClass('done');
449 | } else {
450 | this.innerHTML = $('#' + type + '_nav_totals_' + i)[0].innerHTML = checked + '/' + count;
451 | $(this).removeClass('done').addClass('in_progress');
452 | $(this).parent('h3').removeClass('completed');// Show heading for not yet completed category
453 | $($('#' + type + '_nav_totals_' + i)[0]).removeClass('done').addClass('in_progress');
454 | }
455 | $(this).parent('h3').next('div').children('h4').addClass('completed');// Hide all subheadings...
456 | $(this).parent('h3').next('div').children('ul').children('li').children('div').children('label:not(.completed)').parent('div').parent('li').parent('ul').prev('h4').removeClass('completed');// ... except those where not all entries below the subheading are labeled as completed
457 | });
458 | if (overallChecked === overallCount) {
459 | this.innerHTML = 'DONE';
460 | $(this).removeClass('in_progress').addClass('done');
461 | } else {
462 | this.innerHTML = overallChecked + '/' + overallCount;
463 | $(this).removeClass('done').addClass('in_progress');
464 | }
465 | // Update textarea for profile export
466 | document.getElementById("profileText").value = JSON.stringify(profiles);
467 | });
468 | }
469 |
470 | function addCheckbox(el) {
471 | var $el = $(el);
472 | // assuming all content lies on the first line
473 | var content = $el.html().split('\n')[0];
474 | var sublists = $el.children('ul');
475 |
476 | content =
477 | '
' +
478 | '' +
482 | '
';
483 |
484 | $el.html(content).append(sublists);
485 |
486 | if (profiles[profilesKey][profiles.current].checklistData[$el.attr('data-id')] === true) {
487 | $('#' + $el.attr('data-id')).prop('checked', true);
488 | $('label', $el).addClass('completed');
489 | }
490 | }
491 |
492 | function canDelete() {
493 | var count = 0;
494 | $.each(profiles[profilesKey], function(index, value) {
495 | count++;
496 | });
497 | return (count > 1);
498 | }
499 |
500 | function getFirstProfile() {
501 | for (var profile in profiles[profilesKey]) {
502 | return profile;
503 | }
504 | }
505 |
506 | function canFilter(entry) {
507 | var classAttr = entry.attr('class');
508 | if (!classAttr) {
509 | return false;
510 | }
511 | if (classAttr === 'f_none') {
512 | // If some filters are enabled, all entries marked f_none are automatically filtered as well
513 | return Object.values(profiles[profilesKey][profiles.current].hidden_categories).some(function(f){return f});
514 | }
515 | var classList = classAttr.split(/\s+/);
516 | for (var i = 0; i < classList.length; i++) {
517 | // Hide(h) or show(s) entries based on journey number
518 | if ((classList[i].match(/^h_ng\+*$/) && classList[i].match(/^h_ng(\+*)$/)[1].length < profiles[profilesKey][profiles.current].journey) ||
519 | (classList[i].match(/^s_ng\+*$/) && classList[i].match(/^s_ng(\+*)$/)[1].length >= profiles[profilesKey][profiles.current].journey)) {
520 | return true;
521 | }
522 | }
523 | var foundMatch = 0;
524 | for (var i = 0; i < classList.length; i++) {
525 | if (!classList[i].match(/^f_.*/)) {
526 | continue;
527 | }
528 | if(classList[i] in profiles[profilesKey][profiles.current].hidden_categories) {
529 | if(!profiles[profilesKey][profiles.current].hidden_categories[classList[i]]) {
530 | return false;
531 | }
532 | foundMatch = 1;
533 | }
534 | }
535 | if (foundMatch === 0) {
536 | return false;
537 | }
538 | return true;
539 | }
540 |
541 | function toggleFilteredClasses(str) {
542 | $("li." + str).each(function() {
543 | if(canFilter($(this))) {
544 | $(this).css('display', 'none');
545 | } else {
546 | $(this).css('display', '');
547 | }
548 | });
549 | }
550 |
551 | /*
552 | * ----------------------------------
553 | * Search and highlight functionality
554 | * ----------------------------------
555 | */
556 | $(function() {
557 | var jets = [new Jets({
558 | searchTag: '#playthrough_search',
559 | contentTag: '#playthrough_list ul'
560 | }), new Jets({
561 | searchTag: '#item_search',
562 | contentTag: '#item_list h4, #item_list ul'// This does not mean that we are searching inside the content of both
and
tags
563 | }), new Jets({
564 | searchTag: '#weapons_search',
565 | contentTag: '#weapons_list h4, #weapons_list ul'// The outcome is that all
Master of the Prosthetic: Upgraded all Prosthetic Tools to their limit
404 |
405 |
Loaded Shuriken
406 |
407 |
Spinning Shuriken
408 |
Gouging Top
409 |
Phantom Kunai
410 |
Sen Throw
411 |
Lazulite Shuriken
412 |
413 |
Shinobi Firecracker
414 |
415 |
Spring-load Firecracker
416 |
Long Spark
417 |
Purple Fume Spark
418 |
419 |
Flame Vent
420 |
421 |
Spring-load Flame Vent
422 |
Okinaga's Flame Vent
423 |
Lazulite Sacred Flame
424 |
425 |
Loaded Axe
426 |
427 |
Spring-load Axe
428 |
Sparking Axe
429 |
Lazulite Axe
430 |
431 |
Mist Raven
432 |
433 |
Aged Feather Mist Raven
434 |
Great Feather Mist Raven
435 |
436 |
Loaded Spear
437 |
438 |
Loaded Spear Thrust Type
439 |
Loaded Spear Cleave Type
440 |
Spiral Spear
441 |
Leaping Flame
442 |
443 |
Sabimaru
444 |
445 |
Improved Sabimaru
446 |
Piercing Sabimaru
447 |
Lazulite Sabimaru
448 |
449 |
Divine Abduction
450 |
451 |
Golden Vortex
452 |
Double Divine Abduction
453 |
454 |
Loaded Umbrella
455 |
456 |
Loaded Umbrella - Magnet
457 |
Phoenix's Lilac Umbrella
458 |
Suzaku's Lotus Umbrella
459 |
460 |
Finger Whistle
461 |
462 |
Mountain Echo
463 |
Malcontent
464 |
465 |
466 |
467 |
Ultimate Healing Gourd: Fully upgraded the Healing Gourd. See Gourd Seeds
468 |
469 |
Ashina Outskirts - Drop from General Naomori Kawarada, immediately past the "Outskirts Wall - Gate Path" Sculptor's Idol
470 |
Ashina Outskirts - In the building right after the Chained Ogre, just past the "Outskirts Wall - Stairway" Sculptor's Idol
471 |
Ashina Outskirts - Bought from the Battlefield Memorial Mob Vendor for 1,000 Sen, located up the steps and to the right from where you fight Gyoubu Oniwa
472 |
Ashina Castle - Just before the "Upper Tower - Antechamber" Sculptor's Idol in a chest
473 |
Dilapidated Temple - One can be bought from Fujioka the Info Broker for 2,000 Sen, once he arrives
474 |
Senpou Temple, Mt. Kongo - In front of the first immortal monk you encounter in the Senpou Temple, in the first building that's filled with crickets
475 |
Sunken Valley - From the "Under-shrine Valley" Idol, progress forward and after encountering the fourth rifleman on the path, climb up the wall on the left to find the gourd seed in a small hut
476 |
Ashina Depths - In the center of Mibu Village, by the orange glowing tree. It is guarded by multiple enemies
477 |
Fountainhead Palace - In a chest in the last room of the palace by the "Palace Grounds" Sculptor's Idol
Nope, not really. This is a set of checklists and information that you can use while playing Dark Souls to make sure you don't miss an item, action, conversation, or boss. If you need playthroughs then you can click on the zone titles to read the wiki walkthrough.
588 |
589 |
Do I need to follow the playthrough in this exact order?
590 |
Sekiro is not a linear game and has multiple ways of progressing. This guide highlights zones as they become available, so feel free to follow however you please. You can always check things off in a different order.
591 |
592 |
Can I use this for multiple characters?
593 |
Yup, use the profile selector and buttons in the options tab at the top of the page to setup multiple profiles.
594 |
595 |
How does the checklist status get saved?
596 |
The checklist is saved to your browser's local storage. Be careful when clearing your browser's cache as it will also destroy your saved progress.
597 |
598 |
599 |
600 |
Options
601 |
602 |
603 |
604 |
Theme selection:
605 |
606 |
607 |
608 |
609 |
Profile management:
610 |
611 |
619 |
620 |
621 |
622 |
623 |
Data import/export:
624 |
625 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
Profile
648 |
649 |
650 |
658 |
659 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
Begin next journey?
677 |
678 |
679 | If you begin the next journey, all progress on the "Playthrough" and "Misc" tabs of this profile will be reset, while achievement and collection checklists will be kept.
680 |
681 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 | Back to Top
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
716 |
717 |
718 |
--------------------------------------------------------------------------------