diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index 6db88cc37d951..e4f3733008eb5 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -41,14 +41,14 @@ //TIMER COOLDOWN MACROS -#define COMSIG_CD_STOP(cd_index) "cooldown_[cd_index]" -#define COMSIG_CD_RESET(cd_index) "cd_reset_[cd_index]" +#define COMSIG_CD_STOP(cd_name) "cooldown_[cd_name]" +#define COMSIG_CD_RESET(cd_name) "cd_reset_[cd_name]" -#define TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_cooldown), cd_source, cd_index), cd_time)) +#define TIMER_COOLDOWN_START(cd_source, cd_name, cd_time) LAZYSET(cd_source.cooldowns, cd_name, addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_cooldown), cd_source, cd_name), cd_time)) -#define TIMER_COOLDOWN_CHECK(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index) +#define TIMER_COOLDOWN_CHECK(cd_source, cd_name) LAZYACCESS(cd_source.cooldowns, cd_name) -#define TIMER_COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index) +#define TIMER_COOLDOWN_END(cd_source, cd_name) LAZYREMOVE(cd_source.cooldowns, cd_name) /* * Stoppable timer cooldowns. @@ -57,11 +57,11 @@ * A bit more expensive than the regular timers, but can be reset before they end and the time left can be checked. */ -#define S_TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_cooldown), cd_source, cd_index), cd_time, TIMER_STOPPABLE)) +#define S_TIMER_COOLDOWN_START(cd_source, cd_name, cd_time) LAZYSET(cd_source.cooldowns, cd_name, addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_cooldown), cd_source, cd_name), cd_time, TIMER_STOPPABLE)) -#define S_TIMER_COOLDOWN_RESET(cd_source, cd_index) reset_cooldown(cd_source, cd_index) +#define S_TIMER_COOLDOWN_RESET(cd_source, cd_name) reset_cooldown(cd_source, cd_name) -#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_index) (timeleft(TIMER_COOLDOWN_CHECK(cd_source, cd_index))) +#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_name) (timeleft(TIMER_COOLDOWN_CHECK(cd_source, cd_name))) /* @@ -69,17 +69,36 @@ * Better performance over timer cooldowns, lower control. Same functionality. */ -#define COOLDOWN_DECLARE(cd_index) var/##cd_index = 0 +#define COOLDOWN_DECLARE(cd_name) var/##cd_name = 0 -#define COOLDOWN_STATIC_DECLARE(cd_index) var/static/##cd_index = 0 +#define COOLDOWN_STATIC_DECLARE(cd_name) var/static/##cd_name = 0 -#define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + (cd_time)) +#define COOLDOWN_START(cd_source, cd_name, cd_time) (cd_source.cd_name = world.time + (cd_time)) //Returns true if the cooldown has run its course, false otherwise -#define COOLDOWN_FINISHED(cd_source, cd_index) (cd_source.cd_index < world.time) +#define COOLDOWN_FINISHED(cd_source, cd_name) (cd_source.cd_name < world.time) -#define COOLDOWN_RESET(cd_source, cd_index) cd_source.cd_index = 0 +#define COOLDOWN_RESET(cd_source, cd_name) cd_source.cd_name = 0 -#define COOLDOWN_TIMELEFT(cd_source, cd_index) (max(0, cd_source.cd_index - world.time)) +#define COOLDOWN_TIMELEFT(cd_source, cd_name) (max(0, cd_source.cd_name - world.time)) -#define COOLDOWN_TIMELEFT_TEXT(cd_source, cd_index) DisplayTimeText(COOLDOWN_TIMELEFT(cd_source, cd_index)) +#define COOLDOWN_TIMELEFT_TEXT(cd_source, cd_name) DisplayTimeText(COOLDOWN_TIMELEFT(cd_source, cd_name)) + + +// when a timer should track targets individually +// this is useful when an item should individually trigger cooldown time per mob +#define COOLDOWN_LIST_DECLARE(cd_name) var/list/##cd_name = list() + +#define COOLDOWN_STATIC_LIST_DECLARE(cd_name) var/static/list/##cd_name = list() + +/// IMPORTANT: "cd_target_index" should be individual because it's assoc key +#define COOLDOWN_LIST_START(cd_source, cd_name, cd_target_index, cd_time) (cd_source.cd_name[cd_target_index] = world.time + (cd_time)) + +#define COOLDOWN_LIST_FINISHED(cd_source, cd_name, cd_target_index) (cd_source.cd_name[cd_target_index] < world.time) + +#define COOLDOWN_LIST_RESET(cd_source, cd_name, cd_target_index) cd_source.cd_name[cd_target_index] = 0 + +#define COOLDOWN_LIST_TIMELEFT(cd_source, cd_name, cd_target_index) (max(0, cd_source.cd_name[cd_target_index] - world.time)) + +/// use to change existing cooldown +#define COOLDOWN_LIST_ADJUST_TIME(cd_source, cd_name, cd_target_index, cd_time) (cd_source.cd_name[cd_target_index] = cd_source.cd_name[cd_target_index] - (cd_time)) diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index d27af0811c81c..1f4651031d458 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -56,7 +56,7 @@ /obj/item/reagent_containers/food/snacks/grown/proc/add_juice() if(reagents) if(bitesize_mod) - bitesize = 1 + round(reagents.total_volume / bitesize_mod) + bitesize = max(1, round(reagents.total_volume / bitesize_mod)) return 1 return 0 diff --git a/code/modules/hydroponics/grown/cannabis.dm b/code/modules/hydroponics/grown/cannabis.dm index 3aa6700245301..002d02e1e9a23 100644 --- a/code/modules/hydroponics/grown/cannabis.dm +++ b/code/modules/hydroponics/grown/cannabis.dm @@ -125,5 +125,6 @@ desc = "You feel dizzy looking at it. What the fuck?" icon_state = "ocannabis" volume = 420 + bitesize = 1 wine_power = 90 discovery_points = 300 diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 1257fd5306beb..3ad5407fccd44 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -251,10 +251,14 @@ // Also affects plant batteries see capatative cell production datum name = "Electrical Activity" rate = 0.2 + COOLDOWN_STATIC_LIST_DECLARE(recent_victims) /datum/plant_gene/trait/cell_charge/on_slip(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/C) + if(!COOLDOWN_LIST_FINISHED(src, recent_victims, FAST_REF(C))) // if you were a victim recently, you won't get it again + return var/power = round(G.seed.potency*rate) if(prob(power)) + COOLDOWN_LIST_START(src, recent_victims, FAST_REF(C), 2 SECONDS) C.electrocute_act(power, G, 1, 1) var/turf/T = get_turf(C) if(C.ckey != G.fingerprintslast) @@ -262,10 +266,13 @@ log_combat(C, G, "slipped on and got electrocuted by", null, "with the power of 10. Last fingerprint: [G.fingerprintslast]") /datum/plant_gene/trait/cell_charge/on_squash(obj/item/reagent_containers/food/snacks/grown/G, atom/target) + if(!COOLDOWN_LIST_FINISHED(src, recent_victims, target)) // if you were a victim recently, you won't get it again + return if(iscarbon(target)) var/mob/living/carbon/C = target var/power = G.seed.potency*rate if(prob(power)) + COOLDOWN_LIST_START(src, recent_victims, FAST_REF(C), 2 SECONDS) C.electrocute_act(round(power), G, 1, 1) if(C.ckey != G.fingerprintslast) log_combat(G.thrownby, C, "hit and electrocuted", G, "at [AREACOORD(G)] with power of [power]") @@ -439,6 +446,7 @@ /datum/plant_gene/trait/stinging name = "Hypodermic Prickles" + COOLDOWN_STATIC_LIST_DECLARE(recent_victims) /datum/plant_gene/trait/stinging/on_slip(obj/item/reagent_containers/food/snacks/grown/G, atom/target) if(!isliving(target) || !G.reagents || !G.reagents.total_volume) @@ -464,11 +472,23 @@ if(!L.reagents && !L.can_inject(null, 0)) return FALSE - var/injecting_amount = max(1, G.seed.potency*0.2) // Minimum of 1, max of 20 - var/fraction = min(injecting_amount/G.reagents.total_volume, 1) + // Mechanism: It will always inject the amount as "injecting_amount" variable no matter the total size is + var/prick_efficiency = 0.02 // default (maximum: 2u) + if(locate(/datum/plant_gene/trait/squash) in G.seed.genes) + prick_efficiency = 0.01 // how can a smooth plant be deadly? (maximum: 1u) + else if(istype(G, /obj/item/seeds/nettle/death)) // as long as it has not Liquid Content + prick_efficiency = 0.06 // bonus to "death" nettle (maximum: 6u) + else if(G.force) + prick_efficiency = 0.04 // bonus to blunt plants (miaxmum: 4u) + if(!COOLDOWN_LIST_FINISHED(src, recent_victims, L)) // until 10s cooldown time from a victim is finished, the effective becomes half + prick_efficiency = round(prick_efficiency/2, 0.01) // i.e) 4u to 2u + + var/injecting_amount = round(max(1, G.seed.potency * prick_efficiency), 0.1) // mimumum 1u to maximum 5/10/15/20u + var/fraction = min(injecting_amount/G.reagents.total_volume, 1) // Let's say you have 90u + 10u. Injecting 5u will be "4.5u + 0.5u" by the fraction G.reagents.reaction(L, INJECT, fraction) G.reagents.trans_to(L, injecting_amount) to_chat(L, "You are pricked by [G]!") + COOLDOWN_LIST_START(src, recent_victims, FAST_REF(L), 10 SECONDS) // this refreshes 10s cooldown time. repeated attack will not be effective return TRUE /datum/plant_gene/trait/smoke diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index 5987fc61442c9..8191bdae974a8 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -248,6 +248,10 @@ return initial(plant.name) else return "[initial(plant.name)] (renamed as [plantname])" + +/obj/item/seeds/proc/log_rename(mob/user, obj/item, type, input) + src.investigate_log("[key_name(user)] has changed [src] ([type]) into '[input]'", INVESTIGATE_BOTANY) + // log_game() might fit, but I wanted botany logs contained in a specific log file. //--------- /// Setters procs /// @@ -405,20 +409,32 @@ var/input = stripped_input(user,"What do you want to name the plant?", default=plantname, max_length=MAX_NAME_LEN) if(QDELETED(src) || !user.canUseTopic(src, BE_CLOSE)) return + if(CHAT_FILTER_CHECK(input)) + to_chat(src, "That message contained a word prohibited in OOC chat! Consider reviewing the server rules.\n\"[input]\"") + return + log_rename(user, src, "plant name", input) name = "pack of [input] seeds" plantname = input renamedByPlayer = TRUE if(penchoice == "Plant Description") - var/input = stripped_input(user,"What do you want to change the description of the plant to?", default=plantdesc, max_length=MAX_NAME_LEN) + var/input = stripped_input(user,"What do you want to change the description of the plant to?", default=plantdesc, max_length=MAX_MESSAGE_LEN) if(QDELETED(src) || !user.canUseTopic(src, BE_CLOSE)) return + if(CHAT_FILTER_CHECK(input)) + to_chat(src, "That message contained a word prohibited in OOC chat! Consider reviewing the server rules.\n\"[input]\"") + return + log_rename(user, src, "plant desc", input) plantdesc = input if(penchoice == "Seed Description") - var/input = stripped_input(user,"What do you want to change the description of the seeds to?", default=desc, max_length=MAX_NAME_LEN) + var/input = stripped_input(user,"What do you want to change the description of the seeds to?", default=desc, max_length=MAX_MESSAGE_LEN) if(QDELETED(src) || !user.canUseTopic(src, BE_CLOSE)) return + if(CHAT_FILTER_CHECK(input)) + to_chat(src, "That message contained a word prohibited in OOC chat! Consider reviewing the server rules.\n\"[input]\"") + return + log_rename(user, src, "seed desc", input) desc = input ..() // Fallthrough to item/attackby() so that bags can pick seeds up