Adds a button to Dead Frontier Inventory to open challenges inside the game inventory. So you don't need to come back to outpost to check if you completed the challenges.
// ==UserScript==
// @name Challenges Inside Inventory
// @namespace http://tampermonkey.net/
// @version 1.3
// @description Adds a button to Dead Frontier Inventory to open challenges inside the game inventory. So you don't need to come back to outpost to check if you completed the challenges.
// @author Lucky11
// @match https://fairview.deadfrontier.com/onlinezombiemmo/DF3D/DF3D_InventoryPage.php?page=31*
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// Inject challenges CSS
const style = document.createElement('style');
style.type = 'text/css';
style.textContent = `
body {
background-color: #1a1a1a; /* Dark background */
color: #e6e6e6; /* Light text color */
}
#pageLogo {
color: red;
font-size: 14pt;
}
#invController {
padding-top: 20px;
overflow-y: auto;
}
.challengeContainer {
border: 1px solid #555;
margin: 10px;
background-color: rgba(0, 0, 0, 0.6);
padding-bottom: 8px;
text-align: left;
cursor: pointer;
}
.challengeContainer .challengeNamefield {
position: relative;
border-bottom: 1px solid darkgrey;
background-image: linear-gradient(black, black, rgba(50, 50, 50, 0.5));
padding: 3px 5px;
font-weight: 900;
color: #E6CC4D;
}
.challengeContainer .challengeDescription {
padding: 3px 5px;
border-bottom: 1px solid darkgrey;
}
.challengeContainer .challengeHidden {
max-height: 0;
overflow-y: hidden;
transition: max-height 0.1s;
}
.challengeContainer .challengeComplete {
position: absolute;
text-align: center;
top: 0;
left: 0;
right: 0;
color: #00ff00;
font-size: 12pt;
}
.challengeContainer.challengeOpened .challengeHidden {
max-height: 500px;
}
.challengeContainer .challengeNamefield::before {
content: "\\25b2 ";
}
.challengeContainer.challengeOpened .challengeNamefield::before {
content: "\\25bc ";
}
.challengeContainer .challengeRewards {
float: right;
border-left: 1px solid red;
width: 160px;
}
.challengeContainer .challengeRewards .item_rewards {
border-top: 1px solid #660000;
}
.challengeContainer .challengeRewards .autoPad {
padding: 5px 10px;
}
.challengeContainer .challengeRewards .fakeItem {
border-bottom: 1px solid #660000;
padding: 5px 10px;
}
.challengeContainer .challengeObjectives {
margin-right: 160px;
}
.challengeContainer.clanChallenge .challengeRewards {
width: 200px;
}
.challengeContainer.clanChallenge .challengeRewards {
text-align: center;
}
.challengeContainer.clanChallenge .challengeObjectives {
margin-right: 200px;
}
.challengeContainer .challengeObjectives .challengeObjective {
border: 1px solid #660000;
border-right: 1px solid red;
background-color: black;
}
.challengeContainer .challengeObjectives .objectiveProgress {
background-color: #128800;
white-space: nowrap;
}
.challengeContainer .challengeObjectives .objectiveProgress .pads {
padding: 5px 10px;
}
.challengeContainer .challengeProgress {
background-color: black;
text-align: center;
}
.challengeContainer .challengeBar {
background-color: #128800;
white-space: nowrap;
}
`;
document.head.appendChild(style);
// Create overlay elements
const overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
overlay.style.zIndex = '9999';
overlay.style.display = 'none';
overlay.style.justifyContent = 'center';
overlay.style.alignItems = 'center';
const overlayContent = document.createElement('div');
overlayContent.style.backgroundColor = 'rgba(50, 50, 50, 0.9)'; // Dark background
overlayContent.style.padding = '20px';
overlayContent.style.borderRadius = '8px';
overlayContent.style.maxWidth = '600px';
overlayContent.style.width = '90%';
overlayContent.style.overflowY = 'auto';
overlayContent.style.maxHeight = '80%';
const closeButton = document.createElement('button');
closeButton.innerText = '✖'; // Change text to match the style
closeButton.style.marginLeft = '550px';
closeButton.style.fontFamily = 'Downcome'; // Match font family
//closeButton.style.color = 'rgb(153, 0, 0)'; // Match text color
closeButton.style.fontSize = '20pt'; // Match font size
closeButton.style.backgroundColor = 'transparent'; // Make background transparent
closeButton.style.border = 'none'; // Remove border
closeButton.style.cursor = 'pointer'; // Pointer cursor
closeButton.style.marginBottom = '5px'; // Maintain margin
closeButton.addEventListener('click', () => {
overlay.style.display = 'none';
});
overlayContent.appendChild(closeButton);
overlay.appendChild(overlayContent);
document.body.appendChild(overlay);
// Event listener to close the overlay when clicking outside of it
overlay.addEventListener('click', (event) => {
if (event.target === overlay) {
overlay.style.display = 'none'; // Hide the overlay
}
});
// Function to serialize the request parameters
function serializeObject(obj) {
return Object.keys(obj).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(obj[key])).join('&');
}
// Function to make the POST request
function makeRequest() {
const requestUrl = "https://fairview.deadfrontier.com/onlinezombiemmo/hotrods/load_challenge.php";
const playerLevel = unsafeWindow.userVars["DFSTATS_df_level"]; // Get player's level
const requestParams = {
userID: unsafeWindow.userVars["userID"],
password: unsafeWindow.userVars["password"],
sc: unsafeWindow.userVars["sc"],
action: "get",
minLevel: playerLevel, // Set minLevel to player's level
maxLevel: playerLevel // Set maxLevel to player's level
};
// Calculate the hash
const payload = serializeObject(requestParams);
const hash = unsafeWindow.hash(payload);
const fullPayload = "hash=" + hash + "&" + payload;
// Send the POST request
GM_xmlhttpRequest({
method: "POST",
url: requestUrl,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: fullPayload,
onload: function(response) {
//console.log('Response:', response.responseText);
displayChallenges(response.responseText);
},
onerror: function(error) {
console.error('Error:', error);
alert('Error sending POST request.');
}
});
}
// Function to display challenges in the overlay
function displayChallenges(data) {
const challenges = parseChallengeData(data);
overlayContent.innerHTML = ''; // Clear existing content
overlayContent.appendChild(closeButton); // Re-add close button
if (challenges.length === 0) {
overlayContent.innerHTML = "<p style='color: white;'>No challenges available.</p>";
overlay.style.display = 'flex'; // Show the overlay
return;
}
challenges.forEach(challenge => {
const challengeContainer = document.createElement("div");
challengeContainer.classList.add("challengeContainer");
const nameField = document.createElement("div");
nameField.classList.add("challengeNamefield");
nameField.innerHTML = `${challenge.name}<span style="float: right;">Ends: ${challenge.endTime}</span>`;
challengeContainer.appendChild(nameField);
const description = document.createElement("div");
description.classList.add("challengeDescription");
description.textContent = challenge.description;
challengeContainer.appendChild(description);
const rewards = document.createElement("div");
rewards.classList.add("challengeRewards");
let rewardsHTML = `<div class='autoPad'>
<div class='cashhack redElements' style='position: relative;' data-cash='Rewards'>Rewards</div>`;
if (challenge.rewardCash > 0) {
rewardsHTML += `<div class='cashhack' style='position: relative;' data-cash='Cash: ${parseInt(challenge.rewardCash).toLocaleString()}'>Cash: ${parseInt(challenge.rewardCash).toLocaleString()}</div>`;
}
if (challenge.rewardExp > 0) {
rewardsHTML += `<div class='credits cashhack' style='position: relative;' data-cash='Exp: ${parseInt(challenge.rewardExp).toLocaleString()}'>Exp: ${parseInt(challenge.rewardExp).toLocaleString()}</div>`;
}
rewardsHTML += `</div>`;
rewards.innerHTML = rewardsHTML;
challengeContainer.appendChild(rewards);
const objectives = document.createElement("div");
objectives.classList.add("challengeObjectives");
challenge.objectives.forEach(obj => {
const objective = document.createElement("div");
objective.classList.add("challengeObjective");
objective.innerHTML = `<div class='objectiveProgress' style='width: ${obj.progress}%;'>
<div class='pads'>${obj.name}: ${obj.current}/${obj.target}</div>
</div>`;
objectives.appendChild(objective);
});
challengeContainer.appendChild(objectives);
const progress = document.createElement("div");
progress.classList.add("challengeProgress");
//progress.innerHTML = `<div class='challengeBar' style='width: ${challenge.progress}%;'>${challenge.progress}%</div>`;
// Determine margin-top based on conditions
let marginTopStyle = "3px"; // Default margin
const hasCash = challenge.rewardCash > 0;
const hasExp = challenge.rewardExp > 0;
const totalObjectives = challenge.objectives.length;
if (hasCash && hasExp && totalObjectives === 1) {
marginTopStyle = "34px";
} else if (!hasCash && hasExp && totalObjectives === 1) {
marginTopStyle = "16px";
}
progress.innerHTML = `
<div class='challengeProgress' style='margin-top: ${marginTopStyle};'>
<div class='challengeBar' style='width: ${challenge.progress}%;'>${challenge.progress}%</div>
</div>
`;
challengeContainer.appendChild(progress);
overlayContent.appendChild(challengeContainer);
});
overlay.style.display = 'flex'; // Show the overlay
}
// Function to parse challenge data from the response
function parseChallengeData(data) {
const challenges = [];
const parsedData = new URLSearchParams(data);
const maxChallenges = parseInt(parsedData.get('max_challenges')) || 0;
const playerLevel = unsafeWindow.userVars["DFSTATS_df_level"]; // Get player's level
for (let i = 0; i < maxChallenges; i++) {
const minLevel = parseInt(parsedData.get(`challenge_${i}_min_level`)) || 0;
const maxLevel = parseInt(parsedData.get(`challenge_${i}_max_level`)) || 0;
// Check if the player's level is within the challenge's level range
if (playerLevel < minLevel || playerLevel > maxLevel) {
continue; // Skip this challenge if the player's level is not appropriate
}
let rewardExp = parseInt(parsedData.get(`challenge_${i}_reward_exp`)) || 0; // Get rewardExp and ensure it's a number
// Check if the user is a gold member and double the rewardExp if true
if (unsafeWindow.userVars['DFSTATS_df_goldmember'] === '1') {
rewardExp *= 2; // Double the experience reward for gold members
}
rewardExp *= playerLevel; // Now multiply by player level
const challenge = {
name: parsedData.get(`challenge_${i}_name`),
description: parsedData.get(`challenge_${i}_description`),
endTime: new Date(new Date(0).setUTCSeconds(parseInt(parsedData.get(`challenge_${i}_end_time`)) + 1200000000)).toLocaleString(),
rewardCash: parsedData.get(`challenge_${i}_reward_cash`),
rewardExp: rewardExp,
objectives: [],
progress: 0
};
const totalObjectives = parseInt(parsedData.get(`challenge_${i}_objectives`)) || 0;
let totalProgress = 0; // To accumulate total progress for the challenge
let totalTargetScore = 0; // To accumulate total target score for the challenge
let totalPlayerScore = 0; // To accumulate player's score for the challenge
for (let j = 1; j <= totalObjectives; j++) {
const targetKey = `challenge_${i}_objectives_${j}_target`;
const playerScoreKey = `challenge_${i}_objective_${j}_player_score`;
const objectiveNameKey = `challenge_${i}_objectives_${j}_name`;
const target = parseInt(parsedData.get(targetKey)) || 0; // Correctly retrieve target
const playerScore = parseInt(parsedData.get(playerScoreKey)) || 0;
const objectiveName = parsedData.get(objectiveNameKey);
// Calculate progress for the objective
const progress = (target > 0) ? Math.min((playerScore / target) * 100, 100) : 0;
challenge.objectives.push({
name: objectiveName,
target: target, // Ensure target is set correctly
current: playerScore,
progress: progress // Store the calculated progress
});
// Accumulate total target and player scores
totalTargetScore += target;
totalPlayerScore += playerScore;
totalProgress += progress; // Accumulate individual progress
}
// Calculate overall progress as the average of individual objective progress
const overallProgress = (totalObjectives > 0) ? (totalProgress / totalObjectives) : 0;
// Set the challenge progress based on overall progress
challenge.progress = Math.min(100, parseFloat(overallProgress.toFixed(2)));
// Uncomment for debugging
// console.log("Specific Objective Progress: ", specificObjectiveProgress);
// console.log("Overall Progress: ", overallProgress);
// console.log("Challenge Progress: ", challenge.progress);
challenges.push(challenge);
}
return challenges;
}
// Create the button
const button = document.createElement('button');
button.innerText = 'Show Current Challenges';
button.style.position = 'absolute';
//<button class="opElem" style="left: 20px; bottom: 86px;">SlotLock?</button>
//button.style.backgroundColor = '#4CAF50'; // Green button
button.style.left = '20px';
button.style.bottom = '110px';
button.style.cursor = 'pointer';
// Append the button to the body
//document.body.appendChild(button);
var invController = document.getElementById('invController'); // Select the element with ID 'invController'
invController.appendChild(button); // Append the button to the selected element
// Add click event listener to the button
button.addEventListener('click', makeRequest);
})();