From f063fa7cd72b493d9b101e6e0ed855dd960792d6 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:06:20 +0000 Subject: [PATCH 1/6] adds poll subsystem, entities and ui --- code/controllers/subsystem/polls.dm | 317 ++++++++++++++++++++++ code/modules/mob/new_player/new_player.dm | 4 + colonialmarines.dme | 1 + tgui/packages/tgui/interfaces/Poll.tsx | 132 +++++++++ 4 files changed, 454 insertions(+) create mode 100644 code/controllers/subsystem/polls.dm create mode 100644 tgui/packages/tgui/interfaces/Poll.tsx diff --git a/code/controllers/subsystem/polls.dm b/code/controllers/subsystem/polls.dm new file mode 100644 index 000000000000..c34a9d17049d --- /dev/null +++ b/code/controllers/subsystem/polls.dm @@ -0,0 +1,317 @@ +SUBSYSTEM_DEF(polls) + name = "Polls" + + var/list/datum/poll/active_polls + var/list/datum/poll/concluded_polls + +/datum/controller/subsystem/polls/Initialize() + setup_polls() + + return SS_INIT_SUCCESS + +/// Clear and populate the poll lists with fresh data +/datum/controller/subsystem/polls/proc/setup_polls() + active_polls = list() + + var/list/datum/view_record/poll/all_active_polls = DB_VIEW( + /datum/view_record/poll, + DB_AND( + DB_COMP("active", DB_EQUALS, TRUE), + DB_COMP("expiry", DB_GREATER_EQUAL, time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")) + ) + ) + + for(var/datum/view_record/poll/poll as anything in all_active_polls) + var/datum/poll/new_poll = new(poll.question) + + var/list/datum/view_record/poll_answer/poll_answers = DB_VIEW( + /datum/view_record/poll_answer, + DB_COMP("poll_id", DB_EQUALS, poll.id) + ) + + for(var/datum/view_record/poll_answer/answer as anything in poll_answers) + new_poll.answers["[answer.id]"] = answer.answer + + active_polls["[poll.id]"] = new_poll + + concluded_polls = list() + + var/list/datum/view_record/poll/all_concluded_polls = DB_VIEW( + /datum/view_record/poll, + DB_AND( + DB_COMP("active", DB_EQUALS, TRUE), + DB_COMP("expiry", DB_LESS, time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")) + ) + ) + + for(var/datum/view_record/poll/poll as anything in all_concluded_polls) + var/datum/poll/concluded/concluded_poll = new(poll.question) + + var/list/datum/view_record/poll_answer/poll_answers = DB_VIEW( + /datum/view_record/poll_answer, + DB_COMP("poll_id", DB_EQUALS, poll.id) + ) + + for(var/datum/view_record/poll_answer/answer as anything in poll_answers) + var/total = length(DB_VIEW(/datum/view_record/player_poll_answer, DB_COMP("answer_id", DB_EQUALS, answer.id))) + + concluded_poll.answer_totals[answer.answer] = total + + concluded_polls["[poll.id]"] = concluded_poll + + update_static_data_for_all_viewers() + +/datum/controller/subsystem/polls/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Poll", name) + ui.open() + +/datum/controller/subsystem/polls/ui_static_data(mob/user) + . = ..() + + .["polls"] = list() + for(var/id in active_polls) + var/datum/poll/poll = active_polls[id] + .["polls"] += list( + list("id" = id, "question" = poll.question, "answers" = poll.answers) + ) + + .["concluded_polls"] = list() + for(var/id in concluded_polls) + var/datum/poll/concluded/concluded = concluded_polls[id] + .["concluded_polls"] += list( + list("id" = id, "question" = concluded.question, "answers" = concluded.answer_totals) + ) + + .["is_poll_maker"] = CLIENT_HAS_RIGHTS(user.client, R_PERMISSIONS) + +/datum/controller/subsystem/polls/ui_data(mob/user) + . = ..() + + var/datum/entity/player/player = user.client?.player_data + if(!player) + return + + .["voted_polls"] = list() + for(var/datum/view_record/player_poll_answer/answer in DB_VIEW(/datum/view_record/player_poll_answer, DB_COMP("player_id", DB_EQUALS, player.id))) + .["voted_polls"] += answer.answer_id + +/datum/controller/subsystem/polls/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/datum/entity/player/player = ui.user.client?.player_data + if(!player) + return + + switch(action) + if("vote") + var/voting_in = params["poll_id"] + + if(!isnum(text2num(voting_in))) + return + + var/datum/poll/selected_poll = active_polls[voting_in] + if(!selected_poll) + return + + var/selected_answer = params["answer_id"] + if(!isnum(text2num(selected_answer)) || !selected_poll.answers[selected_answer]) + return + + var/list/datum/view_record/player_poll_answer/existing_votes = DB_VIEW( + /datum/view_record/player_poll_answer, + DB_AND( + DB_COMP("player_id", DB_EQUALS, player.id), + DB_COMP("poll_id", DB_EQUALS, text2num(voting_in)) + ) + ) + + if(length(existing_votes)) + if(tgui_alert(ui.user, "Change existing vote?", "Change Vote", list("Yes", "No")) != "Yes") + return + + for(var/datum/view_record/player_poll_answer/existing_vote as anything in existing_votes) + var/datum/entity/player_poll_answer/answer = DB_ENTITY(/datum/entity/player_poll_answer, existing_vote.id) + answer.sync() + + answer.answer_id = text2num(selected_answer) + answer.save() + return + + var/datum/entity/player_poll_answer/answer = DB_ENTITY(/datum/entity/player_poll_answer) + answer.player_id = player.id + answer.answer_id = text2num(selected_answer) + answer.poll_id = text2num(voting_in) + answer.save() + answer.detach() + + if("create") + if(!CLIENT_HAS_RIGHTS(ui.user.client, R_PERMISSIONS)) + return + + var/poll_question = tgui_input_text(ui.user, "What's the question?", "Poll Question", encode = FALSE) + if(!poll_question) + return + + var/list/answers = list() + + var/answers_to_add = tgui_input_text(ui.user, "What answers should be added? Separate answers with ;", "Poll Answers", encode = FALSE, multiline = TRUE) + if(!answers_to_add) + return + + answers = splittext(answers_to_add, ";") + + if(length(answers) <= 1) + to_chat(ui.user, SPAN_WARNING("Poll creation cancelled - not enough added.")) + return + + var/expiry = tgui_input_number(ui.user, "How many days should this poll run for?", "Poll Length", 14) + if(!expiry || expiry <= 0) + return + + if(tgui_alert(ui.user, "Confirm creating poll with question: '[poll_question]', answers: [english_list(answers)] and duration: [expiry] days.", "BuildAPoll", list("Confirm", "Cancel")) != "Confirm") + return + + var/datum/entity/poll/poll = DB_ENTITY(/datum/entity/poll) + poll.active = TRUE + poll.question = poll_question + poll.expiry = time2text(world.realtime + (expiry * 24 HOURS), "YYYY-MM-DD hh:mm:ss") + poll.save() + poll.sync() + + for(var/answer in answers) + var/datum/entity/poll_answer/new_answer = DB_ENTITY(/datum/entity/poll_answer) + new_answer.answer = answer // ... + new_answer.poll_id = poll.id + new_answer.save() + new_answer.sync() + + to_chat(ui.user, SPAN_ALERT("Poll '[poll_question]' created successfully.")) + setup_polls() + + if("delete") + if(!CLIENT_HAS_RIGHTS(ui.user.client, R_PERMISSIONS)) + return + + var/to_delete = params["poll_id"] + if(!isnum(text2num(to_delete))) + return + + var/datum/poll/delete_poll = active_polls[to_delete] + if(!delete_poll) + return + + var/datum/entity/poll/poll = DB_ENTITY(/datum/entity/poll, text2num(to_delete)) + poll.sync() + + poll.active = FALSE + poll.save() + poll.sync() + + to_chat(ui.user, SPAN_ALERT("Poll deleted.")) + + setup_polls() + + return TRUE + +/datum/controller/subsystem/polls/ui_state(mob/user) + return GLOB.always_state + +/datum/poll + var/question + var/list/answers = list() + +/datum/poll/New(question) + src.question = question + +/datum/poll/concluded + var/answer_totals = list() + +/datum/entity/poll + var/question + var/active + var/expiry + +/datum/entity_meta/poll + entity_type = /datum/entity/poll + table_name = "polls" + field_types = list( + "question" = DB_FIELDTYPE_STRING_LARGE, + "active" = DB_FIELDTYPE_INT, + "expiry" = DB_FIELDTYPE_DATE, + ) + +/datum/view_record/poll + var/id + var/question + var/active + var/expiry + +/datum/entity_view_meta/poll + root_record_type = /datum/entity/poll + destination_entity = /datum/view_record/poll + fields = list( + "id", + "question", + "active", + "expiry", + ) + +/datum/entity/poll_answer + var/poll_id + var/answer + +/datum/entity_meta/poll_answer + entity_type = /datum/entity/poll_answer + table_name = "poll_answers" + field_types = list( + "poll_id" = DB_FIELDTYPE_BIGINT, + "answer" = DB_FIELDTYPE_STRING_LARGE, + ) + +/datum/view_record/poll_answer + var/id + var/poll_id + var/answer + +/datum/entity_view_meta/poll_answer + root_record_type = /datum/entity/poll_answer + destination_entity = /datum/view_record/poll_answer + fields = list( + "id", + "poll_id", + "answer", + ) + +/datum/entity/player_poll_answer + var/player_id + var/poll_id + var/answer_id + +/datum/entity_meta/player_poll_answer + entity_type = /datum/entity/player_poll_answer + table_name = "player_poll_answers" + field_types = list( + "player_id" = DB_FIELDTYPE_BIGINT, + "poll_id" = DB_FIELDTYPE_BIGINT, + "answer_id" = DB_FIELDTYPE_BIGINT, + ) + +/datum/view_record/player_poll_answer + var/id + var/player_id + var/poll_id + var/answer_id + +/datum/entity_view_meta/player_poll_answer + root_record_type = /datum/entity/player_poll_answer + destination_entity = /datum/view_record/player_poll_answer + fields = list( + "id", + "player_id", + "poll_id", + "answer_id" + ) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index e80538353210..99505d39c6df 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -47,6 +47,7 @@ output +="
[(client.prefs && client.prefs.real_name) ? client.prefs.real_name : client.key]" output +="
[xeno_text]" output += "

Tutorial

" + output += "

View Polls

" output += "

Setup Character

" output += "

View Playtimes

" @@ -210,6 +211,9 @@ if("tutorial") tutorial_menu() + if("polls") + SSpolls.tgui_interact(src) + else new_player_panel() diff --git a/colonialmarines.dme b/colonialmarines.dme index 423b66356dd5..c202153f801c 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -290,6 +290,7 @@ #include "code\controllers\subsystem\ping.dm" #include "code\controllers\subsystem\playtime.dm" #include "code\controllers\subsystem\police_clues.dm" +#include "code\controllers\subsystem\polls.dm" #include "code\controllers\subsystem\power.dm" #include "code\controllers\subsystem\predships.dm" #include "code\controllers\subsystem\profiler.dm" diff --git a/tgui/packages/tgui/interfaces/Poll.tsx b/tgui/packages/tgui/interfaces/Poll.tsx new file mode 100644 index 000000000000..391c8261be79 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Poll.tsx @@ -0,0 +1,132 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../backend'; +import { + Button, + Collapsible, + ProgressBar, + Section, + Stack, +} from '../components'; +import { Window } from '../layouts'; + +type PollType = { + id: number; + question: string; + answers: { [id: string]: string }; +}; + +type ConcludedPoll = { + id: number; + question: string; + answers: { [answer: string]: number }; +}; + +type PollData = { + polls: PollType[]; + concluded_polls: ConcludedPoll[]; + voted_polls: number[]; + is_poll_maker: BooleanLike; +}; + +export const Poll = () => { + const { act, data } = useBackend(); + + const { polls, is_poll_maker, concluded_polls } = data; + + return ( + + + {!!is_poll_maker && ( +
+ +
+ )} + {polls.map((poll) => ( + + ))} + {polls.length === 0 && ( +
No polls are available to vote in.
+ )} +
+ {concluded_polls.map((concludedPoll) => ( + + ))} + {concluded_polls.length === 0 && ( + <>No polls have been concluded and are available to view. + )} +
+
+
+ ); +}; + +const RenderConcludedPoll = (props: { readonly poll: ConcludedPoll }) => { + const { poll } = props; + + const total = Object.values(poll.answers).reduce( + (prev, current) => prev + current, + 0, + ); + + return ( + + + {Object.keys(poll.answers).map((answer) => ( + + + {answer} ({poll.answers[answer]} vote + {poll.answers[answer] === 1 ? '' : 's'}) + + + ))} + + + ); +}; + +const RenderPoll = (props: { readonly poll: PollType }) => { + const { poll } = props; + + const { act, data } = useBackend(); + const { voted_polls, is_poll_maker } = data; + + const votedIn = + Object.keys(poll.answers).filter((value) => + voted_polls.includes(Number.parseInt(value, 10)), + ).length > 0; + + return ( +
act('delete', { poll_id: poll.id })}> + Delete + + ) + } + > + + {Object.keys(poll.answers).map((answerId) => ( + + + + ))} + +
+ ); +}; From cde36c4d47e065308b11d02c648d4f9fc2254dc5 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:13:20 +0000 Subject: [PATCH 2/6] long list lint fix --- code/controllers/subsystem/polls.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystem/polls.dm b/code/controllers/subsystem/polls.dm index c34a9d17049d..742c9d366adc 100644 --- a/code/controllers/subsystem/polls.dm +++ b/code/controllers/subsystem/polls.dm @@ -313,5 +313,5 @@ SUBSYSTEM_DEF(polls) "id", "player_id", "poll_id", - "answer_id" + "answer_id", ) From b0daea5f8590d0bc828f00547581bfa15f43786a Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:26:58 +0000 Subject: [PATCH 3/6] set the subsystem as not firing --- code/controllers/subsystem/polls.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/controllers/subsystem/polls.dm b/code/controllers/subsystem/polls.dm index 742c9d366adc..5ab85306f333 100644 --- a/code/controllers/subsystem/polls.dm +++ b/code/controllers/subsystem/polls.dm @@ -1,5 +1,6 @@ SUBSYSTEM_DEF(polls) name = "Polls" + flags = SS_NO_FIRE var/list/datum/poll/active_polls var/list/datum/poll/concluded_polls From d2f1815433b22cf29310f2f344bad063601c0826 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:03:46 +0000 Subject: [PATCH 4/6] bother players to engage democratically --- code/controllers/subsystem/polls.dm | 60 +++++++++++++++++++++++++++++ code/datums/soundOutput.dm | 2 - 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/polls.dm b/code/controllers/subsystem/polls.dm index 5ab85306f333..106711b03443 100644 --- a/code/controllers/subsystem/polls.dm +++ b/code/controllers/subsystem/polls.dm @@ -2,12 +2,39 @@ SUBSYSTEM_DEF(polls) name = "Polls" flags = SS_NO_FIRE + /// Stores the polls that have not expired, and set as active var/list/datum/poll/active_polls + + /// Stores the polls that have expired, and set as active var/list/datum/poll/concluded_polls + /// For storing messages to remind people to vote, that we do not want to get lost in the mess of a server starting + VAR_PRIVATE/list/datum/callback/to_send_at_lobby = list() + /datum/controller/subsystem/polls/Initialize() setup_polls() + for(var/id in active_polls) + var/list/datum/view_record/player_poll_answer/completed_polls = DB_VIEW( + /datum/view_record/player_poll_answer, + DB_COMP("polL_id", DB_EQUALS, id) + ) + + var/voted_ids = list() + for(var/datum/view_record/player_poll_answer/answer as anything in completed_polls) + voted_ids += answer.player_id + + var/datum/poll/active_poll = active_polls[id] + + for(var/client/client as anything in GLOB.clients) + if(client.player_data.id in voted_ids) + continue + + to_send_at_lobby += CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), client, SPAN_LARGE("You have not voted in the '[active_poll.question]' poll. Click here to vote.")) + + RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PREGAME_LOBBY, PROC_REF(handle_lobby)) + RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN, PROC_REF(handle_new_user)) + return SS_INIT_SUCCESS /// Clear and populate the poll lists with fresh data @@ -62,6 +89,39 @@ SUBSYSTEM_DEF(polls) update_static_data_for_all_viewers() +/datum/controller/subsystem/polls/proc/handle_lobby(source) + SIGNAL_HANDLER + + for(var/datum/callback/callback as anything in to_send_at_lobby) + callback.InvokeAsync() + +/datum/controller/subsystem/polls/proc/handle_new_user(source, client/new_client) + SIGNAL_HANDLER + + INVOKE_ASYNC(src, PROC_REF(remind_new_user), new_client) + +/datum/controller/subsystem/polls/proc/remind_new_user(client/new_client) + set waitfor = FALSE + + while(!new_client.player_data) + stoplag() + + for(var/id in active_polls) + var/voted = length(DB_VIEW( + /datum/view_record/player_poll_answer, + DB_AND( + DB_COMP("player_id", DB_EQUALS, new_client.player_data.id), + DB_COMP("poll_id", DB_EQUALS, id) + ) + )) + + if(voted) + continue + + var/datum/poll/active_poll = active_polls[id] + + to_chat(new_client, SPAN_LARGE("You have not voted in the '[active_poll.question]' poll. Click here to vote.")) + /datum/controller/subsystem/polls/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/datums/soundOutput.dm b/code/datums/soundOutput.dm index cc7334d2cb98..97889adf6d92 100644 --- a/code/datums/soundOutput.dm +++ b/code/datums/soundOutput.dm @@ -19,8 +19,6 @@ return ..() /datum/soundOutput/Destroy() - UnregisterSignal(owner.mob, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGOUT)) - UnregisterSignal(owner, COMSIG_CLIENT_MOB_LOGGED_IN) owner = null return ..() From 4500793ab43c183acb39c09602ef27dac984a01c Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:58:55 +0000 Subject: [PATCH 5/6] rename poll_answers to votes (obviously), open polls should be on /mob Topic --- code/controllers/subsystem/polls.dm | 63 ++++++++++++----------- code/modules/mob/mob.dm | 2 + code/modules/mob/new_player/new_player.dm | 5 +- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/code/controllers/subsystem/polls.dm b/code/controllers/subsystem/polls.dm index 106711b03443..73f1e1803ee6 100644 --- a/code/controllers/subsystem/polls.dm +++ b/code/controllers/subsystem/polls.dm @@ -15,14 +15,14 @@ SUBSYSTEM_DEF(polls) setup_polls() for(var/id in active_polls) - var/list/datum/view_record/player_poll_answer/completed_polls = DB_VIEW( - /datum/view_record/player_poll_answer, + var/list/datum/view_record/player_poll_vote/votes = DB_VIEW( + /datum/view_record/player_poll_vote, DB_COMP("polL_id", DB_EQUALS, id) ) var/voted_ids = list() - for(var/datum/view_record/player_poll_answer/answer as anything in completed_polls) - voted_ids += answer.player_id + for(var/datum/view_record/player_poll_vote/vote as anything in votes) + voted_ids += vote.player_id var/datum/poll/active_poll = active_polls[id] @@ -30,7 +30,7 @@ SUBSYSTEM_DEF(polls) if(client.player_data.id in voted_ids) continue - to_send_at_lobby += CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), client, SPAN_LARGE("You have not voted in the '[active_poll.question]' poll. Click here to vote.")) + to_send_at_lobby += CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), client, SPAN_LARGE("You have not voted in the '[active_poll.question]' poll. Click here to vote.")) RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PREGAME_LOBBY, PROC_REF(handle_lobby)) RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN, PROC_REF(handle_new_user)) @@ -81,7 +81,7 @@ SUBSYSTEM_DEF(polls) ) for(var/datum/view_record/poll_answer/answer as anything in poll_answers) - var/total = length(DB_VIEW(/datum/view_record/player_poll_answer, DB_COMP("answer_id", DB_EQUALS, answer.id))) + var/total = length(DB_VIEW(/datum/view_record/player_poll_vote, DB_COMP("answer_id", DB_EQUALS, answer.id))) concluded_poll.answer_totals[answer.answer] = total @@ -89,6 +89,8 @@ SUBSYSTEM_DEF(polls) update_static_data_for_all_viewers() +/// Sends all the queued messages when we enter the +/// lobby mode, so the messages do not get lost /datum/controller/subsystem/polls/proc/handle_lobby(source) SIGNAL_HANDLER @@ -100,6 +102,7 @@ SUBSYSTEM_DEF(polls) INVOKE_ASYNC(src, PROC_REF(remind_new_user), new_client) +/// Reminds new users logging in of any uncompleted polls. /datum/controller/subsystem/polls/proc/remind_new_user(client/new_client) set waitfor = FALSE @@ -108,7 +111,7 @@ SUBSYSTEM_DEF(polls) for(var/id in active_polls) var/voted = length(DB_VIEW( - /datum/view_record/player_poll_answer, + /datum/view_record/player_poll_vote, DB_AND( DB_COMP("player_id", DB_EQUALS, new_client.player_data.id), DB_COMP("poll_id", DB_EQUALS, id) @@ -120,7 +123,7 @@ SUBSYSTEM_DEF(polls) var/datum/poll/active_poll = active_polls[id] - to_chat(new_client, SPAN_LARGE("You have not voted in the '[active_poll.question]' poll. Click here to vote.")) + to_chat(new_client, SPAN_LARGE("You have not voted in the '[active_poll.question]' poll. Click here to vote.")) /datum/controller/subsystem/polls/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -155,7 +158,7 @@ SUBSYSTEM_DEF(polls) return .["voted_polls"] = list() - for(var/datum/view_record/player_poll_answer/answer in DB_VIEW(/datum/view_record/player_poll_answer, DB_COMP("player_id", DB_EQUALS, player.id))) + for(var/datum/view_record/player_poll_vote/answer in DB_VIEW(/datum/view_record/player_poll_vote, DB_COMP("player_id", DB_EQUALS, player.id))) .["voted_polls"] += answer.answer_id /datum/controller/subsystem/polls/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) @@ -182,8 +185,8 @@ SUBSYSTEM_DEF(polls) if(!isnum(text2num(selected_answer)) || !selected_poll.answers[selected_answer]) return - var/list/datum/view_record/player_poll_answer/existing_votes = DB_VIEW( - /datum/view_record/player_poll_answer, + var/list/datum/view_record/player_poll_vote/existing_votes = DB_VIEW( + /datum/view_record/player_poll_vote, DB_AND( DB_COMP("player_id", DB_EQUALS, player.id), DB_COMP("poll_id", DB_EQUALS, text2num(voting_in)) @@ -194,20 +197,20 @@ SUBSYSTEM_DEF(polls) if(tgui_alert(ui.user, "Change existing vote?", "Change Vote", list("Yes", "No")) != "Yes") return - for(var/datum/view_record/player_poll_answer/existing_vote as anything in existing_votes) - var/datum/entity/player_poll_answer/answer = DB_ENTITY(/datum/entity/player_poll_answer, existing_vote.id) - answer.sync() + for(var/datum/view_record/player_poll_vote/existing_vote as anything in existing_votes) + var/datum/entity/player_poll_vote/vote = DB_ENTITY(/datum/entity/player_poll_vote, existing_vote.id) + vote.sync() - answer.answer_id = text2num(selected_answer) - answer.save() + vote.answer_id = text2num(selected_answer) + vote.save() return - var/datum/entity/player_poll_answer/answer = DB_ENTITY(/datum/entity/player_poll_answer) - answer.player_id = player.id - answer.answer_id = text2num(selected_answer) - answer.poll_id = text2num(voting_in) - answer.save() - answer.detach() + var/datum/entity/player_poll_vote/vote = DB_ENTITY(/datum/entity/player_poll_vote) + vote.player_id = player.id + vote.answer_id = text2num(selected_answer) + vote.poll_id = text2num(voting_in) + vote.save() + vote.detach() if("create") if(!CLIENT_HAS_RIGHTS(ui.user.client, R_PERMISSIONS)) @@ -347,29 +350,29 @@ SUBSYSTEM_DEF(polls) "answer", ) -/datum/entity/player_poll_answer +/datum/entity/player_poll_vote var/player_id var/poll_id var/answer_id -/datum/entity_meta/player_poll_answer - entity_type = /datum/entity/player_poll_answer - table_name = "player_poll_answers" +/datum/entity_meta/player_poll_vote + entity_type = /datum/entity/player_poll_vote + table_name = "player_poll_votes" field_types = list( "player_id" = DB_FIELDTYPE_BIGINT, "poll_id" = DB_FIELDTYPE_BIGINT, "answer_id" = DB_FIELDTYPE_BIGINT, ) -/datum/view_record/player_poll_answer +/datum/view_record/player_poll_vote var/id var/player_id var/poll_id var/answer_id -/datum/entity_view_meta/player_poll_answer - root_record_type = /datum/entity/player_poll_answer - destination_entity = /datum/view_record/player_poll_answer +/datum/entity_view_meta/player_poll_vote + root_record_type = /datum/entity/player_poll_vote + destination_entity = /datum/view_record/player_poll_vote fields = list( "id", "player_id", diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 712bef37afad..2506e321ce1a 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -985,6 +985,8 @@ note dizziness decrements automatically in the mob's Life() proc. if(client) client.prefs.process_link(src, href_list) return TRUE + if(href_list["poll"]) + SSpolls.tgui_interact(src) /mob/proc/reset_perspective(atom/A) if(!client) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index c54cff993b42..abebf84e5904 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -47,7 +47,7 @@ output +="
[(client.prefs && client.prefs.real_name) ? client.prefs.real_name : client.key]" output +="
[xeno_text]" output += "

Tutorial

" - output += "

View Polls

" + output += "

View Polls

" output += "

Setup Character

" output += "

View Playtimes

" @@ -226,9 +226,6 @@ if("tutorial") tutorial_menu() - if("polls") - SSpolls.tgui_interact(src) - else new_player_panel() From ddd2f66fd9ee60f828928d4bd2ca3f2cdb9ced1a Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:59:25 +0000 Subject: [PATCH 6/6] firaviews --- code/controllers/subsystem/polls.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/controllers/subsystem/polls.dm b/code/controllers/subsystem/polls.dm index 73f1e1803ee6..c0ebdd932ee8 100644 --- a/code/controllers/subsystem/polls.dm +++ b/code/controllers/subsystem/polls.dm @@ -100,14 +100,13 @@ SUBSYSTEM_DEF(polls) /datum/controller/subsystem/polls/proc/handle_new_user(source, client/new_client) SIGNAL_HANDLER - INVOKE_ASYNC(src, PROC_REF(remind_new_user), new_client) + remind_new_user(new_client) /// Reminds new users logging in of any uncompleted polls. /datum/controller/subsystem/polls/proc/remind_new_user(client/new_client) set waitfor = FALSE - while(!new_client.player_data) - stoplag() + UNTIL(new_client.player_data) for(var/id in active_polls) var/voted = length(DB_VIEW(