diff --git a/README.md b/README.md
index c31b7e4..7ba5f46 100644
--- a/README.md
+++ b/README.md
@@ -183,7 +183,7 @@ You will have 50 love gems on 01/16/2016. Good things come to those who wait!
## The Web App
-You asked for a web app, and here it is! The [web_app](web_app) directory contains a (mostly) fully featured web app version of SIF Tools. The best part is, you don't need a web server to run it. You should just be able to open the [sif_tools.html](web_app/sif_tools.html) file in your local web browser and run it right on your own computer. You will need to have JavaScript enabled in your browser however. (Of course you can host these files on a web server just like any other website, if you happen to have access to a web server.)
+You asked for a web app, and here it is! The [web_app](web_app) directory contains a fully featured web app version of SIF Tools. In fact, the web app actually does some things that the original Python scripts don't! (yet.) The best part is, you don't need a web server to run it. You should just be able to open the [sif_tools.html](web_app/sif_tools.html) file in your local web browser and run it right on your own computer. You will need to have JavaScript enabled in your browser however. (Of course you can host these files on a web server just like any other website, if you happen to have access to a web server.) Or you can run the copy hosted on my own web server [here](https://beta.DonaldBurr.com/sif_tools/sif_tools.html).
## Credits
diff --git a/web_app/index.html b/web_app/index.html
index 7c11c2c..9c94c0e 100644
--- a/web_app/index.html
+++ b/web_app/index.html
@@ -1,10 +1,13 @@
+
-
+
diff --git a/web_app/js/sif_tools.js b/web_app/js/sif_tools.js
index a0d11aa..bc89759 100644
--- a/web_app/js/sif_tools.js
+++ b/web_app/js/sif_tools.js
@@ -22,20 +22,26 @@
// TODO:
// =====
-// * account for 1.2x bonus when feeding cards of the same attribute
-// (maybe also the super (1.5) and ultra (2.0) success bonuses too?)
-// * @sifen_trackbot update code gets "stuck" sometimes - not sure if the problem
-// is in the twitter fetcher or elsewhere
-// * needs a lot more error/bounds checking
+// * General improvements:
+// - needs a lot more error/bounds checking in general
+// * Card Level Calc:
+// - maybe also the super (1.5) and ultra (2.0) success bonuses too?
+// * Event Tracker:
+// - @sifen_trackbot update code gets "stuck" sometimes - not sure if the problem
+// is in the twitter fetcher or elsewhere
// Set to 0 to disable debugging, 1+ to enable debugging (higher = more verbose)
var DEBUG_LEVEL = 0;
// EXP tables
-var exp_table_n = [-1, 0, 6, 18, 28, 40, 51, 61, 72, 82, 93, 104, 114, 124, 135, 145, 156, 165, 176, 187, 196, 207, 217, 226, 238, 247, 257, 268, 277, 288, 297, 308, 317, 328, 337, 348, 358, 367, 377, 388, 397];
-var exp_table_r = [-1, 0, 14, 31, 45, 55, 67, 76, 85, 94, 103, 110, 119, 125, 134, 140, 148, 155, 161, 168, 174, 181, 187, 193, 199, 206, 211, 217, 223, 228, 235, 240, 245, 251, 256, 262, 267, 272, 277, 283, 288, 292, 298, 303, 308, 313, 317, 323, 327, 332, 337, 342, 346, 351, 356, 360, 365, 370, 374, 378, 383];
-var exp_table_sr = [-1, 0, 54, 98, 127, 150, 169, 187, 203, 218, 232, 245, 257, 269, 281, 291, 302, 311, 322, 331, 340, 349, 358, 366, 374, 383, 391, 398, 406, 413, 421, 428, 435, 442, 449, 456, 462, 469, 475, 482, 488, 494, 500, 507, 512, 518, 524, 530, 536, 541, 547, 552, 558, 563, 568, 574, 579, 584, 590, 594, 600, 605, 609, 615, 619, 625, 629, 634, 639, 643, 648, 653, 657, 662, 667, 670, 676, 680, 684, 689, 693];
-var exp_table_ur = [-1, 0, 201, 294, 345, 382, 411, 438, 460, 481, 499, 517, 532, 547, 561, 574, 587, 598, 611, 621, 631, 642, 651, 661, 670, 679, 687, 696, 704, 712, 720, 727, 734, 742, 749, 755, 763, 769, 775, 782, 788, 794, 800, 806, 812, 818, 823, 829, 834, 840, 845, 850, 856, 860, 866, 870, 875, 880, 885, 890, 894, 899, 903, 908, 912, 917, 921, 925, 930, 933, 938, 942, 946, 950, 954, 959, 961, 966, 970, 974, 977, 981, 985, 988, 992, 996, 999, 1003, 1006, 1010, 1013, 1017, 1020, 1024, 1027, 1030, 1034, 1037, 1040, 1043, 1047];
+// from: http://www59.atwiki.jp/lovelive-sif/pages/32.html
+var exp_table_n = [ -1, 0, 6, 18, 28, 40, 51, 61, 72, 82, 93, 104, 114, 124, 135, 145, 156, 165, 176, 187, 196, 207, 217, 226, 238, 247, 257, 268, 277, 288, 297, 308, 317, 328, 337, 348, 358, 367, 377, 388, 397 ];
+
+var exp_table_r = [ -1, 0, 14, 31, 45, 55, 67, 76, 85, 94, 103, 110, 119, 125, 134, 140, 148, 155, 161, 168, 174, 181, 187, 193, 199, 206, 211, 217, 223, 228, 235, 240, 245, 251, 256, 262, 267, 272, 277, 283, 288, 292, 298, 303, 308, 313, 317, 323, 327, 332, 337, 342, 346, 351, 356, 360, 365, 370, 374, 378, 383 ];
+
+var exp_table_sr = [ -1, 0, 54, 98, 127, 150, 169, 187, 203, 218, 232, 245, 257, 269, 281, 291, 302, 311, 322, 331, 340, 349, 358, 366, 374, 383, 391, 398, 406, 413, 421, 428, 435, 442, 449, 456, 462, 469, 475, 482, 488, 494, 500, 507, 512, 518, 524, 530, 536, 541, 547, 552, 558, 563, 568, 574, 579, 584, 590, 594, 600, 605, 609, 615, 619, 625, 629, 634, 639, 643, 648, 653, 657, 662, 667, 670, 676, 680, 684, 689, 693 ];
+
+var exp_table_ur = [ -1, 0, 201, 294, 345, 382, 411, 438, 460, 481, 499, 517, 532, 547, 561, 574, 587, 598, 611, 621, 631, 642, 651, 661, 670, 679, 687, 696, 704, 712, 720, 727, 734, 742, 749, 755, 763, 769, 775, 782, 788, 794, 800, 806, 812, 818, 823, 829, 834, 840, 845, 850, 856, 860, 866, 870, 875, 880, 885, 890, 894, 899, 903, 908, 912, 917, 921, 925, 930, 933, 938, 942, 946, 950, 954, 959, 961, 966, 970, 974, 977, 981, 985, 988, 992, 996, 999, 1003, 1006, 1010, 1013, 1017, 1020, 1024, 1027, 1030, 1034, 1037, 1040, 1043, 1047 ];
// global variable to keep event state, because we need it to live between function calls.
// YES I KNOW THIS IS BAD. SO SUE ME. IT WORKS THOUGH. :P
@@ -43,159 +49,211 @@ var exp_table_ur = [-1, 0, 201, 294, 345, 382, 411, 438, 460, 481, 499, 517, 532
var current_type_of_event = 1;
// debug logging
-function LOG(level, msg)
-{
- if (DEBUG_LEVEL > 0 && DEBUG_LEVEL >= level) {
- console.log(msg);
- }
+function LOG(level, msg) {
+ if (DEBUG_LEVEL > 0 && DEBUG_LEVEL >= level) {
+ console.log(msg);
+ }
}
// Main function, runs automatically at document-ready (i.e. when the page is finished loading)
-$(document).ready(function(){
+$(document).ready(function() {
// Hide the address bar on mobile browsers
- setTimeout(function(){
+ setTimeout(function() {
// some sites suggest 0,0 and others 0,1 - not sure which is correct
window.scrollTo(0, 0);
}, 0);
- // set up UI (buttons, etc.)
- setup_ui_elements();
- // set up button handlers
- setup_button_handlers();
- // set up slider handlers
+ // set up UI (buttons, etc.)
+ setup_ui_elements();
+ // set up button handlers
+ setup_button_handlers();
+ // set up slider handlers
window.timerInterval = 0;
});
// Set up UI elements (tabs, buttons, etc.)
-function setup_ui_elements()
-{
- LOG(1, "setup_ui_elements()");
- var default_tab = $.cookie("default_tab");
- if (isNaN(default_tab)) {
- default_tab = 0;
+function setup_ui_elements() {
+ LOG(1, "setup_ui_elements()");
+ var QueryString = function() {
+ // http://stackoverflow.com/a/979995
+ // This function is anonymous, is executed immediately and
+ // the return value is assigned to QueryString!
+ var query_string = {};
+ var query = window.location.search.substring(1);
+ var vars = query.split("&");
+ for (var i = 0; i < vars.length; i++) {
+ var pair = vars[i].split("=");
+ // If first entry with this name
+ if (typeof query_string[pair[0]] === "undefined") {
+ query_string[pair[0]] = decodeURIComponent(pair[1]);
+ } else if (typeof query_string[pair[0]] === "string") {
+ var arr = [ query_string[pair[0]], decodeURIComponent(pair[1]) ];
+ query_string[pair[0]] = arr;
+ } else {
+ query_string[pair[0]].push(decodeURIComponent(pair[1]));
+ }
+ }
+ return query_string;
+ }();
+ var default_tab = 0;
+ if (!isNaN(QueryString.tab)) {
+ if (QueryString.tab >= 1 && QueryString.tab <= 4) {
+ default_tab = QueryString.tab - 1;
+ }
+ } else {
+ var default_tab_from_cookie = $.cookie("default_tab");
+ if (isNaN(default_tab_from_cookie)) {
+ default_tab = 0;
+ } else {
+ default_tab = default_tab_from_cookie;
+ }
}
-
- $( "#tabs" ).tabs({
- active: default_tab,
- create: function(event, ui) {
- var theTab = ui.tab.index();
- LOG(3, "INIT tab created " + theTab);
- set_up_tab(theTab);
- },
- activate: function(event, ui) {
- var theTab = ui.newTab.index();
- LOG(3, "INIT tab selected " + theTab);
- set_up_tab(theTab);
- }
- });
-
+ $("#tabs").tabs({
+ active: default_tab,
+ create: function(event, ui) {
+ var theTab = ui.tab.index();
+ LOG(3, "INIT tab created " + theTab);
+ set_up_tab(theTab);
+ },
+ activate: function(event, ui) {
+ var theTab = ui.newTab.index();
+ LOG(3, "INIT tab selected " + theTab);
+ set_up_tab(theTab);
+ }
+ });
// only set up keypads on mobile browsers
// not sure what the best way of doing this is
var pageWidth = $(window).width();
if (pageWidth < 1024) {
- $( "#current_rank" ).prop('readonly', true);
- $( "#current_rank" ).keypad(); // {prompt: 'Enter here'}
- $( "#current_exp" ).prop('readonly', true);
- $( "#current_exp" ).keypad(); // {prompt: 'Enter here'}
- $( "#desired_rank" ).prop('readonly', true);
- $( "#desired_rank" ).keypad(); // {prompt: 'Enter here'}
- $( "#current_gems" ).prop('readonly', true);
- $( "#current_gems" ).keypad(); // {prompt: 'Enter here'}
- $( "#gem_desired_gems" ).prop('readonly', true);
- $( "#gem_desired_gems" ).keypad(); // {prompt: 'Enter here'}
- $( "#card_current_level" ).prop('readonly', true);
- $( "#card_current_level" ).keypad(); // {prompt: 'Enter here'}
- $( "#card_current_exp" ).prop('readonly', true);
- $( "#card_current_exp" ).keypad(); // {prompt: 'Enter here'}
- $( "#card_desired_level" ).prop('readonly', true);
- $( "#card_desired_level" ).keypad(); // {prompt: 'Enter here'}
- $( "#card_feed_exp" ).prop('readonly', true);
- $( "#card_feed_exp" ).keypad(); // {prompt: 'Enter here'}
+ $("#current_rank").prop("readonly", true);
+ $("#current_rank").keypad();
+ // {prompt: 'Enter here'}
+ $("#current_exp").prop("readonly", true);
+ $("#current_exp").keypad();
+ // {prompt: 'Enter here'}
+ $("#desired_rank").prop("readonly", true);
+ $("#desired_rank").keypad();
+ // {prompt: 'Enter here'}
+ $("#current_gems").prop("readonly", true);
+ $("#current_gems").keypad();
+ // {prompt: 'Enter here'}
+ $("#gem_desired_gems").prop("readonly", true);
+ $("#gem_desired_gems").keypad();
+ // {prompt: 'Enter here'}
+ $("#card_current_level").prop("readonly", true);
+ $("#card_current_level").keypad();
+ // {prompt: 'Enter here'}
+ $("#card_current_exp").prop("readonly", true);
+ $("#card_current_exp").keypad();
+ // {prompt: 'Enter here'}
+ $("#card_desired_level").prop("readonly", true);
+ $("#card_desired_level").keypad();
+ // {prompt: 'Enter here'}
+ $("#card_feed_exp").prop("readonly", true);
+ $("#card_feed_exp").keypad();
} else {
- $( "#current_rank" ).prop('readonly', false);
- $( "#current_exp" ).prop('readonly', false);
- $( "#desired_rank" ).prop('readonly', false);
- $( "#current_gems" ).prop('readonly', false);
- $( "#gem_desired_gems" ).prop('readonly', false);
- $( "#card_current_level" ).prop('readonly', false);
- $( "#card_current_exp" ).prop('readonly', false);
- $( "#card_desired_level" ).prop('readonly', false);
- $( "#card_feed_exp" ).prop('readonly', false);
+ $("#current_rank").prop("readonly", false);
+ $("#current_exp").prop("readonly", false);
+ $("#desired_rank").prop("readonly", false);
+ $("#current_gems").prop("readonly", false);
+ $("#gem_desired_gems").prop("readonly", false);
+ $("#card_current_level").prop("readonly", false);
+ $("#card_current_exp").prop("readonly", false);
+ $("#card_desired_level").prop("readonly", false);
+ $("#card_feed_exp").prop("readonly", false);
}
-
// set up date/time pickers
- $( "#gem_desired_date" ).datepicker();
- $( "#event_end_date" ).datepicker();
+ $("#gem_desired_date").datepicker();
+ $("#event_end_date").datepicker();
// $( "#event_end_time" ).timepicker();
- $('#event_end_time').timepicker({ 'timeFormat': 'H:i', 'disableTextInput': true });
-
- // set up buttons
- ["calculate-rank", "reset-rank", "calculate-gems", "reset-gems", "calculate-card", "reset-card", "start-stop-timer", "clear-timer"].forEach(function(entry) {
- var selector = "#button-" + entry;
- LOG(1, "setting up " + selector);
- $(selector).button();
- });
-
+ $("#event_end_time").timepicker({
+ timeFormat: "H:i",
+ disableTextInput: true
+ });
+ // set up buttons
+ [ "calculate-rank", "reset-rank", "calculate-gems", "reset-gems", "card-max-level", "calculate-card", "reset-card", "start-stop-timer", "clear-timer" ].forEach(function(entry) {
+ var selector = "#button-" + entry;
+ LOG(1, "setting up " + selector);
+ $(selector).button();
+ });
// hide result divs
- ["rank-calc-result-area", "gem-calc-result-area", "card-calc-result-area"].forEach(function(entry) {
+ [ "rank-calc-result-area", "gem-calc-result-area", "card-calc-result-area" ].forEach(function(entry) {
var selector = "#" + entry;
LOG(1, "setting up " + selector);
$(selector).hide();
});
-
// set up radio button listeners
$("input[name=gem-mode]").change(handle_gem_mode_select);
$("input[name=card-mode]").change(handle_card_mode_select);
-
- // hide non-selected option divs
- ["gem-event-options-area", "gem-desired-gems-area", "card-exp-area", "gem_jp_daily_gems"].forEach(function(entry) {
- var selector = "#" + entry;
- LOG(1, "setting up " + selector);
- $(selector).hide();
- });
-
// set up checkbox change event handler
$("#gems_include_events").change(function() {
- handle_gem_event_box(this.checked);
+ update_ui();
});
-
// set up gem event calc note dialog
// $("#dialog").dialog({ autoOpen: false });
$("a#gem_event_readme").click(function(e) {
- e.preventDefault();
- $("#gem_event_readme_dialog").dialog({height:300});
+ e.preventDefault();
+ $("#gem_event_readme_dialog").dialog({
+ height: 300
+ });
});
$("a#gem_quest_readme").click(function(e) {
- e.preventDefault();
- $("#gem_quest_readme_dialog").dialog({height:300});
+ e.preventDefault();
+ $("#gem_quest_readme_dialog").dialog({
+ height: 300
+ });
});
-
// set up show/hide JP-only options
- $('#gem_game_version').on('change', function (e) {
- handle_gem_game_version_change();
+ $("#gem_game_version").on("change", function(e) {
+ update_ui();
});
+ // update the UI based on what is selected
+ update_ui();
}
-function handle_gem_game_version_change()
+// show/hide option div's based on which modes are selected
+function update_ui()
{
- var game_version = $("#gem_game_version").val();
- if (game_version === "JP") {
+ // gem screen - show/hide the options based on game version
+ var gem_game_version = $("#gem_game_version").val();
+ if (gem_game_version === "JP") {
$("#gem_jp_daily_gems").show();
} else {
$("#gem_jp_daily_gems").hide();
}
-}
-
-function handle_gem_event_box(show_it)
-{
- if (show_it) {
+ // gem screen - hide event tier selector
+ var gem_events_selected = $("#gems_include_events").is(":checked");
+ if (gem_events_selected) {
$("#gem-event-options-area").show();
} else {
$("#gem-event-options-area").hide();
}
+ // gem screen - mode
+ var gem_mode = $("#gem-mode").val();
+ switch(gem_mode) {
+ case "DATE":
+ $("#gem-date-area").show();
+ $("#gem-desired-gems-area").hide();
+ break;
+ case "GEMS":
+ $("#gem-date-area").hide();
+ $("#gem-desired-gems-area").show();
+ break;
+ }
+ // card screen - mode
+ var card_mode = $("#card-mode").val();
+ switch(card_mode) {
+ case "LEVEL":
+ $("#card-level-area").show();
+ $("#card-exp-area").hide();
+ break;
+ case "EXP":
+ $("#card-level-area").hide();
+ $("#card-exp-area").show();
+ break;
+ }
}
-function setup_button_handlers()
-{
+function setup_button_handlers() {
$("#button-calculate-rank").click(function(evt) {
calculate_rank();
});
@@ -208,6 +266,9 @@ function setup_button_handlers()
$("#button-reset-gems").click(function(evt) {
reset_gems();
});
+ $("#button-card-max-level").click(function(evt) {
+ card_set_max_level();
+ });
$("#button-calculate-card").click(function(evt) {
calculate_card();
});
@@ -223,43 +284,47 @@ function setup_button_handlers()
}
// tab functions
+function set_up_tab(tab) {
+ switch (tab) {
+ case 0:
+ rank_calc_tab_selected();
+ break;
-function set_up_tab(tab)
-{
- switch(tab) {
- case 0: rank_calc_tab_selected(); break;
- case 1: love_gem_calc_tab_selected(); break;
- case 2: card_level_calc_tab_selected(); break;
- case 3: event_end_calc_tab_selected(); break;
+ case 1:
+ love_gem_calc_tab_selected();
+ break;
+
+ case 2:
+ card_level_calc_tab_selected();
+ break;
+
+ case 3:
+ event_end_calc_tab_selected();
+ break;
}
}
-function rank_calc_tab_selected()
-{
+function rank_calc_tab_selected() {
LOG(1, "rank_calc_tab_selected");
$.cookie("default_tab", 0);
}
-function love_gem_calc_tab_selected()
-{
- LOG(1, "love_gem_calc_tab_selected");
+function love_gem_calc_tab_selected() {
+ LOG(1, "love_gem_calc_tab_selected");
$.cookie("default_tab", 1);
}
-function card_level_calc_tab_selected()
-{
- LOG(1, "card_level_calc_tab_selected");
+function card_level_calc_tab_selected() {
+ LOG(1, "card_level_calc_tab_selected");
$.cookie("default_tab", 2);
}
-function event_end_calc_tab_selected()
-{
- LOG(1, "event_end_calc_tab_selected");
+function event_end_calc_tab_selected() {
+ LOG(1, "event_end_calc_tab_selected");
$.cookie("default_tab", 3);
}
-function calculate_rank()
-{
+function calculate_rank() {
// validate data
var current_rank = parseInt($("#current_rank").val());
var current_exp_input = $("#current_exp").val();
@@ -278,17 +343,17 @@ function calculate_rank()
} else if (desired_rank <= current_rank) {
window.alert("Error: desired rank must be greater than current rank.");
} else {
- var required_exp = 0
- for (rank = current_rank ; rank < desired_rank ; rank++) {
- var required_exp_for_next_rank = Math.round(34.45 * rank - 551)
+ var required_exp = 0;
+ for (rank = current_rank; rank < desired_rank; rank++) {
+ var required_exp_for_next_rank = Math.round(34.45 * rank - 551);
// account for half EXP on JP (only if rank < 100)
if (game_version === "JP" && rank < 100) {
required_exp_for_next_rank /= 2;
}
- required_exp = required_exp + required_exp_for_next_rank
+ required_exp = required_exp + required_exp_for_next_rank;
}
// account for exp we already have
- required_exp -= current_exp
+ required_exp -= current_exp;
// convert to integer
required_exp = Math.round(required_exp);
// now calc the # of songs needed
@@ -297,17 +362,33 @@ function calculate_rank()
var normal_count = Math.round(required_exp / 26);
var hard_count = Math.round(required_exp / 46);
var expert_count = Math.round(required_exp / 83);
+ var m3_easy_count = Math.round(required_exp / (12*3));
+ var m3_normal_count = Math.round(required_exp / (26*3));
+ var m3_hard_count = Math.round(required_exp / (46*3));
+ var m3_expert_count = Math.round(required_exp / (83*3));
+ // Increases the amount of EXP gained by 10%.
+ var m3b_easy_count = Math.round(required_exp / (12*1.1*3));
+ var m3b_normal_count = Math.round(required_exp / (26*1.1*3));
+ var m3b_hard_count = Math.round(required_exp / (46*1.1*3));
+ var m3b_expert_count = Math.round(required_exp / (83*1.1*3));
// calc LP and FP
- var LP = 25 + Math.floor(Math.min(desired_rank, 300) / 2) + Math.floor(Math.max(desired_rank - 300, 0) / 3)
+ var LP = 25 + Math.floor(Math.min(desired_rank, 300) / 2) + Math.floor(Math.max(desired_rank - 300, 0) / 3);
// calc friend slots
- var friend_slots = 10 + Math.floor(Math.min(desired_rank, 50) / 5) + Math.floor(Math.max(desired_rank - 50, 0) / 10)
-
+ var friend_slots = 10 + Math.floor(Math.min(desired_rank, 50) / 5) + Math.floor(Math.max(desired_rank - 50, 0) / 10);
// display the results
$("#rank-result-exp").text(required_exp);
$("#rank-result-songs-easy").text(easy_count);
$("#rank-result-songs-normal").text(normal_count);
$("#rank-result-songs-hard").text(hard_count);
$("#rank-result-songs-expert").text(expert_count);
+ $("#rank-result-songs-easy-mf").text(m3_easy_count);
+ $("#rank-result-songs-normal-mf").text(m3_normal_count);
+ $("#rank-result-songs-hard-mf").text(m3_hard_count);
+ $("#rank-result-songs-expert-mf").text(m3_expert_count);
+ $("#rank-result-songs-easy-mfb").text(m3b_easy_count);
+ $("#rank-result-songs-normal-mfb").text(m3b_normal_count);
+ $("#rank-result-songs-hard-mfb").text(m3b_hard_count);
+ $("#rank-result-songs-expert-mfb").text(m3b_expert_count);
// rank-results-lp">- LP and 2) || (game_version === "JP" && current_type_of_event > 3)) {
+ if (game_version === "EN" && current_type_of_event > 2 || game_version === "JP" && current_type_of_event > 3) {
current_type_of_event = 1;
}
}
-
LOG(1, "end event type is " + current_type_of_event);
LOG(1, return_tuple);
// now return what we got
return return_tuple;
}
-function calculate_gems()
-{
+function calculate_gems() {
// reset current event indicator (start out with a token event)
current_type_of_event = 1;
-
- var verbose = $("#gems_verbose").is(':checked');
+ var verbose = $("#gems_verbose").is(":checked");
var current_gems_text = $("#current_gems").val();
var current_gems = 0;
if (current_gems_text != "") {
@@ -569,47 +641,43 @@ function calculate_gems()
alert("Error: invalid number of current gems. Please check your input and try again.");
return;
}
-
var tier = parseInt($("#gems_tier_level").val());
var game_version = $("#gem_game_version").val();
var calc_daily_quest_gems = false;
- var calc_event_gems = $("#gems_include_events").is(':checked');
+ var calc_event_gems = $("#gems_include_events").is(":checked");
if (game_version === "JP") {
- calc_daily_quest_gems = $("#gems_include_daily_gems").is(':checked');
+ calc_daily_quest_gems = $("#gems_include_daily_gems").is(":checked");
}
var mode = $("input[name=gem-mode]:checked").val();
- if (mode === "DATE") {
+ if (mode === "DATE") {
var target_date = $("#gem_desired_date").val();
if (target_date === "") {
alert("Error: invalid date. Please check and try again.");
return;
}
var target_date_object = moment(new Date(target_date));
- if (!target_date_object.isValid()) {
+ if (!target_date_object.isValid()) {
alert("Error: invalid date. Please check and try again.");
return;
}
-
var now = moment(new Date());
if (target_date_object.isBefore(now) || is_same_day(now, target_date_object)) {
window.alert("Error: the date must be in the future.");
return;
}
-
// ready to rock
var resultsString = sprintf("Today is %02d/%02d/%04d and you currently have %d love gems. (Assuming you collected any gems you got today and already counted those.)", month(now), day(now), year(now), current_gems);
var verboseText = "";
if (calc_daily_quest_gems) {
verboseText = "(Including daily 'quest' gems in the calculation. There will not be a separate daily entry for each one.)
";
}
- var gems = current_gems
- now = now.add(1, 'days')
+ var gems = current_gems;
+ now = now.add(1, "days");
while (now.isBefore(target_date_object) || is_same_day(now, target_date_object)) {
// is it a login bonus?
if (is_gem_day(now)) {
gems += 1;
}
-
// is it a birthday?
var birthday_tuple = is_muse_members_birthday(now);
var is_bday = birthday_tuple[0];
@@ -617,61 +685,57 @@ function calculate_gems()
if (is_bday) {
gems += 5;
}
-
// account for daily login quest gem
if (calc_daily_quest_gems) {
gems++;
}
-
- // account for event
- // format of returned tuple:
- // tuple[0] - was this an event day? (boolean, duh)
- // tuple[1] - name of event, or "" if none (string)
- // tuple[2] - amount of gems spent (int)
- // tuple[3] - amount of gems gained (int)
- var event_results = handle_event(day(now), game_version, tier);
- var is_event = event_results[0];
- var event_name = "";
- var spent_gems = 0;
- var won_gems = 0;
- if (is_event) {
- event_name = event_results[1];
- spent_gems = event_results[2];
- won_gems = event_results[3];
- // did any gems get spent?
- if (spent_gems > 0) {
- // do we have enough to cover it?
- if (gems >= spent_gems) {
- // spend the gems
- gems -= spent_gems;
- // now reap the winnings
- gems += won_gems;
+ if (calc_event_gems) {
+ // account for event
+ // format of returned tuple:
+ // tuple[0] - was this an event day? (boolean, duh)
+ // tuple[1] - name of event, or "" if none (string)
+ // tuple[2] - amount of gems spent (int)
+ // tuple[3] - amount of gems gained (int)
+ var event_results = calculate_event(day(now), game_version, tier);
+ var is_event = event_results[0];
+ var event_name = "";
+ var spent_gems = 0;
+ var won_gems = 0;
+ if (is_event) {
+ event_name = event_results[1];
+ spent_gems = event_results[2];
+ won_gems = event_results[3];
+ // did any gems get spent?
+ if (spent_gems > 0) {
+ // do we have enough to cover it?
+ if (gems >= spent_gems) {
+ // spend the gems
+ gems -= spent_gems;
+ // now reap the winnings
+ gems += won_gems;
+ } else {
+ // flag to indicate that we didn't have the gems
+ spent_gems = -1;
+ }
} else {
- // flag to indicate that we didn't have the gems
- spent_gems = -1;
+ gems += won_gems;
}
- } else {
- gems += won_gems;
}
}
-
// record verbose output if desired
if (verbose) {
- if (is_gem_day(now) || is_bday || is_event) {
+ if (is_gem_day(now) || is_bday || is_event) {
verboseText += sprintf("%02d/%02d/%04d ", month(now), day(now), year(now));
-
if (is_gem_day(now)) {
verboseText += "Free gem as login bonus! ";
}
-
if (is_bday) {
verboseText += sprintf("It's %s's birthday! You get 5 gems! ", name);
}
-
// account for events
if (is_event) {
verboseText += sprintf("A " + event_name + " just ended! ", month(now), day(now), year(now), event_name);
- if (spent_gems == -1) {
+ if (spent_gems == -1) {
verboseText += "You didn't have enough gems to participate. ";
} else {
if (spent_gems == 0) {
@@ -681,14 +745,12 @@ function calculate_gems()
}
}
}
-
// add a newline
verboseText += sprintf("That brings you to %d gems!
", gems);
}
}
- now = now.add(1, 'days')
+ now = now.add(1, "days");
}
-
resultsString = resultsString + sprintf(" You will have %d love gems on %02d/%02d/%04d. Good things come to those who wait!", gems, month(target_date_object), day(target_date_object), year(target_date_object));
$("#gem-result-summary").html(resultsString);
if (verbose) {
@@ -698,35 +760,29 @@ function calculate_gems()
$("#gem-result-verbose-area").html(verboseText);
$("#gem-result-textarea").hide();
}
- } else if (mode === "GEMS") {
+ } else if (mode === "GEMS") {
var target_gems = parseInt($("#gem_desired_gems").val());
if (isNaN(target_gems)) {
window.alert("Error: you have entered an invalid (non-numeric) value. Please check your input and try again.");
return;
}
-
var now = moment(new Date());
// arbitrary limit to make sure we don't go wander off into infinity
- var cutoff = moment(now).add(5, 'years');
+ var cutoff = moment(now).add(5, "years");
var resultsString = sprintf("Today is %02d/%02d/%04d and you currently have %d love gems. (Assuming you collected any gems you got today and already counted those.)", month(now), day(now), year(now), current_gems);
var verboseText = "";
if (calc_daily_quest_gems) {
verboseText = "(Including daily 'quest' gems in the calculation. There will not be a separate daily entry for each one.)
";
}
-
// make sure we don't go off into infinity (i.e. user gives input that is impossible to calculate)
var abort = false;
-
- var gems = current_gems
-
+ var gems = current_gems;
while (gems < target_gems && !abort) {
- now = now.add(1, 'days')
-
+ now = now.add(1, "days");
// is it a login bonus?
if (is_gem_day(now)) {
gems += 1;
}
-
// is it a birthday?
var birthday_tuple = is_muse_members_birthday(now);
var is_bday = birthday_tuple[0];
@@ -734,61 +790,57 @@ function calculate_gems()
if (is_bday) {
gems += 5;
}
-
// account for daily login quest gem
if (calc_daily_quest_gems) {
gems++;
}
-
- // account for event
- // format of returned tuple:
- // tuple[0] - was this an event day? (boolean, duh)
- // tuple[1] - name of event, or "" if none (string)
- // tuple[2] - amount of gems spent (int)
- // tuple[3] - amount of gems gained (int)
- var event_results = handle_event(day(now), game_version, tier);
- var is_event = event_results[0];
- var event_name = "";
- var spent_gems = 0;
- var won_gems = 0;
- if (is_event) {
- event_name = event_results[1];
- spent_gems = event_results[2];
- won_gems = event_results[3];
- // did any gems get spent?
- if (spent_gems > 0) {
- // do we have enough to cover it?
- if (gems >= spent_gems) {
- // spend the gems
- gems -= spent_gems;
- // now reap the winnings
- gems += won_gems;
+ if (calc_event_gems) {
+ // account for event
+ // format of returned tuple:
+ // tuple[0] - was this an event day? (boolean, duh)
+ // tuple[1] - name of event, or "" if none (string)
+ // tuple[2] - amount of gems spent (int)
+ // tuple[3] - amount of gems gained (int)
+ var event_results = calculate_event(day(now), game_version, tier);
+ var is_event = event_results[0];
+ var event_name = "";
+ var spent_gems = 0;
+ var won_gems = 0;
+ if (is_event) {
+ event_name = event_results[1];
+ spent_gems = event_results[2];
+ won_gems = event_results[3];
+ // did any gems get spent?
+ if (spent_gems > 0) {
+ // do we have enough to cover it?
+ if (gems >= spent_gems) {
+ // spend the gems
+ gems -= spent_gems;
+ // now reap the winnings
+ gems += won_gems;
+ } else {
+ // flag to indicate that we didn't have the gems
+ spent_gems = -1;
+ }
} else {
- // flag to indicate that we didn't have the gems
- spent_gems = -1;
+ gems += won_gems;
}
- } else {
- gems += won_gems;
}
}
-
// record verbose output if desired
if (verbose) {
- if (is_gem_day(now) || is_bday || is_event) {
+ if (is_gem_day(now) || is_bday || is_event) {
verboseText += sprintf("%02d/%02d/%04d ", month(now), day(now), year(now));
-
if (is_gem_day(now)) {
verboseText += "Free gem as login bonus! ";
}
-
if (is_bday) {
verboseText += sprintf("It's %s's birthday! You get 5 gems! ", name);
}
-
// account for events
if (is_event) {
verboseText += sprintf("A " + event_name + " just ended! ", month(now), day(now), year(now), event_name);
- if (spent_gems == -1) {
+ if (spent_gems == -1) {
verboseText += "You didn't have enough gems to participate. ";
} else {
if (spent_gems == 0) {
@@ -798,19 +850,16 @@ function calculate_gems()
}
}
}
-
// add a newline
verboseText += sprintf("That brings you to %d gems!
", gems);
}
}
-
// do we abort?
- if (now.isAfter(cutoff)) {
+ if (now.isAfter(cutoff)) {
verboseText += sprintf("(Cannot proceed, this appears to be an unattainable amount of gems given your constraints.)");
abort = true;
}
}
-
resultsString = resultsString + sprintf(" You will have %d love gems on %02d/%02d/%04d. Good things come to those who wait!", gems, month(now), day(now), year(now));
if (abort) {
resultsString += " (Note: the calculation was stopped because it appears that you will be unable to attain the desired amount of gems given your constraints.)";
@@ -824,27 +873,24 @@ function calculate_gems()
$("#gem-result-textarea").hide();
}
}
-
$("#gem-calc-result-area").show();
}
-function reset_gems()
-{
+function reset_gems() {
$("#gem-calc-result-area").hide();
$("#gem-result-summary").text("-");
$("#gem-desired-gems-area").hide();
$("#gem-date-area").hide();
$("#current_gems").val(0);
- var $radios = $('input:radio[name=gem-mode]');
- $radios.filter('[value=DATE]').prop('checked', true);
+ var $radios = $("input:radio[name=gem-mode]");
+ $radios.filter("[value=DATE]").prop("checked", true);
$("#gem_desired_date").val("");
$("#gem_desired_gems").val("");
- $('#gems_verbose').prop('checked', false);
+ $("#gems_verbose").prop("checked", false);
$("#gem-date-area").show();
}
-function get_level_cap(rarity)
-{
+function get_level_cap(rarity) {
if (rarity === "N") {
return 40;
} else if (rarity === "R") {
@@ -858,40 +904,51 @@ function get_level_cap(rarity)
return -1;
}
-function is_valid_level(rarity, level)
-{
+function is_valid_level(rarity, level) {
var return_value = false;
if (level >= 1) {
- return_value = (level <= get_level_cap(rarity));
+ return_value = level <= get_level_cap(rarity);
}
return return_value;
}
-function is_valid_exp(rarity, level, exp)
-{
+function is_valid_exp(rarity, level, exp) {
var return_value = false;
if (rarity === "N" && is_valid_level(rarity, level)) {
- return_value = (exp >= 0 && exp < exp_table_n[level+1]);
+ return_value = exp >= 0 && exp < exp_table_n[level + 1];
} else if (rarity === "R" && is_valid_level(rarity, level)) {
- return_value = (exp >= 0 && exp < exp_table_r[level+1]);
- } else if (rarity === "SR" && is_valid_level(rarity, level+1)) {
- return_value = (exp >= 0 && exp < exp_table_sr[level+1]);
+ return_value = exp >= 0 && exp < exp_table_r[level + 1];
+ } else if (rarity === "SR" && is_valid_level(rarity, level + 1)) {
+ return_value = exp >= 0 && exp < exp_table_sr[level + 1];
} else if (rarity === "UR" && is_valid_level(rarity, level)) {
- return_value = (exp >= 0 && exp < exp_table_ur[level+1]);
+ return_value = exp >= 0 && exp < exp_table_ur[level + 1];
}
- return return_value
+ return return_value;
}
-function calculate_card()
-{
+function get_exp_table_entry(rarity, level) {
+ var exp = 0;
+ if (rarity === "N") {
+ exp = exp_table_n[level];
+ } else if (rarity === "R") {
+ exp = exp_table_r[level];
+ } else if (rarity === "SR") {
+ exp = exp_table_sr[level];
+ } else if (rarity === "UR") {
+ exp = exp_table_ur[level];
+ }
+ return exp;
+}
+
+function calculate_card() {
var current_level = parseInt($("#card_current_level").val());
var current_exp_input = $("#card_current_exp").val();
+ var same_attribute = $("#card_same_attribute").is(":checked"); // 1.2x bonus for feeding same attribute cards
var current_exp = 0;
if (current_exp_input != "") {
current_exp = parseInt(current_exp_input);
}
var rarity = $("#card_rarity").val();
-
if (isNaN(current_level) || !is_valid_level(rarity, current_level)) {
alert("Error: invalid level. Please check your input and try again.");
return;
@@ -900,96 +957,79 @@ function calculate_card()
alert("Error: invalid EXP. Please check your input and try again.");
return;
}
-
var mode = $("input[name=card-mode]:checked").val();
- if (mode === "LEVEL") {
+ if (mode === "LEVEL") {
var target_level = parseInt($("#card_desired_level").val());
if (isNaN(target_level) || !is_valid_level(rarity, target_level)) {
window.alert("Error: the desired level is invalid.");
return;
}
-
// ready to rock
var required_exp = 0;
var resultsString = "";
- for (level = current_level+1; level <= target_level; level++) {
- if (rarity === "N") {
- required_exp += exp_table_n[level];
- } else if (rarity === "R") {
- required_exp += exp_table_r[level];
- } else if (rarity === "SR") {
- required_exp += exp_table_sr[level];
- } else if (rarity === "UR") {
- required_exp += exp_table_ur[level];
- }
+ for (level = current_level + 1; level <= target_level; level++) {
+ required_exp += get_exp_table_entry(rarity, level);
}
-
// subtract what we have
required_exp -= current_exp;
-
var resultString = sprintf("To get a %s card from level %d (with %d EXP) to %d requires %d EXP. ", rarity, current_level, current_exp, target_level, required_exp);
-
// calculate equiv N cards
- var number_of_n_cards = Math.round(required_exp / 100) + 1;
+ // FINDME
+ if (same_attribute) {
+ n_card_factor = 120;
+ } else {
+ n_card_factor = 100;
+ }
+ var number_of_n_cards = Math.round(required_exp / n_card_factor) + 1;
resultString += sprintf("(the equivalent of about %d level-1 N cards fed to it)", number_of_n_cards);
-
// output the result
$("#card-result-summary").html(resultString);
- } else if (mode === "EXP") {
+ } else if (mode === "EXP") {
var exp_to_feed = parseInt($("#card_feed_exp").val());
if (isNaN(exp_to_feed)) {
window.alert("Error: you have entered an invalid (non-numeric) value. Please check your input and try again.");
return;
}
-
+ var real_exp_to_feed = exp_to_feed;
// ready to rock
- var resultsString = "FOO";
-
+ var resultsString = "";
// XXX do some calculating
var exp_tally = current_exp;
var level = 0;
- for (level = current_level+1; level <= get_level_cap(rarity); level++) {
- if (rarity === "N") {
- exp_tally += exp_table_n[level];
- } else if (rarity === "R") {
- exp_tally += exp_table_r[level];
- } else if (rarity === "SR") {
- exp_tally += exp_table_sr[level];
- } else if (rarity === "UR") {
- exp_tally += exp_table_ur[level];
- }
- if (exp_tally > exp_to_feed) {
+ for (level = current_level + 1; level <= get_level_cap(rarity); level++) {
+ exp_tally += get_exp_table_entry(rarity, level);
+ if (exp_tally > real_exp_to_feed) {
break;
}
}
-
level--;
- var resultString = sprintf("If you feed a %s card at level %d (with %d EXP) a total of %d EXP, it will end up at level %d.%s", rarity, current_level, current_exp, exp_to_feed, level, (level == get_level_cap(rarity) ? " (MAX LEVEL!)" : ""));
-
+ var resultString = "";
+ if (exp_to_feed > exp_tally) {
+ resultString = sprintf("If you feed a %s card at level %d (with %d EXP) a total of %d EXP, it will end up at level %d.%s This is way overkill, you fed %d more EXP than was necessary.", rarity, current_level, current_exp, exp_to_feed, level, (level == get_level_cap(rarity) ? " (MAX LEVEL!)" : ""), exp_to_feed - exp_tally);
+ } else {
+ resultString = sprintf("If you feed a %s card at level %d (with %d EXP) a total of %d EXP, it will end up at level %d.%s", rarity, current_level, current_exp, exp_to_feed, level, level == get_level_cap(rarity) ? " (MAX LEVEL!)" : "");
+ }
// output the result
$("#card-result-summary").html(resultString);
}
-
$("#card-calc-result-area").show();
}
-function reset_card()
-{
+function reset_card() {
$("#card-calc-result-area").hide();
$("#card-result-summary").text("-");
$("#card-level-area").hide();
$("#card-exp-area").hide();
$("#card_current_level").val("");
$("#card_current_exp").val("");
- var $radios = $('input:radio[name=card-mode]');
- $radios.filter('[value=LEVEL]').prop('checked', true);
+ var $radios = $("input:radio[name=card-mode]");
+ $radios.filter("[value=LEVEL]").prop("checked", true);
$("#card_desired_level").val("");
$("#card_feed_exp").val("");
$("#card-level-area").show();
}
-function start_stop_timer()
-{
+function start_stop_timer() {
if (window.timerInterval != 0) {
// stop it
clearInterval(window.timerInterval);
@@ -999,7 +1039,7 @@ function start_stop_timer()
// 2013-02-08 09:30 # An hour and minute time part
var dateString = $("#event_end_date").val() + " " + $("#event_end_time").val() + "Z";
window.the_end = moment(dateString, "MM/DD/YYYY HH:mmZ");
- window.timerInterval = setInterval(run_timer, 1000);
+ window.timerInterval = setInterval(run_timer, 1e3);
$("#button-start-stop-timer span").text("Stop Timer");
// run the first update ourselves, so that it doesn't stay blank until the timer kicks in
window.immediately_refresh_tier_cutoffs = true;
@@ -1007,57 +1047,54 @@ function start_stop_timer()
}
}
-function run_timer()
-{
+function run_timer() {
var now = moment(new Date());
var end = window.the_end;
var string = "
CURRENT TIME
" + now.utc().format("MM/DD/YYYY HH:mm:ss") + " UTC
EVENT ENDS:
" + end.utc().format("MM/DD/YYYY HH:mm:ss") + " UTC
";
- if (now.isBefore(end)) {
+ if (now.isBefore(end)) {
var ms = end.diff(now.utc());
var t = moment.duration(ms).asMilliseconds();
- var seconds = Math.floor( (t/1000) % 60 );
- var minutes = Math.floor( (t/1000/60) % 60 );
- var hours = Math.floor( (t/(1000*60*60)) % 24 );
- var days = Math.floor( t/(1000*60*60*24) );
- var total_hours = (days * 24) + hours;
-
+ var seconds = Math.floor(t / 1e3 % 60);
+ var minutes = Math.floor(t / 1e3 / 60 % 60);
+ var hours = Math.floor(t / (1e3 * 60 * 60) % 24);
+ var days = Math.floor(t / (1e3 * 60 * 60 * 24));
+ var total_hours = days * 24 + hours;
var time_till = "
";
}
$("#timer_output_area").html(string);
-
- // @sifen_trackbot updates come out at 36 minutes past the hour, fetch them at 37 minutes to allow for some slop
- if ((minute(now) == 37 && second(now) == 0) || window.immediately_refresh_tier_cutoffs) {
+ // @sifen_trackbot updates come out at 36 minutes past the hour, fetch them at 38 minutes to allow for some slop
+ if (minute(now) == 38 && second(now) == 0 || window.immediately_refresh_tier_cutoffs) {
$("#tier_info_output_area").html("
Updating tier cutoff data, please wait...
");
// dumb ass way to fetch and display @sifen_trackbot tier cutoff tweets hourly
// using this twitter fetcher: http://jasonmayes.com/projects/twitterApi/#sthash.budgYosd.dpbs
twitterFetcher.fetch({
- "id": '654587648904794112',
- "domId": '',
- "maxTweets": 1,
- "enableLinks": false,
- "showUser": true,
- "showTime": true,
- "dateFunction": '',
- "showRetweet": false,
- "customCallback": function(tweets) {
+ id: "654587648904794112",
+ domId: "",
+ maxTweets: 1,
+ enableLinks: false,
+ showUser: true,
+ showTime: true,
+ dateFunction: "",
+ showRetweet: false,
+ customCallback: function(tweets) {
if (tweets.length > 0) {
// we only care about the first one
var tweet = tweets[0];
@@ -1077,14 +1114,13 @@ function run_timer()
$("#tier_info_output_area").html("
Latest Tier Cutoffs as of UTC " + updateTime + ": " + tier1 + " " + tier2 + "
Due to the variable nature of events, calculation of gems gotten through events is at best an approximation. To make the calculations simpler, it assumes that each month has 2 events, ending on the 1st and the 15th, and events alternate between token events and score matches (and medley festivals if on JP.) Also, if you are tiering, it assumes that you will spend some gems to tier, and will use an estimate based on your average tier, but this will only be an estimate.)
-
- Average tier:
-
-
-
- Mode:
- Number of gems you'll have on a date?
- Date you will have this many gems?
-
- Date:
-
-
- Desired gems:
-
-
- Verbose Mode
-
-
Calculate
-
-
-
Results
- -
-
-
-
-
-
Reset
-
-
+
+
SIF Tools
-
-
-
- Card Rarity:
-
-
- Current Level:
-
- Current EXP:
-
- Mode:
- EXP needed to get card to a level?
- Final level after feeding an amount of EXP?
+ Current Rank:
+ Current EXP:
+ Desired Rank:
+ Game Version:
+
+
+ Calculate
+
+
+
+
Results
EXP required: -
+
+ You will need to play the following number of songs in order to get this amount of EXP:
+ (Single / 3xMedFes / 3xMedFes w/EXP boost)
+ EASY: - / - / -
+ NORMAL: - / - / -
+ HARD: - / - / -
+ EXPERT: - / - / -
+
+ At this rank you will have - LP and - friend slots.
+
+
+ Reset
+
+
+
-
+
+
+ Current Gems:
+ Game Version:
+
+ Include daily "quest" gems?
+ (What is this?)
+
+
+
On JP, you can now obtain a gem every day by completing the following steps, in the following order:
+
+
Scout three Normal students. (The daily free scout counts.)
+
Clear five live shows (any difficulty.)
+
Practice ("feed") 5 cards of any kind.
+
Play a live show (any difficulty) and get a Full Combo.
Due to the variable nature of events, calculation of gems gotten through events is at best an approximation. To make the calculations simpler,
+ it assumes that each month has 2 events, ending on the 1st and the 15th, and events alternate between token events and score matches (and medley
+ festivals if on JP.) Also, if you are tiering, it assumes that you will spend some gems to tier, and will use an estimate based on your average
+ tier, but this will only be an estimate.)
+
Average tier:
+
+ Mode:
+ Number of gems you'll have on a date?
+ Date you will have this many gems?
+
+
+ Date:
+
+
+ Desired gems:
+
+
+ Verbose Mode
+
+
+
+ Calculate
+
+
+
+
Results
-
+
+
+
+ -
+
+
+
+ Reset
+
+
+
-
Clear Timer
-
-
-
-
-
-
-
-
+
+
+ Card Rarity:
+ Current Level:
+ Current EXP:
+
+ Mode:
+ EXP needed to get card to a level?
+ Final level after feeding an amount of EXP?
+
+