diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_arcade.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_arcade.dm new file mode 100644 index 00000000000..e9e96770f28 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_arcade.dm @@ -0,0 +1,6 @@ +///Called when a mob plays a videogame +#define COMSIG_MOB_PLAYED_VIDEOGAME "mob_played_videogame" +///Called when a mob loses a videogame +#define COMSIG_MOB_LOST_VIDEOGAME "mob_lost_videogame" +///Called when a mob wins a videogame +#define COMSIG_MOB_WON_VIDEOGAME "mob_won_videogame" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 68e8f99df28..275b6fdbcdc 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -541,6 +541,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Gives you the Shifty Eyes quirk, rarely making people who examine you think you examined them back even when you didn't #define TRAIT_SHIFTY_EYES "shifty_eyes" +///Trait for the gamer quirk. +#define TRAIT_GAMER "gamer" + ///Trait for dryable items #define TRAIT_DRYABLE "trait_dryable" ///Trait for dried items diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 7d4f60143da..1afdad429da 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -172,6 +172,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BLOODSHOT_EYES" = TRAIT_BLOODSHOT_EYES, "TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES, "TRAIT_CANNOT_BE_UNBUCKLED" = TRAIT_CANNOT_BE_UNBUCKLED, + "TRAIT_GAMER" = TRAIT_GAMER, ), /obj/item/bodypart = list( "TRAIT_PARALYSIS" = TRAIT_PARALYSIS, diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index 72405540cc9..ac9b891a7d5 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -20,8 +20,8 @@ PROCESSING_SUBSYSTEM_DEF(quirks) var/static/list/quirk_blacklist = list( list("Blind","Nearsighted"), list("Jolly","Depression","Apathetic","Hypersensitive"), - list("Ageusia","Vegetarian","Deviant Tastes"), - list("Ananas Affinity","Ananas Aversion"), + list("Ageusia","Vegetarian","Deviant Tastes", "Gamer"), + list("Ananas Affinity","Ananas Aversion", "Gamer"), list("Alcohol Tolerance","Light Drinker"), list("Clown Enjoyer","Mime Fan"), list("Bad Touch", "Friendly"), diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index b6f2bb7a263..cf5fa3a3bf6 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -361,3 +361,12 @@ description = "I hate being sprayed with water!\n" mood_change = -1 timeout = 30 SECONDS + +/datum/mood_event/gamer_withdrawal + description = span_warning("I wish I was gaming right now...\n") + mood_change = -5 + +/datum/mood_event/gamer_lost + description = span_boldwarning("If I'm not good at video games, can I truly call myself a gamer?\n") + mood_change = -10 + timeout = 10 MINUTES diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 1395e237b35..6724e19a1de 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -269,3 +269,14 @@ return description = span_nicegreen("Ahaha! [spilled_mob] spilled [spilled_mob.p_their()] [soda_can ? soda_can.name : "soda"] all over [spilled_mob.p_them()]self! Classic.\n") + +/datum/mood_event/gaming + description = span_nicegreen("I'm enjoying a nice gaming session!\n") + mood_change = 2 + timeout = 30 SECONDS + +/datum/mood_event/gamer_won + description = span_nicegreen("I love winning videogames!\n") + mood_change = 10 + timeout = 5 MINUTES + diff --git a/code/datums/quirks/neutral.dm b/code/datums/quirks/neutral.dm index db97e3c68b9..9f97063f93a 100644 --- a/code/datums/quirks/neutral.dm +++ b/code/datums/quirks/neutral.dm @@ -362,3 +362,99 @@ /datum/quirk/item_quirk/colorist/add_unique() give_item_to_holder(/obj/item/dyespray, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +#define GAMING_WITHDRAWAL_TIME (15 MINUTES) +/datum/quirk/gamer + name = "Gamer" + desc = "You are a hardcore gamer, and you have a need to game. You love winning and hate losing. You only like gamer food." + icon = "gamepad" + value = 0 + gain_text = span_notice("You feel the sudden urge to game.") + lose_text = span_notice("You've lost all interest in gaming.") + medical_record_text = "Patient has a severe video game addiction." + mob_trait = TRAIT_GAMER + /// Timer for gaming withdrawal to kick in + var/gaming_withdrawal_timer = TIMER_ID_NULL + +/datum/quirk/gamer/add() + // Gamer diet + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/species/species = human_holder.dna.species + species.liked_food = JUNKFOOD + RegisterSignal(human_holder, COMSIG_SPECIES_GAIN, .proc/on_species_gain) + RegisterSignal(human_holder, COMSIG_MOB_WON_VIDEOGAME, .proc/won_game) + RegisterSignal(human_holder, COMSIG_MOB_LOST_VIDEOGAME, .proc/lost_game) + RegisterSignal(human_holder, COMSIG_MOB_PLAYED_VIDEOGAME, .proc/gamed) + +/datum/quirk/gamer/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) + SIGNAL_HANDLER + new_species.liked_food = JUNKFOOD + +/datum/quirk/gamer/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/species/species = human_holder.dna.species + species.liked_food = initial(species.liked_food) + UnregisterSignal(human_holder, COMSIG_SPECIES_GAIN) + UnregisterSignal(human_holder, COMSIG_MOB_WON_VIDEOGAME) + UnregisterSignal(human_holder, COMSIG_MOB_LOST_VIDEOGAME) + UnregisterSignal(human_holder, COMSIG_MOB_PLAYED_VIDEOGAME) + +/datum/quirk/gamer/add_unique() + // The gamer starts off quelled + gaming_withdrawal_timer = addtimer(CALLBACK(src, .proc/enter_withdrawal), GAMING_WITHDRAWAL_TIME, TIMER_STOPPABLE) + +/** + * Gamer won a game + * + * Executed on the COMSIG_MOB_WON_VIDEOGAME signal + * This signal should be called whenever a player has won a video game. + * (E.g. Orion Trail) + */ +/datum/quirk/gamer/proc/won_game() + SIGNAL_HANDLER + // Epic gamer victory + var/mob/living/carbon/human/human_holder = quirk_holder + SEND_SIGNAL(human_holder, COMSIG_ADD_MOOD_EVENT, "gamer_won", /datum/mood_event/gamer_won) + +/** + * Gamer lost a game + * + * Executed on the COMSIG_MOB_LOST_VIDEOGAME signal + * This signal should be called whenever a player has lost a video game. + * (E.g. Orion Trail) + */ +/datum/quirk/gamer/proc/lost_game() + SIGNAL_HANDLER + // Executed when a gamer has lost + var/mob/living/carbon/human/human_holder = quirk_holder + SEND_SIGNAL(human_holder, COMSIG_ADD_MOOD_EVENT, "gamer_lost", /datum/mood_event/gamer_lost) + // Executed asynchronously due to say() + INVOKE_ASYNC(src, .proc/gamer_moment) +/** + * Gamer is playing a game + * + * Executed on the COMSIG_MOB_PLAYED_VIDEOGAME signal + * This signal should be called whenever a player interacts with a video game. + */ +/datum/quirk/gamer/proc/gamed() + SIGNAL_HANDLER + + var/mob/living/carbon/human/human_holder = quirk_holder + // Remove withdrawal malus + SEND_SIGNAL(human_holder, COMSIG_CLEAR_MOOD_EVENT, "gamer_withdrawal") + // Reset withdrawal timer + if (gaming_withdrawal_timer) + deltimer(gaming_withdrawal_timer) + gaming_withdrawal_timer = addtimer(CALLBACK(src, .proc/enter_withdrawal), GAMING_WITHDRAWAL_TIME, TIMER_STOPPABLE) + + +/datum/quirk/gamer/proc/gamer_moment() + // It was a heated gamer moment... + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.say(";[pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER")]!!", forced = name) + +/datum/quirk/gamer/proc/enter_withdrawal() + var/mob/living/carbon/human/human_holder = quirk_holder + SEND_SIGNAL(human_holder, COMSIG_ADD_MOOD_EVENT, "gamer_withdrawal", /datum/mood_event/gamer_withdrawal) + +#undef GAMING_WITHDRAWAL_TIME diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm index f2bae1674a5..97c5ce27887 100644 --- a/code/game/machinery/computer/arcade/arcade.dm +++ b/code/game/machinery/computer/arcade/arcade.dm @@ -285,6 +285,8 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( if(usr?.mind) gamerSkill = usr.mind.get_skill_level(/datum/skill/gaming) + usr.played_game() + if (!blocked && !gameover) var/attackamt = rand(5,7) + rand(0, gamerSkill) @@ -559,6 +561,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( prizevend(user) xp_gained += 50 SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("win", (obj_flags & EMAGGED ? "emagged":"normal"))) + user.won_game() else if(player_hp <= 0) if(timer_id) @@ -573,6 +576,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( if (istype(living_user)) living_user.gib() SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & EMAGGED ? "emagged":"normal"))) + user.lost_game() if(gameover) user?.mind?.adjust_experience(/datum/skill/gaming, xp_gained+1)//always gain at least 1 point of XP @@ -648,6 +652,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( if(!c_user.get_bodypart(BODY_ZONE_L_ARM) && !c_user.get_bodypart(BODY_ZONE_R_ARM)) return to_chat(c_user, span_warning("You move your hand towards the machine, and begin to hesitate as a bloodied guillotine emerges from inside of it...")) + usr.played_game() if(do_after(c_user, 50, target = src)) to_chat(c_user, span_userdanger("The guillotine drops on your arm, and the machine sucks it in!")) playsound(loc, 'sound/weapons/slice.ogg', 25, TRUE, -1) @@ -658,10 +663,12 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( chopchop.dismember() qdel(chopchop) user.mind?.adjust_experience(/datum/skill/gaming, 100) + user.won_game() playsound(loc, 'sound/arcade/win.ogg', 50, TRUE) prizevend(user, rand(3,5)) else to_chat(c_user, span_notice("You (wisely) decide against putting your hand in the machine.")) + user.lost_game() /obj/machinery/computer/arcade/amputation/festive //dispenses wrapped gifts instead of arcade prizes, also known as the ancap christmas tree name = "Mediborg's Festive Amputation Adventure" diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm index dd3f975eae0..65dc6022ab5 100644 --- a/code/game/machinery/computer/arcade/orion.dm +++ b/code/game/machinery/computer/arcade/orion.dm @@ -211,6 +211,8 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) var/xp_gained = 0 + gamer.played_game() + if(event) event.response(src, action) if(!settlers.len || food <= 0 || fuel <= 0) @@ -345,6 +347,8 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) event.emag_effect(src, gamer) /obj/machinery/computer/arcade/orion_trail/proc/set_game_over(user, given_reason) + usr.lost_game() + gameStatus = ORION_STATUS_GAMEOVER event = null reason = given_reason || death_reason(user) @@ -471,6 +475,8 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events()) settlermoods[settlers[i]] = min(settlermoods[settlers[i]], 3) /obj/machinery/computer/arcade/orion_trail/proc/win(mob/user) + usr.won_game() + gameStatus = ORION_STATUS_START say("Congratulations, you made it to Orion!") if(obj_flags & EMAGGED) diff --git a/code/modules/mob/mob_arcade.dm b/code/modules/mob/mob_arcade.dm new file mode 100644 index 00000000000..93092bd09a7 --- /dev/null +++ b/code/modules/mob/mob_arcade.dm @@ -0,0 +1,24 @@ +/** + * This proc sends the COMSIG_MOB_WON_VIDEOGAME signal + * + * This should be called by games when the gamer reaches a winning state + */ +/mob/proc/won_game() + SEND_SIGNAL(src, COMSIG_MOB_WON_VIDEOGAME) + +/** + * This proc sends the COMSIG_MOB_LOST_VIDEOGAME signal + * + * This should be called by games when the gamer reaches a losing state + */ +/mob/proc/lost_game() + SEND_SIGNAL(src, COMSIG_MOB_LOST_VIDEOGAME) + +/** + * This proc sends the COMSIG_MOB_PLAYED_VIDEOGAME signal + * + * This should be called by games whenever the gamer interacts with the device + */ +/mob/proc/played_game() + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "gaming", /datum/mood_event/gaming) + SEND_SIGNAL(src, COMSIG_MOB_PLAYED_VIDEOGAME) diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm index 10fee422e0d..cde6b59e0a1 100644 --- a/code/modules/modular_computers/file_system/programs/arcade.dm +++ b/code/modules/modular_computers/file_system/programs/arcade.dm @@ -35,6 +35,7 @@ computer.update_appearance() ticket_count += 1 user?.mind?.adjust_experience(/datum/skill/gaming, 50) + usr.won_game() sleep(10) else if(player_hp <= 0 || player_mp <= 0) heads_up = "You have been defeated... how will the station survive?" @@ -44,6 +45,7 @@ if(istype(computer)) computer.update_appearance() user?.mind?.adjust_experience(/datum/skill/gaming, 10) + usr.lost_game() sleep(10) /datum/computer_file/program/arcade/proc/enemy_check(mob/user) @@ -100,6 +102,8 @@ if(computer) printer = computer.all_components[MC_PRINT] + usr.played_game() + var/gamerSkillLevel = 0 var/gamerSkill = 0 if(usr?.mind) diff --git a/tgstation.dme b/tgstation.dme index d492f234d80..de3ec01751d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -246,6 +246,7 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_main.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_silicon.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_simple.dm" +#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_arcade.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm" @@ -2942,6 +2943,7 @@ #include "code\modules\mob\login.dm" #include "code\modules\mob\logout.dm" #include "code\modules\mob\mob.dm" +#include "code\modules\mob\mob_arcade.dm" #include "code\modules\mob\mob_defines.dm" #include "code\modules\mob\mob_helpers.dm" #include "code\modules\mob\mob_lists.dm"