Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 112 additions & 81 deletions assets/scripts/lobby/buttonEventListeners2.js
Original file line number Diff line number Diff line change
@@ -1,93 +1,79 @@
function redButtonFunction() {
console.log('red');
// if the button isn't disabled
if (
document.querySelector('#red-button').classList.contains('disabled') ===
false
) {
if (isSpectator === true) {
} else if (gameStarted === false) {
// if we are spectating
if (document.querySelector('#red-button').innerText === 'Spectate') {
socket.emit('standUpFromGame');
// remove claim status when a player sits down
// then stands up
socket.emit('setClaim', false);

enableDisableButtons();
}
// we are the host, open kick menu
else {
// host kicking
// Set the kick modal content
let str = '<h4>Select the players you want to kick.</h4>';

str += '<div class="btn-group-vertical" data-toggle="buttons">';

for (let i = 0; i < roomPlayersData.length; i++) {
if (ownUsername !== roomPlayersData[i].username) {
str += '<label class="btn btn-mine">';

str += `<input name="${roomPlayersData[i].username}" id="${roomPlayersData[i].username}" type="checkbox" autocomplete="off">${roomPlayersData[i].username}`;

str += '</label>';
str += '<br>';
} else {
str += '<label class="btn btn-mine" style="display: none;">';

str += `<input name="${roomPlayersData[i].username}" id="${roomPlayersData[i].username}" type="checkbox" autocomplete="off">${roomPlayersData[i].username}`;
async function redButtonFunction() {
if (document.querySelector('#red-button').classList.contains('disabled') === true) {
return;
}

str += '</label>';
str += '<br>';
}
if (isSpectator === true) {
} else if (gameStarted === false) {
// non-host player standing up
if (document.querySelector('#red-button').innerText === 'Spectate') {
socket.emit('standUpFromGame');
socket.emit('setClaim', false);
enableDisableButtons();
}
// host opening kick menu
else {
let str = '<h4>Select the players you want to kick.</h4>';
str += '<div class="btn-group-vertical" data-toggle="buttons">';
for (let i = 0; i < roomPlayersData.length; i++) {
if (ownUsername !== roomPlayersData[i].username) {
str += '<label class="btn btn-mine">';
str += `<input name="${roomPlayersData[i].username}" id="${roomPlayersData[i].username}" type="checkbox" autocomplete="off">${roomPlayersData[i].username}`;
str += '</label>';
str += '<br>';
} else {
str += '<label class="btn btn-mine" style="display: none;">';
str += `<input name="${roomPlayersData[i].username}" id="${roomPlayersData[i].username}" type="checkbox" autocomplete="off">${roomPlayersData[i].username}`;
str += '</label>';
str += '<br>';
}

str += '</div>';

$('#kickModalContent')[0].innerHTML = str;
}
} else if (
gameData.phase === 'VotingTeam' ||
gameData.phase === 'VotingMission'
) {
socket.emit('gameMove', ['no', []]);
str += '</div>';
$('#kickModalContent')[0].innerHTML = str;
}
$('#mainRoomBox div').removeClass('highlight-avatar');
} else if (
gameData.phase === 'VotingTeam' &&
!(await preventMisclick('no'))
Copy link
Owner

@vck3000 vck3000 Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of preventMisclick, can we name this confirmUserClick? That way the return type is clearer. I.e. returning true means it's ok, and returning false means stop.

Or we can call the function isMisclick as well.

) {
socket.emit('gameMove', ['no', []]);
} else if (gameData.phase === 'VotingMission') {
socket.emit('gameMove', ['no', []]);
}

$('#mainRoomBox div').removeClass('highlight-avatar');
}

function greenButtonFunction() {
// if button isn't disabled:
if (
document.querySelector('#green-button').classList.contains('disabled') ===
false
) {
if (isSpectator === true) {
socket.emit('join-game', roomId);
} else if (gameStarted === false) {
const startGameData = {
options: getOptions(),
gameMode: $($('.gameModeSelect')[1]).val(),
timeouts: {
default: ((parseInt($('#startGameOptionsDefaultPhaseTimeoutMin').val()) * 60 + parseInt($('#startGameOptionsDefaultPhaseTimeoutSec').val())) * 1000).toString(),
critMission: ((parseInt($('#startGameOptionsCritMissionTimeoutMin').val()) * 60 + parseInt($('#startGameOptionsCritMissionTimeoutSec').val())) * 1000).toString(),
assassination: ((parseInt($('#startGameOptionsAssassinationPhaseTimeoutMin').val()) * 60 + parseInt($('#startGameOptionsAssassinationPhaseTimeoutSec').val())) * 1000).toString(),
},
anonymousMode: $('#startGameOptionsAnonymousMode')[0].checked,
};

socket.emit('startGame', startGameData);
} else if (
gameData.phase === 'VotingTeam' ||
gameData.phase === 'VotingMission'
) {
socket.emit('gameMove', ['yes', []]);
} else {
socket.emit('gameMove', ['yes', getHighlightedAvatars()]);
}
async function greenButtonFunction() {
if (document.querySelector('#green-button').classList.contains('disabled') === true) {
return;
}

$('#mainRoomBox div').removeClass('highlight-avatar');
if (isSpectator === true) {
socket.emit('join-game', roomId);
} else if (gameStarted === false) {
const startGameData = {
options: getOptions(),
gameMode: $($('.gameModeSelect')[1]).val(),
timeouts: {
default: ((parseInt($('#startGameOptionsDefaultPhaseTimeoutMin').val()) * 60 + parseInt($('#startGameOptionsDefaultPhaseTimeoutSec').val())) * 1000).toString(),
critMission: ((parseInt($('#startGameOptionsCritMissionTimeoutMin').val()) * 60 + parseInt($('#startGameOptionsCritMissionTimeoutSec').val())) * 1000).toString(),
assassination: ((parseInt($('#startGameOptionsAssassinationPhaseTimeoutMin').val()) * 60 + parseInt($('#startGameOptionsAssassinationPhaseTimeoutSec').val())) * 1000).toString(),
},
anonymousMode: $('#startGameOptionsAnonymousMode')[0].checked,
};
socket.emit('startGame', startGameData);
} else if (
gameData.phase === 'VotingTeam' &&
!(await preventMisclick('yes'))
) {
socket.emit('gameMove', ['yes', []]);
} else if (gameData.phase === 'VotingMission') {
socket.emit('gameMove', ['yes', []]);
} else if (gameData.phase === 'PickingTeam') {
Copy link
Owner

@vck3000 vck3000 Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this break anything? For example when using lady of the lake? I think it's safer to keep it as the old logic where it was just an else statement.

socket.emit('gameMove', ['yes', getHighlightedAvatars()]);
}

$('#mainRoomBox div').removeClass('highlight-avatar');
}

//= =====================================
Expand Down Expand Up @@ -259,3 +245,48 @@ function handleTimeoutInput(inputId) {
input.value = 60;
}
}

async function preventMisclick(button) {
Copy link
Owner

@vck3000 vck3000 Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's looking good!

Can we restructure the code a bit so each check is a bit clearer?

E.g.

async function preventMisclick(button) {
    // blah check


    // Check onrej
    if (phase == "votingTeam" && button == "no")
    {
        if (isOnTeam) { str = "blah" }
    }
    // Check hammer rej
    else if (phase == "votingTeam" && pickNum === 5 && youAreRes)
    {
        str = "are you sure you wanna rej hammer"
    }
    ...
}

This way you can get rid of isVoteExpected as well which is a bit confusing as a name for what it's doing.

if (
$('#optionGameplayPreventMisclicks')[0].checked === false ||
// only applies to 6 player
gameData.playerUsernamesOrdered.length !== 6
) {
return false;
}

const isPlayerOnTeam = gameData.proposedTeam.includes(gameData.username);
const missionsToCatchOnrej = [1, 2];
const missionsToCatchOffapp = [1, 2, 3, 5];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would've thought you'd want to check all missions for offapps? Or is the idea because at least one res has to approve mission 4 hammer?

let isVoteExpected = true;
let str = '';
if (gameData.pickNum === 5) {
isVoteExpected = button === 'yes';
str = 'Really reject hammer?'
} else if (
isPlayerOnTeam &&
missionsToCatchOnrej.includes(gameData.missionNum)
) {
isVoteExpected = button === 'yes';
str = 'You\'re on the team!'
} else if (
!isPlayerOnTeam &&
missionsToCatchOffapp.includes(gameData.missionNum)
) {
isVoteExpected = button === 'no';
str = 'You\'re off the team!'
}
if (isVoteExpected) {
return false;
}
// launch sweetalert to confirm click
const input = await swal({
title: str,
type: 'warning',
showCancelButton: true,
reverseButtons: true,
confirmButtonText: button === 'yes' ? 'Approve' : 'Reject',
confirmButtonColor: button === 'yes' ? '#5cb85c' : '#d9534f',
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to add a tiny text at the bottom of the swal saying "you can disable misclick prevention in settings"? Just so we don't annoy the vets :).

return !input.value;
}
23 changes: 23 additions & 0 deletions assets/scripts/lobby/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,29 @@ var userOptions = {
);
},
},

//---------------------------------------------
// Gameplay
//---------------------------------------------

optionGameplayPreventMisclicks: {
defaultValue: 'false',
Copy link
Owner

@vck3000 vck3000 Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put this on true and let people disable it as desired.

onLoad() {
if (docCookies.getItem('optionGameplayPreventMisclicks') === 'true') {
$('#optionGameplayPreventMisclicks')[0].checked = true;
}
},
initialiseEventListener() {
$('#optionGameplayPreventMisclicks')[0].addEventListener('click', () => {
const { checked } = $('#optionGameplayPreventMisclicks')[0];
docCookies.setItem(
'optionGameplayPreventMisclicks',
checked.toString(),
Infinity
);
});
},
},
};

// run through each userOption load and initialiseEventListener
Expand Down
25 changes: 24 additions & 1 deletion src/views/partials/header.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,14 @@
</td>
</tr>

<tr>
<td id="gameplayOptionsButton">
<span class="optionCategoriesText">
Gameplay
</span>
</td>
</tr>

<tr>
<td id="resetOptionsButton">
<span class="optionCategoriesText">
Expand Down Expand Up @@ -453,7 +461,21 @@
</div>
</div>


<div id="gameplayOptionsMenu" class="hidden rightMenu">
<h4><u>Gameplay: </u></h4>
<div>
<label><input type="checkbox" name="optionGameplayPreventMisclicks" id="optionGameplayPreventMisclicks"> Prevent misclicks</label>
<ul>
<li>Triggers confirmation for common misclicks in 6 player games
<ul>
<li>Catches hammer rejects</li>
<li>Catches on-team rejects for missions 1 and 2</li>
<li>Catches off-team approves for missions 1, 2, 3, and 5</li>
</ul>
</li>
</ul>
</div>
</div>

<div id="resetOptionsMenu" class="hidden rightMenu">
<h4><u>Reset: </u></h4>
Expand Down Expand Up @@ -697,6 +719,7 @@ function hideAllNotifs(){
var optionsList = [
"display",
"notifications",
"gameplay",
"reset"
]

Expand Down