diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm index c39531971cb..9da8ea2440a 100644 --- a/code/__DEFINES/achievements.dm +++ b/code/__DEFINES/achievements.dm @@ -106,3 +106,6 @@ // DB ID for amount of consumed maintenance pills #define MAINTENANCE_PILL_SCORE "Maintenance Pill Score" + +// DB ID for intento score +#define INTENTO_SCORE "Intento Score" diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 7512aa2fc59..23cfaba6ea4 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -126,7 +126,7 @@ var/obj/item/W = get_active_held_item() if(W == A) - W.attack_self(src) + W.attack_self(src, modifiers) update_inv_hands() return diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 93c90fd49d1..4c77a25e21d 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -63,7 +63,7 @@ return afterattack(target, user, TRUE, params) /// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown. -/obj/item/proc/attack_self(mob/user) +/obj/item/proc/attack_self(mob/user, modifiers) if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) & COMPONENT_CANCEL_ATTACK_CHAIN) return TRUE interact(user) diff --git a/code/datums/achievements/misc_scores.dm b/code/datums/achievements/misc_scores.dm index 7ffc50c0152..067cd68d7df 100644 --- a/code/datums/achievements/misc_scores.dm +++ b/code/datums/achievements/misc_scores.dm @@ -9,3 +9,9 @@ name = "Maintenance Pills Consumed" desc = "Wait why?" database_id = MAINTENANCE_PILL_SCORE + +///How high of a score on the Intento did we get? +/datum/award/score/intento_score + name = "Intento Score" + desc = "A blast from the future?" + database_id = INTENTO_SCORE diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index ac922889034..367d0ca2742 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -178,6 +178,8 @@ inhand_icon_state = "arrestballoon" random_color = FALSE +#undef BALLOON_COLORS + /* * Fake singularity */ @@ -1571,3 +1573,240 @@ animate(pixel_y = user.pixel_y - (2 * direction), time = 1, easing = SINE_EASING) animate(pixel_y = user.pixel_y + (1 * direction), time = 1, easing = SINE_EASING) user.changeNext_move(CLICK_CD_MELEE) + +#define HELP "help" +#define DISARM "disarm" +#define GRAB "grab" +#define HARM "harm" +#define ICON_SPLIT world.icon_size/2 + +// These states do not have any associated processing. +#define STATE_AWAITING_PLAYER_INPUT "awaiting_player_input" +#define STATE_OFF "off" + +// When the Intento is in one of these four states, it has an accompanying +// set of code that runs in processing() +#define STATE_STARTING "starting" +#define STATE_DEMO "demo" +#define STATE_END_OF_GAME "end_of_game" +#define STATE_RETALIATION "retaliation" + +#define TIME_TO_BEGIN 1.6 SECONDS +#define TIME_PER_DEMO_STEP 0.6 SECONDS +#define TIME_TO_RESET_ICON 0.5 SECONDS + + +/obj/item/toy/intento + name = "\improper Intento" + desc = "Fundamentally useless for all intentsive purposes." + icon = 'icons/obj/intents.dmi' + icon_state = "blank" + /// Current sequence of intents + var/list/current_sequence = list() + /// Sequence player inputs + var/list/player_sequence = list() + /// Score of the player + var/score = 0 + /// Associated list of intents to their sounds + var/static/list/sound_by_intent = list( + HELP = 'sound/items/intents/Help.ogg', + DISARM = 'sound/items/intents/Disarm.ogg', + GRAB = 'sound/items/intents/Grab.ogg', + HARM = 'sound/items/intents/Harm.ogg', + ) + + /// What state the toy is in. + var/state = STATE_OFF + /// Index used for iteration of steps for both demo and retaliation states + var/index + /// Time to delay until we start processing whatever state we're in + COOLDOWN_DECLARE(next_process) + /// Time until we reset the icon of the Intento + COOLDOWN_DECLARE(next_icon_reset) + +/obj/item/toy/intento/attack_self(mob/user, modifiers) //added params to attack_self, the alternative is registering a signal on clickon but i was advised not to + ..() + if(state == STATE_OFF) + boot() + return + + if(!modifiers) + return + + if(state != STATE_AWAITING_PLAYER_INPUT) + return + + var/input + var/icon_x = text2num(modifiers["icon-x"]) + var/icon_y = text2num(modifiers["icon-y"]) + if(icon_x > ICON_SPLIT && icon_y > ICON_SPLIT) + input = DISARM + if(icon_x < ICON_SPLIT && icon_y > ICON_SPLIT) + input = HELP + if(icon_x > ICON_SPLIT && icon_y < ICON_SPLIT) + input = GRAB + if(icon_x < ICON_SPLIT && icon_y < ICON_SPLIT) + input = HARM + + player_input(user, input) + +/obj/item/toy/intento/proc/boot() + say("Game starting!") + playsound(src, 'sound/machines/synth_yes.ogg', 50, FALSE) + + state = STATE_STARTING + COOLDOWN_START(src, next_process, TIME_TO_BEGIN) + START_PROCESSING(SSfastprocess, src) + +/obj/item/toy/intento/proc/player_input(mob/player, intent) + // All branches of this proc lead to us wanting to process + START_PROCESSING(SSfastprocess, src) + + render(intent) + + player_sequence += intent + for(var/i in 1 to player_sequence.len) + if(player_sequence[i] != current_sequence[i]) + state = STATE_END_OF_GAME + COOLDOWN_START(src, next_process, TIME_TO_RESET_ICON) + return + + if(player_sequence.len == current_sequence.len) + score++ + + state = STATE_STARTING + COOLDOWN_START(src, next_process, TIME_TO_BEGIN) + + +/obj/item/toy/intento/process() + if(next_icon_reset && next_icon_reset <= world.time) + icon_state = initial(icon_state) + COOLDOWN_RESET(src, next_icon_reset) + + if(next_process && next_process > world.time) + return + + switch(state) + if(STATE_STARTING) + process_start() + + if(STATE_DEMO) + process_demo() + + if(STATE_END_OF_GAME) + process_end(isliving(loc) ? loc : null) + + if(STATE_RETALIATION) + process_retaliation() + + if(!next_process && !next_icon_reset) + return PROCESS_KILL + +/obj/item/toy/intento/proc/process_start() + player_sequence.Cut() + + current_sequence += pick(list(HELP, DISARM, GRAB, HARM)) + + state = STATE_DEMO + next_process = world.time + index = 1 + +/obj/item/toy/intento/proc/process_demo() + if(index > length(current_sequence)) + state = STATE_AWAITING_PLAYER_INPUT + COOLDOWN_RESET(src, next_process) + return + + var/intent = current_sequence[index] + render(intent) + + index += 1 + COOLDOWN_START(src, next_process, TIME_PER_DEMO_STEP) + +/obj/item/toy/intento/proc/process_end(mob/user) + if(user) + var/award_score = score + var/award_status = user.client.get_award_status(/datum/award/score/intento_score) + if(award_score - award_status > 0) + award_score -= award_status + user.client.give_award(/datum/award/score/intento_score, user, award_score) + + say("GAME OVER. Your score was [score]!") + playsound(src, 'sound/machines/synth_no.ogg', 50, FALSE) + + if(user && loc == user && obj_flags & EMAGGED) + ADD_TRAIT(src, TRAIT_NODROP, type) + to_chat(user, "Bad mistake.") + + state = STATE_RETALIATION + next_process = world.time + index = 1 + else + cleanup() + +/obj/item/toy/intento/proc/process_retaliation() + var/mob/living/victim = loc + if(!isliving(victim) || index > length(current_sequence)) + cleanup() + return + + var/intent = current_sequence[index] + render(intent) + switch(intent) + if(HELP) + to_chat(victim, "[src] hugs you to make you feel better!") + SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug) + if(DISARM) + to_chat(victim, "You're knocked down from a shove by [src]!") + victim.Knockdown(2 SECONDS) + if(GRAB) + to_chat(victim, "[src] grabs you aggressively!") + victim.Stun(2 SECONDS) + if(HARM) + to_chat(victim, "You're punched by [src]!") + victim.apply_damage(rand(20, 30), BRUTE) + + index += 1 + COOLDOWN_START(src, next_process, TIME_PER_DEMO_STEP) + +/obj/item/toy/intento/proc/cleanup() + score = 0 + index = 1 + player_sequence.Cut() + current_sequence.Cut() + + state = STATE_OFF + COOLDOWN_RESET(src, next_process) + REMOVE_TRAIT(src, TRAIT_NODROP, type) + +/obj/item/toy/intento/proc/render(input) + icon_state = input + playsound(src, sound_by_intent[input], 50, FALSE) + + START_PROCESSING(SSfastprocess, src) + COOLDOWN_START(src, next_icon_reset, TIME_TO_RESET_ICON) + +/obj/item/toy/intento/emag_act(mob/user) + if(obj_flags & EMAGGED) + return + obj_flags |= EMAGGED + to_chat(user, "You short-circuit [src], activating the negative feedback loop.") + +/obj/item/toy/intento/Destroy() + STOP_PROCESSING(SSfastprocess, src) + return ..() + +#undef HELP +#undef DISARM +#undef GRAB +#undef HARM +#undef ICON_SPLIT +#undef STATE_AWAITING_PLAYER_INPUT +#undef STATE_OFF +#undef STATE_STARTING +#undef STATE_DEMO +#undef STATE_END_OF_GAME +#undef STATE_RETALIATION +#undef TIME_TO_BEGIN +#undef TIME_PER_DEMO_STEP +#undef TIME_TO_RESET_ICON diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm index 1d8873a15dc..4321952e15a 100644 --- a/code/modules/vending/games.dm +++ b/code/modules/vending/games.dm @@ -27,7 +27,8 @@ premium = list(/obj/item/melee/skateboard/pro = 3, /obj/item/clothing/shoes/wheelys/rollerskates= 3, /obj/item/melee/skateboard/hoverboard = 1, - /obj/item/storage/box/tail_pin = 1) + /obj/item/storage/box/tail_pin = 1, + /obj/item/toy/intento = 3) refill_canister = /obj/item/vending_refill/games default_price = PAYCHECK_ASSISTANT extra_price = PAYCHECK_HARD * 1.25 diff --git a/icons/obj/intents.dmi b/icons/obj/intents.dmi new file mode 100644 index 00000000000..f08c169e9b2 Binary files /dev/null and b/icons/obj/intents.dmi differ diff --git a/sound/items/intents/Disarm.ogg b/sound/items/intents/Disarm.ogg new file mode 100644 index 00000000000..8c7a664c41a Binary files /dev/null and b/sound/items/intents/Disarm.ogg differ diff --git a/sound/items/intents/Grab.ogg b/sound/items/intents/Grab.ogg new file mode 100644 index 00000000000..e63d5ceae20 Binary files /dev/null and b/sound/items/intents/Grab.ogg differ diff --git a/sound/items/intents/Harm.ogg b/sound/items/intents/Harm.ogg new file mode 100644 index 00000000000..f424def2e55 Binary files /dev/null and b/sound/items/intents/Harm.ogg differ diff --git a/sound/items/intents/Help.ogg b/sound/items/intents/Help.ogg new file mode 100644 index 00000000000..c7606a2ddfe Binary files /dev/null and b/sound/items/intents/Help.ogg differ