From 8c773ab39e03b42c778e6c7b51b7ce6a4cc0c1c8 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 10 Dec 2024 14:51:06 -0500 Subject: [PATCH] refactors monkecoin rewards + challenges to use `/datum/player_details` --- .../~monkestation-helpers/roundend.dm | 51 +++++++------ code/_onclick/hud/new_player.dm | 9 ++- code/controllers/subsystem/ticker.dm | 25 +++---- code/modules/client/client_defines.dm | 3 - code/modules/client/player_details.dm | 6 ++ .../modules/mob/dead/new_player/new_player.dm | 17 ++--- .../code/modules/client/player_details.dm | 18 +++++ .../challenges/challenge/_challenge_base.dm | 41 ++++++----- .../challenges/challenge/paranoia.dm | 46 ++++++------ .../challenges/challenge_controller.dm | 7 +- .../challenges/challenge_selector.dm | 71 +++++++++---------- 11 files changed, 160 insertions(+), 134 deletions(-) diff --git a/code/__HELPERS/~monkestation-helpers/roundend.dm b/code/__HELPERS/~monkestation-helpers/roundend.dm index f3c34f4615b9..082c3aaeca38 100644 --- a/code/__HELPERS/~monkestation-helpers/roundend.dm +++ b/code/__HELPERS/~monkestation-helpers/roundend.dm @@ -4,28 +4,35 @@ /datum/controller/subsystem/ticker/proc/distribute_rewards() var/hour = round((world.time - SSticker.round_start_time) / 36000) var/minute = round(((world.time - SSticker.round_start_time) - (hour * 36000)) / 600) - var/added_xp = round(25 + (minute**0.85)) + var/added_xp = round(25 + (minute ** 0.85)) for(var/client/client as anything in GLOB.clients) - if(!istype(client) || QDELING(client)) - continue - if(!QDELETED(client?.prefs)) - client?.prefs?.adjust_metacoins(client?.ckey, 75, "Played a Round") - client?.prefs?.adjust_metacoins(client?.ckey, client?.reward_this_person, "Special Bonus") - // WHYYYYYY - if(QDELETED(client)) - continue - if(client?.mob?.mind?.assigned_role) - add_jobxp(client, added_xp, client?.mob?.mind?.assigned_role?.title) + distribute_rewards_to_client(client, added_xp) + +/datum/controller/subsystem/ticker/proc/distribute_rewards_to_client(client/client, added_xp) + if(!istype(client) || QDELING(client)) + return + var/datum/player_details/details = get_player_details(client) + if(!QDELETED(client?.prefs)) + client?.prefs?.adjust_metacoins(client?.ckey, 75, "Played a Round") + var/bonus = details?.roundend_monkecoin_bonus + if(bonus) + client?.prefs?.adjust_metacoins(client?.ckey, bonus, "Special Bonus") + // WHYYYYYY if(QDELETED(client)) - continue - if(length(client?.applied_challenges)) - var/mob/living/client_mob = client?.mob - if(!istype(client_mob) || QDELING(client_mob) || client_mob?.stat == DEAD) + return + if(client?.mob?.mind?.assigned_role) + add_jobxp(client, added_xp, client?.mob?.mind?.assigned_role?.title) + if(QDELETED(client)) + return + var/list/applied_challenges = details?.applied_challenges + if(LAZYLEN(applied_challenges)) + var/mob/living/client_mob = client?.mob + if(!istype(client_mob) || QDELING(client_mob) || client_mob?.stat == DEAD) + return + var/total_payout = 0 + for(var/datum/challenge/listed_challenge as anything in applied_challenges) + if(listed_challenge.failed) continue - var/total_payout = 0 - for(var/datum/challenge/listed_challenge as anything in client?.applied_challenges) - if(listed_challenge.failed) - continue - total_payout += listed_challenge.challenge_payout - if(total_payout) - client?.prefs?.adjust_metacoins(client?.ckey, total_payout, "Challenge rewards.") + total_payout += listed_challenge.challenge_payout + if(total_payout) + client?.prefs?.adjust_metacoins(client?.ckey, total_payout, "Challenge rewards.") diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index 758886a8b788..d5bee6641c3d 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -300,11 +300,10 @@ /atom/movable/screen/lobby/button/intents/Click(location, control, params) . = ..() - if(!hud.mymob.client.challenge_menu) - var/datum/challenge_selector/new_tgui = new(hud.mymob) - new_tgui.ui_interact(hud.mymob) - else - hud.mymob.client.challenge_menu.ui_interact(hud.mymob) + var/datum/player_details/details = get_player_details(hud.mymob) + details.challenge_menu ||= new(details) + details.challenge_menu.ui_interact(hud.mymob) + /atom/movable/screen/lobby/button/discord icon = 'icons/hud/lobby/bottom_buttons.dmi' icon_state = "discord" diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 8d46ec714c30..542c4842f379 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -531,19 +531,20 @@ SUBSYSTEM_DEF(ticker) qdel(player) ADD_TRAIT(living, TRAIT_NO_TRANSFORM, SS_TICKER_TRAIT) if(living.client) - var/atom/movable/screen/splash/S = new(null, living.client, TRUE) - S.Fade(TRUE) - living.client.init_verbs() + var/atom/movable/screen/splash/splash = new(null, living.client, TRUE) + splash.Fade(TRUE) + living.client?.init_verbs() livings += living - if(living.client && length(living.client?.active_challenges)) - SSchallenges.apply_challenges(living.client) - for(var/processing_reward_bitflags in bitflags_to_reward)//you really should use department bitflags if possible - if(living.mind.assigned_role.departments_bitflags & processing_reward_bitflags) - living.client.reward_this_person += 150 - for(var/processing_reward_jobs in jobs_to_reward)//just in case you really only want to reward a specific job - if(living.job == processing_reward_jobs) - living.client.reward_this_person += 150 - if(livings.len) + var/datum/player_details/details = get_player_details(living) + if(details) + SSchallenges.apply_challenges(details) + for(var/processing_reward_bitflags in bitflags_to_reward)//you really should use department bitflags if possible + if(living.mind.assigned_role.departments_bitflags & processing_reward_bitflags) + details.roundend_monkecoin_bonus += 150 + for(var/processing_reward_jobs in jobs_to_reward)//just in case you really only want to reward a specific job + if(living.job == processing_reward_jobs) + details.roundend_monkecoin_bonus += 150 + if(length(livings)) addtimer(CALLBACK(src, PROC_REF(release_characters), livings), 3 SECONDS, TIMER_CLIENT_TIME) /datum/controller/subsystem/ticker/proc/release_characters(list/livings) diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 4b59a2f8e738..7d726960b5be 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -275,9 +275,6 @@ /// Does this client have typing indicators enabled? var/typing_indicators = FALSE - /// used for rewarding players monkecoins at round end - var/reward_this_person = 0 - /// Does this client's mob need to rebuild its plane masters after login? /// This is currently only used so a client can switch between 515 and 516 without breaking their rendering. var/rebuild_plane_masters = FALSE diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm index 658d6f578887..8187dc723e3c 100644 --- a/code/modules/client/player_details.dm +++ b/code/modules/client/player_details.dm @@ -27,6 +27,12 @@ GLOBAL_LIST_EMPTY_TYPED(player_details, /datum/player_details) src.ckey = ckey(player_key) achievements = new(src.ckey) +/datum/player_details/Destroy(force) + if(!force) + stack_trace("Something is trying to delete player details for [ckey]") + return QDEL_HINT_LETMELIVE + return ..() + /// Returns the full version string (i.e 515.1642) of the BYOND version and build. /datum/player_details/proc/full_byond_version() if(!byond_version) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 5f0a7ecda1cc..6fb429925942 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -197,14 +197,15 @@ SSjob.EquipRank(character, job, character.client) job.after_latejoin_spawn(character) - if(character.client && length(character.client?.active_challenges)) - SSchallenges.apply_challenges(character.client) - for(var/processing_reward_bitflags in SSticker.bitflags_to_reward)//you really should use department bitflags if possible - if(character.mind.assigned_role.departments_bitflags & processing_reward_bitflags) - character.client.reward_this_person += 425 - for(var/processing_reward_jobs in SSticker.jobs_to_reward)//just in case you really only want to reward a specific job - if(character.job == processing_reward_jobs) - character.client.reward_this_person += 425 + var/datum/player_details/details = get_player_details(character) + if(details) + SSchallenges.apply_challenges(details) + for(var/processing_reward_bitflags in SSticker.bitflags_to_reward)//you really should use department bitflags if possible + if(character.mind.assigned_role.departments_bitflags & processing_reward_bitflags) + details.roundend_monkecoin_bonus += 425 + for(var/processing_reward_jobs in SSticker.jobs_to_reward)//just in case you really only want to reward a specific job + if(character.job == processing_reward_jobs) + details.roundend_monkecoin_bonus += 425 #define IS_NOT_CAPTAIN 0 #define IS_ACTING_CAPTAIN 1 #define IS_FULL_CAPTAIN 2 diff --git a/monkestation/code/modules/client/player_details.dm b/monkestation/code/modules/client/player_details.dm index 5e24cc9bde28..98e0d4b7b4b8 100644 --- a/monkestation/code/modules/client/player_details.dm +++ b/monkestation/code/modules/client/player_details.dm @@ -3,12 +3,30 @@ var/datum/patreon_data/patreon /// Twitch subscription data for this player. var/datum/twitch_data/twitch + /// Currently active challenges. + var/list/datum/challenge/active_challenges + /// Currently applied challenges. + var/list/datum/challenge/applied_challenges + /// The challenge menu for this mob. + var/datum/challenge_selector/challenge_menu + /// Bonus monkecoins to reward this player at roundend. + var/roundend_monkecoin_bonus = 0 /datum/player_details/New(player_key) . = ..() patreon = new(src) twitch = new(src) +/// Finds the current mob this player is in control of. +/datum/player_details/proc/find_current_mob() as /mob + RETURN_TYPE(/mob) + var/client/client = GLOB.directory[ckey] + if(client?.mob) + return client.mob + for(var/mob/mob as anything in GLOB.mob_list) + if(!QDELETED(mob) && mob.ckey == ckey) + return mob + /** * Gets a player details instance from a variable, whether it be a mob, a client, or a ckey. */ diff --git a/monkestation/code/modules/coin-events/challenges/challenge/_challenge_base.dm b/monkestation/code/modules/coin-events/challenges/challenge/_challenge_base.dm index 85b2c0740fa5..d917d5b9ff09 100644 --- a/monkestation/code/modules/coin-events/challenges/challenge/_challenge_base.dm +++ b/monkestation/code/modules/coin-events/challenges/challenge/_challenge_base.dm @@ -1,39 +1,43 @@ -/client - var/list/active_challenges = list() - var/list/applied_challenges = list() - /datum/challenge ///the challenge name var/challenge_name = "God's Weakest Challenge" ///the challenge payout var/challenge_payout = 100 ///our host - var/client/host + var/datum/player_details/host ///have we failed if we are a fail action var/failed = FALSE ///the difficulty of the channgle var/difficulty = "Easy" ///do we need to process? var/processes = FALSE - ///the current mob we are in - var/mob/current_mob ///the trait we apply if any var/applied_trait -/datum/challenge/New(client/creator) +/datum/challenge/New(datum/player_details/host) . = ..() - if(!creator) - return - host = creator - current_mob = host.mob if(!host) return - RegisterSignal(host.mob, COMSIG_MIND_TRANSFERRED, PROC_REF(on_transfer)) + src.host = host + var/mob/current_mob = host.find_current_mob() + if(!current_mob) + CRASH("Couldn't find mob for [host]") + RegisterSignal(current_mob, COMSIG_MIND_TRANSFERRED, PROC_REF(on_transfer)) + +/datum/challenge/Destroy(force) + host = null + return ..() ///we just use the client to try and apply this as its easier to track mobs -/datum/challenge/proc/on_apply(client/owner) - if(applied_trait) - ADD_TRAIT(host.mob, applied_trait, CHALLENGE_TRAIT) +/datum/challenge/proc/on_apply() + SHOULD_CALL_PARENT(TRUE) + LAZYADD(host.applied_challenges, src) + if(!applied_trait) + return + var/mob/current_mob = host.find_current_mob() + if(!current_mob) + CRASH("Couldn't find mob for [host]") + ADD_TRAIT(current_mob, applied_trait, CHALLENGE_TRAIT) ///this fires every 10 seconds /datum/challenge/proc/on_process() @@ -47,9 +51,8 @@ /datum/challenge/proc/on_revive() return -/datum/challenge/proc/on_transfer(datum/source, mob/previous_body) +/datum/challenge/proc/on_transfer(datum/mind/source, mob/previous_body) SIGNAL_HANDLER if(applied_trait) REMOVE_TRAIT(previous_body, applied_trait, CHALLENGE_TRAIT) - var/datum/mind/mind = source - ADD_TRAIT(mind.current, applied_trait, CHALLENGE_TRAIT) + ADD_TRAIT(source.current, applied_trait, CHALLENGE_TRAIT) diff --git a/monkestation/code/modules/coin-events/challenges/challenge/paranoia.dm b/monkestation/code/modules/coin-events/challenges/challenge/paranoia.dm index 2f69aa50f53d..0498e57cbde4 100644 --- a/monkestation/code/modules/coin-events/challenges/challenge/paranoia.dm +++ b/monkestation/code/modules/coin-events/challenges/challenge/paranoia.dm @@ -6,13 +6,14 @@ icon = FA_ICON_OPTIN_MONSTER /datum/quirk/extra_sensory_paranoia/add() - var/datum/brain_trauma/magic/stalker/T = new() - var/mob/living/carbon/human/H = quirk_holder - H.gain_trauma(T, TRAUMA_RESILIENCE_ABSOLUTE) + var/mob/living/carbon/human/human_holder = quirk_holder + if(ishuman(human_holder)) + human_holder.gain_trauma(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) /datum/quirk/extra_sensory_paranoia/remove() - var/mob/living/carbon/human/H = quirk_holder - H.cure_trauma_type(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) + var/mob/living/carbon/human/human_holder = quirk_holder + if(ishuman(human_holder)) + human_holder.cure_trauma_type(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) /datum/challenge/paranoia challenge_name = "Paranoia" @@ -21,36 +22,29 @@ applied_trait = TRAIT_PARANOIA var/added = FALSE - -/datum/challenge/paranoia/on_apply(client/owner) +/datum/challenge/paranoia/on_apply() . = ..() - var/mob/living/carbon/human/H = host.mob - if(!ishuman(H)) + var/mob/living/carbon/human/current_human = host.find_current_mob() + if(!ishuman(current_human)) return - var/datum/brain_trauma/magic/stalker/T = new() - H.gain_trauma(T, TRAUMA_RESILIENCE_ABSOLUTE) + current_human.gain_trauma(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) added = TRUE /datum/challenge/paranoia/on_process() if(added) return - - var/mob/living/carbon/human/H = host.mob - if(!ishuman(H)) + var/mob/living/carbon/human/current_human = host.find_current_mob() + if(!ishuman(current_human)) return - var/datum/brain_trauma/magic/stalker/T = new() - H.gain_trauma(T, TRAUMA_RESILIENCE_ABSOLUTE) + current_human.gain_trauma(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) added = TRUE -/datum/challenge/paranoia/on_transfer(datum/source, mob/previous_body) +/datum/challenge/paranoia/on_transfer(datum/mind/source, mob/previous_body) . = ..() - var/mob/living/carbon/human/H = previous_body - H.cure_trauma_type(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) + var/mob/living/carbon/human/previous_human = previous_body + if(ishuman(previous_human)) + previous_human.cure_trauma_type(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) - var/datum/mind/mind = source - var/datum/brain_trauma/magic/stalker/T = new() - if(isliving(mind.current)) - var/mob/living/carbon/human/current_human = mind.current - if(!ishuman(current_human)) - return - current_human.gain_trauma(T, TRAUMA_RESILIENCE_ABSOLUTE) + var/mob/living/carbon/human/current_human = source.current + if(ishuman(current_human)) + current_human.gain_trauma(/datum/brain_trauma/magic/stalker, TRAUMA_RESILIENCE_ABSOLUTE) diff --git a/monkestation/code/modules/coin-events/challenges/challenge_controller.dm b/monkestation/code/modules/coin-events/challenges/challenge_controller.dm index 54f489bb1b78..bb9337208cfb 100644 --- a/monkestation/code/modules/coin-events/challenges/challenge_controller.dm +++ b/monkestation/code/modules/coin-events/challenges/challenge_controller.dm @@ -17,12 +17,15 @@ SUBSYSTEM_DEF(challenges) for(var/datum/challenge/listed as anything in processing_challenges) listed.on_process() -/datum/controller/subsystem/challenges/proc/apply_challenges(client/owner) +/datum/controller/subsystem/challenges/proc/apply_challenges(datum/player_details/owner) + owner = get_player_details(owner) + if(!owner) + CRASH("Attempted to apply challenges to invalid owner") for(var/datum/challenge/listed as anything in owner.active_challenges) var/datum/challenge/new_challenge = new listed(owner) if(new_challenge.processes) processing_challenges += processing_challenges new_challenge.on_apply(owner) - owner.applied_challenges += new_challenge + LAZYADD(owner.applied_challenges, new_challenge) diff --git a/monkestation/code/modules/coin-events/challenges/challenge_selector.dm b/monkestation/code/modules/coin-events/challenges/challenge_selector.dm index 7564bc2b4571..59d4f40c2449 100644 --- a/monkestation/code/modules/coin-events/challenges/challenge_selector.dm +++ b/monkestation/code/modules/coin-events/challenges/challenge_selector.dm @@ -1,76 +1,73 @@ -/client - var/datum/challenge_selector/challenge_menu - /datum/challenge_selector /// The client of the person using the UI - var/client/owner + var/datum/player_details/owner /datum/challenge_selector/New(user) - owner = CLIENT_FROM_VAR(user) + owner = get_player_details(user) owner.challenge_menu = src /datum/challenge_selector/Destroy(force) + if(owner?.challenge_menu == src) + owner.challenge_menu = null owner = null return ..() /datum/challenge_selector/ui_state(mob/user) return GLOB.always_state +/datum/challenge_selector/ui_status(mob/user, datum/ui_state/state) + if(isliving(user) || isobserver(user)) + return UI_CLOSE + return ..() + /datum/challenge_selector/ui_interact(mob/user, datum/tgui/ui) . = ..() ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "ChallengeSelector", "Select Challenges") + ui.set_autoupdate(FALSE) ui.open() -/datum/challenge_selector/ui_data(mob/user) - var/list/data = list() +/datum/challenge_selector/ui_static_data(mob/user) var/list/buyables = list() - for(var/datum/challenge/listed as anything in subtypesof(/datum/challenge)) - var/datum/challenge/created = new listed + for(var/datum/challenge/challenge as anything in subtypesof(/datum/challenge)) buyables += list( list( - "name" = created.challenge_name, - "payout" = created.challenge_payout, - "difficulty" = created.difficulty, - "path" = created.type + "name" = challenge::challenge_name, + "payout" = challenge::challenge_payout, + "difficulty" = challenge::difficulty, + "path" = challenge::type ) ) - var/list/paths = list() - for(var/listed as anything in owner.active_challenges) - if(isnull(listed)) - owner.active_challenges -= listed - continue - paths += listed + return list("challenges" = buyables) - data["challenges"] = buyables - data["selected_challenges"] = paths - return data +/datum/challenge_selector/ui_data(mob/user) + var/list/selected = list() + for(var/datum/challenge/challenge_path as anything in owner.active_challenges) + selected += "[challenge_path]" + return list("selected_challenges" = selected) /datum/challenge_selector/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() . = ..() if(.) return + var/mob/user = ui.user switch(action) if("select_challenge") - add_selection(params) + add_selection(user, params) return TRUE -/datum/challenge_selector/proc/add_selection(list/params) - if(isliving(usr) || isobserver(usr)) +/datum/challenge_selector/proc/add_selection(mob/user, list/params) + if(user.ckey != owner.ckey) + CRASH("User [user.ckey] tried to use challenge selector of [owner.ckey]") + if(isliving(user) || isobserver(user)) return - var/id = params["path"] - var/path = text2path(id) - if(!ispath(path, /datum/challenge)) + var/challenge_path = text2path(params["path"]) + if(!ispath(challenge_path, /datum/challenge)) return - if(length(usr.client.active_challenges)) - for(var/listed as anything in usr.client.active_challenges) - if(listed == path) - usr.client.active_challenges -= listed - return - - var/datum/challenge/challenge = text2path(id) - usr.client.active_challenges += challenge + if(challenge_path in owner.active_challenges) + LAZYREMOVE(owner.active_challenges, challenge_path) + else + LAZYADD(owner.active_challenges, challenge_path)