diff --git a/_maps/map_files/generic/centcomm.dmm b/_maps/map_files/generic/centcomm.dmm index 2c6f94f0e0e..03c69d2aa3d 100644 --- a/_maps/map_files/generic/centcomm.dmm +++ b/_maps/map_files/generic/centcomm.dmm @@ -1433,10 +1433,6 @@ icon_state = "cmo" }, /area/shuttle/escape) -"fz" = ( -/mob/living/carbon/human/monkey, -/turf/simulated/floor/wood, -/area/wizard_station) "fE" = ( /obj/structure/table, /obj/item/storage/box/handcuffs, @@ -3561,19 +3557,6 @@ }, /turf/simulated/floor/plasteel, /area/admin) -"mh" = ( -/obj/structure/rack, -/obj/item/clothing/under/rank/centcom/captain{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/clothing/under/rank/centcom/officer, -/obj/item/clothing/under/rank/procedure/representative{ - pixel_x = 3; - pixel_y = -3 - }, -/turf/simulated/floor/plasteel, -/area/admin) "mi" = ( /obj/structure/rack, /obj/item/clothing/suit/pirate_black{ @@ -7402,6 +7385,19 @@ }, /turf/simulated/floor/plasteel, /area/tdome/arena_source) +"Ar" = ( +/obj/structure/rack, +/obj/item/clothing/under/rank/centcom/captain{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/clothing/under/rank/centcom/officer, +/obj/item/clothing/under/rank/procedure/representative{ + pixel_x = 3; + pixel_y = -3 + }, +/turf/simulated/floor/plasteel, +/area/admin) "As" = ( /obj/structure/table/wood, /obj/item/reagent_containers/food/drinks/drinkingglass/devilskiss, @@ -12581,6 +12577,10 @@ /obj/structure/filingcabinet/security, /turf/simulated/floor/wood, /area/centcom/control) +"Sv" = ( +/mob/living/carbon/human/monkey/magic, +/turf/simulated/floor/wood, +/area/wizard_station) "Sw" = ( /obj/structure/sign/poster/official/high_class_martini, /turf/simulated/wall/indestructible/riveted, @@ -61499,7 +61499,7 @@ BX UJ GN BR -fz +Sv ed fx GN @@ -68522,7 +68522,7 @@ wk lI lY mb -mh +Ar mx mU nm diff --git a/code/datums/spells/mind_transfer.dm b/code/datums/spells/mind_transfer.dm index 6cc0e82d554..c8cd5aa2ab0 100644 --- a/code/datums/spells/mind_transfer.dm +++ b/code/datums/spells/mind_transfer.dm @@ -10,7 +10,7 @@ selection_activated_message = "You prepare to transfer your mind. Click on a target to cast the spell." selection_deactivated_message = "You decide that your current form is good enough." cooldown_min = 200 //100 deciseconds reduction per rank - var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell + var/list/protected_roles = list(SPECIAL_ROLE_WIZARD, SPECIAL_ROLE_CHANGELING, SPECIAL_ROLE_CULTIST) //which roles are immune to the spell var/paralysis_amount_caster = 40 SECONDS //how much the caster is paralysed for after the spell var/paralysis_amount_victim = 40 SECONDS //how much the victim is paralysed for after the spell action_icon_state = "mindswap" diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index c72ca00faaf..7673794a69b 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -28,9 +28,10 @@ /mob/living/carbon/human/proc/mind_checks() if(!mind) - return + return FALSE if(mind.miming) qdel(GetComponent(/datum/component/footstep)) + return TRUE /** * Sets up DNA and species. diff --git a/code/modules/mob/living/carbon/human/npcs.dm b/code/modules/mob/living/carbon/human/npcs.dm index e291abe72ce..bfb37b40a4a 100644 --- a/code/modules/mob/living/carbon/human/npcs.dm +++ b/code/modules/mob/living/carbon/human/npcs.dm @@ -21,3 +21,91 @@ real_name = name resize = 0.8 update_transform() + +/mob/living/carbon/human/monkey/magic + /// Stores the timer ID of the timer that happens in Life() to prevent multiple of the same timer happening. + var/return_timer + +/mob/living/carbon/human/monkey/magic/Initialize(mapload) + . = ..() + var/headwear = pick(/obj/item/clothing/head/wizard, /obj/item/clothing/head/wizard/red, /obj/item/clothing/head/wizard/black) + + name = pick(GLOB.wizard_first) + if(prob(20)) + name = "[name] [pick(GLOB.wizard_second)]" + if(prob(0.1)) + name = "MERLIN THE MAGNIFICENT" + headwear = /obj/item/clothing/head/wizard // he's gotta wear blue, ya know? + resize = 2 + update_transform() + real_name = name + + equip_to_slot_or_del(new headwear(src), SLOT_HUD_HEAD) + RegisterSignal(src, list(COMSIG_HUMAN_ATTACKED, COMSIG_HOSTILE_ATTACKINGTARGET), PROC_REF(ouch)) + + for(var/trait in list(TRAIT_RESISTHEAT, TRAIT_NOBREATH, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE)) + ADD_TRAIT(src, trait, MAGIC_TRAIT) + +/mob/living/carbon/human/monkey/magic/proc/ouch(mob/living/victim, mob/living/attacker) + SIGNAL_HANDLER + if(src == attacker) + return // I'm afraid you do not get a free blink + if(blink_away()) + return COMPONENT_CANCEL_ATTACK_CHAIN // prevent people from attacking the monkey + +/mob/living/carbon/human/monkey/magic/proc/blink_away() + if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED)) + return + + // A monkey, with a blink spell? Preposterous + playsound(get_turf(src), 'sound/magic/blink.ogg', 50, TRUE) + + var/list/turfs = list() + var/list/target_turfs = range(src, 5) - range(src, 1) + for(var/turf/T in target_turfs) + if(isspaceturf(T)) + continue + if(is_blocked_turf(T)) + continue + if(T.x > world.maxx - 5 || T.x < 5) + continue //putting them at the edge is dumb + if(T.y > world.maxy - 5 || T.y < 5) + continue + if(islava(T) || ischasm(T)) + continue + turfs += T + + var/turf/picked = pick(turfs) + if(!picked || !isturf(picked)) + return + + visible_message("[src] blinks away!", "Your instincts kick in, and you blink away!") + INVOKE_ASYNC(src, PROC_REF(after_the_attack), picked) + + playsound(get_turf(src), 'sound/magic/blink.ogg', 50, TRUE) + return_timer = null + return TRUE + +/mob/living/carbon/human/monkey/magic/proc/after_the_attack(turf/picked) + forceMove(picked) + + var/datum/effect_system/smoke_spread/smoke = new /datum/effect_system/smoke_spread() + smoke.set_up(1, FALSE, src) + smoke.start() + +/mob/living/carbon/human/monkey/magic/proc/i_want_to_go_home() + if(client || !istype(loc, /turf/simulated/floor/plating/asteroid)) + return + blink_away() + +/mob/living/carbon/human/monkey/magic/Life(seconds, times_fired) + . = ..() + if(!client && !return_timer && prob(10) && istype(loc, /turf/simulated/floor/plating/asteroid)) + return_timer = addtimer(CALLBACK(src, PROC_REF(i_want_to_go_home)), 5 MINUTES) + // I'm out out the wizard's den, I want to go back inside! + +/mob/living/carbon/human/monkey/magic/mind_checks() + if(!..()) + return FALSE + mind.AddSpell(new /obj/effect/proc_holder/spell/turf_teleport/blink(null)) + mind.special_role = SPECIAL_ROLE_WIZARD diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm index d65bfb4fde7..0ab9e22ebef 100644 --- a/code/modules/mob/living/carbon/human/species/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/monkey.dm @@ -48,10 +48,14 @@ /datum/species/monkey/handle_npc(mob/living/carbon/human/H) if(H.stat != CONSCIOUS) return - if(prob(33) && (H.mobility_flags & MOBILITY_MOVE) && isturf(H.loc) && !H.pulledby) //won't move if being pulled - step(H, pick(GLOB.cardinal)) if(prob(1)) H.emote(pick("scratch","jump","roll","tail")) + if(prob(33) && (H.mobility_flags & MOBILITY_MOVE) && isturf(H.loc) && !H.pulledby) //won't move if being pulled + var/dir_to_go = pick(GLOB.cardinal) + var/turf/to_go = get_step(H, dir_to_go) + if(islava(to_go) || ischasm(to_go)) + return + step(H, dir_to_go) /datum/species/monkey/get_random_name() return "[lowertext(name)] ([rand(100,999)])" diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index a429d1c2295..54685786b5f 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -326,7 +326,8 @@ FindTarget() /mob/living/simple_animal/hostile/proc/AttackingTarget() - SEND_SIGNAL(src, COMSIG_HOSTILE_ATTACKINGTARGET, target) + if(SEND_SIGNAL(target, COMSIG_HOSTILE_ATTACKINGTARGET, src) & COMPONENT_CANCEL_ATTACK_CHAIN) + return FALSE in_melee = TRUE return target.attack_animal(src)