// This code is licensed under the same terms as Habitica: // https://raw.githubusercontent.com/HabitRPG/habitrpg/develop/LICENSE /* ========================================== */ /* [Users] Required script data to fill in */ /* ========================================== */ const USER_ID = "PasteYourUserIdHere" const API_TOKEN = "PasteYourApiTokenHere" // Do not share this to anyone const WEB_APP_URL = "PasteGeneratedWebAppUrlHere" /* ========================================== */ /* [Users] Required customizations to fill in */ /* ========================================== */ /* ========================================== */ /* [Users] Optional customizations to fill in */ /* ========================================== */ // Do you want to get private message notifications if you've already entered Bad Day Mode? // If you don't want them, change the 1 to a 0 in the line below const NOTIFICATIONS_ON = 1 /* ========================================== */ /* [Users] Do not edit code below this line */ /* ========================================== */ const AUTHOR_ID = "0034eb14-b4d8-494e-8386-d3f33cff7922" const SCRIPT_NAME = "Bad Day Mode" const HEADERS = { "x-client" : AUTHOR_ID + " - " + SCRIPT_NAME, "x-api-user" : USER_ID, "x-api-key" : API_TOKEN, } // Messages const MSG_ALREADY_IN_BAD_DAY_MODE = "You are already in Bad Day Mode, so clicking the button additional times has no effect." const BAD_DAY_MODE_TEXT = "**Bad Day Mode**" const BAD_DAY_MODE_ALIAS = "badDayMode" const BAD_DAY_MODE_NOTES = "Declare today a 'day of low expectations', fully healing you, buffing your CON to 9999, and Stealthing all your Dailies so you take no damage if you don't complete them. This wears off tomorrow at Cron." const BAD_DAY_MODE_VALUE = "0" const BAD_DAY_MODE_BUTTON = { "text": BAD_DAY_MODE_TEXT, "type": "reward", "alias": BAD_DAY_MODE_ALIAS, "notes": BAD_DAY_MODE_NOTES, "value": BAD_DAY_MODE_VALUE, } function doOneTimeSetup() { api_createNewTaskForUser([BAD_DAY_MODE_BUTTON]) // Next, create the webhook const options = { "scored" : true, } const payload = { "url" : WEB_APP_URL, "label" : SCRIPT_NAME + " Webhook", "type" : "taskActivity", "options" : options, } apiMult_createNewWebhookNoDuplicates(payload) } // do things when the webhook runs function doPost(e) { const dataContents = JSON.parse(e.postData.contents) const type = dataContents.type const task = dataContents.task // Sanitize task alias let sanitizedAlias = "sanitized" // This will be the value if undefined, null, or blank if ( (task.alias != undefined) && (task.alias != null) && (task.alias != "") ) { sanitizedAlias = task.alias } if (type == "scored") { if (sanitizedAlias == BAD_DAY_MODE_ALIAS) { // Get user info const responseUser = api_getAuthenticatedUserProfile("stats,tasksOrder,items.gear.equipped") user = JSON.parse(responseUser).data // Get equipment stats info const responseContent = apiFree_getAllAvailableContentObjects() content = JSON.parse(responseContent).data let totalDailies = user.tasksOrder.dailys.length let stealthedDailies = user.stats.buffs.stealth if (!stealthedDailies) {stealthedDailies = 0} let constitutionBuffs = user.stats.buffs.con if (!user.stats.buffs.con) { constitutionBuffs = 0 } let con = calculateConstitution() let unbuffedConstitution = con - constitutionBuffs let hp = user.stats.hp doButtonBadDayMode(constitutionBuffs, stealthedDailies, totalDailies, hp, unbuffedConstitution) } } return HtmlService.createHtmlOutput() } function doButtonBadDayMode(constitutionBuffs, stealthedDailies, totalDailies, hp, unbuffedConstitution){ // Check if they're already in Bad Day Mode by seeing if CON is really high and all Dailies are Stealthed and HP is high if ( ( constitutionBuffs > 8000 ) && ( stealthedDailies >= totalDailies ) && ( hp >= 45 ) ) { api_sendPrivateMessage({"message" : MSG_ALREADY_IN_BAD_DAY_MODE, "toUserId" : USER_ID}) } else { // Full heal api_updateUser({"stats.hp" : 50}) // Set CON to 9999 let buffCon = 9999 - unbuffedConstitution api_updateUser({"stats.buffs.con" : buffCon}) // Stealth all Dailies api_updateUser({"stats.buffs.stealth" : totalDailies}) } } // Create custom reward buttons function api_createNewTaskForUser(payload) { var params = { "method" : "post", "headers" : HEADERS, "contentType" : "application/json", "payload" : JSON.stringify(payload), // Rightmost button goes on top "muteHttpExceptions" : true, } var url = "https://habitica.com/api/v3/tasks/user" UrlFetchApp.fetch(url, params) } // Create a webhook if no duplicate exists function apiMult_createNewWebhookNoDuplicates(payload) { const response = api_getWebhooks() const webhooks = JSON.parse(response).data var duplicateExists = 0 for (var i in webhooks) { if (webhooks[i].label == payload.label) { duplicateExists = 1; } } // If webhook to be created doesn't exist yet if (!duplicateExists) { api_createNewWebhook(payload) } } // Used to see existing webhooks, and therefore if there's a duplicate function api_getWebhooks() { const params = { "method" : "get", "headers" : HEADERS, "muteHttpExceptions" : true, } const url = "https://habitica.com/api/v3/user/webhook" return UrlFetchApp.fetch(url, params) } // Creates a webhook (as part of the "don't make it if there's a duplicate" function) function api_createNewWebhook(payload) { const params = { "method" : "post", "headers" : HEADERS, "contentType" : "application/json", "payload" : JSON.stringify(payload), "muteHttpExceptions" : true, } const url = "https://habitica.com/api/v3/user/webhook" return UrlFetchApp.fetch(url, params) } // Gets user info so I can use it, especially stats like mana, experience, and level function api_getAuthenticatedUserProfile(userFields) { const params = { "method" : "get", "headers" : HEADERS, "muteHttpExceptions" : true, } var url = "https://habitica.com/api/v3/user" if (userFields != "") { url += "?userFields=" + userFields } return UrlFetchApp.fetch(url, params) } function apiFree_getAllAvailableContentObjects() { const params = { "method" : "get", "muteHttpExceptions" : true, } const url = "https://habitica.com/api/v3/content" return UrlFetchApp.fetch(url, params) } // Send a notification as a private message, only if they're enabled function api_sendPrivateMessage(payload) { switch (NOTIFICATIONS_ON){ // Check if notifications are on, send message if yes case 0: break case 1: const params = { "method" : "post", "headers" : HEADERS, "contentType" : "application/json", "payload" : JSON.stringify(payload), "muteHttpExceptions" : true, } const url = "https://habitica.com/api/v3/members/send-private-message" return UrlFetchApp.fetch(url, params) break } } // Calculate total CON function calculateConstitution() { const levelConRaw = Math.floor(user.stats.lvl / 2) const levelCon = (levelConRaw > 50) ? 50 : levelConRaw var totalEquipmentAndClassCon = 0 const allocatedCon = user.stats.con const buffsCon = user.stats.buffs.con // Get CON from equipped gear totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.weapon]) totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.shield]) totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.head]) totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.armor]) totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.headAccessory]) totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.eyewear]) totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.body]) totalEquipmentAndClassCon += calcEquipmentAndClassCon(content.gear.flat[user.items.gear.equipped.back]) return levelCon + totalEquipmentAndClassCon + allocatedCon + buffsCon } function calcEquipmentAndClassCon(equipment) { var equipmentAndClassCon = 0 if (equipment != undefined) { equipmentAndClassCon += equipment.con if ( (equipment.klass == user.stats.class) || ( (equipment.klass == "special") && (equipment.specialClass == user.stats.class) ) ) { equipmentAndClassCon += equipment.con / 2 } } return equipmentAndClassCon } // Changes stats function api_updateUser(payload) { const params = { "method" : "put", "headers" : HEADERS, "contentType" : "application/json", "payload" : JSON.stringify(payload), "muteHttpExceptions" : true, } const url = "https://habitica.com/api/v3/user" return UrlFetchApp.fetch(url, params) }