Skip to content

Commit 0c44407

Browse files
authored
Merge pull request #84 from OSRS-Taskman/roll_take2
ok rolls for real
2 parents 543d290 + 4d3693e commit 0c44407

5 files changed

Lines changed: 355 additions & 79 deletions

File tree

static/js/task.js

Lines changed: 205 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,202 @@
1-
$(window).on('load', function(){
2-
var frameSpeed = 1000,
3-
frameContainer = $('#frame-container'),
4-
frames = $('.frame',frameContainer ),
5-
frameCount = frames.length,
6-
messageContainer = $('#message-container'),
7-
messages = $('.message', messageContainer)
8-
messageCount = messages.length,
9-
t = null,
10-
start = $('#start'),
11-
showFrame = function (n){
12-
if (n != frameCount){
13-
return frames.hide().eq(n).show() && messages.hide().eq(n).show();
14-
15-
}
16-
return frames.eq(frameCount).show() && messages.eq(messageCount).show();
17-
18-
},
19-
nextFrame = function(){
20-
if (index == frameCount){
21-
stopFrames();
22-
showFrame(frameCount - 1);
23-
}
24-
else {
25-
showFrame(++index);
26-
t = setTimeout(nextFrame,frameSpeed);
27-
}
28-
29-
},
30-
stopFrames = function(){
31-
clearInterval(t);
32-
index = 0;
33-
};
34-
frameContainer
35-
start.on('click', nextFrame)
36-
stopFrames();
37-
showFrame(0);
38-
});
1+
const SPECIAL_ROLL_USERNAMES = new Set(['shadukat', 'gerni shadu']);
2+
3+
function getCurrentUsername() {
4+
const profileLink = document.querySelector('a.profile');
5+
return profileLink ? profileLink.textContent.trim().toLowerCase() : '';
6+
}
7+
8+
function isSpecialRollUser() {
9+
return SPECIAL_ROLL_USERNAMES.has(getCurrentUsername());
10+
}
11+
12+
function shuffleArray(items) {
13+
const cloned = items.slice();
14+
for (let i = cloned.length - 1; i > 0; i -= 1) {
15+
const randomIndex = Math.floor(Math.random() * (i + 1));
16+
[cloned[i], cloned[randomIndex]] = [cloned[randomIndex], cloned[i]];
17+
}
18+
return cloned;
19+
}
20+
21+
function ensureRollModal() {
22+
let modal = document.getElementById('taskRollModal');
23+
if (modal) {
24+
return modal;
25+
}
26+
27+
modal = document.createElement('dialog');
28+
modal.id = 'taskRollModal';
29+
modal.className = 'task-roll-modal';
30+
modal.innerHTML = `
31+
<div class="task-roll-shell rsText">
32+
<div class="task-roll-title">Rolling Task</div>
33+
<div class="task-roll-content">
34+
<img id="taskRollModalImage" class="task-roll-image" src="/static/assets/Cake_of_guidance_detail.png" alt="Task roll image" />
35+
<p id="taskRollModalMessage" class="task-roll-message">Rolling...</p>
36+
<p id="taskRollModalSpecial" class="task-roll-special" hidden>Hi Youtube &lt;3 Gerni Task</p>
37+
</div>
38+
<div class="task-roll-actions">
39+
<button id="taskRollModalClose" class="task-roll-button" type="button">Continue</button>
40+
</div>
41+
</div>
42+
`;
43+
44+
document.body.appendChild(modal);
45+
46+
const closeButton = modal.querySelector('#taskRollModalClose');
47+
closeButton.addEventListener('click', () => {
48+
if (typeof modal.close === 'function') {
49+
modal.close();
50+
}
51+
});
52+
53+
return modal;
54+
}
55+
56+
function buildFallbackRollCandidates() {
57+
return [
58+
{ name: 'Rolling...', image: '/static/assets/Cake_of_guidance_detail.png' },
59+
{ name: 'Rolling...', image: '/static/assets/Tome_of_fire_(empty).png' },
60+
{ name: 'Rolling...', image: '/static/assets/Cockatrice_head.png' },
61+
{ name: 'Rolling...', image: '/static/assets/Dragon_sword.png' },
62+
{ name: 'Rolling...', image: '/static/assets/Guilded_smile_flag.png' },
63+
{ name: 'Rolling...', image: '/static/assets/Malediction_shard_2.png' }
64+
];
65+
}
66+
67+
function getOfficialRollCandidates() {
68+
const frameNodes = document.querySelectorAll('#frame-container .frame');
69+
const messageNodes = document.querySelectorAll('#message-container .message');
70+
const candidates = [];
71+
72+
frameNodes.forEach((frameNode, index) => {
73+
const imageSrc = frameNode.getAttribute('src');
74+
const messageNode = messageNodes[index];
75+
const messageText = messageNode ? messageNode.textContent.trim() : 'Rolling...';
76+
if (imageSrc) {
77+
candidates.push({ name: messageText || 'Rolling...', image: imageSrc });
78+
}
79+
});
80+
81+
return candidates.length > 0 ? candidates : buildFallbackRollCandidates();
82+
}
83+
84+
function normalizeServerRollCandidates(serverCandidates) {
85+
if (!Array.isArray(serverCandidates)) {
86+
return [];
87+
}
88+
89+
return serverCandidates
90+
.map((candidate) => ({
91+
name: candidate && candidate.name ? candidate.name : 'Rolling...',
92+
image: candidate && candidate.image ? candidate.image : '/static/assets/Cake_of_guidance_detail.png'
93+
}))
94+
.filter((candidate) => Boolean(candidate.image));
95+
}
96+
97+
function resolveTaskImageSource(imageValue) {
98+
if (!imageValue) {
99+
return '/static/assets/Cake_of_guidance_detail.png';
100+
}
101+
if (imageValue.startsWith('http://') || imageValue.startsWith('https://') || imageValue.startsWith('/static/')) {
102+
return imageValue;
103+
}
104+
return `/static/assets/${imageValue}`;
105+
}
106+
107+
function rollTaskModal(options) {
108+
const {
109+
finalName,
110+
finalImage,
111+
instant = false,
112+
candidates = []
113+
} = options;
114+
115+
return new Promise((resolve) => {
116+
const modal = ensureRollModal();
117+
const imageNode = modal.querySelector('#taskRollModalImage');
118+
const messageNode = modal.querySelector('#taskRollModalMessage');
119+
const specialNode = modal.querySelector('#taskRollModalSpecial');
120+
const closeButton = modal.querySelector('#taskRollModalClose');
121+
122+
let settled = false;
123+
124+
const finish = () => {
125+
if (settled) {
126+
return;
127+
}
128+
settled = true;
129+
closeButton.onclick = null;
130+
resolve();
131+
};
132+
133+
closeButton.onclick = () => {
134+
if (typeof modal.close === 'function') {
135+
modal.close();
136+
}
137+
finish();
138+
};
139+
140+
if (typeof modal.showModal === 'function') {
141+
modal.showModal();
142+
}
143+
144+
const finalImageSource = resolveTaskImageSource(finalImage);
145+
specialNode.hidden = !instant;
146+
147+
if (instant) {
148+
imageNode.src = finalImageSource;
149+
messageNode.textContent = finalName;
150+
closeButton.disabled = false;
151+
return;
152+
}
153+
154+
const baseCandidates = candidates.length > 0 ? candidates : buildFallbackRollCandidates();
155+
const randomizedCandidates = shuffleArray(baseCandidates).concat([{ name: finalName, image: finalImageSource }]);
156+
let pointer = 0;
157+
closeButton.disabled = true;
158+
159+
const intervalId = window.setInterval(() => {
160+
const nextCandidate = randomizedCandidates[pointer];
161+
imageNode.src = resolveTaskImageSource(nextCandidate.image);
162+
messageNode.textContent = nextCandidate.name || 'Rolling...';
163+
pointer += 1;
164+
165+
if (pointer >= randomizedCandidates.length) {
166+
window.clearInterval(intervalId);
167+
imageNode.src = finalImageSource;
168+
messageNode.textContent = finalName;
169+
closeButton.disabled = false;
170+
}
171+
}, 120);
172+
});
173+
}
39174

40175
$(document).on('click', '#start', function(){
41176
req = $.ajax({
42177
url : '/generate/',
43178
type : 'POST'
44-
})
179+
});
45180

46-
req.done(function(data){
47-
delay(function(){
48-
const message = document.getElementById("message_target");
49-
const image = document.getElementById("image_target");
50-
const imageLink = document.getElementById("taskImage");
51-
imageLink.href = data.link;
52-
imageLink.setAttribute('data-tip', data.tip);
53-
message.innerHTML = data.name;
54-
image.src = data.image;
55-
document.getElementById("start").disabled = true;
56-
document.getElementById("complete").disabled = false;
57-
}, 6000);
181+
req.done(async function(data){
182+
const serverCandidates = normalizeServerRollCandidates(data.rollCandidates);
183+
const rollCandidates = serverCandidates.length > 0 ? serverCandidates : getOfficialRollCandidates();
184+
await rollTaskModal({
185+
finalName: data.name,
186+
finalImage: data.image,
187+
instant: isSpecialRollUser(),
188+
candidates: rollCandidates
189+
});
190+
191+
const message = document.getElementById("message_target");
192+
const image = document.getElementById("image_target");
193+
const imageLink = document.getElementById("taskImage");
194+
imageLink.href = data.link;
195+
imageLink.setAttribute('data-tip', data.tip);
196+
message.innerHTML = data.name;
197+
image.src = resolveTaskImageSource(data.image);
198+
document.getElementById("start").disabled = true;
199+
document.getElementById("complete").disabled = false;
58200
});
59201
});
60202

@@ -70,14 +212,6 @@ $(document).on('click', '#complete', function(){
70212
});
71213

72214

73-
var delay = (function(){
74-
var timer = 0;
75-
return function(callback, ms) {
76-
clearTimeout (timer);
77-
timer = setTimeout(callback, ms);
78-
};
79-
})();
80-
81215
// $(document).on('click', '#easy_generate', function(){
82216
// $('form').submit(false);
83217
// req = $.ajax({
@@ -103,7 +237,15 @@ $(document).on('click', '#generate_unofficial', function(){
103237
type : 'POST',
104238
data : {tier : tier + 'Tasks'}
105239
});
106-
req.done(function(data){
240+
req.done(async function(data){
241+
const rollCandidates = normalizeServerRollCandidates(data.rollCandidates);
242+
await rollTaskModal({
243+
finalName: data.name,
244+
finalImage: data.image,
245+
instant: isSpecialRollUser(),
246+
candidates: rollCandidates.length > 0 ? rollCandidates : getOfficialRollCandidates()
247+
});
248+
107249
const task = document.getElementById(tier + "_task");
108250
const image = document.getElementById(tier + "_image");
109251
const imagePreview = document.getElementById(tier + "_image_preview");
@@ -115,13 +257,9 @@ $(document).on('click', '#generate_unofficial', function(){
115257
imagePlaceholder.href = data.link
116258
imagePreview.name = data.name;
117259
task.innerHTML = data.name;
118-
if (data.image === 'Cake_of_guidance_detail.png') {
119-
image.src = '/static/assets/Cake_of_guidance_detail.png';
120-
imagePreview.src = '/static/assets/Cake_of_guidance_detail.png';
121-
} else {
122-
image.src = data.image;
123-
imagePreview.src = data.image;
124-
}
260+
const resolvedImageSource = resolveTaskImageSource(data.image);
261+
image.src = resolvedImageSource;
262+
imagePreview.src = resolvedImageSource;
125263
});
126264
});
127265

0 commit comments

Comments
 (0)