diff --git a/ModularTegustation/Teguicons/128x128.dmi b/ModularTegustation/Teguicons/128x128.dmi index c66435676118..98dd771130f5 100644 Binary files a/ModularTegustation/Teguicons/128x128.dmi and b/ModularTegustation/Teguicons/128x128.dmi differ diff --git a/ModularTegustation/Teguicons/32x32.dmi b/ModularTegustation/Teguicons/32x32.dmi index 28a5ef514355..4cba7ba7b637 100644 Binary files a/ModularTegustation/Teguicons/32x32.dmi and b/ModularTegustation/Teguicons/32x32.dmi differ diff --git a/ModularTegustation/Teguicons/48x64.dmi b/ModularTegustation/Teguicons/48x64.dmi index 6435a7dc36f5..bc19cbeff14a 100644 Binary files a/ModularTegustation/Teguicons/48x64.dmi and b/ModularTegustation/Teguicons/48x64.dmi differ diff --git a/ModularTegustation/Teguicons/64x64.dmi b/ModularTegustation/Teguicons/64x64.dmi index 4315c96000a1..ee0ab8cff8db 100644 Binary files a/ModularTegustation/Teguicons/64x64.dmi and b/ModularTegustation/Teguicons/64x64.dmi differ diff --git a/ModularTegustation/Teguicons/64x96.dmi b/ModularTegustation/Teguicons/64x96.dmi index 2d4bde4fac96..10c07ddf57ed 100644 Binary files a/ModularTegustation/Teguicons/64x96.dmi and b/ModularTegustation/Teguicons/64x96.dmi differ diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 14908a15c681..ca56b145a1f3 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -1055,6 +1055,7 @@ #define COMSIG_WORK_COMPLETED "work_completed" // Work Complete #define COMSIG_GLOB_WORK_COMPLETED "!work_completed" // Ditto #define COMSIG_MELTDOWN_FINISHED "meltdown_finished" +#define COMSIG_GLOB_MELTDOWN_FINISHED "!meltdown_finished" // General Abnormality Signals diff --git a/code/controllers/subsystem/lobotomy_corp.dm b/code/controllers/subsystem/lobotomy_corp.dm index 01bc358bc96a..c5b70d308d3f 100644 --- a/code/controllers/subsystem/lobotomy_corp.dm +++ b/code/controllers/subsystem/lobotomy_corp.dm @@ -3,6 +3,7 @@ #define MELTDOWN_GOLD 3 #define MELTDOWN_PURPLE 4 #define MELTDOWN_CYAN 5 +#define MELTDOWN_BLACK 6 // TODO: Do something about it, idk SUBSYSTEM_DEF(lobotomy_corp) diff --git a/code/datums/abnormality/_ego_datum/aleph.dm b/code/datums/abnormality/_ego_datum/aleph.dm index 504ec954b370..ef6a8fd4a22f 100644 --- a/code/datums/abnormality/_ego_datum/aleph.dm +++ b/code/datums/abnormality/_ego_datum/aleph.dm @@ -123,11 +123,11 @@ // Distorted Form - Distortion /datum/ego_datum/armor/distortion item_path = /obj/item/clothing/suit/armor/ego_gear/aleph/distortion - cost = 100 + cost = 200 -/datum/ego_datum/weapon/distortion +/datum/ego_datum/weapon/distortion // not able to be extracted item_path = /obj/item/ego_weapon/shield/distortion - cost = 100 + cost = 300 // Dongrang Personal E.G.O - Farmwatch /datum/ego_datum/weapon/farmwatch diff --git a/code/datums/abnormality/datum/abnormality.dm b/code/datums/abnormality/datum/abnormality.dm index 636e6e4ead41..9bd69c4cbcbc 100644 --- a/code/datums/abnormality/datum/abnormality.dm +++ b/code/datums/abnormality/datum/abnormality.dm @@ -258,3 +258,13 @@ SSlobotomy_corp.work_stats[user_name]["pe"] += pe if(attribute_type != "N/A" && attribute_given) SSlobotomy_corp.work_stats[user_name]["gain"][attribute_type] += attribute_given + +/datum/abnormality/proc/GetName() + if(current) + return current.GetName() + return name + +/datum/abnormality/proc/GetRiskLevel() + if(current) + return current.GetRiskLevel() + return threat_level diff --git a/code/datums/looping_sounds/abnormalities.dm b/code/datums/looping_sounds/abnormalities.dm index 418e3e023566..9d31b51f91c7 100644 --- a/code/datums/looping_sounds/abnormalities.dm +++ b/code/datums/looping_sounds/abnormalities.dm @@ -119,6 +119,12 @@ volume = 15 extra_range = -4 +/datum/looping_sound/distortedform + mid_sounds = 'sound/abnormalities/distortedform/DF_soundloop.ogg' + mid_length = 15 SECONDS + volume = 75 + extra_range = -4 + // Ordeals /datum/looping_sound/amberdusk mid_sounds = 'sound/effects/ordeals/amber/dusk_ambience.ogg' diff --git a/code/game/machinery/computer/abnormality_work.dm b/code/game/machinery/computer/abnormality_work.dm index 3e0d46b0b7d4..27bfafd2e3d9 100644 --- a/code/game/machinery/computer/abnormality_work.dm +++ b/code/game/machinery/computer/abnormality_work.dm @@ -40,8 +40,8 @@ . = ..() if(!datum_reference) return - . += "This console is connected to [datum_reference.name]'s containment unit." - var/threat_level = "[THREAT_TO_NAME[datum_reference.threat_level]]" + . += "This console is connected to [datum_reference.GetName()]'s containment unit." + var/threat_level = "[THREAT_TO_NAME[datum_reference.GetRiskLevel()]]" . += "Risk Level: [threat_level]." // Professionals have standards if(datum_reference.qliphoth_meter_max > 0) . += "Current Qliphoth Counter: [datum_reference.qliphoth_meter]." @@ -58,6 +58,8 @@ melt_text = " of Waves. Upon clearing the meltdown the dark waves will disappear" if(MELTDOWN_CYAN) melt_text = " of Pillars. Success rates reduced by 20%. Failing to clear it will cause Arbiter to perform their deadly attack" + if(MELTDOWN_BLACK) + melt_text = " of Lunacy. Failure to clear the meltdown will cause another abnormality to breach" . += "The containment unit is currently affected by a Qliphoth Meltdown[melt_text]. Time left: [meltdown_time]." /obj/machinery/computer/abnormality/ui_interact(mob/user) @@ -68,7 +70,7 @@ to_chat(user, "The console has no information stored!") return var/dat - dat += "\[[THREAT_TO_NAME[datum_reference.threat_level]]\] [datum_reference.name]
" + dat += "\[[THREAT_TO_NAME[datum_reference.GetRiskLevel()]]\] [datum_reference.GetName()]
" if(datum_reference.overload_chance[user.ckey]) dat += "Personal Work Success Rates are modified by [datum_reference.overload_chance[user.ckey]]%.
" if(datum_reference.overload_chance_limit < 0 && datum_reference.overload_chance[user.ckey] <= datum_reference.overload_chance_limit) // How the fuck did you hit the limit..? @@ -163,6 +165,7 @@ meltdown = FALSE // Reset meltdown if(was_melting) SEND_SIGNAL(src, COMSIG_MELTDOWN_FINISHED, datum_reference, TRUE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MELTDOWN_FINISHED, datum_reference, TRUE) update_icon() datum_reference.working = TRUE var/work_chance = datum_reference.get_work_chance(work_type, user) @@ -286,6 +289,7 @@ update_icon() datum_reference.qliphoth_change(-999) SEND_SIGNAL(src, COMSIG_MELTDOWN_FINISHED, datum_reference, FALSE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MELTDOWN_FINISHED, datum_reference, FALSE) return TRUE // Scrambles work types for this specific console diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 9cac6773c613..3a7654d8112a 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -1020,3 +1020,8 @@ name = "heavenly blessing" icon_state = "onesin_blessing" duration = 12 + +/obj/effect/temp_visual/distortedform_shift + name = "shift" + icon_state = "shift" + duration = 3 diff --git a/code/game/objects/items/ego_weapons/aleph.dm b/code/game/objects/items/ego_weapons/aleph.dm index 9e9818041e12..15511205a05b 100644 --- a/code/game/objects/items/ego_weapons/aleph.dm +++ b/code/game/objects/items/ego_weapons/aleph.dm @@ -718,8 +718,8 @@ desc = "The fragile human mind is fated to twist and distort." special = "This weapon requires two hands to use and always blocks ranged attacks." icon_state = "distortion" - force = 180 //Just make sure you don't hit anyone! - attack_speed = 3 + force = 35 //Twilight but lower in terms of damage + attack_speed = 1.8 damtype = RED_DAMAGE attack_verb_continuous = list("pulverizes", "bashes", "slams", "blockades") attack_verb_simple = list("pulverize", "bash", "slam", "blockade") @@ -731,21 +731,29 @@ block_sound = 'sound/weapons/ego/heavy_guard.ogg' attribute_requirements = list( FORTITUDE_ATTRIBUTE = 100, - PRUDENCE_ATTRIBUTE = 80, - TEMPERANCE_ATTRIBUTE = 80, - JUSTICE_ATTRIBUTE = 80 + PRUDENCE_ATTRIBUTE = 100, + TEMPERANCE_ATTRIBUTE = 100, + JUSTICE_ATTRIBUTE = 100 ) attacking = TRUE //ALWAYS blocking ranged attacks + +/obj/item/ego_weapon/shield/distortion/EgoAttackInfo(mob/user) + return "It deals [force * 4] red, white, black and pale damage combined." + /obj/item/ego_weapon/shield/distortion/attack(mob/living/target, mob/living/user) . = ..() if(!.) return FALSE + for(var/damage_type in list(WHITE_DAMAGE, BLACK_DAMAGE, PALE_DAMAGE)) + damtype = damage_type + target.attacked_by(src, user) + damtype = initial(damtype) var/atom/throw_target = get_edge_target_turf(target, user.dir) if(!target.anchored) - var/whack_speed = (prob(60) ? 4 : 8) - target.throw_at(throw_target, rand(3, 4), whack_speed, user) + var/whack_speed = (prob(60) ? 3 : 6) + target.throw_at(throw_target, rand(2, 3), whack_speed, user) /obj/item/ego_weapon/shield/distortion/CanUseEgo(mob/living/user) . = ..() diff --git a/code/modules/clothing/suits/ego_gear/aleph.dm b/code/modules/clothing/suits/ego_gear/aleph.dm index 12f45576ce4b..051eec109f2e 100644 --- a/code/modules/clothing/suits/ego_gear/aleph.dm +++ b/code/modules/clothing/suits/ego_gear/aleph.dm @@ -364,12 +364,12 @@ Any attempt to code risk class armor will result in a 10 day Github ban.*/ name = "distortion" desc = "To my eyes, I’m the only one who doesn’t appear distorted. In a world full of distorted people, could the one person who remains unchanged be the \"distorted\" one?" icon_state = "distortion" - armor = list(RED_DAMAGE = 70, WHITE_DAMAGE = 70, BLACK_DAMAGE = 70, PALE_DAMAGE = 30) // 240 + armor = list(RED_DAMAGE = 80, WHITE_DAMAGE = 70, BLACK_DAMAGE = 80, PALE_DAMAGE = 50) // 280 attribute_requirements = list( FORTITUDE_ATTRIBUTE = 100, - PRUDENCE_ATTRIBUTE = 80, - TEMPERANCE_ATTRIBUTE = 80, - JUSTICE_ATTRIBUTE = 80 + PRUDENCE_ATTRIBUTE = 100, + TEMPERANCE_ATTRIBUTE = 100, + JUSTICE_ATTRIBUTE = 100 ) /obj/item/clothing/suit/armor/ego_gear/aleph/willing diff --git a/code/modules/mob/living/carbon/human/ego_gifts.dm b/code/modules/mob/living/carbon/human/ego_gifts.dm index a8ceefadb3a8..139748a5086b 100644 --- a/code/modules/mob/living/carbon/human/ego_gifts.dm +++ b/code/modules/mob/living/carbon/human/ego_gifts.dm @@ -1285,3 +1285,27 @@ /datum/ego_gifts/blessing/Remove(mob/living/carbon/human/user) user.physiology.pale_mod /= 0.8 .=..() + +/datum/ego_gifts/fervor + name = "Fervor" + desc = "Provides the user with 5% resistance to all damage types." + icon_state = "fervor" + fortitude_bonus = 4 + prudence_bonus = 4 + temperance_bonus = 4 + justice_bonus = 4 + slot = SPECIAL + +/datum/ego_gifts/fervor/Initialize(mob/living/carbon/human/user) // Lowered Stats but grants resistance + .=..() + user.physiology.red_mod *= 0.95 + user.physiology.white_mod *= 0.95 + user.physiology.black_mod *= 0.95 + user.physiology.pale_mod *= 0.95 + +/datum/ego_gifts/fervor/Remove(mob/living/carbon/human/user) + user.physiology.red_mod /= 0.95 + user.physiology.white_mod /= 0.95 + user.physiology.black_mod /= 0.95 + user.physiology.pale_mod /= 0.95 + .=..() diff --git a/code/modules/mob/living/simple_animal/abnormality/_abnormality.dm b/code/modules/mob/living/simple_animal/abnormality/_abnormality.dm index f58b63b99121..26490584ae6c 100644 --- a/code/modules/mob/living/simple_animal/abnormality/_abnormality.dm +++ b/code/modules/mob/living/simple_animal/abnormality/_abnormality.dm @@ -391,6 +391,12 @@ return TRUE return FALSE +/mob/living/simple_animal/hostile/abnormality/proc/GetName() + return name + +/mob/living/simple_animal/hostile/abnormality/proc/GetRiskLevel() + return threat_level + // Actions /datum/action/innate/abnormality_attack name = "Abnormality Attack" diff --git a/code/modules/mob/living/simple_animal/abnormality/_tools/waw/clock.dm b/code/modules/mob/living/simple_animal/abnormality/_tools/waw/clock.dm index 6967bd75ee6c..0d5ece803379 100644 --- a/code/modules/mob/living/simple_animal/abnormality/_tools/waw/clock.dm +++ b/code/modules/mob/living/simple_animal/abnormality/_tools/waw/clock.dm @@ -17,6 +17,7 @@ var/list/exceptions = list( //It only affects abnormalities and ordeals, so claw and arbiter are not even included. /mob/living/simple_animal/hostile/abnormality/white_night, + /mob/living/simple_animal/hostile/abnormality/distortedform, /mob/living/simple_animal/hostile/abnormality/nihil ) diff --git a/code/modules/mob/living/simple_animal/abnormality/aleph/distortedform.dm b/code/modules/mob/living/simple_animal/abnormality/aleph/distortedform.dm new file mode 100644 index 000000000000..f87b89e5cde4 --- /dev/null +++ b/code/modules/mob/living/simple_animal/abnormality/aleph/distortedform.dm @@ -0,0 +1,1740 @@ +/* + Coded by Coxswain, sprited by Mr. Heavenly and Mel Taculo + A monster that turns into other abnormalities, + roughly as dangerous as white night and as rewarding. +*/ +/mob/living/simple_animal/hostile/abnormality/distortedform + name = "Distorted Form" + desc = "A manmade horror beyond description." + icon = 'ModularTegustation/Teguicons/128x128.dmi' + maxHealth = 20000 + health = 20000 + attack_verb_continuous = "attacks" + attack_verb_simple = "attack" + attack_sound = 'sound/abnormalities/distortedform/slam.ogg' + threat_level = ALEPH_LEVEL + fear_level = ALEPH_LEVEL + 1 + icon_state = "distortedform" + icon_living = "distortedform" + icon_dead = "distortedform_dead" + melee_damage_type = RED_DAMAGE + damage_coeff = list(BRUTE = 1, RED_DAMAGE = 0.4, WHITE_DAMAGE = 0.4, BLACK_DAMAGE = 0.4, PALE_DAMAGE = 0.8) + melee_damage_lower = 55 + melee_damage_upper = 65 + move_to_delay = 3 + ranged = TRUE + pixel_x = -48 + base_pixel_x = -48 + del_on_death = FALSE + deathmessage = "reverts into a tiny, disgusting fetus-like creature." + deathsound = 'sound/abnormalities/doomsdaycalendar/Limbus_Dead_Generic.ogg' + can_breach = TRUE + work_chances = list( + ABNORMALITY_WORK_INSTINCT = 25, + ABNORMALITY_WORK_INSIGHT = 0, + ABNORMALITY_WORK_ATTACHMENT = list(0, 0, 0, 40, 45), + ABNORMALITY_WORK_REPRESSION = list(0, 0, 0, 50, 55) + ) + start_qliphoth = 3 + work_damage_amount = 4 //Work damage is later + work_damage_type = RED_DAMAGE + + ego_list = list( + /datum/ego_datum/armor/distortion + ) + gift_type = /datum/ego_gifts/distortion + abnormality_origin = ABNORMALITY_ORIGIN_ARTBOOK + +//Work vars + var/transform_timer + var/list/transform_blacklist = list( + /mob/living/simple_animal/hostile/abnormality/hammer_light, /mob/living/simple_animal/hostile/abnormality/black_swan, + /mob/living/simple_animal/hostile/abnormality/fire_bird, /mob/living/simple_animal/hostile/abnormality/punishing_bird + ) + var/datum/looping_sound/distortedform/soundloop + var/transformed = FALSE //We'll use this variable to check for whether or not to play the sound loop + /// List of melting consoles + var/list/meltdowns = list() + +//Spawning + var/obj/machinery/door/airlock/vault/connected_door + var/obj/machinery/containment_panel/connected_panel + +//Visuals + var/obj/viscon_filtereffect/distortedform/current_effect + var/fakename + var/fakerisklevel + +//Breach vars + var/breached // what it says on the tin + /// List of Living People on Breach + var/list/survivors = list() + /// Can it perform Another Attack? + var/can_act = TRUE + var/can_move = FALSE + var/can_attack = TRUE + var/changed = FALSE + var/transform_cooldown + var/transform_cooldown_time_short = 4 SECONDS + var/transform_cooldown_time = 6 SECONDS + var/transform_cooldown_time_long = 12 SECONDS + var/list/transform_list = list("Nothing There", "Apocalypse bird", "Puss in Boots", "Crumbling Armor", "Hammer of Light", "Halberd Apostle", "Red Queen", "Blubbering Toad", "Bloodbath") + var/list/transform_list_longrange = list("Doomsday Calendar", "Blue Star", "Der Freischutz", "Apocalypse bird") + var/list/transform_list_jump = list("Light", "Medium", "Heavy") + var/transform_count = 0 + var/jump_ready = FALSE + var/special_attack = null + var/special_attack_cooldown + var/list/been_hit = list() + +/mob/living/simple_animal/hostile/abnormality/distortedform/Initialize() + . = ..() + soundloop = new(list(src), TRUE) + +/mob/living/simple_animal/hostile/abnormality/distortedform/PostSpawn() + ..() + RegisterSignal(SSdcs, COMSIG_GLOB_MELTDOWN_FINISHED, .proc/OnMeltdownFinish) + soundloop.start() + transform_timer = addtimer(CALLBACK(src, .proc/Transform), 3 MINUTES, TIMER_STOPPABLE & TIMER_OVERRIDE) + +/mob/living/simple_animal/hostile/abnormality/distortedform/FearEffectText(mob/affected_mob, level = 0) + level = num2text(clamp(level, 1, 5)) + var/list/result_text_list = list( + "1" = list("There's no room for error here.", "My legs are trembling...", "Damn, it's scary."), + "2" = list("GODDAMN IT!!!!", "H-Help...", "I don't want to die!"), + "3" = list("What am I seeing...?", "I-I can't take it...", "I can't understand..."), + "4" = list("I'm so dead...", "That thing's just a monster!", "I need to get out of here!"), + "5" = list("Is that what it really looks like?", "It's over...", "I can’t even move my legs...") + ) + return pick(result_text_list[level]) + +//Work Mechanics +/mob/living/simple_animal/hostile/abnormality/distortedform/AttemptWork(mob/living/carbon/human/user, work_type) + if(transformed) // distorted form jumpscare + UnTransform(TRUE) + return ..() + +/mob/living/simple_animal/hostile/abnormality/distortedform/WorktickFailure(mob/living/carbon/human/user) + var/list/damtypes = list(RED_DAMAGE, WHITE_DAMAGE, BLACK_DAMAGE, PALE_DAMAGE) + for(var/damagetype in damtypes) // take 4 of every damage type every failed tick + user.apply_damage(work_damage_amount, damagetype, null, user.run_armor_check(null, damagetype)) + +/mob/living/simple_animal/hostile/abnormality/distortedform/SuccessEffect(mob/living/carbon/human/user, work_type, pe) + datum_reference.qliphoth_change(1) + return + +/mob/living/simple_animal/hostile/abnormality/distortedform/FailureEffect(mob/living/carbon/human/user, work_type, pe) + addtimer(CALLBACK(src, .proc/CauseMelts), 10) //Delaying it prevents some bugs; call a meltdown on a bad result or failed stat check + return + +/mob/living/simple_animal/hostile/abnormality/distortedform/PostWorkEffect(mob/living/carbon/human/user, work_type, pe, work_time) + if(get_attribute_level(user, JUSTICE_ATTRIBUTE) < 100) + if(pe > datum_reference.neutral_boxes) // Not work failure, we don't need to call TWO melts + addtimer(CALLBACK(src, .proc/CauseMelts), 10) + return + +//Contained Mechanics +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/Transform() + if(!(IsContained(src))) + return + if(datum_reference.working) //If we are being worked on - transform later instead. + transform_timer = addtimer(CALLBACK(src, .proc/Transform), 3 MINUTES, TIMER_STOPPABLE & TIMER_OVERRIDE) + return + var/list/abno_list = AbnoListGen() + if(!LAZYLEN(abno_list)) + return + var/datum/abnormality/abno_datum = pick(abno_list) + var/mob/living/simple_animal/hostile/abnormality/abno = abno_datum.current + if(!abno || (abno.health <= 0)) //If the target is dead or otherwise missing, we'll try again in a minute + transform_timer = addtimer(CALLBACK(src, .proc/Transform), 1 MINUTES, TIMER_STOPPABLE & TIMER_OVERRIDE) + return + soundloop.stop() + new /obj/effect/temp_visual/distortedform_shift(get_turf(src)) + name = abno.name + fakename = abno.name + fakerisklevel = abno.threat_level + desc = abno.desc + icon = abno.icon + icon_state = abno.icon_state + pixel_x = abno.pixel_x + base_pixel_x = abno.base_pixel_x + pixel_y = abno.pixel_y + base_pixel_y = abno.base_pixel_y + if(!datum_reference?.console) + return + datum_reference.console.updateUsrDialog() //Update the console and change our name into a lie + transformed = TRUE + transform_timer = addtimer(CALLBACK(src, .proc/UnTransform), 1 MINUTES, TIMER_STOPPABLE & TIMER_OVERRIDE) + update_icon() + if(!connected_panel) // Update the panel and door so they don't give us away + for(var/obj/machinery/door/airlock/vault/door in orange(3, src)) + if(door.name == "Distorted Form containment zone") + connected_door = door + connected_panel = datum_reference.console.linked_panel + if(connected_door) //doors can be destroyed + connected_door.name = "[abno.name] containment zone" + connected_panel.name = "[abno.name]'s containment panel" + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/UnTransform() + if(transform_timer) + transform_timer = null + soundloop.start() //Change EVERYTHING back to normal + if(name != initial(name)) + new /obj/effect/temp_visual/distortedform_shift(get_turf(src)) + name = initial(name) + desc = initial(desc) + icon = initial(icon) + icon_state = initial(icon_state) + pixel_x = initial(pixel_x) + base_pixel_x = initial(base_pixel_x) + pixel_y = initial(pixel_y) + base_pixel_y = initial(base_pixel_y) + fakename = null + fakerisklevel = null + if(!datum_reference?.console) + return + datum_reference.console.updateUsrDialog() + if(connected_door) //doors can be destroyed + connected_door.name = "Distorted Form containment zone" //Initial() turns it into "vault door" + connected_panel.name = "Distorted Form's containment panel" + transformed = FALSE + transform_timer = addtimer(CALLBACK(src, .proc/Transform), 3 MINUTES, TIMER_STOPPABLE & TIMER_OVERRIDE) + update_icon() + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/AbnoListGen() // List of possible transformations + . = list() + if(LAZYLEN(SSlobotomy_corp.all_abnormality_datums)) + for(var/datum/abnormality/A in SSlobotomy_corp.all_abnormality_datums) + if(isnull(A.current)) + continue + if(A.abno_path in transform_blacklist) + continue + if(A.name != name) //lets not turn into ourselves + . += A + return + +/mob/living/simple_animal/hostile/abnormality/distortedform/GetName() + if(fakename) + return fakename + return name + +/mob/living/simple_animal/hostile/abnormality/distortedform/GetRiskLevel() + if(fakerisklevel) + return fakerisklevel + return threat_level + +//Qlipthoth Stuff +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/OnMeltdownFinish(datum/source, datum/abnormality/abno_datum, worked) + SIGNAL_HANDLER + if(!worked) + datum_reference.qliphoth_change(-1) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/CauseMelts(datum/source, datum/abnormality/abno_datum, worked) + var/meltdown_text = "Horrible screeches have caused a disturbance in the containment zones of the following abnormalities:" + var/meltdown_sound = pick("sound/abnormalities/distortedform/screech3.ogg","sound/abnormalities/distortedform/screech4.ogg") + var/player_count = 0 + for(var/mob/player in GLOB.player_list) + if(isliving(player) && (player.mind?.assigned_role in GLOB.security_positions)) + player_count += 1.5 + player_count = round(player_count) + (player_count > round(player_count) ? TRUE : FALSE) // Trying to round up + meltdowns = SSlobotomy_corp.InitiateMeltdown(clamp(rand(player_count*0.5, player_count), 1, 10), TRUE, MELTDOWN_BLACK, 45, 60, meltdown_text, meltdown_sound) + for(var/obj/machinery/computer/abnormality/A in meltdowns) // TODO: Figure out a way to exclude it entirely from melts so it doesn't breach itself. + if(A == datum_reference.console) // TODO: This shouldn't be neccessary when I fix the above comment + continue + RegisterSignal(A, COMSIG_MELTDOWN_FINISHED, .proc/SpecialMeltFinish) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/SpecialMeltFinish(datum/source, datum/abnormality/abno_datum, worked) + SIGNAL_HANDLER + if(!LAZYLEN(meltdowns)) + return + meltdowns -= source + UnregisterSignal(source, COMSIG_MELTDOWN_FINISHED) + var/list/breaching_list = shuffle(GLOB.abnormality_mob_list) + if(!worked) + for(var/mob/living/simple_animal/hostile/abnormality/A in breaching_list) + if(A.datum_reference.qliphoth_meter > 0 && A.IsContained() && A.z == z) + A.datum_reference.qliphoth_change(-200) + return + +//Breach +/mob/living/simple_animal/hostile/abnormality/distortedform/BreachEffect(mob/living/carbon/human/user) + . = ..() + if(breached) + return + breached = TRUE + if(transformed) + UnTransform(TRUE) + UnregisterSignal(SSdcs, COMSIG_GLOB_MELTDOWN_FINISHED) + sound_to_playing_players_on_level("sound/abnormalities/distortedform/screech1.ogg", 85, zlevel = z) + for(var/mob/M in GLOB.player_list) + if(isnewplayer(M)) + continue + var/check_z = M.z + if(isatom(M.loc)) + check_z = M.loc.z // So it plays even when you are in a locker/sleeper + if((check_z == z) && M.client) + to_chat(M, "Horrifying screams come from out of the darkness!") + flash_color(M, flash_color = COLOR_ALMOST_BLACK, flash_time = 80) + if(M.stat != DEAD && ishuman(M) && M.ckey) + survivors += M + can_act = FALSE + addtimer(CALLBACK(src, .proc/GoActive), 50) + addtimer(CALLBACK(src, .proc/BreachAudioFX), 45) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/GoActive(mob/living/carbon/human/user) + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/BreachAudioFX(mob/living/carbon/human/user) + sound_to_playing_players_on_level("sound/abnormalities/distortedform/screech2.ogg", 85, zlevel = z) + +/mob/living/simple_animal/hostile/abnormality/distortedform/death(gibbed) + if(changed) + ChangeForm() + can_act = FALSE + icon_state = icon_dead + icon = 'ModularTegustation/Teguicons/32x32.dmi' + desc = "A gross, pathetic looking thing that was once a terrible monster." + pixel_x = 0 + base_pixel_x = 0 + pixel_y = 0 + base_pixel_y = 0 + density = FALSE + playsound(src, 'sound/abnormalities/doomsdaycalendar/Limbus_Dead_Generic.ogg', 60, 1) + animate(src, transform = matrix()*0.6,time = 0) + for(var/mob/living/carbon/human/survivor in survivors) + if(survivor.stat == DEAD || !survivor.ckey) + continue + survivor.Apply_Gift(new /datum/ego_gifts/fervor) + survivor.playsound_local(get_turf(survivor), 'sound/weapons/black_silence/snap.ogg', 50) + to_chat(survivor, "The screams subside - you recieve a gift!") + animate(src, alpha = 0, time = 10 SECONDS) + QDEL_IN(src, 10 SECONDS) + new /obj/item/ego_weapon/shield/distortion(get_turf(src)) + ..() + +/mob/living/simple_animal/hostile/abnormality/distortedform/Move() + if(!can_move || !can_act) + return FALSE + if(name == "Nothing There") + playsound(get_turf(src), 'sound/abnormalities/nothingthere/walk.ogg', 50, 0, 3) + return ..() + +/mob/living/simple_animal/hostile/abnormality/distortedform/Moved() + . = ..() + MoveVFX() + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/MoveVFX() + set waitfor = FALSE + var/obj/viscon_filtereffect/distortedform_trail/trail = new(src.loc,themob = src, waittime = 5) + trail.vis_contents += src + trail.filters += filter(type="drop_shadow", x=0, y=0, size=3, offset=2, color=rgb(0, 250, 229)) + trail.filters += filter(type = "blur", size = 3) + animate(trail, alpha=120) + animate(alpha = 0, time = 10) + +/mob/living/simple_animal/hostile/abnormality/distortedform/Life() + . = ..() + if(!.) // Dead + return FALSE + if(status_flags & GODMODE) + return + if(!can_act) //Don't transform mid-attack + return + if(transform_cooldown > world.time) + return + if(changed && (transform_count >= 3)) //change back into our base form + transform_count = 0 + ChangeForm() + return + var/punishment = TRUE + var/transform_target + for(var/mob/living/L in livinginrange(15, src)) + if(L.z != z) + continue + if(faction_check_mob(L)) + continue + if((L.stat == DEAD) || (L.status_flags & GODMODE)) + continue + punishment = FALSE + break + if(punishment && !jump_ready) //No one is within 15 tiles? Let's just snipe players instead! + transform_target = pick(transform_list_longrange) + jump_ready = TRUE + else if (jump_ready) + transform_target = "Jump" + jump_ready = FALSE + else + transform_target = pick(transform_list) + if(prob(1)) + transform_target = "Pause" + ChangeForm(transform_target) + transform_count += 1 + +//Attacks +/mob/living/simple_animal/hostile/abnormality/distortedform/CanAttack(atom/the_target) + if(!can_attack || !can_act) + return FALSE + return ..() + +/mob/living/simple_animal/hostile/abnormality/distortedform/OpenFire() + if(!can_act) + return + if(special_attack_cooldown > world.time) + return + if(special_attack) + if(target) + call(src, special_attack)(target) + else + call(src, special_attack)() + return + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeForm(form) + new /obj/effect/temp_visual/distortedform_shift(get_turf(src)) + TurnNormal() //reset offsets/icon/resistances + clear_filters() + vis_contents.Cut() + current_effect = null + SLEEP_CHECK_DEATH(1) + if(!form) + TurnNormal(TRUE) + changed = FALSE + return + switch(form) + if("Nothing There") + ChangeNT() + if("Puss in Boots") + ChangeCat() + if("Crumbling Armor") + ChangeArmor() + if("Hammer of Light") + ChangeHammer() + if("Halberd Apostle") + ChangeApostle() + if("Red Queen") + ChangeQueen() + if("Blubbering Toad") + ChangeToad() + if("Bloodbath") + ChangeBloodBath() + if("Doomsday Calendar") + ChangeCalander() + if("Blue Star") + ChangeStar() + if("Der Freischutz") + ChangeDer() + if("Apocalypse bird") + ChangeApoc() + if("Jump") + ReadyJump() + if("Pause") // Unused for now + Pause() + changed = TRUE + DFApplyFilters() + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFApplyFilters() +//Filter stuff - Generates a randomized displacement of the icon's sprites + var/icon/filter_icon = new(icon, icon_state) + var/newcolor = pick(COLOR_RED, COLOR_BLUE, COLOR_YELLOW, COLOR_GREEN, COLOR_PURPLE, COLOR_ORANGE) + filter_icon.Blend(newcolor,ICON_MULTIPLY) + filters += filter(type="displace", size=3, icon=filter_icon, render_source = src) + alpha = rand(150,255) + qdel(filter_icon) + current_effect = new() //Visual contents - An animation underlay for the icon + current_effect.icon = icon + current_effect.icon_state = icon_state + current_effect.vis_flags |= VIS_UNDERLAY + src.vis_contents += current_effect + current_effect.render_target = "displace" + var/size = rand(-5,5) + var/size_end = rand(-10,10) + current_effect.color = rgb(rand(120,255), rand(120,255), rand(120,255), rand(120,160)) + current_effect.filters += filter(type="displace", size=rand(5,10), render_source="displace") + var/f1 = current_effect.filters[current_effect.filters.len] + animate(f1, size = size,time=10,loop=-1) + animate(size = size_end, time=10) + update_icon() + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/TurnNormal(newicon) //We'll use the variable to see if this is just an icon update or an actual transformation + name = "Distorted Form" + desc = "A manmade horror beyond description." + icon = 'ModularTegustation/Teguicons/128x128.dmi' + icon_state = null // We can change this into a between-frame for transformation when I have one + pixel_x = initial(pixel_x) + base_pixel_x = initial(base_pixel_x) + pixel_y = initial(pixel_y) + base_pixel_y = initial(base_pixel_y) + attack_verb_continuous = "attacks" + attack_verb_simple = "attack" + attack_sound = 'sound/abnormalities/distortedform/slam.ogg' + melee_damage_type = RED_DAMAGE + ChangeResistances(list(RED_DAMAGE = 0.4, WHITE_DAMAGE = 0.4, BLACK_DAMAGE = 0.4, PALE_DAMAGE = 0.8)) + melee_damage_lower = 55 + melee_damage_upper = 65 + rapid_melee = 1 + can_move = FALSE + can_attack = TRUE + special_attack = null + alpha = 255 + color = null + update_icon() + if(!newicon) + return + icon_state = icon_living + addtimer(CALLBACK(src, .proc/DFScreech), 10) + addtimer(CALLBACK(src, .proc/DFAttack), 60) //We call DFAttack() which picks one of four attacks + transform_cooldown = transform_cooldown_time + world.time + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFScreech() + if(!can_act) + return + playsound(src, "sound/abnormalities/distortedform/screech4.ogg", 75, FALSE, 8) + for(var/i = 1 to 8) + new /obj/effect/temp_visual/fragment_song(get_turf(src)) + for(var/mob/living/L in view(8, src)) + if(faction_check_mob(L, FALSE)) + continue + if(L.stat == DEAD) + continue + L.apply_damage(5, WHITE_DAMAGE, null, L.run_armor_check(null, WHITE_DAMAGE), spread_damage = TRUE) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFAttack() + if(!can_act) + return + if(!target) + for(var/mob/living/L in livinginrange(10, src)) + if(L.z != z || (L.status_flags & GODMODE)) + continue + if(faction_check_mob(L, FALSE)) + continue + target = L + break + if(!target || !ishuman(target) || QDELETED(target)) + if(prob(50)) + DFDonut() //Donut AOE, safe in the middle + else + DFSlam() //Your usual run of the mill AOE + return + if(prob(50)) + DFSpread(target) //Everyone has to stand far away from eachother. or die. + else + DFStack(target) //Everyone has to bunch up together. or die. + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFDonut() + can_act = FALSE + for(var/turf/L in view(10, src)) + if((get_dist(src, L) <= 4)) + continue + new /obj/effect/temp_visual/cult/sparks(L) + playsound(get_turf(src), 'sound/abnormalities/armyinblack/black_attack.ogg', 50, 0, 5) + SLEEP_CHECK_DEATH(10) + for(var/turf/T in view(10, src)) + if((get_dist(src, T) <= 4)) + continue + new /obj/effect/temp_visual/small_smoke/halfsecond(T) + for(var/mob/living/carbon/human/H in HurtInTurf(T, list(), 150, WHITE_DAMAGE, null, null, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)) + if(H.health <= 0) + H.gib() + playsound(get_turf(src), 'ModularTegustation/Tegusounds/claw/prepare.ogg', 50, 0, 5) + SLEEP_CHECK_DEATH(3) + can_act = TRUE + transform_cooldown = world.time + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFSlam() + can_act = FALSE + for(var/turf/L in view(4, src)) + new /obj/effect/temp_visual/cult/sparks(L) + playsound(get_turf(src), 'sound/abnormalities/apocalypse/pre_attack.ogg', 50, 0, 5) // todo: find a better sfx set + SLEEP_CHECK_DEATH(10) + for(var/turf/T in view(4, src)) + var/obj/effect/temp_visual/smash_effect/bloodeffect = new(T) + bloodeffect.color = "#b52e19" + for(var/mob/living/carbon/human/H in HurtInTurf(T, list(), 150, RED_DAMAGE, null, null, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)) + if(H.sanity_lost) + H.gib() + playsound(get_turf(src), 'sound/abnormalities/apocalypse/slam.ogg', 50, 0, 5) + SLEEP_CHECK_DEATH(3) + can_act = TRUE + transform_cooldown = world.time + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFSpread(mob/living/carbon/human/target) + if(!isliving(target)) + DFDonut() + return + can_act = FALSE + playsound(src, 'sound/abnormalities/ichthys/charge.ogg', 75, 1) + face_atom(target) + var/list/potential_targets = list() + var/list/chosen_targets = list() + var/mob/living/Y + potential_targets += target + for(var/mob/living/L in view(10, src)) + if(faction_check_mob(L, FALSE) || L.stat >= HARD_CRIT || z != L.z || (L.status_flags & GODMODE)) // Dead or in hard crit, insane, or on a different Z level. + continue + if(L == target) + continue + potential_targets += L + if((LAZYLEN(potential_targets)) > 5) + break + for(var/i = LAZYLEN(potential_targets), i >= 1, i--) + if(potential_targets.len <= 0) + break + Y = pick(potential_targets) + potential_targets -= Y + if(Y.stat == DEAD) //they chose to die instead of facing the fear + continue + Y.add_overlay(icon('icons/effects/effects.dmi', "spreadwarning")) + addtimer(CALLBACK(Y, .atom/proc/cut_overlay, \ + icon('icons/effects/effects.dmi', "spreadwarning")), 45) + chosen_targets += Y + SLEEP_CHECK_DEATH(50) + for(var/i = LAZYLEN(chosen_targets), i >= 1, i--) + if(chosen_targets.len <= 0) + break + Y = pick(chosen_targets) + chosen_targets -= Y + if(Y.stat == DEAD) //they chose to die instead of facing the fear + continue + DFSpreadAttack(Y) + can_act = TRUE + transform_cooldown = world.time + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFSpreadAttack(mob/living/carbon/human/target) + playsound(target, 'sound/abnormalities/bloodbath/Bloodbath_EyeOn.ogg', 80, FALSE, -3) + new /obj/effect/gibspawner/generic/silent/wrath_acid(get_turf(target)) + for(var/turf/T in range(1, target)) + new /obj/effect/temp_visual/mustardgas(T) + var/list/target_list = list() + for(var/mob/living/L in livinginrange(1, target)) + if(L.z != z || (L.status_flags & GODMODE)) + continue + if(faction_check_mob(L, FALSE)) + continue + L.apply_damage(20, BLACK_DAMAGE, null, target.run_armor_check(null, BLACK_DAMAGE)) + if(target == L) + continue + target_list += L + + if(LAZYLEN(target_list)) + target_list += target + for(var/mob/living/L in target_list) + L.apply_damage(300, BLACK_DAMAGE, null, target.run_armor_check(null, BLACK_DAMAGE)) //You - you are probably going to die! + if(L.health < 0) + L.gib() //maybe someday we'll have a cool acid melting animation for this + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DFStack(mob/living/carbon/human/target) + if((!isliving(target)) || (!(target in view(src, 10)))) + DFSlam() + return + can_act = FALSE + playsound(target, 'sound/abnormalities/fairy_longlegs/attack.ogg', 50, FALSE) + face_atom(target) + target.Immobilize(55) + if(target.sanity_lost) + target.Stun(55) //Immobilize does not stop AI controllers from moving, for some reason. + target.add_overlay(icon('icons/effects/effects.dmi', "distortedgrab")) + addtimer(CALLBACK(target, .atom/proc/cut_overlay, \ + icon('icons/effects/effects.dmi', "distortedgrab")), 50) + if(get_dist(src, target) > 3) + var/list/all_turfs = RANGE_TURFS(1, src) //We need to grab the player, but also have them be visible. + for(var/turf/T in all_turfs) + if(T == get_turf(src)) + continue + if(get_dir(src,T) == NORTH) //directly north is icky, blocks view. + continue + var/list/target_line = getline(T, src) + var/available_turf + for(var/turf/line_turf in target_line) + if(line_turf.is_blocked_turf(exclude_mobs = TRUE)) + available_turf = FALSE + break + available_turf = TRUE + if(!available_turf) + continue + target.forceMove(T) + break + SLEEP_CHECK_DEATH(5) + new/obj/effect/temp_visual/distortedwarning(get_turf(target)) + playsound(src, 'sound/abnormalities/crying_children/sorrow_charge.ogg', 50, FALSE, 5) + SLEEP_CHECK_DEATH(50) + playsound(target, 'sound/abnormalities/crying_children/sorrow_shot.ogg', 50, FALSE) + new /obj/effect/temp_visual/beam_in_giant(get_turf(target)) + var/list/target_list = list() + for(var/mob/living/L in livinginrange(2, target)) + if(L.z != z || (L.status_flags & GODMODE)) + continue + if(faction_check_mob(L, FALSE)) + continue + if(target == L) + continue + target_list += L + + if(LAZYLEN(target_list)) + target_list += target + var/total_damage = 30 //There will very rarely be over 2 people in the stack + var/new_damage = total_damage / (target_list.len) + for(var/mob/living/L in target_list) + L.apply_damage(new_damage, PALE_DAMAGE, null, target.run_armor_check(null, PALE_DAMAGE)) + if(L.health < 0) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + H.dust() + else + L.gib() + else + target.apply_damage(250, PALE_DAMAGE, null, target.run_armor_check(null, PALE_DAMAGE)) //You - you are probably going to die! + if(target.health < 0) + target.dust() + can_act = TRUE + transform_cooldown = world.time + +//Nothing There +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeNT() + transform_cooldown = transform_cooldown_time_long + world.time + name = "Nothing There" + desc = "A wicked creature that consists of various human body parts and organs." + icon = 'ModularTegustation/Teguicons/64x96.dmi' + icon_state = "nothing" + pixel_x = -16 + base_pixel_x = -16 + attack_verb_continuous = "strikes" + attack_verb_simple = "strike" + attack_sound = 'sound/abnormalities/nothingthere/attack.ogg' + ChangeResistances(list(RED_DAMAGE = 0, WHITE_DAMAGE = 0.4, BLACK_DAMAGE = 0.4, PALE_DAMAGE = 0.8)) + melee_damage_lower = 65 + melee_damage_upper = 75 + move_to_delay = 4.5 + UpdateSpeed() + can_move = TRUE + addtimer(CALLBACK(src, .proc/Goodbye), 30) + special_attack = .proc/Hello + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/Goodbye() + if(!can_act) + return + can_act = FALSE + playsound(get_turf(src), 'sound/abnormalities/nothingthere/goodbye_cast.ogg', 75, FALSE, 5) + icon_state = "nothing_blade" + SLEEP_CHECK_DEATH(8) + for(var/turf/T in view(2, src)) + new /obj/effect/temp_visual/nt_goodbye(T) + for(var/mob/living/L in HurtInTurf(T, list(), 500, RED_DAMAGE, null, null, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE)) + if(L.health < 0) + L.gib() + playsound(get_turf(src), 'sound/abnormalities/nothingthere/goodbye_attack.ogg', 75, FALSE, 7) + SLEEP_CHECK_DEATH(3) + icon_state = "nothing" + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/Hello(target) + if(!can_act) + return + if(!target) + return + special_attack_cooldown = world.time + 6 SECONDS + can_act = FALSE + face_atom(target) + playsound(get_turf(src), 'sound/abnormalities/nothingthere/hello_cast.ogg', 75, FALSE, 3) + icon_state = "nothing_ranged" + var/turf/target_turf = get_turf(target) + for(var/i = 1 to 3) + target_turf = get_step(target_turf, get_dir(get_turf(src), target_turf)) + // Close range gives you more time to dodge + var/hello_delay = (get_dist(src, target) <= 2) ? (1 SECONDS) : (0.5 SECONDS) + SLEEP_CHECK_DEATH(hello_delay) + var/list/been_hit = list() + var/broken = FALSE + for(var/turf/T in getline(get_turf(src), target_turf)) + if(T.density) + if(broken) + break + broken = TRUE + for(var/turf/TF in range(1, T)) // AAAAAAAAAAAAAAAAAAAAAAA + if(TF.density) + continue + new /obj/effect/temp_visual/smash_effect(TF) + been_hit = HurtInTurf(TF, been_hit, 120, RED_DAMAGE, null, null, TRUE, FALSE, TRUE, TRUE) + for(var/mob/living/L in been_hit) + if(L.health < 0) + L.gib() + playsound(get_turf(src), 'sound/abnormalities/nothingthere/hello_bam.ogg', 100, 0, 7) + playsound(get_turf(src), 'sound/abnormalities/nothingthere/hello_clash.ogg', 75, 0, 3) + icon_state = "nothing" + can_act = TRUE + +//Puss in Boots +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeCat() + transform_cooldown = transform_cooldown_time_long + world.time + name = "Puss in Boots" + desc = "A scraggly looking black cat, it seems like the boots are missing." + icon = 'ModularTegustation/Teguicons/tegumobs.dmi' + icon_state = "cat_breached" + pixel_x = 0 + base_pixel_x = 0 + attack_sound = 'sound/weapons/ego/rapier1.ogg' + melee_damage_lower = 17 + melee_damage_upper = 25 + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" + rapid_melee = 4 + move_to_delay = 2.5 + UpdateSpeed() + can_move = TRUE + can_attack = TRUE + special_attack = .proc/Execute + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/Execute(target) //Puss in boots execute but it hits up to 5 people with 300 pale. Youch! + if(!can_act) + return + if(!isliving(target)) + return + special_attack_cooldown = world.time + 10 SECONDS + can_act = FALSE + playsound(src, 'sound/abnormalities/crumbling/warning.ogg', 50, 1) + face_atom(target) + var/list/potential_targets = list() + var/list/chosen_targets = list() + var/mob/living/Y + potential_targets += target + for(var/mob/living/L in view(10, src)) + if(faction_check_mob(L, FALSE) || L.stat >= HARD_CRIT || z != L.z || (L.status_flags & GODMODE)) // Dead or in hard crit, insane, or on a different Z level. + continue + if(L == target) + continue + potential_targets += L + if((LAZYLEN(potential_targets)) > 5) + break + for(var/i = LAZYLEN(potential_targets), i >= 1, i--) + if(potential_targets.len <= 0) + break + Y = pick(potential_targets) + potential_targets -= Y + if(Y.stat == DEAD) //they chose to die instead of facing the fear + continue + Y.add_overlay(icon('icons/effects/effects.dmi', "zorowarning")) + addtimer(CALLBACK(Y, .atom/proc/cut_overlay, \ + icon('icons/effects/effects.dmi', "zorowarning")), 40) + chosen_targets += Y + SLEEP_CHECK_DEATH(35) + for(var/i = LAZYLEN(chosen_targets), i >= 1, i--) + if(chosen_targets.len <= 0) + break + Y = pick(chosen_targets) + chosen_targets -= Y + if(Y.stat == DEAD) //they chose to die instead of facing the fear + continue + if(!(Y in view(src, 8))) + continue + var/turf/jump_turf = get_step(Y, pick(GLOB.alldirs)) + if(jump_turf.is_blocked_turf(exclude_mobs = TRUE)) + jump_turf = get_turf(Y) + Y.add_overlay(icon('icons/effects/effects.dmi', "zoro")) + addtimer(CALLBACK(Y, .atom/proc/cut_overlay, \ + icon('icons/effects/effects.dmi', "zoro")), 14) + playsound(Y, 'sound/abnormalities/pussinboots/slash.ogg', 50, FALSE, 2) + forceMove(jump_turf) + if(ishuman(Y)) + var/mob/living/carbon/human/H = Y + H.Stun(9) + SLEEP_CHECK_DEATH(3) + playsound(Y, 'sound/abnormalities/pussinboots/counterslash.ogg', 50, FALSE, 2) + SLEEP_CHECK_DEATH(6) + playsound(Y, 'sound/abnormalities/crumbling/attack.ogg', 50, TRUE) + Finisher(Y) + can_act = TRUE + icon_state = "cat_breached" + transform_cooldown = world.time + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/Finisher(mob/living/target) + to_chat(target,"[src] is trying to cut you in half!") + if(!ishuman(target)) + target.apply_damage(150, PALE_DAMAGE, null, target.run_armor_check(null, PALE_DAMAGE)) //bit more than usual DPS in pale damage + return + target.apply_damage(500, RED_DAMAGE, null, target.run_armor_check(null, RED_DAMAGE)) //You are probably going to die! + if(target.health > 0) + return + var/mob/living/carbon/human/H = target + new /obj/effect/temp_visual/human_horizontal_bisect(get_turf(H)) + H.set_lying_angle(360) //gunk code I know, but it is the simplest way to override gib_animation() without touching other code. Also looks smoother. + H.gib() + +//Crumbling Armor +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeArmor() + transform_cooldown = transform_cooldown_time_short + world.time + name = "Crumbling Armor" + desc = "A thoroughly aged suit of samurai style armor with a V shaped crest on the helmet. It appears desuetude." + icon = 'ModularTegustation/Teguicons/32x48.dmi' + icon_state = "crumbling" + ChangeResistances(list(RED_DAMAGE = 0.2, WHITE_DAMAGE = 0.5, BLACK_DAMAGE = 0.5, PALE_DAMAGE = 0.2)) + pixel_x = 0 + base_pixel_x = 0 + can_move = FALSE + can_attack = FALSE + addtimer(CALLBACK(src, .proc/CrumblingArmorAttack), 20) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/CrumblingArmorAttack() + for(var/mob/living/L in livinginrange(10, src)) + if(L.z != z || (L.status_flags & GODMODE)) + continue + if(faction_check_mob(L, FALSE)) + continue + if(!ishuman(L)) + playsound(get_turf(L), 'sound/abnormalities/crumbling/attack.ogg', 50, FALSE) + L.apply_damage(50, PALE_DAMAGE, null, L.run_armor_check(null, PALE_DAMAGE), spread_damage = TRUE) + new /obj/effect/temp_visual/slice(get_turf(L)) + else + var/mob/living/carbon/human/H = L + playsound(get_turf(H), 'sound/abnormalities/crumbling/warning.ogg', 50, FALSE, -3) + to_chat(H, "Show me that you can stand your ground!") + new /obj/effect/temp_visual/markedfordeath(get_turf(H)) + H.apply_status_effect(/datum/status_effect/cowardice) + var/datum/status_effect/cowardice/C = H.has_status_effect(/datum/status_effect/cowardice) + C.punishment_damage = 60 + +//Hammer of Light +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeHammer() + transform_cooldown = transform_cooldown_time_short + world.time + name = "Hammer of Light" + desc = "A white specter carrying a white hammer engraved with yellow runic writing." + icon = 'ModularTegustation/Teguicons/64x96.dmi' + icon_state = "hammer_distorted" + ChangeResistances(list(RED_DAMAGE = 0.3, WHITE_DAMAGE = 0.5, BLACK_DAMAGE = 0.5, PALE_DAMAGE = 0)) + pixel_x = -16 + base_pixel_x = -16 + can_attack = FALSE + can_move = FALSE + can_act = FALSE //we stay transformed until the attack finishes firing + playsound(get_turf(src), 'sound/abnormalities/lighthammer/chain.ogg', 75, FALSE, 7) + addtimer(CALLBACK(src, .proc/HammerOfLightAttack), 20) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/HammerOfLightAttack() + playsound(src, 'sound/abnormalities/crying_children/sorrow_shot.ogg', 50, FALSE, 7) + var/targetAmount = 0 + for(var/mob/living/L in livinginrange(10, src)) + if(L.z != z || (L.status_flags & GODMODE)) + continue + if(faction_check_mob(L, FALSE)) + continue + if (targetAmount <= 5) + ++targetAmount + if(!ishuman(L)) + new /obj/effect/temp_visual/beam_in(get_turf(L)) + L.apply_damage(60, PALE_DAMAGE, null, L.run_armor_check(null, PALE_DAMAGE), spread_damage = TRUE) + if(L.health < 0) + L.gib() + else + var/obj/effect/lightbolt/light = new /obj/effect/lightbolt(get_turf(L))//do this for the # of targets + 1 + light.target = L + targetAmount = 0 + can_act = TRUE + +/obj/effect/lightbolt //lightbolt objects + name = "light bolt" + desc = "LOOK OUT!" + icon = 'icons/effects/effects.dmi' + icon_state = "lightwarning" + move_force = INFINITY + pull_force = INFINITY + generic_canpass = FALSE + movement_type = PHASING | FLYING + layer = POINT_LAYER //Sprite should always be visible + var/boom_damage = 50 + var/mob/living/carbon/human/target + var/times_hit = 0 + +/obj/effect/lightbolt/Initialize() + . = ..() + addtimer(CALLBACK(src, .proc/explode), 2 SECONDS) + +/obj/effect/lightbolt/proc/explode() + playsound(get_turf(src), 'sound/abnormalities/thunderbird/tbird_bolt.ogg', 50, FALSE, -3) + for(var/mob/living/carbon/human/H in view(1, src)) + H.apply_damage(boom_damage, PALE_DAMAGE, null, H.run_armor_check(null, PALE_DAMAGE), spread_damage = TRUE) + if(H.health < 0) + H.dust() + new /obj/effect/temp_visual/beam_in(get_turf(src)) + times_hit ++ + if(times_hit >= 3) + qdel(src) + return + if(target) //not movable so we cannot forcemove() + var/obj/effect/lightbolt/light = new /obj/effect/lightbolt(get_turf(target)) + light.target = target + light.times_hit = times_hit + qdel(src) + +//White Night Apostle +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeApostle() + transform_cooldown = transform_cooldown_time_long + world.time + name = "Halberd Apostle" + desc = "A disformed human wielding a halberd." + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" + attack_sound = 'sound/abnormalities/whitenight/scythe.ogg' + icon_state = "apostle_halberd" + icon = 'ModularTegustation/Teguicons/48x64.dmi' + ChangeResistances(list(RED_DAMAGE = 0.4, WHITE_DAMAGE = 0.4, BLACK_DAMAGE = 0.8, PALE_DAMAGE = 0.4)) + melee_damage_type = PALE_DAMAGE + melee_damage_lower = 25 + melee_damage_upper = 30 + pixel_x = -8 + base_pixel_x = -8 + move_to_delay = 5 + can_move = TRUE + special_attack = .proc/SpearAttack + addtimer(CALLBACK(src, .proc/ScytheAttack), 30) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ScytheAttack() + if(!can_act) + return + can_act = FALSE + for(var/turf/T in view(3, src)) + new /obj/effect/temp_visual/cult/sparks(T) + SLEEP_CHECK_DEATH(10) + var/gibbed = FALSE + for(var/turf/T in view(3, src)) + new /obj/effect/temp_visual/smash_effect(T) + for(var/mob/living/L in T) // Does not gib pre-dead bodies, only living ones. + if(L.stat == DEAD) + continue + if(faction_check_mob(L)) + continue + L.apply_damage(150, PALE_DAMAGE, null, L.run_armor_check(null, PALE_DAMAGE), spread_damage = TRUE) + if(L.stat == DEAD) + for(var/i = 1 to 5) // Eventually turn this into a horizontal bisect. That would be cool. + new /obj/effect/temp_visual/dir_setting/bloodsplatter(get_turf(L), pick(GLOB.alldirs)) + new /obj/effect/gibspawner/generic/silent(get_turf(L)) + gibbed = TRUE + playsound(get_turf(src), (gibbed ? 'sound/abnormalities/whitenight/scythe_gib.ogg' : 'sound/abnormalities/whitenight/scythe_spell.ogg'), (gibbed ? 100 : 75), FALSE, (gibbed ? 12 : 5)) + SLEEP_CHECK_DEATH(5) + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/SpearAttack(target) + can_act = FALSE + var/dir_to_target = get_dir(src, target) + var/turf/T = get_turf(src) + for(var/i = 1 to 50) + T = get_step(T, dir_to_target) + if(T.density) + if(i < 4) // Mob attempted to dash into a wall too close, stop it + can_act = TRUE + return + break + new /obj/effect/temp_visual/cult/sparks(T) + special_attack_cooldown = world.time + 10 SECONDS + playsound(get_turf(src), 'sound/abnormalities/whitenight/spear_charge.ogg', 75, FALSE, 5) + SLEEP_CHECK_DEATH(22) + been_hit = list() + playsound(get_turf(src), 'sound/abnormalities/whitenight/spear_dash.ogg', 100, FALSE, 20) + do_dash(dir_to_target, 0) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/do_dash(move_dir, times_ran) + var/stop_charge = FALSE + if(times_ran >= 50) + stop_charge = TRUE + var/turf/T = get_step(get_turf(src), move_dir) + if(!T) + transform_cooldown += 1 SECONDS + can_act = TRUE + addtimer(CALLBACK(src, .proc/ScytheAttack), 5) + return + if(T.density) + stop_charge = TRUE + for(var/obj/structure/window/W in T.contents) + W.obj_destruction("holy spear") + for(var/obj/machinery/door/D in T.contents) + if(D.density) + addtimer(CALLBACK (D, .obj/machinery/door/proc/open)) + if(stop_charge) + transform_cooldown += 1 SECONDS + can_act = TRUE + addtimer(CALLBACK(src, .proc/ScytheAttack), 5) + return + forceMove(T) + for(var/turf/TF in view(1, T)) + new /obj/effect/temp_visual/small_smoke/halfsecond(TF) + var/list/new_hits = HurtInTurf(T, been_hit, 250, BLACK_DAMAGE, check_faction = TRUE, hurt_mechs = TRUE, hurt_structure = TRUE) - been_hit + been_hit += new_hits + for(var/mob/living/L in new_hits) + visible_message("[src] runs through [L]!", "You impaled heretic [L]!") + new /obj/effect/temp_visual/cleave(get_turf(L)) + addtimer(CALLBACK(src, .proc/do_dash, move_dir, (times_ran + 1)), 0.5) // SPEED + +//Red Queen +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeQueen() + name = "Red Queen" + desc = "A noble red abnormality sitting in her chair." + icon = 'ModularTegustation/Teguicons/48x64.dmi' + icon_state = "redqueen" + pixel_x = -8 + base_pixel_x = -8 + can_move = FALSE + can_attack = FALSE + can_act = FALSE //we stay transformed until the skill finishes firing + var/target_counter = 0 + for(var/mob/living/L in orange(6, get_turf(src))) + if(faction_check_mob(L, FALSE) || L.stat == DEAD || target_counter >= 2) // Dead or in hard crit, insane, or on a different Z level. + continue + if(L.status_flags & GODMODE) //no aiming for cleanbots + continue + QueenAttack(L) + target_counter += 1 + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/QueenAttack(target) + set waitfor = FALSE + if(!target) + return + playsound(get_turf(src), 'sound/weapons/fixer/generic/sheath2.ogg', 75, FALSE, 5) + var/turf/target_turf = get_turf(target) + for(var/i = 1 to 3) + target_turf = get_step(target_turf, get_dir(get_turf(src), target_turf)) + // Close range gives you more time to dodge + var/slash_delay = (get_dist(src, target) <= 2) ? (1.5 SECONDS) : (1 SECONDS) + SLEEP_CHECK_DEATH(slash_delay) + var/list/been_hit = list() + var/broken = FALSE + for(var/turf/T in getline(get_turf(src), target_turf)) + if(T.density) + if(broken) + break + broken = TRUE + for(var/turf/TF in range(1, T)) // AAAAAAAAAAAAAAAAAAAAAAA + if(TF.density) + continue + new /obj/effect/temp_visual/smash_effect(TF) + been_hit = HurtInTurf(TF, been_hit, 80, RED_DAMAGE, null, null, TRUE, FALSE, TRUE, TRUE) + for(var/mob/living/L in been_hit) + if(L.health < 0) + if(!ishuman(L)) + L.gib() + else + var/mob/living/carbon/human/H = L + var/obj/item/bodypart/head/head = H.get_bodypart("head") + //OFF WITH HIS HEAD! + if(!istype(head)) + return FALSE + head.dismember() + playsound(get_turf(src), 'sound/weapons/guillotine.ogg', 100, FALSE, 6) + +//Blubbering Toad +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeToad() + transform_cooldown = transform_cooldown_time_long + world.time + name = "Blubbering Toad" + desc = "A giant toad, wailing with tears in its eyes. The tears are thick, like a blue resin. This one seems to be missing an eye." + icon = 'ModularTegustation/Teguicons/64x64.dmi' + icon_state = "blubbering_red" + ChangeResistances(list(RED_DAMAGE = 0.5, WHITE_DAMAGE = 0.3, BLACK_DAMAGE = 0.3, PALE_DAMAGE = 0.8)) + melee_damage_type = BLACK_DAMAGE + pixel_x = -16 + base_pixel_x = -16 + attack_sound = 'sound/abnormalities/blubbering_toad/attack.ogg' + attack_verb_continuous = "mauls" + attack_verb_simple = "maul" + UpdateSpeed() + can_move = TRUE + special_attack = .proc/ToadAttack + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ToadAttack() + if(!can_act) + return + if(!target) + return + var/dist = get_dist(target, src) + if((dist > 2) && (dist < 5)) + TongueAttack(target) + if(dist >= 5) + ToadJump(target) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ToadJump(mob/living/target) + special_attack_cooldown = world.time + 6 SECONDS + can_act = FALSE + animate(src, alpha = 1,pixel_x = 0, pixel_z = 16, time = 0.1 SECONDS) + src.pixel_z = 16 + playsound(src, 'sound/abnormalities/blubbering_toad/windup.ogg', 50, FALSE, 4) + var/turf/target_turf = get_turf(target) + SLEEP_CHECK_DEATH(0.5 SECONDS) + forceMove(target_turf) //look out, someone is rushing you! + animate(src, alpha = 255,pixel_x = 0, pixel_z = -16, time = 0.1 SECONDS) + src.pixel_z = 0 + for(var/turf/T in view(1, src)) + var/obj/effect/temp_visual/small_smoke/halfsecond/FX = new(T) + FX.color = "#0A1172" + for(var/mob/living/L in T) + if(faction_check_mob(L)) + continue + L.apply_damage(50, BLACK_DAMAGE, null, L.run_armor_check(null, BLACK_DAMAGE), spread_damage = TRUE) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.sanity_lost) + H.gib() + playsound(src, 'sound/abnormalities/blubbering_toad/attack.ogg', 50, FALSE, 4) + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/TongueAttack(mob/living/target) + special_attack_cooldown = world.time + 2 SECONDS + can_act = FALSE + var/turf/target_turf = get_turf(target) + var/list/turfs_to_hit = getline(src, target_turf) + var/turf/MT = get_turf(src) + playsound(get_turf(src), "sound/abnormalities/blubbering_toad/tongue.ogg", 100, FALSE) + MT.Beam(target_turf, "tongue", time=5) + icon_state = "blubbering_tongue_red" + for(var/turf/T in turfs_to_hit) + if(T.density) + break + for(var/mob/living/L in T) + if(L.z != z) + continue + if(faction_check_mob(L)) + continue + L.apply_damage(30, BLACK_DAMAGE, null, L.run_armor_check(null, BLACK_DAMAGE), spread_damage = TRUE) + new /obj/effect/temp_visual/dir_setting/bloodsplatter(get_turf(L), pick(GLOB.alldirs)) + if(!L.anchored) + var/whack_speed = (prob(60) ? 1 : 4) + L.throw_at(MT, rand(1, 2), whack_speed, src) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.sanity_lost) + H.gib() + SLEEP_CHECK_DEATH(5) + can_act = TRUE + icon_state = "blubbering_red" + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeBloodBath() + transform_cooldown = transform_cooldown_time_long + world.time + name = "Bloodbath" + desc = "A large humanoid made of blood" + icon = 'ModularTegustation/Teguicons/48x64.dmi' + icon_state = "bloodbath_DF" + ChangeResistances(list(RED_DAMAGE = 0.3, WHITE_DAMAGE = 0.3, BLACK_DAMAGE = 0.5, PALE_DAMAGE = 0.8)) + melee_damage_lower = 65 + melee_damage_upper = 75 + move_to_delay = 4.5 + melee_damage_type = WHITE_DAMAGE + pixel_x = -8 + base_pixel_x = -8 + attack_sound = 'sound/abnormalities/ichthys/slap.ogg' + attack_verb_continuous = "mauls" + attack_verb_simple = "maul" + UpdateSpeed() + can_move = TRUE + addtimer(CALLBACK(src, .proc/BloodBathBeamPrep), 30) + special_attack = .proc/BloodBathSlam + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/BloodBathBeamPrep() + if(!can_act) + return FALSE + can_act = FALSE + var/target_counter = 0 + for(var/mob/living/L in view(10, get_turf(src))) + if(faction_check_mob(L, FALSE) || L.stat == DEAD || target_counter >= 3) // Dead or in hard crit, insane, or on a different Z level. + continue + if(L.status_flags & GODMODE) + continue + BloodBathBeam(L) + target_counter += 1 + SLEEP_CHECK_DEATH(2 SECONDS) //Delay VFX + if(target_counter) + for(var/turf/T in view(1, src)) + var/obj/effect/temp_visual/small_smoke/halfsecond/FX = new(T) + FX.color = "#b52e19" + SLEEP_CHECK_DEATH(2 SECONDS) //Rest after laser beam + icon_state = "bloodbath_DF" + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/BloodBathBeam(target_mob) //Headless Ichthys beam, but lots of them. + set waitfor = FALSE + if(!target_mob) + return FALSE + var/datum/beam/current_beam + icon_state = "bloodbath_slamprepare" + var/turf/target_turf = get_turf(target_mob) + face_atom(target_turf) + var/turf/my_turf = get_turf(src) + playsound(src, "sound/abnormalities/ichthys/charge.ogg", 50, FALSE) + var/turf/TT = get_ranged_target_turf_direct(my_turf, target_turf, 15) + SLEEP_CHECK_DEATH(2 SECONDS) //Chargin' mah lazor + icon_state = "bloodbath_slam" + var/list/target_line = getline(my_turf, TT) //gets a line 15 tiles away + for(var/turf/TF in target_line) //checks if that line has anything in the way, resets TT as the new beam end location + if(TF.density) + TT = TF + break + var/list/hit_line = getline(my_turf, TT) //old target_line is discarded with hit_line which respects walls + for(var/turf/TF in hit_line) //spawns blood effects, separate loop because we only want to do it once + if(TF.density) + break + var/obj/effect/decal/cleanable/blood/B = new(TF) + B.bloodiness = 100 + current_beam = my_turf.Beam(TT, "qoh") + playsound(src, "sound/abnormalities/ichthys/blast.ogg", 50, FALSE) + for(var/h = 1 to 20) //from this point on it's basically the same as queenie's but with balance adjustments + var/list/already_hit = list() + current_beam.visuals.color = COLOR_RED + for(var/turf/TF in hit_line) + if(TF.density) + break + for(var/mob/living/L in range(1, TF)) + if(L.status_flags & GODMODE) + continue + if(L == src) //stop hitting yourself + continue + if(L in already_hit) + continue + if(L.stat == DEAD) + continue + if(faction_check_mob(L)) + continue + already_hit += L + var/truedamage = ishuman(L) ? 25 : 20 //less damage dealt to nonhumans + L.apply_damage(truedamage, BLACK_DAMAGE, null, L.run_armor_check(null, BLACK_DAMAGE)) + SLEEP_CHECK_DEATH(1.71) + QDEL_NULL(current_beam) + SLEEP_CHECK_DEATH(1 SECONDS) //Rest after laser beam + icon_state = "bloodbath_DF" + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/BloodBathSlam()//AOE attack + if(!can_act) + return + special_attack_cooldown = world.time + 3 SECONDS + can_act = FALSE + for(var/turf/L in view(3, src)) + new /obj/effect/temp_visual/cult/sparks(L) + playsound(get_turf(src), 'sound/abnormalities/ichthys/jump.ogg', 100, FALSE, 6) + icon_state = "bloodbath_slamprepare" + SLEEP_CHECK_DEATH(12) + for(var/turf/T in view(3, src)) + var/obj/effect/temp_visual/small_smoke/halfsecond/FX = new(T) + FX.color = "#b52e19" + for(var/mob/living/carbon/human/H in HurtInTurf(T, list(), 350, WHITE_DAMAGE, null, null, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)) + if(H.sanity_lost) + H.gib() + playsound(get_turf(src), 'sound/abnormalities/bloodbath/Bloodbath_EyeOn.ogg', 125, FALSE, 6) + icon_state = "bloodbath_slam" + SLEEP_CHECK_DEATH(3) + icon_state = "bloodbath_DF" + can_act = TRUE + +/* + Long-ranged "Punishment" Transfromations + The farther you are - the less damage it deals. Followed up by a Teleport +*/ +//Doomsday Calander +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeCalander() + transform_cooldown = transform_cooldown_time_short + world.time + name = "Doomsday Calendar" + desc = "Likely a tool for predicting a date of some kind, judging from the many letters carved on the bricks." + icon = 'ModularTegustation/Teguicons/64x64.dmi' + icon_state = "doomsday_charging" + base_pixel_x = -16 + pixel_x = -16 + can_move = FALSE + can_attack = FALSE + addtimer(CALLBACK(src, .proc/CalanderAttack), 5) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/CalanderAttack(faction_check = "hostile") + icon_state = "doomsday_universe" + been_hit = list() + playsound(src, 'sound/abnormalities/doomsdaycalendar/Doomsday_Universe.ogg', 50, FALSE, 50) + var/turf/target_c = get_turf(src) + var/list/turf_list = list() + for(var/i = 1 to 48) + turf_list = spiral_range_turfs(i, target_c) - spiral_range_turfs(i-1, target_c) + for(var/turf/open/T in turf_list) + var/obj/effect/temp_visual/cult/sparks/S = new(T) + S.color = "#003FFF" + for(var/mob/living/L in T) + new /obj/effect/temp_visual/dir_setting/cult/phase(T, L.dir) + addtimer(CALLBACK(src, .proc/CalanderAttackHit, L, i, faction_check)) + SLEEP_CHECK_DEATH(1.5) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/CalanderAttackHit(mob/living/L, attack_range = 1, faction_check = "hostile") + if(L in been_hit) + return + been_hit += L + if(!(faction_check in L.faction)) + playsound(L.loc, 'sound/abnormalities/doomsdaycalendar/Effect_Burn.ogg', 50 - attack_range, TRUE, -1) + var/dealt_damage = max(5, 75 - (attack_range)) + L.apply_damage(dealt_damage, RED_DAMAGE, null, L.run_armor_check(null, RED_DAMAGE), spread_damage = TRUE) + if(ishuman(L) && dealt_damage > 25) + L.emote("scream") + to_chat(L, "IT BURNS!!") + +//Blue Star +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeStar() + transform_cooldown = transform_cooldown_time_short + world.time + name = "Blue Star" + desc = "Floating heart-shaped object. It's alive, and soon you will become one with it." + icon = 'ModularTegustation/Teguicons/96x96.dmi' + icon_state = "blue_star" + pixel_x = -32 + base_pixel_x = -32 + pixel_y = -16 + base_pixel_y = -16 + can_move = FALSE + can_attack = FALSE + addtimer(CALLBACK(src, .proc/BlueStarAttack), 5) + + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/BlueStarAttack() + playsound(src, 'sound/abnormalities/bluestar/pulse.ogg', 100, FALSE, 40, falloff_distance = 10) + var/matrix/init_transform = transform + animate(src, transform = transform*1.5, time = 3, easing = BACK_EASING|EASE_OUT) + for(var/mob/living/L in livinginrange(48, src)) + if(L.z != z) + continue + if(faction_check_mob(L)) + continue + L.apply_damage((75 - get_dist(src, L)), WHITE_DAMAGE, null, L.run_armor_check(null, WHITE_DAMAGE), spread_damage = TRUE) + flash_color(L, flash_color = COLOR_BLUE_LIGHT, flash_time = 70) + if(!ishuman(L)) + continue + var/mob/living/carbon/human/H = L + if(H.sanity_lost) // TODO: TEMPORARY AS HELL + H.death() + animate(H, transform = H.transform*0.01, time = 5) + QDEL_IN(H, 5) + SLEEP_CHECK_DEATH(3) + animate(src, transform = init_transform, time = 5) + +//Der Freischutz +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeDer() + transform_cooldown = transform_cooldown_time_short + world.time + name = "Der Freischutz" + desc = "A tall man adorned in grey, gold, and regal blue. His aim is impeccable." + icon = 'ModularTegustation/Teguicons/32x64.dmi' + icon_state = "derfreischutz" + addtimer(CALLBACK(src, .proc/DerAttack), 5) + pixel_x = 0 + base_pixel_x = 0 + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/DerAttack(freidir = pick(EAST,WEST)) + icon = 'ModularTegustation/Teguicons/64x64.dmi' + var/list/targets = list() + for(var/mob/M in GLOB.mob_living_list) + if((faction_check_mob(M)) || (src.z != M.z) || (M.stat == DEAD) || (M.status_flags & GODMODE)) + continue + targets += M + if(!LAZYLEN(targets)) + return + var/mob/target = pick(targets) + face_atom(target) + freidir = dir + update_icon() + var/offset = -12 + var/list/portals = list() + var/turf/T = src.loc + var/turf/barrel = locate(T.x + 2, T.y + 1, T.z) + var/turf/tpos = target + if (freidir == EAST) + T = locate(tpos.x - 5, tpos.y, tpos.z) + else if (freidir == WEST) + T = locate(tpos.x + 5, tpos.y, tpos.z) + else if (freidir == SOUTH) + T = locate(tpos.x, tpos.y + 5, tpos.z) + else + T = locate(tpos.x, tpos.y - 5, tpos.z) + playsound(T, 'sound/abnormalities/freischutz/prepare.ogg', 100, FALSE, 20) + playsound(src.loc, 'sound/abnormalities/freischutz/prepare.ogg', 100, FALSE) + for(var/i=1, i<5, i++) + var/obj/effect/frei_magic/P = new(barrel) + P.dir = EAST + P.icon_state = "freicircle[i]" + P.update_icon() + P.pixel_x += offset + portals += P + var/obj/effect/frei_magic/PX = new(T) + PX.dir = freidir + PX.icon_state = "freicircle[i]" + PX.update_icon() + if (freidir == EAST) + PX.pixel_x += offset + else if (freidir == WEST) + PX.pixel_x -= offset + else if (freidir == SOUTH) + PX.pixel_y -= offset + else + PX.pixel_y += offset + offset += 8 + portals += PX + sleep(6) + if(i != 4) + continue + else + var/obj/effect/magic_bullet/B = new(T) + playsound(get_turf(src), 'sound/abnormalities/freischutz/shoot.ogg', 100, FALSE, 20) + B.dir = freidir + addtimer(CALLBACK(B, .obj/effect/magic_bullet/proc/moveBullet), 0.1) + src.icon = 'ModularTegustation/Teguicons/32x64.dmi' + src.update_icon() + for(var/obj/effect/frei_magic/Port in portals) + Port.fade_out() + +//Apocalypse Bird +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ChangeApoc() + transform_cooldown = transform_cooldown_time + world.time + name = "Apocalypse bird" + desc = "A terrifying giant beast that lives in the black forest. It's constantly looking for a monster \ + that terrorizes the forest, without realizing that it is looking for itself." + icon = 'ModularTegustation/Teguicons/224x128.dmi' + icon_state = "apocalypse" + pixel_x = -96 + base_pixel_x = -96 + ChangeResistances(list(RED_DAMAGE = 0, WHITE_DAMAGE = 0, BLACK_DAMAGE = 0, PALE_DAMAGE = 0)) //It is immobile, just run away + can_move = FALSE + can_attack = FALSE + var/LongRange = TRUE //Check if there's anyone within 15 tiles when we transformed + for(var/mob/living/L in livinginrange(15, src)) + if(L.z != z) + continue + if(faction_check_mob(L)) + continue + if((L.stat == DEAD) || (L.status_flags & GODMODE)) + continue + LongRange = FALSE + break + if(LongRange) + addtimer(CALLBACK(src, .proc/ApocJudge), 30) + else + addtimer(CALLBACK(src, .proc/ApocSlam), 30) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ApocSlam() + playsound(src, 'sound/abnormalities/apocalypse/pre_attack.ogg', 125, FALSE, 4) + SLEEP_CHECK_DEATH(1.5 SECONDS) + playsound(src, 'sound/abnormalities/apocalypse/swing.ogg', 125, FALSE, 6) + flick("apocalypse_slam", src) + SLEEP_CHECK_DEATH(4) + playsound(src, 'sound/abnormalities/apocalypse/slam.ogg', 100, FALSE, 12) + visible_message("[src] slams at the floor with its talons!") + // Shake effect + for(var/mob/living/M in livinginrange(20, get_turf(src))) + shake_camera(M, 2, 3) + // Actual stuff + for(var/turf/open/T in view(8, src)) + new /obj/effect/temp_visual/small_smoke(T) + for(var/mob/living/L in livinginview(8, src)) + if(faction_check_mob(L)) + continue + L.apply_damage((300 - (16 * get_dist(src, L))), BLACK_DAMAGE, null, L.run_armor_check(null, BLACK_DAMAGE), spread_damage = TRUE) + SLEEP_CHECK_DEATH(2 SECONDS) + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ApocJudge() + can_act = FALSE + sound_to_playing_players_on_level('sound/abnormalities/apocalypse/judge.ogg', 75, zlevel = z) + icon_state = "apocalypse_judge" + SLEEP_CHECK_DEATH(5 SECONDS) + sound_to_playing_players_on_level('sound/abnormalities/judgementbird/ability.ogg', 75, zlevel = z) + for(var/mob/living/L in GLOB.mob_living_list) + var/check_z = L.z + if(isatom(L.loc)) + check_z = L.loc.z + if(check_z != z) + continue + if(faction_check_mob(L, FALSE)) + continue + if(L.stat == DEAD) + continue + new /obj/effect/temp_visual/judgement(get_turf(L)) + L.apply_damage(max(5, 60 - get_dist(src, L)), PALE_DAMAGE, null, L.run_armor_check(null, PALE_DAMAGE), spread_damage = TRUE) + SLEEP_CHECK_DEATH(1 SECONDS) + icon_state = "apocalypse" + SLEEP_CHECK_DEATH(1 SECONDS) + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/ReadyJump() + var/list/potentialmarked = list() + var/list/marked = list() + var/mob/living/carbon/human/Y + for(var/mob/living/carbon/human/L in GLOB.player_list) + if(faction_check_mob(L, FALSE) || L.stat >= HARD_CRIT || L.sanity_lost || z != L.z) // Dead or in hard crit, insane, or on a different Z level. + continue + potentialmarked += L + var/numbermarked = 1 + round(LAZYLEN(potentialmarked) / 5, 1) //1 + 1 in 5 potential players, to the nearest whole number + for(var/i = numbermarked, i>=1, i--) + if(potentialmarked.len <= 0) + break + Y = pick(potentialmarked) + potentialmarked -= Y + if(Y.stat == DEAD || Y.is_working) + continue + marked+=Y + if(marked.len <= 0) //Oh no, everyone's dead! + ChangeForm("Pause") + return + can_act = FALSE + var/mob/living/carbon/human/final_target = pick(marked) + final_target.apply_status_effect(/datum/status_effect/panicked_lvl_5) + to_chat(final_target, "Look out!") + var/jump_type = pick(transform_list_jump) + playsound(get_turf(src), 'sound/abnormalities/babayaga/charge.ogg', 100, 1) + pixel_z = 128 + alpha = 0 + density = FALSE + var/target_turf = get_turf(final_target) + forceMove(target_turf) //look out, someone is rushing you! + switch(jump_type) + if("Light") + LightJump(target_turf) + if("Medium") + MediumJump(target_turf) + if("Heavy") + HeavyJump(target_turf) + visible_message("[src] drops down from the ceiling!") + density = TRUE + SLEEP_CHECK_DEATH(5) + can_act = TRUE + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/LightJump(turf/target_turf) + name = "Fridge?" + desc = "It refridgerates." + icon = 'ModularTegustation/Teguicons/32x32.dmi' + icon_state = "freezer_fake" + pixel_x = 0 + base_pixel_x = 0 + playsound(target_turf, 'sound/abnormalities/roadhome/Cartoon_Falling_Sound_Effect.ogg', 75, FALSE, -1) + SLEEP_CHECK_DEATH(1 SECONDS) + animate(src, pixel_z = 0, alpha = 255, time = 5) + SLEEP_CHECK_DEATH(5) + playsound(get_turf(src), 'sound/abnormalities/distortedform/metal_impact.ogg', 65, 1) + var/obj/effect/temp_visual/decoy/D = new(get_turf(src), src) + animate(D, alpha = 0, transform = matrix()*2, time = 5) + for(var/turf/T in view(1, src)) + new /obj/effect/temp_visual/small_smoke/halfsecond(T) + for(var/mob/living/carbon/human/H in HurtInTurf(T, list(), 100, RED_DAMAGE, null, null, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)) + if(H.health <= 0) + H.gib() + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/MediumJump(turf/target_turf) + name = "grant us love" + desc = "A dark monolith structure with incomprehensible writing on it." + icon = 'ModularTegustation/Teguicons/48x64.dmi' + icon_state = "violet_noon" + base_pixel_x = -8 + pixel_x = -8 + new /obj/effect/temp_visual/jumpwarning(target_turf) + SLEEP_CHECK_DEATH(5 SECONDS) + animate(src, pixel_z = 0, alpha = 255, time = 7) + SLEEP_CHECK_DEATH(7) + playsound(get_turf(src), 'sound/effects/ordeals/violet/monolith_down.ogg', 65, 1) + var/obj/effect/temp_visual/decoy/D = new(get_turf(src), src) + animate(D, alpha = 0, transform = matrix()*2, time = 5) + for(var/turf/T in view(4, src)) + new /obj/effect/temp_visual/small_smoke/halfsecond(T) + for(var/mob/living/carbon/human/H in HurtInTurf(T, list(), 150, BLACK_DAMAGE, null, null, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)) + if(H.health <= 0) + H.gib() + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/HeavyJump(turf/target_turf) + name = "Baba Yaga" + desc = "A giant house stomping around on an equally large chicken leg." + icon = 'ModularTegustation/Teguicons/96x96.dmi' + icon_state = "babayaga_breach" + pixel_x = -16 + base_pixel_x = -16 + new /obj/effect/temp_visual/giantwarning(target_turf) + SLEEP_CHECK_DEATH(10 SECONDS) + animate(src, pixel_z = 0, alpha = 255, time = 10) + SLEEP_CHECK_DEATH(10) + playsound(get_turf(src), 'sound/abnormalities/babayaga/land.ogg', 100, FALSE, 20) + var/obj/effect/temp_visual/decoy/D = new(get_turf(src), src) + animate(D, alpha = 0, transform = matrix()*2, time = 5) + for(var/turf/open/T in view(3, src)) + new /obj/effect/temp_visual/ice_turf(T) + for(var/turf/open/T in view(8, src)) + new /obj/effect/temp_visual/small_smoke/halfsecond(T) + if(prob(20)) + new /obj/effect/temp_visual/ice_spikes(T) + + for(var/mob/living/L in view(8, src)) + if(faction_check_mob(L, TRUE)) //so it doesn't kill its own minions + continue + var/dist = get_dist(src, L) + if(ishuman(L)) //Different damage formulae for humans vs mobs + L.apply_damage(clamp((15 * (2 ** (8 - dist))), 15, 4000), RED_DAMAGE, null, L.run_armor_check(null, RED_DAMAGE)) //15-3840 damage scaling exponentially with distance + else + L.apply_damage(600 - ((dist > 2 ? dist : 0 )* 75), RED_DAMAGE, null, L.run_armor_check(null, RED_DAMAGE)) //0-600 damage scaling on distance, we don't want it oneshotting mobs + if(L.health < 0) + L.gib() + + +//Miscellaneous random sprites - does nothing. Very low chance. This where you put the silly meme stuff. +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/Pause() + transform_cooldown = transform_cooldown_time_short + world.time + name = "Distorted Form" + desc = "That doesn't look right." + icon = 'ModularTegustation/Teguicons/32x32.dmi' + pixel_x = 0 + base_pixel_x = 0 + can_move = FALSE + can_attack = FALSE + PickForm() + +/mob/living/simple_animal/hostile/abnormality/distortedform/proc/PickForm() + name = pick("bill", "cube", "fairies", "shadow") + icon_state = name + +//Misc Objects +/obj/effect/temp_visual/jumpwarning + name = "stack warning" + desc = "RUN!" + icon = 'icons/effects/effects.dmi' + icon_state = "zorowarning" + randomdir = FALSE + duration = 5 SECONDS + layer = POINT_LAYER //We want this HIGH. SUPER HIGH. We want it so that you can absolutely, guaranteed, see exactly what hit you + +/obj/effect/temp_visual/distortedwarning + name = "stack warning" + desc = "GROUP UP! QUICKLY!" + icon = 'icons/effects/96x96.dmi' + icon_state = "stackwarning" + pixel_x = -32 + base_pixel_x = -32 + pixel_y = -32 + base_pixel_y = -32 + randomdir = FALSE + duration = 5 SECONDS + layer = POINT_LAYER //We want this HIGH. SUPER HIGH. We want it so that you can absolutely, guaranteed, see exactly what hit you + +/obj/effect/temp_visual/beam_in_giant + name = "light beam" + desc = "A beam of light" + icon = 'icons/effects/96x96.dmi' + icon_state = "beamin" + pixel_x = -32 + base_pixel_x = -32 + pixel_y = 16 + base_pixel_y = 16 + randomdir = FALSE + duration = 1 SECONDS + layer = POINT_LAYER + +/obj/effect/temp_visual/beam_in_giant/Initialize(mapload, atom/mimiced_atom) + . = ..() + animate(src, transform = matrix()*1.8, time = 0) + +/obj/viscon_filtereffect/distortedform + name = "Visual Distortion" + render_target = "displace" + appearance_flags = PASS_MOUSE | KEEP_TOGETHER + vis_flags = VIS_INHERIT_ID | VIS_INHERIT_DIR | VIS_UNDERLAY + +/obj/viscon_filtereffect/distortedform_trail + name = "Visual Distortion" + render_target = "displace" + vis_flags = VIS_INHERIT_DIR | VIS_UNDERLAY + +/obj/viscon_filtereffect/distortedform_trail/New(mob/themob, waittime) + set waitfor = FALSE + switch(themob.dir) + if(NORTH) + pixel_y = -24 + if(SOUTH) + pixel_y = 24 + if(WEST) + pixel_x = 24 + if(EAST) + pixel_x = -24 + sleep(waittime) + loc = null + qdel(src) diff --git a/code/modules/mob/living/simple_animal/abnormality/he/pinocchio.dm b/code/modules/mob/living/simple_animal/abnormality/he/pinocchio.dm index 59af98a27006..399834b90ba8 100644 --- a/code/modules/mob/living/simple_animal/abnormality/he/pinocchio.dm +++ b/code/modules/mob/living/simple_animal/abnormality/he/pinocchio.dm @@ -72,8 +72,9 @@ pixel_z = 16 animate(src, alpha = 255,pixel_x = 0, pixel_z = -16, time = 4 SECONDS) pixel_z = 0 - for(var/obj/machinery/computer/abnormality/AC in range(5, src)) //reset console from last breach - AC.updateUsrDialog() + if(!datum_reference?.console) + return + datum_reference.console.updateUsrDialog() //Work/Misc /mob/living/simple_animal/hostile/abnormality/pinocchio/AttemptWork(mob/living/carbon/human/user, work_type) @@ -87,8 +88,7 @@ lying = FALSE datum_reference.qliphoth_change(1) PostWorkEffect() - for(var/obj/machinery/computer/abnormality/AC in range(5, src)) - AC.updateUsrDialog() + datum_reference.console.updateUsrDialog() return else datum_reference.qliphoth_change(-1) diff --git a/code/modules/mob/living/simple_animal/abnormality/teth/crumbling_armor.dm b/code/modules/mob/living/simple_animal/abnormality/teth/crumbling_armor.dm index edfd0025b6ff..f01b5c2f9780 100644 --- a/code/modules/mob/living/simple_animal/abnormality/teth/crumbling_armor.dm +++ b/code/modules/mob/living/simple_animal/abnormality/teth/crumbling_armor.dm @@ -176,6 +176,7 @@ status_type = STATUS_EFFECT_UNIQUE duration = 10 //Lasts 1 second alert_type = /atom/movable/screen/alert/status_effect/cowardice + var/punishment_damage = 25 /atom/movable/screen/alert/status_effect/cowardice name = "Cowardice" @@ -200,7 +201,7 @@ if(!istype(head)) return FALSE playsound(get_turf(H), 'sound/abnormalities/crumbling/attack.ogg', 50, FALSE) - H.apply_damage(25, PALE_DAMAGE, null, H.run_armor_check(null, PALE_DAMAGE), spread_damage = TRUE) + H.apply_damage(punishment_damage, PALE_DAMAGE, null, H.run_armor_check(null, PALE_DAMAGE), spread_damage = TRUE) if(H.health < 0) head.dismember() new /obj/effect/temp_visual/slice(get_turf(H)) diff --git a/code/modules/mob/living/simple_animal/hostile/ordeal/misc.dm b/code/modules/mob/living/simple_animal/hostile/ordeal/misc.dm index 0ced7e3bf002..f7f792efae76 100644 --- a/code/modules/mob/living/simple_animal/hostile/ordeal/misc.dm +++ b/code/modules/mob/living/simple_animal/hostile/ordeal/misc.dm @@ -19,6 +19,7 @@ damage_coeff = list(BRUTE = 1, RED_DAMAGE = 1, WHITE_DAMAGE = 1, BLACK_DAMAGE = 1, PALE_DAMAGE = 1) var/list/blacklist = list(/mob/living/simple_animal/hostile/abnormality/melting_love, + /mob/living/simple_animal/hostile/abnormality/distortedform, /mob/living/simple_animal/hostile/abnormality/white_night, /mob/living/simple_animal/hostile/abnormality/hatred_queen) diff --git a/code/modules/paperwork/records/info/aleph.dm b/code/modules/paperwork/records/info/aleph.dm index dcaf4cdd739e..0122bb2eca84 100644 --- a/code/modules/paperwork/records/info/aleph.dm +++ b/code/modules/paperwork/records/info/aleph.dm @@ -203,3 +203,16 @@ "When the work result was Bad, the Qliphoth Counter decreased.", "When an Abnormality was suppressed, the Qliphoth Counter raised.") +// Distorted Form +/obj/item/paper/fluff/info/aleph/distortedform + abno_type = /mob/living/simple_animal/hostile/abnormality/distortedform + abno_code = "O-06-38" + abno_info = list( + "WARNING: O-06-38 will periodically take on the appearance of another abnormality. The abnormality will reveal its true form when work is attempted.", + "When an employee with Justice 4 or lower finished their work, or work result was a failure, O-06-38 let out a horrifying screech.", + "Other abnormalities became agitated by the screech. The situation needed to be handled as a Qliphoth Meltdown.", + "If agitated abnormalities were not worked on, multiple abnormalities breached simultaneously.", + "When the work result was Good, the Qliphoth Counter increased by 1.", + "When a Qliphoth Meltdown was ignored, the Qliphoth Counter decreased by 1.") + abno_work_damage_type = "All" + abno_breach_damage_type = "Random" diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index a620caa572ce..b683c2aeac0e 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 88b32a0dc450..974ef9151ab1 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/mob/clothing/ego_gear/ego_gifts.dmi b/icons/mob/clothing/ego_gear/ego_gifts.dmi index e5cca5c11034..3d46dacd47f8 100644 Binary files a/icons/mob/clothing/ego_gear/ego_gifts.dmi and b/icons/mob/clothing/ego_gear/ego_gifts.dmi differ diff --git a/icons/obj/computer.dmi b/icons/obj/computer.dmi index bcde3e6a4b42..0af99de7c9d4 100644 Binary files a/icons/obj/computer.dmi and b/icons/obj/computer.dmi differ diff --git a/lobotomy-corp13.dme b/lobotomy-corp13.dme index 85053b0f2410..76c5c967e69f 100644 --- a/lobotomy-corp13.dme +++ b/lobotomy-corp13.dme @@ -2724,6 +2724,7 @@ #include "code\modules\mob\living\simple_animal\abnormality\aleph\blue_star.dm" #include "code\modules\mob\living\simple_animal\abnormality\aleph\censored.dm" #include "code\modules\mob\living\simple_animal\abnormality\aleph\crying_children.dm" +#include "code\modules\mob\living\simple_animal\abnormality\aleph\distortedform.dm" #include "code\modules\mob\living\simple_animal\abnormality\aleph\last_shot.dm" #include "code\modules\mob\living\simple_animal\abnormality\aleph\melting_love.dm" #include "code\modules\mob\living\simple_animal\abnormality\aleph\mountain.dm" diff --git a/sound/abnormalities/distortedform/DF_soundloop.ogg b/sound/abnormalities/distortedform/DF_soundloop.ogg new file mode 100644 index 000000000000..182bdf817d58 Binary files /dev/null and b/sound/abnormalities/distortedform/DF_soundloop.ogg differ diff --git a/sound/abnormalities/distortedform/metal_impact.ogg b/sound/abnormalities/distortedform/metal_impact.ogg new file mode 100644 index 000000000000..8ef7826bf958 Binary files /dev/null and b/sound/abnormalities/distortedform/metal_impact.ogg differ diff --git a/sound/abnormalities/distortedform/screech1.ogg b/sound/abnormalities/distortedform/screech1.ogg new file mode 100644 index 000000000000..a6ab0b11b75c Binary files /dev/null and b/sound/abnormalities/distortedform/screech1.ogg differ diff --git a/sound/abnormalities/distortedform/screech2.ogg b/sound/abnormalities/distortedform/screech2.ogg new file mode 100644 index 000000000000..a62aa057fb16 Binary files /dev/null and b/sound/abnormalities/distortedform/screech2.ogg differ diff --git a/sound/abnormalities/distortedform/screech3.ogg b/sound/abnormalities/distortedform/screech3.ogg new file mode 100644 index 000000000000..70439add3ffe Binary files /dev/null and b/sound/abnormalities/distortedform/screech3.ogg differ diff --git a/sound/abnormalities/distortedform/screech4.ogg b/sound/abnormalities/distortedform/screech4.ogg new file mode 100644 index 000000000000..247249134b7f Binary files /dev/null and b/sound/abnormalities/distortedform/screech4.ogg differ