diff --git a/code/game/objects/structures/tangler.dm b/code/game/objects/structures/tangler.dm new file mode 100644 index 0000000000..d184742e77 --- /dev/null +++ b/code/game/objects/structures/tangler.dm @@ -0,0 +1,129 @@ + +/obj/structure/flora/roguegrass/tangler + name = "grass" + desc = "Green, soft and....I think I saw it move!" + icon = 'icons/roguetown/mob/monster/tangler.dmi' + icon_state = "tangler" + max_integrity = 5 + var/faction = list("plants") + +/obj/structure/flora/roguegrass/tangler/update_icon() + return + +/obj/structure/flora/roguegrass/tangler/real + var/aggroed = 1 + max_integrity = 40 + integrity_failure = 0.15 + attacked_sound = 'sound/misc/woodhit.ogg' + var/list/eatablez = list(/obj/item/bodypart, /obj/item/organ, /obj/item/reagent_containers/food/snacks/rogue/meat) + var/last_eat + buckle_lying = 0 + buckle_prevents_pull = 1 + +/obj/structure/flora/roguegrass/tangler/real/Initialize() + . = ..() + proximity_monitor = new(src, 1) + +/obj/structure/flora/roguegrass/tangler/real/Destroy() + QDEL_NULL(proximity_monitor) + unbuckle_all_mobs() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/structure/flora/roguegrass/tangler/real/obj_break(damage_flag) + ..() + QDEL_NULL(proximity_monitor) + unbuckle_all_mobs() + STOP_PROCESSING(SSobj, src) + update_icon() + +/obj/structure/flora/roguegrass/tangler/real/process() + if(!has_buckled_mobs()) + if(world.time > last_eat + 5) + var/list/around = view(1, src) + for(var/mob/living/M in around) + HasProximity(M) + return + for(var/obj/item/F in around) + if(is_type_in_list(F, eatablez)) + aggroed = world.time + last_eat = world.time + playsound(src,'sound/misc/eat.ogg', rand(30,60), TRUE) + qdel(F) + return + if(world.time > aggroed + 60 SECONDS) + aggroed = 0 + update_icon() + STOP_PROCESSING(SSobj, src) + return TRUE + +/obj/structure/flora/roguegrass/tangler/real/update_icon() + if(obj_broken) + name = "dry vine" + desc = "" // i think this might break, dunno + icon_state = "tangler-dead" + return + if(aggroed) + name = "twisting vine" + icon_state = "tangler" + else + name = "twisting vine" + icon_state = "tangler-hidden" + +/obj/structure/flora/roguegrass/tangler/real/user_unbuckle_mob(mob/living/M, mob/user) + if(obj_broken) + ..() + return + if(isliving(user)) + var/mob/living/L = user + var/time2mount = CLAMP((L.STASTR * 2), 1, 99) + user.changeNext_move(CLICK_CD_RAPID) + if(user != M) + if(prob(time2mount)) + ..() + else + user.visible_message("[user] tries to pull [M] free of [src]!") + return + if(prob(time2mount)) + ..() + else + user.visible_message("[user] tries to break free of [src]!") + +/obj/structure/flora/roguegrass/tangler/real/user_buckle_mob(mob/living/M, mob/living/user) //Don't want them getting put on the rack other than by spiking + return + +/obj/structure/flora/roguegrass/tangler/real/HasProximity(atom/movable/AM) + if(has_buckled_mobs()) + return + if(world.time > last_eat + 5) + var/list/around = view(src, 1) // scan for enemies + if(!(AM in around)) + return + if(istype(AM, /mob/living)) + var/mob/living/L = AM + if(!aggroed) + if(L.m_intent != MOVE_INTENT_RUN) + return + aggroed = world.time + last_eat = world.time + update_icon() + buckle_mob(L, TRUE, check_loc = FALSE) + START_PROCESSING(SSobj, src) + if(!HAS_TRAIT(L, TRAIT_NOPAIN)) + L.emote("painscream", forced = FALSE) + src.visible_message("[src] snatches [L]!") + playsound(src.loc, "plantcross", 100, FALSE, -1) + if(istype(AM, /obj/item)) + if(is_type_in_list(AM, eatablez)) + aggroed = world.time + last_eat = world.time + START_PROCESSING(SSobj, src) + update_icon() + playsound(src,'sound/misc/eat.ogg', rand(30,60), TRUE) + qdel(AM) + return + aggroed = world.time +/obj/structure/flora/roguegrass/tangler/real/attackby(obj/item/W, mob/user, params) + . = ..() + aggroed = world.time + update_icon() diff --git a/code/modules/clothing/rogueclothes/neck.dm b/code/modules/clothing/rogueclothes/neck.dm index 0f34347553..3a94f3bc3b 100644 --- a/code/modules/clothing/rogueclothes/neck.dm +++ b/code/modules/clothing/rogueclothes/neck.dm @@ -241,3 +241,10 @@ resistance_flags = FIRE_PROOF sellprice = 15 anvilrepair = /datum/skill/craft/armorsmithing + +/obj/item/clothing/neck/roguetown/dherbs + name = "druid herbs" + desc = "Crafted from natural materials" + icon_state = "herbs" + sellprice = 5 + slot_flags = ITEM_SLOT_NECK|ITEM_SLOT_HIP|ITEM_SLOT_WRISTS diff --git a/code/modules/hydroponics/grown/roguetown.dm b/code/modules/hydroponics/grown/roguetown.dm index 5aa721c9b0..a68c8cffc4 100644 --- a/code/modules/hydroponics/grown/roguetown.dm +++ b/code/modules/hydroponics/grown/roguetown.dm @@ -76,3 +76,10 @@ GLOBAL_LIST_EMPTY(berrycolors) /obj/item/seeds/berryrogue/poison product = /obj/item/reagent_containers/food/snacks/grown/berries/rogue/poison + +/obj/item/reagent_containers/food/snacks/grown/berries/rogue/blood + seed = null + icon_state = "berries" + tastes = list("berry" = 1, "red" = 1) + list_reagents = list(/datum/reagent/medicine/healthpot = 1.5, /datum/reagent/consumable/nutriment = 2) + color = "#ff0000" diff --git a/code/modules/jobs/job_types/roguetown/church/druid.dm b/code/modules/jobs/job_types/roguetown/church/druid.dm index 18a29e73f3..5bce7b3a6e 100644 --- a/code/modules/jobs/job_types/roguetown/church/druid.dm +++ b/code/modules/jobs/job_types/roguetown/church/druid.dm @@ -57,6 +57,9 @@ H.change_stat("intelligence", 1) H.change_stat("endurance", 1) H.change_stat("perception", -1) + H.mind.AddSpell(new/obj/effect/proc_holder/spell/invoked/bloodberry) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/growvines) + H.mind.AddSpell(new/obj/effect/proc_holder/spell/invoked/budlet) var/datum/devotion/C = new /datum/devotion(H, H.patron) C.grant_spells(H) diff --git a/code/modules/mob/living/simple_animal/rogue/creacher/budlet.dm b/code/modules/mob/living/simple_animal/rogue/creacher/budlet.dm new file mode 100644 index 0000000000..6435747667 --- /dev/null +++ b/code/modules/mob/living/simple_animal/rogue/creacher/budlet.dm @@ -0,0 +1,113 @@ +/mob/living/simple_animal/hostile/retaliate/rogue/budlet + icon = 'icons/roguetown/mob/monster/budlet.dmi' + name = "budlet" + icon_state = "budlet" + icon_living = "budlet" + gender = FEMALE + emote_hear = null + emote_see = null + speak_chance = 2 + turns_per_move = 2 + move_to_delay = 5 + base_intents = list(/datum/intent/unarmed/shove) + butcher_results = null + faction = list("plants") + health = 40 + maxHealth = 40 + melee_damage_lower = 5 + melee_damage_upper = 2 + vision_range = 4 + aggro_vision_range = 5 + retreat_distance = 0 + minimum_distance = 0 + milkies = FALSE + food_type = list(/obj/item/reagent_containers/food/snacks/rogue/meat, /obj/item/bodypart, /obj/item/organ) + footstep_type = FOOTSTEP_MOB_BAREFOOT + pooptype = null + STACON = 5 + STASTR = 4 + STASPD = 2 + deaggroprob = 50 + defprob = 60 + defdrain = 5 + del_on_deaggro = TRUE + del_on_death = TRUE + retreat_health = 0.3 + food = 0 + attack_sound = "plantcross" + dodgetime = 30 + aggressive = 1 +// stat_attack = UNCONSCIOUS + remains_type = null + +/mob/living/simple_animal/hostile/retaliate/rogue/budlet/Initialize() + . = ..() + gender = FEMALE + if(prob(33)) + gender = MALE + update_icon() + +/mob/living/simple_animal/hostile/retaliate/rogue/budlet/get_sound(input) + switch(input) + if("aggro") + return pick('sound/vo/mobs/plant/attack (2).ogg','sound/vo/mobs/plant/attack (3).ogg') + if("pain") + return pick('sound/vo/mobs/plant/pain (1).ogg','sound/vo/mobs/plant/pain (2).ogg','sound/vo/mobs/plant/pain (3).ogg','sound/vo/mobs/plant/pain (4).ogg') + if("death") + return pick('sound/misc/woodhit.ogg') + +/mob/living/simple_animal/hostile/retaliate/rogue/budlet/taunted(mob/user) + emote("aggro") + Retaliate() + GiveTarget(user) + return + +/mob/living/simple_animal/hostile/retaliate/rogue/budlet/Life() + ..() + if(pulledby) + Retaliate() + GiveTarget(pulledby) + + +/mob/living/simple_animal/hostile/retaliate/rogue/budlet/simple_limb_hit(zone) + if(!zone) + return "" + switch(zone) + if(BODY_ZONE_PRECISE_R_EYE) + return "head" + if(BODY_ZONE_PRECISE_L_EYE) + return "head" + if(BODY_ZONE_PRECISE_NOSE) + return "nose" + if(BODY_ZONE_PRECISE_MOUTH) + return "mouth" + if(BODY_ZONE_PRECISE_SKULL) + return "head" + if(BODY_ZONE_PRECISE_EARS) + return "head" + if(BODY_ZONE_PRECISE_NECK) + return "neck" + if(BODY_ZONE_PRECISE_L_HAND) + return "foreleg" + if(BODY_ZONE_PRECISE_R_HAND) + return "foreleg" + if(BODY_ZONE_PRECISE_L_FOOT) + return "leg" + if(BODY_ZONE_PRECISE_R_FOOT) + return "leg" + if(BODY_ZONE_PRECISE_STOMACH) + return "stomach" + if(BODY_ZONE_PRECISE_GROIN) + return "tail" + if(BODY_ZONE_HEAD) + return "head" + if(BODY_ZONE_R_LEG) + return "leg" + if(BODY_ZONE_L_LEG) + return "leg" + if(BODY_ZONE_R_ARM) + return "foreleg" + if(BODY_ZONE_L_ARM) + return "foreleg" + return ..() + diff --git a/code/modules/roguetown/roguecrafting/leather.dm b/code/modules/roguetown/roguecrafting/leather.dm index bf0accdeb1..b1fa282fd2 100644 --- a/code/modules/roguetown/roguecrafting/leather.dm +++ b/code/modules/roguetown/roguecrafting/leather.dm @@ -148,3 +148,10 @@ name = "Drum" result = /obj/item/rogue/instrument/drum reqs = list(/obj/item/natural/hide = 1,/obj/item/grown/log/tree/small = 1) + +/datum/crafting_recipe/roguetown/leather/dherbs + name = "druid herbs" + result = /obj/item/clothing/neck/roguetown/dherbs + reqs = list(/obj/item/natural/hide = 1,/obj/item/seeds/wheat = 1, /obj/item/seeds/apple = 1, + /obj/item/seeds/pipeweed = 1, /obj/item/seeds/sweetleaf = 1 ,/obj/item/seeds/berryrogue = 1, + /obj/item/natural/fibers = 1, /obj/item/reagent_containers/powder = 1, /obj/item/natural/thorn = 1) diff --git a/code/modules/spells/roguetown/druid.dm b/code/modules/spells/roguetown/druid.dm new file mode 100644 index 0000000000..a2edd2e5be --- /dev/null +++ b/code/modules/spells/roguetown/druid.dm @@ -0,0 +1,68 @@ + +/obj/effect/proc_holder/spell/invoked/growvines + name = "Grow vines" + overlay_state = "tangling" + releasedrain = 30 + chargedrain = 0 + chargetime = 0 + range = 15 + warnie = "spellwarning" + movement_interrupt = FALSE + chargedloop = null + req_items = list(/obj/item/clothing/neck/roguetown/dherbs) + sound = 'sound/magic/webspin.ogg' + associated_skill = /datum/skill/magic/druidic + antimagic_allowed = TRUE + charge_max = 60 SECONDS + +/obj/effect/proc_holder/spell/invoked/growvines/cast(list/targets, mob/living/user) + . = ..() + user.blood_volume -= BLOOD_VOLUME_SURVIVE/3 + var/turf/T = get_turf(targets[1]) + user.visible_message("[user] points at [T]!","You feel light-headed!") + if(!isclosedturf(T) && !locate(/turf/open/transparent/openspace) in T) + new /obj/structure/flora/roguegrass/tangler/real(T) + +/obj/effect/proc_holder/spell/invoked/budlet + name = "Summon Buds" + range = 5 + overlay_state = "dendor" + releasedrain = 30 + charge_max = 120 SECONDS + req_items = list(/obj/item/clothing/neck/roguetown/dherbs) + cast_without_targets = TRUE + sound = 'sound/magic/webspin.ogg' + associated_skill = /datum/skill/magic/druidic + antimagic_allowed = TRUE + invocation = "By the power of Dendor, come forth!" + invocation_type = "shout" //can be none, whisper, emote and shout + +/obj/effect/proc_holder/spell/invoked/budlet/cast(list/targets, mob/living/user) + . = ..() + var/turf/T = user.loc + for(var/X in GLOB.cardinals) + user.faction |= "plants" + user.blood_volume -= BLOOD_VOLUME_SURVIVE/2 + var/turf/TT = get_step(T, X) + if(!isclosedturf(TT) && !locate(/mob/living/simple_animal/hostile/retaliate/rogue/budlet) in TT) + new /mob/living/simple_animal/hostile/retaliate/rogue/budlet(TT) + return TRUE + +/obj/effect/proc_holder/spell/invoked/bloodberry + name = "Blood berry" + range = 2 + overlay_state = "bberry" + releasedrain = 15 + charge_max = 30 SECONDS + req_items = list(/obj/item/clothing/neck/roguetown/dherbs) + cast_without_targets = TRUE + sound = 'sound/magic/webspin.ogg' + associated_skill = /datum/skill/magic/druidic + antimagic_allowed = TRUE + invocation = "I clench my fist" + invocation_type = "emote" //can be none, whisper, emote and shout + +/obj/effect/proc_holder/spell/invoked/bloodberry/cast(list/targets, mob/living/user) + . = ..() + var/obj/item/reagent_containers/food/snacks/grown/berries/rogue/blood/I = new + user.put_in_hands(I) diff --git a/icons/mob/actions/roguespells.dmi b/icons/mob/actions/roguespells.dmi index 62263e41e5..97e841325e 100644 Binary files a/icons/mob/actions/roguespells.dmi and b/icons/mob/actions/roguespells.dmi differ diff --git a/icons/roguetown/clothing/neck.dmi b/icons/roguetown/clothing/neck.dmi index 944daa6fc9..6f25fd40e9 100644 Binary files a/icons/roguetown/clothing/neck.dmi and b/icons/roguetown/clothing/neck.dmi differ diff --git a/icons/roguetown/mob/monster/budlet.dmi b/icons/roguetown/mob/monster/budlet.dmi new file mode 100644 index 0000000000..348158af1b Binary files /dev/null and b/icons/roguetown/mob/monster/budlet.dmi differ diff --git a/icons/roguetown/mob/monster/tangler.dmi b/icons/roguetown/mob/monster/tangler.dmi new file mode 100644 index 0000000000..36cb528c25 Binary files /dev/null and b/icons/roguetown/mob/monster/tangler.dmi differ diff --git a/sound/magic/grow_vine.ogg b/sound/magic/grow_vine.ogg new file mode 100644 index 0000000000..a309470f17 Binary files /dev/null and b/sound/magic/grow_vine.ogg differ