Skip to content

Commit

Permalink
refactors monkecoin rewards + challenges to use `/datum/player_detail…
Browse files Browse the repository at this point in the history
…s` (#4536)

* refactors monkecoin rewards + challenges to use `/datum/player_details`

* Incorporate the `SSticker.transfer_characters` split, because it doesn't hurt to make that more resilient too

* slight optimization maybe

* yeah i don't trust some weird horrible timing to not break at that immediate moment
  • Loading branch information
Absolucy authored Dec 12, 2024
1 parent c6fafb3 commit 17928e0
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 143 deletions.
51 changes: 29 additions & 22 deletions code/__HELPERS/~monkestation-helpers/roundend.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
9 changes: 4 additions & 5 deletions code/_onclick/hud/new_player.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
42 changes: 24 additions & 18 deletions code/controllers/subsystem/ticker.dm
Original file line number Diff line number Diff line change
Expand Up @@ -523,27 +523,33 @@ SUBSYSTEM_DEF(ticker)

return output

/datum/controller/subsystem/ticker/proc/transfer_single_character(mob/dead/new_player/player)
var/mob/living = player.transfer_character()
if(!living)
return
qdel(player)
ADD_TRAIT(living, TRAIT_NO_TRANSFORM, SS_TICKER_TRAIT)
if(living.client)
var/atom/movable/screen/splash/splash = new(null, living.client, TRUE)
splash.Fade(TRUE)
living.client?.init_verbs()
. = living
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

/datum/controller/subsystem/ticker/proc/transfer_characters()
var/list/livings = list()
for(var/mob/dead/new_player/player as anything in GLOB.new_player_list)
var/mob/living = player.transfer_character()
if(living)
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()
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)
livings += transfer_single_character(player)
list_clear_nulls(livings)
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)
Expand Down
3 changes: 0 additions & 3 deletions code/modules/client/client_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions code/modules/client/player_details.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
17 changes: 9 additions & 8 deletions code/modules/mob/dead/new_player/new_player.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 22 additions & 3 deletions monkestation/code/modules/client/player_details.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,39 @@
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]
. = client?.mob
if(.)
return
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.
*/
/proc/get_player_details(target) as /datum/player_details
RETURN_TYPE(/datum/player_details)
if(istext(target))
if(istype(target, /datum/player_details))
return target // well, that was easy
else if(istext(target))
return GLOB.player_details[ckey(target)]
else if(ismob(target))
var/mob/mob_target = target
Expand All @@ -27,6 +48,4 @@
else if(IS_CLIENT_OR_MOCK(target))
var/datum/client_interface/client_target = target
return client_target.player_details
else if(istype(target, /datum/player_details))
return target // well, that was easy

Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Loading

0 comments on commit 17928e0

Please sign in to comment.