diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 45337d70c28..ee5d6673556 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1631,3 +1631,20 @@ GLOBAL_LIST_EMPTY(intento_players) #undef TIME_TO_BEGIN #undef TIME_PER_DEMO_STEP #undef TIME_TO_RESET_ICON + +/* + * Runic Scepter + */ +/obj/item/toy/foam_runic_scepter + name = "foam scepter" + desc = "A foam replica of the scepters Wizards us on Vendormancy Soccer." + icon_state = "vendor_staff" + inhand_icon_state = "vendor_staff" + lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' + icon = 'icons/obj/weapons/guns/magic.dmi' + slot_flags = ITEM_SLOT_BACK + attack_verb_continuous = list("smacks", "clubs", "wacks", "vendors") + attack_verb_simple = list("smack", "club", "wacks", "vendor") + w_class = WEIGHT_CLASS_SMALL + resistance_flags = FLAMMABLE diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index 16373e02ac7..44c0a564194 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -390,3 +390,126 @@ whistle.whistler = null whistle = null return ..() + +/////////////////////////////////////////Scepter of Vendormancy/////////////////// +#define RUNIC_SCEPTER_MAX_CHARGES 3 +#define RUNIC_SCEPTER_MAX_RANGE 7 + +/obj/item/runic_vendor_scepter + name = "scepter of runic vendormancy" + desc = "This scepter allows you to conjure, force push and detonate Runic Vendors. It can hold up to 3 charges that can be recovered with a simple magical channeling. A modern spin on the old Geomancy spells." + icon_state = "vendor_staff" + inhand_icon_state = "vendor_staff" + lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' + icon = 'icons/obj/weapons/guns/magic.dmi' + slot_flags = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_NORMAL + force = 10 + damtype = BRUTE + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF + attack_verb_continuous = list("smacks", "clubs", "wacks") + attack_verb_simple = list("smack", "club", "wacks") + + /// Range cap on where you can summon vendors. + var/max_summon_range = RUNIC_SCEPTER_MAX_RANGE + /// Channeling time to summon a vendor. + var/summoning_time = 1 SECONDS + /// Checks if the scepter is channeling a vendor already. + var/scepter_is_busy_summoning = FALSE + /// Checks if the scepter is busy channeling recharges + var/scepter_is_busy_recharging = FALSE + ///Number of summoning charges left. + var/summon_vendor_charges = RUNIC_SCEPTER_MAX_CHARGES + +/obj/item/runic_vendor_scepter/Initialize(mapload) + . = ..() + + RegisterSignal(src, COMSIG_ITEM_MAGICALLY_CHARGED, PROC_REF(on_magic_charge)) + var/static/list/loc_connections = list( + COMSIG_ITEM_MAGICALLY_CHARGED = PROC_REF(on_magic_charge), + ) + +/obj/item/runic_vendor_scepter/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(scepter_is_busy_recharging) + user.balloon_alert(user, "busy!") + return + if(!check_allowed_items(target, not_inside = TRUE)) + return + . |= AFTERATTACK_PROCESSED_ITEM + var/turf/afterattack_turf = get_turf(target) + if(istype(target, /obj/machinery/vending/runic_vendor)) + var/obj/machinery/vending/runic_vendor/runic_explosion_target = target + runic_explosion_target.runic_explosion() + return + var/obj/machinery/vending/runic_vendor/vendor_on_turf = locate() in afterattack_turf + if(vendor_on_turf) + vendor_on_turf.runic_explosion() + return + if(!summon_vendor_charges) + user.balloon_alert(user, "no charges!") + return + if(get_dist(afterattack_turf,src) > max_summon_range) + user.balloon_alert(user, "too far!") + return + if(get_turf(src) == afterattack_turf) + user.balloon_alert(user, "too close!") + return + if(scepter_is_busy_summoning) + user.balloon_alert(user, "already summoning!") + return + if(afterattack_turf.is_blocked_turf(TRUE)) + user.balloon_alert(user, "blocked!") + return + if(summoning_time) + scepter_is_busy_summoning = TRUE + user.balloon_alert(user, "summoning...") + if(!do_after(user, summoning_time, target = target)) + scepter_is_busy_summoning = FALSE + return + scepter_is_busy_summoning = FALSE + if(summon_vendor_charges) + playsound(src,'sound/weapons/resonator_fire.ogg',50,TRUE) + user.visible_message(span_warning("[user] summons a runic vendor!")) + new /obj/machinery/vending/runic_vendor(afterattack_turf) + summon_vendor_charges-- + user.changeNext_move(CLICK_CD_MELEE) + return + return ..() + +/obj/item/runic_vendor_scepter/attack_self(mob/user, modifiers) + . = ..() + user.balloon_alert(user, "recharging...") + scepter_is_busy_recharging = TRUE + if(!do_after(user, 5 SECONDS)) + scepter_is_busy_recharging = FALSE + return + user.balloon_alert(user, "fully charged") + scepter_is_busy_recharging = FALSE + summon_vendor_charges = RUNIC_SCEPTER_MAX_CHARGES + +/obj/item/runic_vendor_scepter/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters) + var/turf/afterattack_secondary_turf = get_turf(target) + var/obj/machinery/vending/runic_vendor/vendor_on_turf = locate() in afterattack_secondary_turf + if(istype(target, /obj/machinery/vending/runic_vendor)) + var/obj/machinery/vending/runic_vendor/vendor_being_throw = target + vendor_being_throw.throw_at(get_edge_target_turf(target, get_cardinal_dir(src, target)), 4, 20, user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + if(vendor_on_turf) + vendor_on_turf.throw_at(get_edge_target_turf(target, get_cardinal_dir(src, target)), 4, 20, user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/item/runic_vendor_scepter/proc/on_magic_charge(datum/source, datum/action/cooldown/spell/charge/spell, mob/living/caster) + SIGNAL_HANDLER + + if(!ismovable(loc)) + return + + . = COMPONENT_ITEM_CHARGED + + summon_vendor_charges = RUNIC_SCEPTER_MAX_CHARGES + return . + +#undef RUNIC_SCEPTER_MAX_CHARGES +#undef RUNIC_SCEPTER_MAX_RANGE diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm index 9b084b90a64..130b9e66264 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/assistance.dm @@ -97,3 +97,12 @@ limit = 3 category = "Assistance" refundable = TRUE + +/datum/spellbook_entry/item/vendormancer + name = "Scepter of Vendormancy" + desc = "A scepter containing the power of Runic Vendormancy.\ + It can summon up to 3 Runic Vendors that decay over time, but can be \ + throw around to squash oponents or be directly detonated. When out of \ + charges a long channel will restore the charges." + item_path = /obj/item/runic_vendor_scepter + category = "Assistance" diff --git a/code/modules/vending/runic_vendor.dm b/code/modules/vending/runic_vendor.dm new file mode 100644 index 00000000000..3edb5b27264 --- /dev/null +++ b/code/modules/vending/runic_vendor.dm @@ -0,0 +1,91 @@ +#define PULSE_DISTANCE_RANGE 2 + +/obj/machinery/vending/runic_vendor + name = "\improper Runic Vending Machine" + desc = "This vending machine was designed for warfare! A perfect bait for Nanotrasen's crew thirst for consumerism." + icon_state = "RunicVendor" + panel_type = "panel10" + product_slogans = "Come get free magic!;50% off on Mjollnirs today!; Buy a warp whistle and get another one free!" + vend_reply = "Please, stand still near the vending machine for your special package!" + resistance_flags = FIRE_PROOF + light_mask = "RunicVendor-light-mask" + /// How long the vendor stays up before it decays. + var/time_to_decay = 30 SECONDS + /// Area around the vendor that will pushback nearby mobs. + var/pulse_distance = PULSE_DISTANCE_RANGE + + +/obj/machinery/vending/runic_vendor/Initialize(mapload) + if(mapload) + log_mapping("[type] is not supposed to be mapped it, it decays after a set time") + stack_trace("Someone mapped in the meme vending machine the wizard scepter spawns, please remove it") + + addtimer(CALLBACK(src, PROC_REF(decay)), time_to_decay, TIMER_STOPPABLE) + INVOKE_ASYNC(src, PROC_REF(runic_pulse)) + + switch(pick(1,3)) + if(1) + products = list( + /obj/item/clothing/head/wizard = 1, + /obj/item/clothing/suit/wizrobe = 1, + /obj/item/clothing/shoes/sandal/magic = 1, + /obj/item/toy/foam_runic_scepter = 1, + ) + if(2) + products = list( + /obj/item/clothing/head/wizard/red = 1, + /obj/item/clothing/suit/wizrobe/red = 1, + /obj/item/clothing/shoes/sandal/magic = 1, + /obj/item/toy/foam_runic_scepter = 1, + ) + if(3) + products = list( + /obj/item/clothing/head/wizard/yellow = 1, + /obj/item/clothing/suit/wizrobe/yellow = 1, + /obj/item/clothing/shoes/sandal/magic = 1, + /obj/item/toy/foam_runic_scepter = 1, + ) + + return ..() + +/obj/machinery/vending/runic_vendor/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + if(held_item) + if(istype(held_item, /obj/item/runic_vendor_scepter)) + context[SCREENTIP_CONTEXT_LMB] = "Detonate" + context[SCREENTIP_CONTEXT_RMB] = "Force push" + + return CONTEXTUAL_SCREENTIP_SET + + return . + + +/obj/machinery/vending/runic_vendor/Destroy() + visible_message(span_warning("[src] flickers and disappears!")) + playsound(src,'sound/weapons/resonator_blast.ogg',25,TRUE) + return ..() + +/obj/machinery/vending/runic_vendor/proc/runic_explosion() + explosion(src, light_impact_range = 2) + qdel(src) + +/obj/machinery/vending/runic_vendor/proc/runic_pulse() + var/pulse_locs = spiral_range_turfs(pulse_distance, get_turf(src)) + var/list/hit_things = list() + for(var/turf/pulsing_turf in pulse_locs) + for(var/mob/living/mob_to_be_pulsed_back in pulsing_turf.contents) + hit_things += mob_to_be_pulsed_back + var/atom/target = get_edge_target_turf(mob_to_be_pulsed_back, get_dir(src, get_step_away(mob_to_be_pulsed_back, src))) + to_chat(mob_to_be_pulsed_back, span_userdanger("The field repels you with tremendous force!")) + playsound(src, 'sound/effects/gravhit.ogg', 50, TRUE) + mob_to_be_pulsed_back.throw_at(target, 4, 4) + +/obj/machinery/vending/runic_vendor/screwdriver_act(mob/living/user, obj/item/I) + explosion(src, light_impact_range = 2) + qdel(src) + +/obj/machinery/vending/runic_vendor/proc/decay() + qdel(src) + +#undef PULSE_DISTANCE_RANGE diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 6a5277636d6..21767289c21 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/inhands/weapons/staves_lefthand.dmi b/icons/mob/inhands/weapons/staves_lefthand.dmi index 82c552b5038..0b7480e211c 100644 Binary files a/icons/mob/inhands/weapons/staves_lefthand.dmi and b/icons/mob/inhands/weapons/staves_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/staves_righthand.dmi b/icons/mob/inhands/weapons/staves_righthand.dmi index 769709f53da..fd85d8913a9 100644 Binary files a/icons/mob/inhands/weapons/staves_righthand.dmi and b/icons/mob/inhands/weapons/staves_righthand.dmi differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi index 0c8eab0e2fb..f74b5ae4a85 100644 Binary files a/icons/obj/vending.dmi and b/icons/obj/vending.dmi differ diff --git a/icons/obj/weapons/guns/magic.dmi b/icons/obj/weapons/guns/magic.dmi index 3a97682ef66..7dbc984c4b6 100644 Binary files a/icons/obj/weapons/guns/magic.dmi and b/icons/obj/weapons/guns/magic.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 8c386c6eeb1..8f28808910c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5201,6 +5201,7 @@ #include "code\modules\vending\nutrimax.dm" #include "code\modules\vending\plasmaresearch.dm" #include "code\modules\vending\robotics.dm" +#include "code\modules\vending\runic_vendor.dm" #include "code\modules\vending\security.dm" #include "code\modules\vending\snack.dm" #include "code\modules\vending\sovietsoda.dm"