From 6b0da2cdf71ca4e726e63e9f091a0e69c175dbb2 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 22 Dec 2023 22:43:06 +0000 Subject: [PATCH 1/5] Cut one digit from the displayed HC scores --- discord-util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discord-util.js b/discord-util.js index eea9042..19336de 100644 --- a/discord-util.js +++ b/discord-util.js @@ -151,8 +151,8 @@ async function UpdateHarmonicCentralityChatChannel(mostCentralUsers) { const lines = []; let maxLength = 0; for (const user of mostCentralUsers) { - const score = user.harmonic_centrality / 100; - const scoreString = Math.round(score).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + const score = user.harmonic_centrality / 1000; + const scoreString = Math.ceil(score).toString(); // To enable commas add .replace(/\B(?=(\d{3})+(?!\d))/g, ','); maxLength = Math.max(scoreString.length, maxLength); const paddedScore = scoreString.padStart(maxLength, ' '); const name = user.getNicknameOrTitleWithInsignia(); From d5dc943de3078bcd320522b94c02d9f500de668a Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 22 Dec 2023 22:55:08 +0000 Subject: [PATCH 2/5] Members with 1 yen can now pay tax --- yen.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yen.js b/yen.js index b4692ed..d053c38 100644 --- a/yen.js +++ b/yen.js @@ -56,8 +56,8 @@ async function CalculateInactivityTaxForecast() { // Users with no yen can't pay tax. return; } - if (user.yen <= 1) { - // Users with 1 or fewer yen are exempt from the tax. + if (user.yen <= 0) { + // Users with 0 yen cannot pay tax. return; } if (!user.last_seen) { @@ -96,8 +96,8 @@ async function CalculateInactivityTaxBase() { // Users with no yen can't pay tax. return; } - if (user.yen <= 1) { - // Users with 1 or fewer yen are exempt from the tax. + if (user.yen <= 0) { + // Users with 0 yen cannot pay tax. return; } if (!user.last_seen) { From 696ed3855da58545c084440748c5b88519843eb6 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 22 Dec 2023 23:22:54 +0000 Subject: [PATCH 3/5] Make lottery respect a minimum tax base and wait for tax to accumulate to 1010. --- server.js | 2 ++ yen.js | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index bd7106f..2e1de1f 100644 --- a/server.js +++ b/server.js @@ -17,6 +17,7 @@ const RoleID = require('./role-id'); const rules = require('./rules'); const TimeTogetherStream = require('./time-together-stream'); const UserCache = require('./user-cache'); +const yen = require('./yen'); // Used for streaming time matrix data to the database. const timeTogetherStream = new TimeTogetherStream(new Clock()); @@ -240,6 +241,7 @@ async function FilterTimeTogetherRecordsToEnforceTimeCap(timeTogetherRecords) { async function RoutineUpdate() { console.log('Routine update'); startTime = new Date().getTime(); + await yen.DoLottery(); await Rank.UpdateUserRanks(); await UpdateVoiceActiveMembersForMainDiscordGuild(); await huddles.ScheduleUpdate(); diff --git a/yen.js b/yen.js index d053c38..9041760 100644 --- a/yen.js +++ b/yen.js @@ -223,9 +223,9 @@ async function UpdateTaxChannel() { setTimeout(async () => { await UpdateTaxChannel(); }, 60 * 1000); -// Lottery once an hour. +// Update tax channel once an hour. setInterval(async () => { - await DoLottery(); + await UpdateTaxChannel(); }, 3600 * 1000); async function CalculateTaxPlan(yenToRaise) { @@ -354,18 +354,28 @@ async function HandleTaxCommand(discordMessage) { await UpdateTaxChannel(); } +// Delay the first lottery by 5 minutes after bot startup to +// avoid too frequent lotteries while testing bot code, which +// involves repeatedly restarting the bot. +let nextLotteryTime = Date.now() + (5 * 60 * 1000); + async function DoLottery() { console.log('LOTTERY'); + const currentTime = Date.now(); + if (currentTime < nextLotteryTime) { + return; + } const taxBase = await CalculateInactivityTaxBase(); let totalTaxBase = 0; for (const i in taxBase) { totalTaxBase += taxBase[i]; } + const minimumTaxBaseForLottery = 1010; + if (totalTaxBase < minimumTaxBaseForLottery) { + return; + } console.log('totalTaxBase', totalTaxBase); - const maxPrizeYen = 10; - const targetPrize = Math.floor(0.1 * totalTaxBase); - console.log('targetPrize', targetPrize); - const prizeYen = Math.min(targetPrize, maxPrizeYen); + const prizeYen = 10; const plan = await CalculateTaxPlan(prizeYen); if (!plan) { console.log('Could not raise enough tax revenue for lottery.'); @@ -400,6 +410,11 @@ async function DoLottery() { await ImplementTaxPlan(plan, recipient); await UpdateYenChannel(); await UpdateTaxChannel(); + // Schedule the minimum time for the next lottery to stop it from + // happening too often. + const oneHour = 60 * 60 * 1000; + const randomJitter = (Math.random() * 2 - 1) * (15 * 60 * 1000); + nextLotteryTime = currentTime + oneHour + randomJitter; } async function UpdateYenChannel() { From ba6a9a12257a9e33497f37dfb213c72146eac3ea Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 23 Dec 2023 00:31:49 +0000 Subject: [PATCH 4/5] Reduce max ban court channels to 49 to be safe. --- ban.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ban.js b/ban.js index abf2968..e00819e 100644 --- a/ban.js +++ b/ban.js @@ -263,7 +263,7 @@ async function UpdateTrial(cu) { async function HandleBanCommand(discordMessage) { const banCourtCategory = await DiscordUtil.GetBanCourtCategoryChannel(); const banCourtChannelCount = banCourtCategory.children.cache.size; - if (banCourtChannelCount >= 50) { + if (banCourtChannelCount >= 49) { await discordMessage.channel.send('Too many ban trials in progress. Get more votes for the ones already underway to speed them up.'); return; } From fffa403cd15cb4b7e238216731c85eab300097a7 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 23 Dec 2023 01:05:15 +0000 Subject: [PATCH 5/5] Add two columns to the user table in DB and cache --- commissar-user.js | 22 +++++++++++++++++++++- setup-database.sql | 2 ++ user-cache.js | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/commissar-user.js b/commissar-user.js index e87ef18..daa789f 100644 --- a/commissar-user.js +++ b/commissar-user.js @@ -27,7 +27,9 @@ class CommissarUser { yen, inactivity_tax_paid_until, ban_conviction_time, - ban_pardon_time) { + ban_pardon_time, + presidential_election_vote, + presidential_election_message_id) { this.commissar_id = commissar_id; this.discord_id = discord_id; this.nickname = nickname; @@ -50,6 +52,8 @@ class CommissarUser { this.inactivity_tax_paid_until = inactivity_tax_paid_until; this.ban_conviction_time = ban_conviction_time; this.ban_pardon_time = ban_pardon_time; + this.presidential_election_vote = presidential_election_vote; + this.presidential_election_message_id = presidential_election_message_id; } async setDiscordId(discord_id) { @@ -234,6 +238,22 @@ class CommissarUser { await this.updateFieldInDatabase('ban_pardon_time', this.ban_pardon_time); } + async setPresidentialElectionVote(presidential_election_vote) { + if (presidential_election_vote === this.presidential_election_vote) { + return; + } + this.presidential_election_vote = presidential_election_vote; + await this.updateFieldInDatabase('presidential_election_vote', this.presidential_election_vote); + } + + async setPresidentialElectionMessageId(presidential_election_message_id) { + if (presidential_election_message_id === this.presidential_election_message_id) { + return; + } + this.presidential_election_message_id = presidential_election_message_id; + await this.updateFieldInDatabase('presidential_election_message_id', this.presidential_election_message_id); + } + async updateFieldInDatabase(fieldName, fieldValue) { //console.log(`DB update ${fieldName} = ${fieldValue} for ${this.nickname} (ID:${this.commissar_id}).`); const sql = `UPDATE users SET ${fieldName} = ? WHERE commissar_id = ?`; diff --git a/setup-database.sql b/setup-database.sql index cb0855a..54ce874 100644 --- a/setup-database.sql +++ b/setup-database.sql @@ -32,6 +32,8 @@ CREATE TABLE users inactivity_tax_paid_until TIMESTAMP, -- Last time this user was taxed. ban_conviction_time TIMESTAMP, -- When this user was convicted & banned in ban court. ban_pardon_time TIMESTAMP, -- When this user was convicted & banned in ban court. + presidential_election_vote INT, -- The commissar_id that this user is voting for in the presidential election. NULL if has not voted. + presidential_election_message_id VARCHAR(32), -- ID of the discord message used to display this user on the presidential election ballot. PRIMARY KEY (commissar_id), INDEX discord_index (discord_id) ); diff --git a/user-cache.js b/user-cache.js index 8216af2..6c53be9 100644 --- a/user-cache.js +++ b/user-cache.js @@ -36,6 +36,8 @@ async function LoadAllUsersFromDatabase() { row.inactivity_tax_paid_until, row.ban_conviction_time, row.ban_pardon_time, + row.presidential_election_vote, + row.presidential_election_message_id, ); newCache[row.commissar_id] = newUser; }); @@ -112,6 +114,7 @@ async function CreateNewDatabaseUser(discordMember) { null, null, null, null, null, null, 0, + null, null, null, null, null, ); commissarUserCache[commissar_id] = newUser; return newUser; @@ -242,6 +245,21 @@ function GetUsersWithRankAndScoreHigherThan(rankIndex, scoreThreshold) { return matches; } +function CountPresidentialElectionVotes() { + const votes = {}; + for (const i in commissarUserCache) { + const u = commissarUserCache[i]; + const v = u.presidential_election_vote; + if (v) { + if (!(v in votes)) { + votes[v] = 0; + } + votes[v]++; + } + } + return votes; +} + module.exports = { BulkCentralityUpdate, CountVoiceActiveUsers,