There are two related bugs that together explain why the vote doesn't appear consistently.
Bug 1: Failed votes incorrectly block future votes (primary cause)
StopVote(), line 939:
else { _skippedNight = _config.Time.MissedNights; // BUG: sets counter even when vote FAILED ... }
When a vote runs out of time and fails (not enough players voted), _skippedNight is set to MissedNights — the same value as a successful skip. IsLimitedSkippingNight() then returns true and blocks the next night's vote, even though no night was ever skipped. This is the direct cause of players being "forced to have multiple in-game nights in a row."
Bug 2: CanResetSkippingNight() can never return true
Line 1443–1444:
private bool CanResetSkippingNight() => _skippedNight > _config.Time.MissedNights && _config.Time.MissedNights > 0;
_skippedNight is only ever assigned _config.Time.MissedNights (in both StartSkip() and the failed-vote branch of StopVote()). It is never set higher than MissedNights, so the > condition is never true. The OnDay() reset to 0 never fires, meaning once the counter is set, it only ticks down via the OnMinute() day-check — and compound with Bug 1, this can leave the plugin perpetually blocking votes.
How to fix
Fix 1 — Don't penalize failed votes:
// StopVote(), around line 939 — remove the _skippedNight assignment from the else branch else { // _skippedNight = _config.Time.MissedNights; <-- REMOVE THIS LINE if (_config.Votes.EnabledPay && _config.Votes.RefundWhenCanceled) foreach (var votedPlayer in _votedPlayers) _config.Economy.AddBalance(votedPlayer, _config.Votes.SkipCost); }
Fix 2 — Increment the skip counter instead of resetting to a fixed value, so CanResetSkippingNight() can actually fire:
// StartSkip(), line 1345 — increment instead of assign _skippedNight++; // was: _skippedNight = _config.Time.MissedNights;
And update IsLimitedSkippingNight() to match:
private bool IsLimitedSkippingNight() => _config.Time.MissedNights > 0 && _skippedNight >= _config.Time.MissedNights;
And CanResetSkippingNight() becomes unnecessary since OnDay() can just always reset it when the counter is spent — or simplify to reset via OnMinute()'s existing decrement logic. The simplest approach: OnDay() resets to 0 unconditionally when MissedNights > 0 and the forced night has been endured, but with the increment approach IsLimitedSkippingNight() naturally becomes false once _skippedNight drops below MissedNights via the existing day-decrement in OnMinute().
In short: The root cause is line 939 — a failed vote sets _skippedNight = MissedNights, which then blocks all subsequent vote prompts as if two nights had already been skipped.