diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index f65f13f4f9f..4136771eef5 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -35,6 +35,7 @@ #define ROLE_SENTIENT "sentient animal" #define ROLE_POSIBRAIN "positronic brain" #define ROLE_GUARDIAN "guardian" +#define ROLE_MORPH "morph" //Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR. @@ -67,4 +68,5 @@ var/global/list/special_roles = list( ROLE_POSIBRAIN, ROLE_REVENANT, ROLE_GUARDIAN, + ROLE_MORPH, ) diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm similarity index 100% rename from code/modules/mob/living/simple_animal/borer.dm rename to code/game/gamemodes/miniantags/borer/borer.dm diff --git a/code/modules/events/borers.dm b/code/game/gamemodes/miniantags/borer/borer_event.dm similarity index 100% rename from code/modules/events/borers.dm rename to code/game/gamemodes/miniantags/borer/borer_event.dm diff --git a/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm similarity index 100% rename from code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm rename to code/game/gamemodes/miniantags/bot_swarm/swarmer.dm diff --git a/code/modules/mob/living/simple_animal/bot_swarm/swarmer_event.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm similarity index 100% rename from code/modules/mob/living/simple_animal/bot_swarm/swarmer_event.dm rename to code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm similarity index 100% rename from code/modules/mob/living/simple_animal/guardian/guardian.dm rename to code/game/gamemodes/miniantags/guardian/guardian.dm diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm new file mode 100644 index 00000000000..378ef84990a --- /dev/null +++ b/code/game/gamemodes/miniantags/morph/morph.dm @@ -0,0 +1,183 @@ +#define MORPH_COOLDOWN 50 + +/mob/living/simple_animal/hostile/morph + name = "morph" + real_name = "morph" + desc = "A revolting, pulsating pile of flesh." + speak_emote = list("gurgles") + emote_hear = list("gurgles") + icon = 'icons/mob/animal.dmi' + icon_state = "morph" + icon_living = "morph" + icon_dead = "morph_dead" + speed = 2 + a_intent = "harm" + stop_automated_movement = 1 + status_flags = CANPUSH + pass_flags = PASSTABLE + ventcrawler = 2 + + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + + minbodytemp = 0 + maxHealth = 150 + health = 150 + environment_smash = 1 + melee_damage_lower = 20 + melee_damage_upper = 20 + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_MINIMUM + idle_vision_range = 1 // Only attack when target is close + wander = 0 + attacktext = "glomps" + attack_sound = 'sound/effects/blobattack.ogg' + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/slab + + var/morphed = 0 + var/atom/movable/form = null + var/morph_time = 0 + + var/playstyle_string = "You are a morph, an abomination of science created primarily with changeling cells. \ + You may take the form of anything nearby by shift-clicking it. This process will alert any nearby \ + observers, and can only be performed once every five seconds. While morphed, you move faster, but do \ + less damage. In addition, anyone within three tiles will note an uncanny wrongness if examining you. \ + You can attack any item or dead creature to consume it - creatures will restore 1/3 of your max health. \ + Finally, you can restore yourself to your original form while morphed by shift-clicking yourself." + +/mob/living/simple_animal/hostile/morph/examine(mob/user) + if(morphed) + if(form) + form.examine(user) // Refactor examine to return desc so it's static? Not sure if worth it + // If the object you've disguised as has been deleted, your cover's probably blown + else + ..() + if(get_dist(user,src)<=3) + user << "It doesn't look quite right..." + else + ..() + return + +/mob/living/simple_animal/hostile/morph/proc/allowed(atom/movable/A) // make it into property/proc ? not sure if worth it + if(istype(A,/obj/screen)) + return 0 + if(istype(A,/obj/singularity)) + return 0 + if(istype(A,/mob/living/simple_animal/hostile/morph)) + return 0 + return 1 + +/mob/living/simple_animal/hostile/morph/proc/eat(atom/movable/A) + if(A && A.loc != src) + visible_message("[src] swallows [A] whole!") + A.forceMove(src) + return 1 + return 0 + +/mob/living/simple_animal/hostile/morph/ShiftClickOn(atom/movable/A) + if(morph_time <= world.time && !stat) + if(A == src) + restore() + return + if(istype(A) && allowed(A)) + assume(A) + else + src << "Your chameleon skin is still repairing itself!" + ..() + +/mob/living/simple_animal/hostile/morph/proc/assume(atom/movable/target) + morphed = 1 + form = target + visible_message("[src] suddenly twists and changes shape, becoming a copy of [target]!", \ + "You twist your body and assume the form of [target].") + + appearance = target.appearance + transform = initial(transform) + pixel_y = initial(pixel_y) + pixel_x = initial(pixel_x) + //Morphed is weaker + melee_damage_lower = 5 + melee_damage_upper = 5 + speed = 0 + + morph_time = world.time + MORPH_COOLDOWN + return + +/mob/living/simple_animal/hostile/morph/proc/restore() + if(!morphed) + return + morphed = 0 + form = null + + //anim(loc,src,'icons/mob/mob.dmi',,"morph",,src.dir) + + visible_message("[src] suddenly collapses in on itself, dissolving into a pile of green flesh!", \ + "You reform to your normal body.") + name = initial(name) + icon = initial(icon) + icon_state = initial(icon_state) + overlays.Cut() + + //Baseline stats + melee_damage_lower = initial(melee_damage_lower) + melee_damage_upper = initial(melee_damage_upper) + speed = initial(speed) + + morph_time = world.time + MORPH_COOLDOWN + +/mob/living/simple_animal/hostile/morph/handle_state_icons() + return + +/mob/living/simple_animal/hostile/morph/death(gibbed) + if(morphed) + visible_message("[src] twists and dissolves into a pile of green flesh!", \ + "Your skin ruptures! Your flesh breaks apart! No disguise can ward off de--") + restore() + if(gibbed) + for(var/atom/movable/AM in src) + AM.forceMove(loc) + if(prob(90)) + step(AM, pick(alldirs)) + ..(gibbed) + +/mob/living/simple_animal/hostile/morph/Aggro() // automated only + ..() + restore() + +/mob/living/simple_animal/hostile/morph/LoseAggro() + vision_range = idle_vision_range + +/mob/living/simple_animal/hostile/morph/AIShouldSleep(var/list/possible_targets) + . = ..() + if(.) + var/list/things = list() + for(var/atom/movable/A in view(src)) + if(allowed(A)) + things += A + var/atom/movable/T = pick(things) + assume(T) + +/mob/living/simple_animal/hostile/morph/AttackingTarget() + if(isliving(target)) // Eat Corpses to regen health + var/mob/living/L = target + if(L.stat == DEAD) + if(do_after(src, 30, target = L)) + if(eat(L)) + heal_overall_damage(50,50) + return + else if(istype(target,/obj/item)) // Eat items just to be annoying + var/obj/item/I = target + if(!I.anchored) + if(do_after(src,20, target = I)) + eat(I) + return + target.attack_animal(src) + +/mob/living/simple_animal/hostile/morph/update_action_buttons() //So all eaten objects are not counted every life + return \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/morph/morph_event.dm b/code/game/gamemodes/miniantags/morph/morph_event.dm new file mode 100644 index 00000000000..4a65ba85d83 --- /dev/null +++ b/code/game/gamemodes/miniantags/morph/morph_event.dm @@ -0,0 +1,45 @@ +/datum/event/spawn_morph + var/key_of_morph + +/datum/event/spawn_morph/proc/get_morph(end_if_fail = 0) + key_of_morph = null + if(!key_of_morph) + var/list/candidates = get_candidates(ROLE_MORPH) + if(!candidates.len) + if(end_if_fail) + return 0 + return find_morph() + var/client/C = pick(candidates) + key_of_morph = C.key + if(!key_of_morph) + if(end_if_fail) + return 0 + return find_morph() + var/datum/mind/player_mind = new /datum/mind(key_of_morph) + player_mind.active = 1 + if(!xeno_spawn) + return find_morph() + var/mob/living/simple_animal/hostile/morph/S = new /mob/living/simple_animal/hostile/morph(pick(xeno_spawn)) + player_mind.transfer_to(S) + player_mind.assigned_role = "Morph" + player_mind.special_role = "Morph" + ticker.mode.traitors |= player_mind + S << S.playstyle_string + S << 'sound/magic/Mutate.ogg' + message_admins("[key_of_morph] has been made into morph by an event.") + log_game("[key_of_morph] was spawned as a morph by an event.") + return 1 + +/datum/event/spawn_morph/start() + get_morph() + + +/datum/event/spawn_morph/proc/find_morph() + message_admins("Attempted to spawn a morph but there was no players available. Will try again momentarily.") + spawn(50) + if(get_morph(1)) + message_admins("Situation has been resolved, [key_of_morph] has been spawned as a morph.") + log_game("[key_of_morph] was spawned as a morph by an event.") + return 0 + message_admins("Unfortunately, no candidates were available for becoming a morph. Shutting down.") + return kill() diff --git a/code/modules/mob/living/simple_animal/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm similarity index 100% rename from code/modules/mob/living/simple_animal/revenant/revenant.dm rename to code/game/gamemodes/miniantags/revenant/revenant.dm diff --git a/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm similarity index 100% rename from code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm rename to code/game/gamemodes/miniantags/revenant/revenant_abilities.dm diff --git a/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm b/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm similarity index 100% rename from code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm rename to code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm similarity index 100% rename from code/modules/mob/living/bloodcrawl.dm rename to code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm similarity index 100% rename from code/modules/mob/living/simple_animal/slaughter/slaughter.dm rename to code/game/gamemodes/miniantags/slaughter/slaughter.dm diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 03af198e808..fcf786745a6 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -169,7 +169,8 @@ var/list/event_last_fired = list() new /datum/event_meta(EVENT_LEVEL_MODERATE, "Flux Anomaly", /datum/event/anomaly/anomaly_flux, 50, list(ASSIGNMENT_ENGINEER = 50)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravitational Anomaly", /datum/event/anomaly/anomaly_grav, 200), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Revenant", /datum/event/revenant, 150), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Swarmer Spawn", /datum/event/spawn_swarmer, 150, is_one_shot = 1) + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Swarmer Spawn", /datum/event/spawn_swarmer, 150, is_one_shot = 1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Morph Spawn", /datum/event/spawn_morph, 0, is_one_shot = 1) ) /datum/event_container/major diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 59afc38f1cd..399ae068586 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -102,6 +102,9 @@ handle_automated_speech() . = 1 + handle_state_icons() + +/mob/living/simple_animal/proc/handle_state_icons() if(resting && icon_resting && stat != DEAD) icon_state = icon_resting else if(stat != DEAD) diff --git a/html/changelogs/crazylemon-morphport.yml b/html/changelogs/crazylemon-morphport.yml new file mode 100644 index 00000000000..a28b15d58e8 --- /dev/null +++ b/html/changelogs/crazylemon-morphport.yml @@ -0,0 +1,4 @@ +author: Crazylemon +delete-after: True +changes: + - rscadd: "New classes of shapeshifters have been sighted around the NSS Cyberiad..." diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 47a0c11e9b2..4b839a4bf66 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/paradise.dme b/paradise.dme index 580b9217bbf..ef97cd9bf11 100644 --- a/paradise.dme +++ b/paradise.dme @@ -335,6 +335,18 @@ #include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" #include "code\game\gamemodes\meteor\meteors.dm" +#include "code\game\gamemodes\miniantags\borer\borer.dm" +#include "code\game\gamemodes\miniantags\borer\borer_event.dm" +#include "code\game\gamemodes\miniantags\bot_swarm\swarmer.dm" +#include "code\game\gamemodes\miniantags\bot_swarm\swarmer_event.dm" +#include "code\game\gamemodes\miniantags\guardian\guardian.dm" +#include "code\game\gamemodes\miniantags\morph\morph.dm" +#include "code\game\gamemodes\miniantags\morph\morph_event.dm" +#include "code\game\gamemodes\miniantags\revenant\revenant.dm" +#include "code\game\gamemodes\miniantags\revenant\revenant_abilities.dm" +#include "code\game\gamemodes\miniantags\revenant\revenant_spawn_event.dm" +#include "code\game\gamemodes\miniantags\slaughter\bloodcrawl.dm" +#include "code\game\gamemodes\miniantags\slaughter\slaughter.dm" #include "code\game\gamemodes\mutiny\auth_key.dm" #include "code\game\gamemodes\mutiny\directive.dm" #include "code\game\gamemodes\mutiny\emergency_authentication_device.dm" @@ -1145,7 +1157,6 @@ #include "code\modules\events\anomaly_pyro.dm" #include "code\modules\events\anomaly_vortex.dm" #include "code\modules\events\blob.dm" -#include "code\modules\events\borers.dm" #include "code\modules\events\brand_intelligence.dm" #include "code\modules\events\carp_migration.dm" #include "code\modules\events\communications_blackout.dm" @@ -1296,7 +1307,6 @@ #include "code\modules\mob\dead\observer\say.dm" #include "code\modules\mob\dead\observer\spells.dm" #include "code\modules\mob\living\autohiss.dm" -#include "code\modules\mob\living\bloodcrawl.dm" #include "code\modules\mob\living\damage_procs.dm" #include "code\modules\mob\living\default_language.dm" #include "code\modules\mob\living\life.dm" @@ -1444,7 +1454,6 @@ #include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_say.dm" #include "code\modules\mob\living\simple_animal\bees.dm" -#include "code\modules\mob\living\simple_animal\borer.dm" #include "code\modules\mob\living\simple_animal\constructs.dm" #include "code\modules\mob\living\simple_animal\corpse.dm" #include "code\modules\mob\living\simple_animal\parrot.dm" @@ -1454,8 +1463,6 @@ #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\tribbles.dm" #include "code\modules\mob\living\simple_animal\vox.dm" -#include "code\modules\mob\living\simple_animal\bot_swarm\swarmer.dm" -#include "code\modules\mob\living\simple_animal\bot_swarm\swarmer_event.dm" #include "code\modules\mob\living\simple_animal\friendly\butterfly.dm" #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" @@ -1472,7 +1479,6 @@ #include "code\modules\mob\living\simple_animal\friendly\slime.dm" #include "code\modules\mob\living\simple_animal\friendly\spiderbot.dm" #include "code\modules\mob\living\simple_animal\friendly\tomato.dm" -#include "code\modules\mob\living\simple_animal\guardian\guardian.dm" #include "code\modules\mob\living\simple_animal\hostile\alien.dm" #include "code\modules\mob\living\simple_animal\hostile\bat.dm" #include "code\modules\mob\living\simple_animal\hostile\bear.dm" @@ -1499,10 +1505,6 @@ #include "code\modules\mob\living\simple_animal\hostile\retaliate\pet.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\undead.dm" -#include "code\modules\mob\living\simple_animal\revenant\revenant.dm" -#include "code\modules\mob\living\simple_animal\revenant\revenant_abilities.dm" -#include "code\modules\mob\living\simple_animal\revenant\revenant_spawn_event.dm" -#include "code\modules\mob\living\simple_animal\slaughter\slaughter.dm" #include "code\modules\mob\new_player\login.dm" #include "code\modules\mob\new_player\logout.dm" #include "code\modules\mob\new_player\new_player.dm" diff --git a/sound/magic/Mutate.ogg b/sound/magic/Mutate.ogg new file mode 100644 index 00000000000..d31514f310b Binary files /dev/null and b/sound/magic/Mutate.ogg differ