diff --git a/_maps/RandomRuins/SpaceRuins/originalcontent.dmm b/_maps/RandomRuins/SpaceRuins/originalcontent.dmm index 678f17b1739..ea2ca46c092 100644 --- a/_maps/RandomRuins/SpaceRuins/originalcontent.dmm +++ b/_maps/RandomRuins/SpaceRuins/originalcontent.dmm @@ -740,7 +740,7 @@ /turf/open/indestructible/paper, /area/ruin/space/has_grav/powered) "cc" = ( -/mob/living/simple_animal/hostile/boss/paper_wizard, +/mob/living/basic/paper_wizard, /turf/open/indestructible/paper, /area/ruin/space/has_grav/powered) "cd" = ( diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index 38d337ff982..8da69d6945c 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -310,6 +310,15 @@ /// Key where we store the charging apc ability #define BB_FESTIVE_APC "BB_festive_apc" +//Paperwizard AI keys +/// Key where we store the summon minions ability +#define BB_WIZARD_SUMMON_MINIONS "BB_summon_minions" +/// Key where we store the mimics ability +#define BB_WIZARD_MIMICS "BB_summon_mimics" +/// Key where we store the paper target +#define BB_FOUND_PAPER "BB_found_paper" +/// Key where we store the list of things we can write on a paper +#define BB_WRITING_LIST "BB_writing_list" /// Key where we store the tentacleing ability #define BB_GOLIATH_TENTACLES "BB_goliath_tentacles" /// Key where goliath stores a hole it wants to get into diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/write_on_paper.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/write_on_paper.dm new file mode 100644 index 00000000000..f5dba58416d --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/write_on_paper.dm @@ -0,0 +1,16 @@ +/datum/ai_behavior/write_on_paper + +/datum/ai_behavior/write_on_paper/perform(seconds_per_tick, datum/ai_controller/controller, found_paper, list_of_writings) + . = ..() + var/mob/living/wizard = controller.pawn + var/list/writing_list = controller.blackboard[list_of_writings] + var/obj/item/paper/target = controller.blackboard[found_paper] + if(length(writing_list)) + target.add_raw_text(pick(writing_list)) + target.update_appearance() + wizard.dropItemToGround(target) + finish_action(controller, TRUE, found_paper) + +/datum/ai_behavior/write_on_paper/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + controller.clear_blackboard_key(target_key) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_paper_and_write.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_paper_and_write.dm new file mode 100644 index 00000000000..900d13e0a04 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_paper_and_write.dm @@ -0,0 +1,23 @@ +/datum/ai_planning_subtree/find_paper_and_write + +/datum/ai_planning_subtree/find_paper_and_write/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/obj/item/inhand_paper = controller.blackboard[BB_SIMPLE_CARRY_ITEM] + var/mob/living/basic/wizard = controller.pawn + + if(!QDELETED(inhand_paper)) + controller.queue_behavior(/datum/ai_behavior/write_on_paper, BB_SIMPLE_CARRY_ITEM, BB_WRITING_LIST) + return SUBTREE_RETURN_FINISH_PLANNING + + var/obj/item/paper/target = controller.blackboard[BB_FOUND_PAPER] + + if(QDELETED(target)) + controller.queue_behavior(/datum/ai_behavior/find_and_set/empty_paper, BB_FOUND_PAPER, /obj/item/paper) + return + + if(get_turf(wizard) != get_turf(target)) + controller.queue_behavior(/datum/ai_behavior/travel_towards, BB_FOUND_PAPER) + return SUBTREE_RETURN_FINISH_PLANNING + + if(!(target in wizard.contents)) + controller.queue_behavior(/datum/ai_behavior/pick_up_item, BB_FOUND_PAPER, BB_SIMPLE_CARRY_ITEM) + return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/datums/elements/effect_trail.dm b/code/datums/elements/effect_trail.dm index 6e51188c0e4..d1d2fbec44a 100644 --- a/code/datums/elements/effect_trail.dm +++ b/code/datums/elements/effect_trail.dm @@ -3,14 +3,17 @@ */ /datum/element/effect_trail + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 /// The effect used for the trail generation. - var/obj/effect/chosen_effect + var/chosen_effect -/datum/element/effect_trail/Attach(datum/target) +/datum/element/effect_trail/Attach(datum/target, chosen_effect = /obj/effect/forcefield/cosmic_field) . = ..() if(!ismovable(target)) return ELEMENT_INCOMPATIBLE RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(generate_effect)) + src.chosen_effect = chosen_effect /datum/element/effect_trail/Detach(datum/target) . = ..() @@ -23,6 +26,3 @@ var/turf/open/open_turf = get_turf(target_object) if(istype(open_turf)) new chosen_effect(open_turf) - -/datum/element/effect_trail/cosmic_trail - chosen_effect = /obj/effect/forcefield/cosmic_field/fast diff --git a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm index 769b1586825..b6b7fa6f77b 100644 --- a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm @@ -182,7 +182,7 @@ if(target.mind && target.stat != DEAD) increase_combo_duration() if(combo_counter == 4) - source.AddElement(/datum/element/effect_trail/cosmic_trail) + source.AddElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast) third_target = second_target second_target = WEAKREF(target) @@ -191,7 +191,7 @@ second_target = null third_target = null if(combo_counter > 3) - source.RemoveElement(/datum/element/effect_trail/cosmic_trail) + source.RemoveElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast) combo_duration = combo_duration_amount combo_counter = 0 new /obj/effect/temp_visual/cosmic_cloud(get_turf(source)) diff --git a/code/modules/antagonists/heretic/magic/star_blast.dm b/code/modules/antagonists/heretic/magic/star_blast.dm index 236fa313daf..297e24455e2 100644 --- a/code/modules/antagonists/heretic/magic/star_blast.dm +++ b/code/modules/antagonists/heretic/magic/star_blast.dm @@ -35,7 +35,7 @@ /obj/projectile/magic/star_ball/Initialize(mapload) . = ..() - AddElement(/datum/element/effect_trail/cosmic_trail) + AddElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast) /obj/projectile/magic/star_ball/on_hit(atom/target, blocked = FALSE, pierce_hit) . = ..() diff --git a/code/modules/antagonists/heretic/magic/star_touch.dm b/code/modules/antagonists/heretic/magic/star_touch.dm index 64c5930e411..fa5a6f25287 100644 --- a/code/modules/antagonists/heretic/magic/star_touch.dm +++ b/code/modules/antagonists/heretic/magic/star_touch.dm @@ -230,7 +230,7 @@ /// What to add when the beam connects to a target /datum/status_effect/cosmic_beam/proc/on_beam_hit(mob/living/target) if(!istype(target, /mob/living/basic/star_gazer)) - target.AddElement(/datum/element/effect_trail/cosmic_trail) + target.AddElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast) return /// What to process when the beam is connected to a target @@ -242,5 +242,5 @@ /// What to remove when the beam disconnects from a target /datum/status_effect/cosmic_beam/proc/on_beam_release(mob/living/target) if(!istype(target, /mob/living/basic/star_gazer)) - target.RemoveElement(/datum/element/effect_trail/cosmic_trail) + target.RemoveElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast) return diff --git a/code/modules/mob/living/basic/heretic/star_gazer.dm b/code/modules/mob/living/basic/heretic/star_gazer.dm index e64f3e82ff2..ff4beb737d4 100644 --- a/code/modules/mob/living/basic/heretic/star_gazer.dm +++ b/code/modules/mob/living/basic/heretic/star_gazer.dm @@ -52,7 +52,7 @@ AddElement(/datum/element/footstep, FOOTSTEP_MOB_SHOE) AddElement(/datum/element/wall_smasher, ENVIRONMENT_SMASH_RWALLS) AddElement(/datum/element/simple_flying) - AddElement(/datum/element/effect_trail/cosmic_trail) + AddElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast) AddElement(/datum/element/ai_target_damagesource) AddComponent(/datum/component/regenerator, outline_colour = "#b97a5d") ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) diff --git a/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_abilities.dm b/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_abilities.dm new file mode 100644 index 00000000000..0e3aaece9c0 --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_abilities.dm @@ -0,0 +1,90 @@ +/datum/action/cooldown/spell/conjure/wizard_summon_minions + name = "Summon Minions" + button_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "art_summon" + invocation = "Rise, my creations! Jump off your pages and into this realm!" + invocation_type = INVOCATION_SHOUT + spell_requirements = NONE + cooldown_time = 15 SECONDS + summon_type = list( + /mob/living/basic/stickman, + /mob/living/basic/stickman/ranged, + /mob/living/basic/stickman/dog, + ) + summon_radius = 1 + summon_amount = 2 + ///How many minions we summoned + var/summoned_minions = 0 + ///How many minions we can have at once + var/max_minions = 6 + + +/datum/action/cooldown/spell/conjure/wizard_summon_minions/can_cast_spell(feedback = TRUE) + . = ..() + if(!.) + return FALSE + if(summoned_minions >= max_minions) + return FALSE + return TRUE + +/datum/action/cooldown/spell/conjure/wizard_summon_minions/post_summon(atom/summoned_object, atom/cast_on) + var/mob/living/chosen_minion = summoned_object + RegisterSignals(chosen_minion, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(lost_minion)) + summoned_minions++ + +/datum/action/cooldown/spell/conjure/wizard_summon_minions/proc/lost_minion(mob/source) + SIGNAL_HANDLER + + UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH)) + summoned_minions-- + +/datum/action/cooldown/spell/pointed/wizard_mimic + name = "Craft Mimicry" + button_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "mimic_summon" + invocation = "My craft defines me, you could even say it IS me!" + invocation_type = INVOCATION_SHOUT + spell_requirements = NONE + cooldown_time = 25 SECONDS + ///when the clones will die + var/clone_lifespan = 15 SECONDS + ///list of clones + var/list/copies = list() + +/datum/action/cooldown/spell/pointed/wizard_mimic/Grant(mob/grant_to) + . = ..() + if(!owner) + return + RegisterSignal(owner, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(delete_clones)) + +/datum/action/cooldown/spell/pointed/wizard_mimic/is_valid_target(atom/cast_on) + if(!isliving(cast_on)) + return FALSE + return TRUE + +/datum/action/cooldown/spell/pointed/wizard_mimic/cast(mob/living/cast_on) + . = ..() + var/list/directions = GLOB.cardinals.Copy() + for(var/i in 1 to 3) + var/mob/living/basic/paper_wizard/copy/copy = new (get_step(cast_on, pick_n_take(directions))) + invocation(copy) + RegisterSignals(copy, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(lost_minion)) + copies += copy + QDEL_IN(copy, clone_lifespan) + owner.forceMove(get_step(cast_on, pick_n_take(directions))) + +/datum/action/cooldown/spell/pointed/wizard_mimic/proc/lost_minion(mob/living/basic/paper_wizard/copy/source) + SIGNAL_HANDLER + + copies -= source + UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(lost_minion)) + +/datum/action/cooldown/spell/pointed/wizard_mimic/proc/delete_clones(mob/source) + SIGNAL_HANDLER + + QDEL_LIST(copies) + +/datum/action/cooldown/spell/pointed/wizard_mimic/Destroy() + QDEL_LIST(copies) + return ..() + diff --git a/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_wizard.dm b/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_wizard.dm new file mode 100644 index 00000000000..3b32fbb4ce7 --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/paper_wizard/paper_wizard.dm @@ -0,0 +1,196 @@ +/mob/living/basic/paper_wizard + name = "Mjor the Creative" + desc = "A wizard with a taste for the arts." + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + faction = list(FACTION_HOSTILE, FACTION_STICKMAN) + icon = 'icons/mob/simple/simple_human.dmi' + icon_state = "paperwizard" + gender = MALE + + response_help_continuous = "brushes" + response_help_simple = "brush" + response_disarm_continuous = "pushes" + response_disarm_simple = "push" + basic_mob_flags = DEL_ON_DEATH + + maxHealth = 1000 + health = 1000 + melee_damage_lower = 10 + melee_damage_upper = 20 + obj_damage = 50 + attack_sound = 'sound/hallucinations/growl1.ogg' + ai_controller = /datum/ai_controller/basic_controller/paper_wizard + ///spell to summon minions + var/datum/action/cooldown/spell/conjure/wizard_summon_minions/summon + ///spell to summon clones + var/datum/action/cooldown/spell/pointed/wizard_mimic/mimic + ///the loot we will drop + var/static/list/dropped_loot = list(/obj/effect/temp_visual/paperwiz_dying) + + +/mob/living/basic/paper_wizard/Initialize(mapload) + . = ..() + apply_dynamic_human_appearance(src, mob_spawn_path = /obj/effect/mob_spawn/corpse/human/wizard/paper) + grant_abilities() + grant_loot() + AddElement(/datum/element/effect_trail, /obj/effect/temp_visual/paper_scatter) + +/mob/living/basic/paper_wizard/proc/grant_abilities() + summon = new(src) + summon.Grant(src) + ai_controller.set_blackboard_key(BB_WIZARD_SUMMON_MINIONS, summon) + mimic = new(src) + mimic.Grant(src) + ai_controller.set_blackboard_key(BB_WIZARD_MIMICS, mimic) + +/mob/living/basic/paper_wizard/proc/grant_loot() + AddElement(/datum/element/death_drops, dropped_loot) + +/mob/living/basic/paper_wizard/Destroy() + QDEL_NULL(summon) + QDEL_NULL(mimic) + return ..() + +/datum/ai_controller/basic_controller/paper_wizard + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_WRITING_LIST = list( + "I can turn the paper into gold and ink into diamonds!", + "Your fate is written and sealed!", + "You shall suffer the wrath of a thousand paper cuts!", + ) + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/targeted_mob_ability/wizard_mimic, + /datum/ai_planning_subtree/use_mob_ability/wizard_summon_minions, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/attack_obstacle_in_path/paper_wizard, + /datum/ai_planning_subtree/find_paper_and_write, + ) + +/datum/ai_planning_subtree/attack_obstacle_in_path/paper_wizard + target_key = BB_FOUND_PAPER + attack_behaviour = /datum/ai_behavior/attack_obstructions/paper_wizard + +/datum/ai_behavior/attack_obstructions/paper_wizard + action_cooldown = 0.4 SECONDS + can_attack_turfs = TRUE + can_attack_dense_objects = TRUE + +/datum/ai_planning_subtree/targeted_mob_ability/wizard_mimic + ability_key = BB_WIZARD_MIMICS + finish_planning = FALSE + +/datum/ai_planning_subtree/use_mob_ability/wizard_summon_minions + ability_key = BB_WIZARD_SUMMON_MINIONS + finish_planning = FALSE + +/datum/ai_behavior/find_and_set/empty_paper + action_cooldown = 10 SECONDS + +/datum/ai_behavior/find_and_set/empty_paper/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/list/empty_papers = list() + + for(var/obj/item/paper/target_paper in oview(search_range, controller.pawn)) + if(target_paper.is_empty()) + empty_papers += target_paper + + if(empty_papers.len) + return pick(empty_papers) + +/mob/living/basic/paper_wizard/copy + desc = "'Tis a ruse!" + health = 1 + maxHealth = 1 + alpha = 200 + faction = list(FACTION_STICKMAN) + melee_damage_lower = 1 + melee_damage_upper = 5 + + ai_controller = /datum/ai_controller/basic_controller/wizard_copy + +/mob/living/basic/paper_wizard/copy/Initialize(mapload) + . = ..() + AddElement(/datum/element/relay_attackers) + RegisterSignal(src, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked)) + +/mob/living/basic/paper_wizard/copy/grant_abilities() + return + +/mob/living/basic/paper_wizard/copy/grant_loot() + return + +//Hit a fake? eat pain! +/mob/living/basic/paper_wizard/copy/proc/on_attacked(mob/source, mob/living/attacker, attack_flags) + SIGNAL_HANDLER + + if(!(attack_flags & (ATTACKER_STAMINA_ATTACK|ATTACKER_SHOVING))) + attacker.adjustBruteLoss(20) + to_chat(attacker, span_warning("The clone casts a spell to damage you before he dies!")) + + +/mob/living/basic/paper_wizard/copy/examine(mob/user) + . = ..() + if(isobserver(user)) + . += span_notice("It's an illusion - what is it hiding?") + else + new /obj/effect/temp_visual/small_smoke/halfsecond(get_turf(src)) + qdel(src) //I see through your ruse! + +/datum/ai_controller/basic_controller/wizard_copy + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +//fancy effects +/obj/effect/temp_visual/paper_scatter + name = "scattering paper" + desc = "Pieces of paper scattering to the wind." + layer = ABOVE_NORMAL_TURF_LAYER + plane = GAME_PLANE + icon = 'icons/effects/effects.dmi' + icon_state = "paper_scatter" + anchored = TRUE + duration = 0.5 SECONDS + randomdir = FALSE + +/obj/effect/temp_visual/paperwiz_dying + name = "craft portal" + desc = "A wormhole sucking the wizard into the void. Neat." + layer = ABOVE_NORMAL_TURF_LAYER + plane = GAME_PLANE + icon = 'icons/effects/effects.dmi' + icon_state = "paperwiz_poof" + anchored = TRUE + duration = 1.8 SECONDS + randomdir = FALSE + +/obj/effect/temp_visual/paperwiz_dying/Initialize(mapload) + . = ..() + visible_message(span_boldannounce("The wizard cries out in pain as a gate appears behind him, sucking him in!")) + playsound(get_turf(src), 'sound/magic/mandswap.ogg', 50, vary = TRUE, pressure_affected = TRUE) + playsound(get_turf(src), 'sound/hallucinations/wail.ogg', 50, vary = TRUE, pressure_affected = TRUE) + RegisterSignal(src, COMSIG_PREQDELETED, PROC_REF(on_delete)) + +/obj/effect/temp_visual/paperwiz_dying/proc/on_delete() + SIGNAL_HANDLER + + for(var/mob/nearby in range(7, src)) + shake_camera(nearby, duration = 7 SECONDS, strength = 1) + var/turf/current_turf = get_turf(src) + playsound(current_turf,'sound/magic/summon_magic.ogg', 50, vary = TRUE, vary = TRUE) + new /obj/effect/temp_visual/paper_scatter(current_turf) + new /obj/item/clothing/suit/wizrobe/paper(current_turf) + new /obj/item/clothing/head/collectable/paper(current_turf) + diff --git a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm b/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm deleted file mode 100644 index 15b439b425f..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm +++ /dev/null @@ -1,210 +0,0 @@ -//Paper Wizard Boss -/mob/living/simple_animal/hostile/boss/paper_wizard - name = "Mjor the Creative" - desc = "A wizard with a taste for the arts." - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - boss_abilities = list(/datum/action/boss/wizard_summon_minions, /datum/action/boss/wizard_mimic) - faction = list(FACTION_HOSTILE,FACTION_STICKMAN) - del_on_death = TRUE - icon = 'icons/mob/simple/simple_human.dmi' - icon_state = "paperwizard" - ranged = TRUE - environment_smash = ENVIRONMENT_SMASH_NONE - minimum_distance = 3 - retreat_distance = 3 - obj_damage = 0 - melee_damage_lower = 10 - melee_damage_upper = 20 - health = 1000 - maxHealth = 1000 - loot = list(/obj/effect/temp_visual/paperwiz_dying) - projectiletype = /obj/projectile/temp - projectilesound = 'sound/weapons/emitter.ogg' - attack_sound = 'sound/hallucinations/growl1.ogg' - footstep_type = FOOTSTEP_MOB_SHOE - var/list/copies = list() - -/mob/living/simple_animal/hostile/boss/paper_wizard/Initialize(mapload) - . = ..() - apply_dynamic_human_appearance(src, mob_spawn_path = /obj/effect/mob_spawn/corpse/human/wizard/paper) - -/mob/living/simple_animal/hostile/boss/paper_wizard/Destroy() - QDEL_LIST(copies) - return ..() - -//Summon Ability -//Lets the wizard summon his art to fight for him -/datum/action/boss/wizard_summon_minions - name = "Summon Minions" - button_icon = 'icons/mob/actions/actions_minor_antag.dmi' - button_icon_state = "art_summon" - usage_probability = 40 - boss_cost = 30 - boss_type = /mob/living/simple_animal/hostile/boss/paper_wizard - needs_target = FALSE - say_when_triggered = "Rise, my creations! Jump off your pages and into this realm!" - ///How many minions we summoned - var/summoned_minions = 0 - ///How many minions we can have at once - var/max_minions = 6 - ///How many minions we should spawn - var/minions_to_summon = 3 - -/datum/action/boss/wizard_summon_minions/IsAvailable(feedback = FALSE) - . = ..() - if(!.) - return FALSE - if(summoned_minions >= max_minions) - return FALSE - return TRUE - -/datum/action/boss/wizard_summon_minions/Trigger(trigger_flags) - . = ..() - if(!.) - return - var/list/minions = list( - /mob/living/basic/stickman, - /mob/living/basic/stickman/ranged, - /mob/living/basic/stickman/dog) - var/list/directions = GLOB.cardinals.Copy() - var/summon_amount = min(minions_to_summon, max_minions - summoned_minions) - for(var/i in 1 to summon_amount) - var/atom/chosen_minion = pick_n_take(minions) - chosen_minion = new chosen_minion(get_step(boss, pick_n_take(directions))) - RegisterSignals(chosen_minion, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(lost_minion)) - summoned_minions++ - -/// Called when a minion is qdeleted or dies, removes it from our minion list -/datum/action/boss/wizard_summon_minions/proc/lost_minion(mob/source) - SIGNAL_HANDLER - - UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH)) - summoned_minions-- - -//Mimic Ability -//Summons mimics of himself with magical papercraft -//Hitting a decoy hurts nearby people excluding the wizard himself -//Hitting the wizard himself destroys all decoys -/datum/action/boss/wizard_mimic - name = "Craft Mimicry" - button_icon = 'icons/mob/actions/actions_minor_antag.dmi' - button_icon_state = "mimic_summon" - usage_probability = 30 - boss_cost = 40 - boss_type = /mob/living/simple_animal/hostile/boss/paper_wizard - say_when_triggered = "" - -/datum/action/boss/wizard_mimic/Trigger(trigger_flags) - if(..()) - var/mob/living/target - if(!boss.client) //AI's target - target = boss.target - else //random mob - var/list/threats = boss.PossibleThreats() - if(threats.len) - target = pick(threats) - if(target) - var/mob/living/simple_animal/hostile/boss/paper_wizard/wiz = boss - var/directions = GLOB.cardinals.Copy() - for(var/i in 1 to 3) - var/mob/living/simple_animal/hostile/boss/paper_wizard/copy/C = new (get_step(target,pick_n_take(directions))) - wiz.copies += C - C.original = wiz - C.say("My craft defines me, you could even say it IS me!") - wiz.say("My craft defines me, you could even say it IS me!") - wiz.forceMove(get_step(target,pick_n_take(directions))) - wiz.minimum_distance = 1 //so he doesn't run away and ruin everything - wiz.retreat_distance = 0 - else - boss.atb.refund(boss_cost) - -/mob/living/simple_animal/hostile/boss/paper_wizard/copy - desc = "'Tis a ruse!" - health = 1 - maxHealth = 1 - alpha = 200 - boss_abilities = list() - melee_damage_lower = 1 - melee_damage_upper = 5 - minimum_distance = 0 - retreat_distance = 0 - ranged = 0 - loot = list() - var/mob/living/simple_animal/hostile/boss/paper_wizard/original - -/mob/living/simple_animal/hostile/boss/paper_wizard/copy/Destroy() - if(original) - original.copies -= src - original = null - return ..() - -//Hit a fake? eat pain! -/mob/living/simple_animal/hostile/boss/paper_wizard/copy/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - if(amount > 0) //damage - if(original) - original.minimum_distance = 3 - original.retreat_distance = 3 - for(var/c in original.copies) - qdel(c) - for(var/mob/living/L in range(5,src)) - if(L == original || istype(L, type)) - continue - L.adjustBruteLoss(50) - qdel(src) - else - . = ..() - -//Hit the real guy? copies go bai-bai -/mob/living/simple_animal/hostile/boss/paper_wizard/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - . = ..() - if(. > 0)//damage - minimum_distance = 3 - retreat_distance = 3 - for(var/copy in copies) - qdel(copy) - -/mob/living/simple_animal/hostile/boss/paper_wizard/copy/examine(mob/user) - . = ..() - if(isobserver(user)) - . += span_notice("It's an illusion - what is it hiding?") - else - qdel(src) //I see through your ruse! - -//fancy effects -/obj/effect/temp_visual/paper_scatter - name = "scattering paper" - desc = "Pieces of paper scattering to the wind." - layer = ABOVE_NORMAL_TURF_LAYER - plane = GAME_PLANE - icon = 'icons/effects/effects.dmi' - icon_state = "paper_scatter" - anchored = TRUE - duration = 5 - randomdir = FALSE - -/obj/effect/temp_visual/paperwiz_dying - name = "craft portal" - desc = "A wormhole sucking the wizard into the void. Neat." - layer = ABOVE_NORMAL_TURF_LAYER - plane = GAME_PLANE - icon = 'icons/effects/effects.dmi' - icon_state = "paperwiz_poof" - anchored = TRUE - duration = 18 - randomdir = FALSE - -/obj/effect/temp_visual/paperwiz_dying/Initialize(mapload) - . = ..() - visible_message(span_boldannounce("The wizard cries out in pain as a gate appears behind him, sucking him in!")) - playsound(get_turf(src),'sound/magic/mandswap.ogg', 50, TRUE, TRUE) - playsound(get_turf(src),'sound/hallucinations/wail.ogg', 50, TRUE, TRUE) - -/obj/effect/temp_visual/paperwiz_dying/Destroy() - for(var/mob/M in range(7,src)) - shake_camera(M, 7, 1) - var/turf/T = get_turf(src) - playsound(T,'sound/magic/summon_magic.ogg', 50, TRUE, TRUE) - new /obj/effect/temp_visual/paper_scatter(T) - new /obj/item/clothing/suit/wizrobe/paper(T) - new /obj/item/clothing/head/collectable/paper(T) - return ..() diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 8dd2eef9465..9a598747708 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -114,8 +114,6 @@ /mob/living/simple_animal/hostile/blob/blobspore/independent, /mob/living/simple_animal/hostile/blob/blobspore/weak, /mob/living/simple_animal/hostile/boss, - /mob/living/simple_animal/hostile/boss/paper_wizard, - /mob/living/simple_animal/hostile/boss/paper_wizard/copy, /mob/living/simple_animal/hostile/construct, /mob/living/simple_animal/hostile/construct/artificer, /mob/living/simple_animal/hostile/construct/artificer/angelic, diff --git a/tgstation.dme b/tgstation.dme index dc4c4336d6d..02242cda20f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -854,8 +854,10 @@ #include "code\datums\ai\basic_mobs\basic_ai_behaviors\tipped_reaction.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\travel_towards.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\ventcrawling.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\write_on_paper.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\attack_obstacle_in_path.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\find_paper_and_write.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\flee_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\opportunistic_ventcrawler.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\simple_attack_target.dm" @@ -4138,6 +4140,8 @@ #include "code\modules\mob\living\basic\space_fauna\netherworld\blankbody.dm" #include "code\modules\mob\living\basic\space_fauna\netherworld\creature.dm" #include "code\modules\mob\living\basic\space_fauna\netherworld\migo.dm" +#include "code\modules\mob\living\basic\space_fauna\paper_wizard\paper_abilities.dm" +#include "code\modules\mob\living\basic\space_fauna\paper_wizard\paper_wizard.dm" #include "code\modules\mob\living\basic\space_fauna\spider\giant_spider\giant_spider.dm" #include "code\modules\mob\living\basic\space_fauna\spider\giant_spider\giant_spider_ai.dm" #include "code\modules\mob\living\basic\space_fauna\spider\giant_spider\giant_spider_subtrees.dm" @@ -4385,7 +4389,6 @@ #include "code\modules\mob\living\simple_animal\hostile\wizard.dm" #include "code\modules\mob\living\simple_animal\hostile\zombie.dm" #include "code\modules\mob\living\simple_animal\hostile\bosses\boss.dm" -#include "code\modules\mob\living\simple_animal\hostile\bosses\paperwizard.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\artificer.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\constructs.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\harvester.dm" diff --git a/tools/UpdatePaths/Scripts/76688_paper_wizard.txt b/tools/UpdatePaths/Scripts/76688_paper_wizard.txt new file mode 100644 index 00000000000..1da513147f2 --- /dev/null +++ b/tools/UpdatePaths/Scripts/76688_paper_wizard.txt @@ -0,0 +1,2 @@ +/mob/living/simple_animal/hostile/boss/paper_wizard : /mob/living/basic/paper_wizard{@OLD} +