diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 1077e2fde8a..6c0da65ee44 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -75,7 +75,9 @@
/////////////////////////
- if(istype(M, /mob/living/simple_animal))
+ if(isanimal(M))
+ var/mob/living/simple_animal/S = M
+ S.attacked_by(src, user)
return 0 // No sanic-speed double-attacks for you - simple mobs will handle being attacked on their own
var/power = force
diff --git a/code/controllers/Processes/weather.dm b/code/controllers/Processes/weather.dm
index 6cdcce750b6..d2149371649 100644
--- a/code/controllers/Processes/weather.dm
+++ b/code/controllers/Processes/weather.dm
@@ -33,7 +33,7 @@ var/global/datum/controller/process/weather/weather_master
var/list/possible_weather_for_this_z = list()
for(var/V in existing_weather)
var/datum/weather/WE = V
- if(WE.target_level == Z && WE.probability) //Another check so that it doesn't run extra weather
+ if(WE.target_z == Z && WE.probability) //Another check so that it doesn't run extra weather
possible_weather_for_this_z[WE] = WE.probability
var/datum/weather/W = pickweight(possible_weather_for_this_z)
run_weather(W.name)
diff --git a/code/datums/action.dm b/code/datums/action.dm
index 446b50243ae..f1c197cdfe8 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -323,6 +323,11 @@
..()
name = "Toggle [target.name]"
button.name = name
+
+/datum/action/item_action/organ_action/use/New(Target)
+ ..()
+ name = "Use [target.name]"
+ button.name = name
// for clothing accessories like holsters
/datum/action/item_action/accessory
diff --git a/code/datums/spell.dm b/code/datums/spell.dm
index a8d8b88e8d2..7772cb6b6e0 100644
--- a/code/datums/spell.dm
+++ b/code/datums/spell.dm
@@ -278,9 +278,6 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
switch(max_targets)
if(0) //unlimited
for(var/mob/living/target in view_or_range(range, user, selection_type))
- for(var/F in user.faction)
- if(F in target.faction)
- continue
targets += target
if(1) //single target can be picked
if(range < 0)
diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm
index 7002f92061b..c87b2b455e7 100644
--- a/code/datums/weather/weather.dm
+++ b/code/datums/weather/weather.dm
@@ -20,6 +20,7 @@
var/weather_duration_upper = 1500 //See above - this is the highest possible duration
var/weather_sound
var/weather_overlay
+ var/weather_color = null
var/end_message = "The wind relents its assault." //Displayed once the wather is over
var/end_duration = 300 //In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely
@@ -28,8 +29,9 @@
var/area_type = /area/space //Types of area to affect
var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins
- var/target_level = MAIN_STATION //The z-level to affect
-
+ var/target_z = MAIN_STATION //The z-level to affect
+ var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas.
+
var/overlay_layer = 10 //Since it's above everything else, this is the layer used by default. 2 is below mobs and walls if you need to use that.
var/aesthetic = FALSE //If the weather has no purpose other than looks
var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather
@@ -50,15 +52,20 @@
if(stage == STARTUP_STAGE)
return
stage = STARTUP_STAGE
+ var/list/affectareas = list()
for(var/V in get_areas(area_type))
+ affectareas += V
+ for(var/V in protected_areas)
+ affectareas -= get_areas(V)
+ for(var/V in affectareas)
var/area/A = V
- if(is_on_level_name(A,target_level))
+ if(is_on_level_name(A,target_z))
impacted_areas |= A
weather_duration = rand(weather_duration_lower, weather_duration_upper)
update_areas()
for(var/V in player_list)
var/mob/M = V
- if(is_on_level_name(M,target_level))
+ if(is_on_level_name(M,target_z))
if(telegraph_message)
to_chat(M, telegraph_message)
if(telegraph_sound)
@@ -72,7 +79,7 @@
update_areas()
for(var/V in player_list)
var/mob/M = V
- if(is_on_level_name(M,target_level))
+ if(is_on_level_name(M,target_z))
if(weather_message)
to_chat(M, weather_message)
if(weather_sound)
@@ -87,7 +94,7 @@
update_areas()
for(var/V in player_list)
var/mob/M = V
- if(is_on_level_name(M,target_level))
+ if(is_on_level_name(M,target_z))
if(end_message)
to_chat(M, end_message)
if(end_sound)
@@ -102,7 +109,7 @@
update_areas()
/datum/weather/proc/can_impact(mob/living/L) //Can this weather impact a mob?
- if(!is_on_level_name(L,target_level))
+ if(!is_on_level_name(L,target_z))
return
if(immunity_type in L.weather_immunities)
return
@@ -119,6 +126,7 @@
N.layer = overlay_layer
N.icon = 'icons/effects/weather_effects.dmi'
N.invisibility = 0
+ N.color = weather_color
switch(stage)
if(STARTUP_STAGE)
N.icon_state = telegraph_overlay
@@ -127,6 +135,7 @@
if(WIND_DOWN_STAGE)
N.icon_state = end_overlay
if(END_STAGE)
+ N.color = null
N.icon_state = initial(N.icon_state)
N.icon = 'icons/turf/areas.dmi'
N.layer = 10 //Just default back to normal area stuff since I assume setting a var is faster than initial
diff --git a/code/datums/weather/weather_types.dm b/code/datums/weather/weather_types.dm
index 90615896e6d..1581938bd96 100644
--- a/code/datums/weather/weather_types.dm
+++ b/code/datums/weather/weather_types.dm
@@ -16,7 +16,7 @@
end_duration = 0
area_type = /area
- target_level = MAIN_STATION
+ target_z = MAIN_STATION
overlay_layer = 2 //Covers floors only
immunity_type = "lava"
@@ -50,7 +50,7 @@
end_duration = 0
area_type = /area
- target_level = MAIN_STATION
+ target_z = MAIN_STATION
/datum/weather/advanced_darkness/update_areas()
for(var/V in impacted_areas)
@@ -87,7 +87,7 @@
end_overlay = "light_ash"
area_type = /area/mine/dangerous
- target_level = MINING
+ target_z = MINING
immunity_type = "ash"
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index b32c574e999..cbaacfb1175 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -964,22 +964,33 @@ var/list/turret_icons
// Syndicate turrets
/obj/machinery/porta_turret/syndicate
- installation = null
- always_up = 1
- use_power = 0
- has_cover = 0
- scan_range = 9
projectile = /obj/item/projectile/bullet
eprojectile = /obj/item/projectile/bullet
shot_sound = 'sound/weapons/Gunshot.ogg'
eshot_sound = 'sound/weapons/Gunshot.ogg'
+
icon_state = "syndieturret0"
var/icon_state_initial = "syndieturret0"
var/icon_state_active = "syndieturret1"
var/icon_state_destroyed = "syndieturret2"
+
+ installation = null
+ always_up = 1
+ use_power = 0
+ has_cover = 0
+ raised = 1
+ scan_range = 9
+
faction = "syndicate"
emp_vulnerable = 0
- raised = 1
+
+ check_arrest = 0
+ check_records = 0
+ check_weapons = 0
+ check_access = 0
+ check_anomalies = 1
+ check_synth = 1
+ ailock = 1
/obj/machinery/porta_turret/syndicate/New()
..()
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index 2fca35d58da..260da98d221 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -110,6 +110,14 @@ var/global/list/datum/stack_recipe/human_recipes = list( \
icon_state = "sinew"
origin_tech = "biotech=4"
+var/global/list/datum/stack_recipe/sinew_recipes = list ( \
+ new/datum/stack_recipe("sinew restraints", /obj/item/weapon/restraints/handcuffs/sinew, 1, on_floor = 1), \
+ )
+
+/obj/item/stack/sheet/sinew/New(var/loc, var/amount=null)
+ recipes = sinew_recipes
+ return ..()
+
/obj/item/stack/sheet/animalhide/goliath_hide
name = "goliath hide plates"
desc = "Pieces of a goliath's rocky hide, these might be able to make your suit a bit more durable to attack from the local fauna."
diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm
index d7e4b3b7b23..7b1187bcc50 100644
--- a/code/game/objects/items/weapons/handcuffs.dm
+++ b/code/game/objects/items/weapons/handcuffs.dm
@@ -62,6 +62,15 @@
target.update_handcuffed()
return
+/obj/item/weapon/restraints/handcuffs/sinew
+ name = "sinew restraints"
+ desc = "A pair of restraints fashioned from long strands of flesh."
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "sinewcuff"
+ item_state = "sinewcuff"
+ breakouttime = 300 //Deciseconds = 30s
+ cuffsound = 'sound/weapons/cablecuff.ogg'
+
/obj/item/weapon/restraints/handcuffs/cable
name = "cable restraints"
desc = "Looks like some cables tied together. Could be used to tie something up."
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index b2864d1c7cc..6bf82a0f889 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -26,6 +26,8 @@
var/corpseidicon = null //For setting it to be a gold, silver, centcomm etc ID
var/timeofdeath = null
var/coffin = 0
+ var/brute_damage = 0
+ var/oxy_damage = 0
/obj/effect/landmark/corpse/initialize()
if(istype(src,/obj/effect/landmark/corpse/clown))
@@ -37,34 +39,38 @@
var/mob/living/carbon/human/human/M = new /mob/living/carbon/human/human (src.loc)
M.real_name = src.name
M.death(1) //Kills the new mob
+ M.adjustOxyLoss(oxy_damage)
+ M.adjustBruteLoss(brute_damage)
+ M.adjustOxyLoss(oxy_damage)
+ M.adjustBruteLoss(brute_damage)
M.timeofdeath = timeofdeath
- if(src.mob_species)
- M.set_species(src.mob_species)
- if(src.corpseuniform)
- M.equip_to_slot_or_del(new src.corpseuniform(M), slot_w_uniform)
- if(src.corpsesuit)
- M.equip_to_slot_or_del(new src.corpsesuit(M), slot_wear_suit)
- if(src.corpseshoes)
- M.equip_to_slot_or_del(new src.corpseshoes(M), slot_shoes)
- if(src.corpsegloves)
- M.equip_to_slot_or_del(new src.corpsegloves(M), slot_gloves)
- if(src.corpseradio)
- M.equip_to_slot_or_del(new src.corpseradio(M), slot_l_ear)
- if(src.corpseglasses)
- M.equip_to_slot_or_del(new src.corpseglasses(M), slot_glasses)
- if(src.corpsemask)
- M.equip_to_slot_or_del(new src.corpsemask(M), slot_wear_mask)
- if(src.corpsehelmet)
- M.equip_to_slot_or_del(new src.corpsehelmet(M), slot_head)
- if(src.corpsebelt)
- M.equip_to_slot_or_del(new src.corpsebelt(M), slot_belt)
- if(src.corpsepocket1)
- M.equip_to_slot_or_del(new src.corpsepocket1(M), slot_r_store)
- if(src.corpsepocket2)
- M.equip_to_slot_or_del(new src.corpsepocket2(M), slot_l_store)
- if(src.corpseback)
- M.equip_to_slot_or_del(new src.corpseback(M), slot_back)
- if(src.corpseid == 1)
+ if(mob_species)
+ M.set_species(mob_species)
+ if(corpseuniform)
+ M.equip_to_slot_or_del(new corpseuniform(M), slot_w_uniform)
+ if(corpsesuit)
+ M.equip_to_slot_or_del(new corpsesuit(M), slot_wear_suit)
+ if(corpseshoes)
+ M.equip_to_slot_or_del(new corpseshoes(M), slot_shoes)
+ if(corpsegloves)
+ M.equip_to_slot_or_del(new corpsegloves(M), slot_gloves)
+ if(corpseradio)
+ M.equip_to_slot_or_del(new corpseradio(M), slot_l_ear)
+ if(corpseglasses)
+ M.equip_to_slot_or_del(new corpseglasses(M), slot_glasses)
+ if(corpsemask)
+ M.equip_to_slot_or_del(new corpsemask(M), slot_wear_mask)
+ if(corpsehelmet)
+ M.equip_to_slot_or_del(new corpsehelmet(M), slot_head)
+ if(corpsebelt)
+ M.equip_to_slot_or_del(new corpsebelt(M), slot_belt)
+ if(corpsepocket1)
+ M.equip_to_slot_or_del(new corpsepocket1(M), slot_r_store)
+ if(corpsepocket2)
+ M.equip_to_slot_or_del(new corpsepocket2(M), slot_l_store)
+ if(corpseback)
+ M.equip_to_slot_or_del(new corpseback(M), slot_back)
+ if(corpseid == 1)
var/obj/item/weapon/card/id/W = new(M)
W.name = "[M.real_name]'s ID Card"
var/datum/job/jobdatum
@@ -73,9 +79,9 @@
if(J.title == corpseidaccess)
jobdatum = J
break
- if(src.corpseidicon)
+ if(corpseidicon)
W.icon_state = corpseidicon
- if(src.corpseidaccess)
+ if(corpseidaccess)
if(jobdatum)
W.access = jobdatum.get_access()
else
@@ -84,18 +90,14 @@
W.assignment = corpseidjob
W.registered_name = M.real_name
M.equip_to_slot_or_del(W, slot_wear_id)
- if(src.coffin == 1)
+ if(coffin == 1)
var/obj/structure/closet/coffin/sarcophagus/sarc = locate(/obj/structure/closet/coffin/sarcophagus) in loc
if(sarc) M.loc = sarc
qdel(src)
-
-
// I'll work on making a list of corpses people request for maps, or that I think will be commonly used. Syndicate operatives for example.
-
-
-
-
+/obj/effect/landmark/corpse/damaged
+ brute_damage = 1000
/obj/effect/landmark/corpse/syndicatesoldier
name = "Syndicate Operative"
diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm
index adc9bf1b818..22d1e4cca8d 100644
--- a/code/modules/mining/lavaland/ash_flora.dm
+++ b/code/modules/mining/lavaland/ash_flora.dm
@@ -149,7 +149,7 @@
H.visible_message("[H] steps on a cactus!", \
"You step on a cactus!")
-/obj/item/weapon/reagent_containers/food/snacks/ash_flora/
+/obj/item/weapon/reagent_containers/food/snacks/ash_flora
name = "mushroom shavings"
desc = "Some shavings from a tall mushroom. With enough, might serve as a bowl."
icon = 'icons/obj/lavaland/ash_flora.dmi'
@@ -162,25 +162,20 @@
pixel_x = rand(-4, 4)
pixel_y = rand(-4, 4)
-
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/shavings //for actual crafting
-
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_leaf
name = "mushroom leaf"
desc = "A leaf, from a mushroom."
list_reagents = list("nutriment" = 3, "vitfro" = 2, "nicotine" = 2)
icon_state = "mushroom_leaf"
-
-
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_cap
name = "mushroom cap"
desc = "The cap of a large mushroom."
list_reagents = list("mindbreaker" = 2, "entpoly" = 4, "mushroomhallucinogen" = 2)
icon_state = "mushroom_cap"
-
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_stem
name = "mushroom stem"
desc = "A long mushroom stem. It's slightly glowing."
@@ -194,7 +189,6 @@
desc = "A cactus fruit covered in a thick, reddish skin. And some ash."
icon_state = "cactus_fruit"
-
/obj/item/mushroom_bowl
name = "mushroom bowl"
desc = "A bowl made out of mushrooms. Not food, though it might have contained some at some point."
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 1565ab40b75..c671763502d 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -6,6 +6,68 @@
icon_state = "necrocrate"
icon_opened = "necrocrateopen"
icon_closed = "necrocrate"
+
+/obj/structure/closet/crate/necropolis/tendril
+ desc = "It's watching you suspiciously."
+
+/obj/structure/closet/crate/necropolis/tendril/New()
+ ..()
+ // uncomment me once these items are being implemented
+ /*var/loot = rand(1,25)
+ switch(loot)
+ if(1)
+ new /obj/item/device/shared_storage/red(src)
+ if(2)
+ new /obj/item/clothing/suit/space/hardsuit/cult(src)
+ if(3)
+ new /obj/item/device/soulstone/anybody(src)
+ if(4)
+ new /obj/item/weapon/katana/cursed(src)
+ if(5)
+ new /obj/item/clothing/glasses/godeye(src)
+ if(6)
+ new /obj/item/weapon/reagent_containers/glass/bottle/potion/flight(src)
+ if(7)
+ new /obj/item/weapon/pickaxe/diamond(src)
+ if(8)
+ new /obj/item/clothing/head/culthood(src)
+ new /obj/item/clothing/suit/cultrobes(src)
+ new /obj/item/weapon/bedsheet/cult(src)
+ if(9)
+ new /obj/item/organ/brain/alien(src)
+ if(10)
+ new /obj/item/organ/heart/cursed(src)
+ if(11)
+ new /obj/item/ship_in_a_bottle(src)
+ if(12)
+ new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker(src)
+ if(13)
+ new /obj/item/weapon/sord(src)
+ if(14)
+ new /obj/item/weapon/nullrod/scythe/talking(src)
+ if(15)
+ new /obj/item/weapon/nullrod/armblade(src)
+ if(16)
+ new /obj/item/weapon/guardiancreator(src)
+ if(17)
+ new /obj/item/borg/upgrade/modkit/aoe/turfs/andmobs(src)
+ if(18)
+ new /obj/item/device/warp_cube/red(src)
+ if(19)
+ new /obj/item/device/wisp_lantern(src)
+ if(20)
+ new /obj/item/device/immortality_talisman(src)
+ if(21)
+ new /obj/item/weapon/gun/magic/hook(src)
+ if(22)
+ new /obj/item/voodoo(src)
+ if(23)
+ new /obj/item/weapon/grenade/clusterbuster/inferno(src)
+ if(24)
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater/hell(src)
+ new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src)
+ if(25)
+ new /obj/item/weapon/spellbook/oneuse/summonitem(src)*/
///Bosses
//Dragon
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index b90d57cc63d..6c0b0430e57 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -42,6 +42,8 @@
/obj/structure/rack,
/obj/structure/barricade) //turned into a typecache in New()
var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such
+ var/list/emote_taunt = list()
+ var/taunt_chance = 0
/mob/living/simple_animal/hostile/New()
..()
@@ -78,6 +80,19 @@
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
AIStatus = AI_IDLE // otherwise we go idle
return 1
+
+/mob/living/simple_animal/hostile/attacked_by(obj/item/I, mob/living/user)
+ if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client && user)
+ FindTarget(list(user), 1)
+ return ..()
+
+/mob/living/simple_animal/hostile/bullet_act(obj/item/projectile/P)
+ if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client)
+ if(P.firer && get_dist(src, P.firer) <= aggro_vision_range)
+ FindTarget(list(P.firer), 1)
+ Goto(P.starting, move_to_delay, 3)
+ return ..()
+
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
@@ -97,46 +112,57 @@
. += Objects
/mob/living/simple_animal/hostile/proc/FindTarget(var/list/possible_targets, var/HasTargetsList = 0)//Step 2, filter down possible targets to things we actually care about
- var/list/Targets = list()
+ . = list()
if(!HasTargetsList)
possible_targets = ListTargets()
- for(var/atom/A in possible_targets)
+ for(var/pos_targ in possible_targets)
+ var/atom/A = pos_targ
if(Found(A))//Just in case people want to override targetting
- Targets = list(A)
+ . = list(A)
break
if(CanAttack(A))//Can we attack it?
- Targets += A
+ . += A
continue
- var/Target = PickTarget(Targets)
+ var/Target = PickTarget(.)
GiveTarget(Target)
return Target //We now have a target
+
+/mob/living/simple_animal/hostile/proc/PossibleThreats()
+ . = list()
+ for(var/pos_targ in ListTargets())
+ var/atom/A = pos_targ
+ if(Found(A))
+ . = list(A)
+ break
+ if(CanAttack(A))
+ . += A
+ continue
/mob/living/simple_animal/hostile/proc/Found(var/atom/A)//This is here as a potential override to pick a specific target if available
return
-/mob/living/simple_animal/hostile/proc/PickTarget(var/list/Targets)//Step 3, pick amongst the possible, attackable targets
- if(!Targets.len)//We didnt find nothin!
- return
+/mob/living/simple_animal/hostile/proc/PickTarget(list/Targets)//Step 3, pick amongst the possible, attackable targets
if(target != null)//If we already have a target, but are told to pick again, calculate the lowest distance between all possible, and pick from the lowest distance targets
- for(var/atom/A in Targets)
+ for(var/pos_targ in Targets)
+ var/atom/A = pos_targ
var/target_dist = get_dist(targets_from, target)
var/possible_target_distance = get_dist(targets_from, A)
if(target_dist < possible_target_distance)
Targets -= A
- var/chosen_target = safepick(Targets)//Pick the remaining targets (if any) at random
+ if(!Targets.len)//We didnt find nothin!
+ return
+ var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random
return chosen_target
/mob/living/simple_animal/hostile/CanAttack(var/atom/the_target)//Can we actually attack a possible target?
+ if(!the_target)
+ return 0
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
return 0
if(search_objects < 2)
if(isliving(the_target))
var/mob/living/L = the_target
- var/faction_check = 0
- for(var/F in faction)
- if(F in L.faction)
- faction_check = 1
- break
+ var/faction_check = faction_check(L)
if(robust_searching)
if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive == 1)
return 0
@@ -177,9 +203,10 @@
return 1
return 0
-/mob/living/simple_animal/hostile/proc/GiveTarget(var/new_target)//Step 4, give us our selected target
+/mob/living/simple_animal/hostile/proc/GiveTarget(new_target)//Step 4, give us our selected target
target = new_target
if(target != null)
+ Aggro()
return 1
/mob/living/simple_animal/hostile/proc/MoveToTarget(var/list/possible_targets)//Step 5, handle movement between us and our target
@@ -192,41 +219,41 @@
LoseTarget()
return 0
var/target_distance = get_dist(targets_from,target)
- if(ranged)//We ranged? Shoot at em
+ if(ranged) //We ranged? Shoot at em
if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
OpenFire(target)
- if(retreat_distance != null)//If we have a retreat distance, check if we need to run from our target
- if(target_distance <= retreat_distance)//If target's closer than our retreat distance, run
+ if(retreat_distance != null) //If we have a retreat distance, check if we need to run from our target
+ if(target_distance <= retreat_distance) //If target's closer than our retreat distance, run
walk_away(src,target,retreat_distance,move_to_delay)
else
- Goto(target,move_to_delay,minimum_distance)//Otherwise, get to our minimum distance so we chase them
+ Goto(target,move_to_delay,minimum_distance) //Otherwise, get to our minimum distance so we chase them
else
Goto(target,move_to_delay,minimum_distance)
if(target)
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack
AttackingTarget()
return 1
- return 1
+ return 0
if(environment_smash)
- if(target.loc != null && get_dist(targets_from, target.loc) <= vision_range)//We can't see our target, but he's in our vision range still
+ if(target.loc != null && get_dist(targets_from, target.loc) <= vision_range) //We can't see our target, but he's in our vision range still
if(ranged_ignores_vision && ranged_cooldown <= world.time) //we can't see our target... but we can fire at them!
OpenFire(target)
- if(environment_smash >= 2)//If we're capable of smashing through walls, forget about vision completely after finding our target
+ if(environment_smash >= 2) //If we're capable of smashing through walls, forget about vision completely after finding our target
Goto(target,move_to_delay,minimum_distance)
FindHidden()
return 1
else
if(FindHidden())
return 1
- LostTarget()
+ LoseTarget()
return 0
-/mob/living/simple_animal/hostile/proc/Goto(var/target, var/delay, var/minimum_distance)
+/mob/living/simple_animal/hostile/proc/Goto(target, delay, minimum_distance)
walk_to(src, target, minimum_distance, delay)
/mob/living/simple_animal/hostile/adjustHealth(damage)
- ..(damage)
- if(!stat && search_objects < 3)//Not unconscious, and we don't ignore mobs
+ . = ..()
+ if(!ckey && !stat && search_objects < 3 && damage > 0)//Not unconscious, and we don't ignore mobs
if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight
search_objects = 0
target = null
@@ -241,26 +268,25 @@
/mob/living/simple_animal/hostile/proc/Aggro()
vision_range = aggro_vision_range
+ if(target && emote_taunt.len && prob(taunt_chance))
+ emote("me", 1, "[pick(emote_taunt)] at [target].")
+ taunt_chance = max(taunt_chance-7,2)
/mob/living/simple_animal/hostile/proc/LoseAggro()
stop_automated_movement = 0
vision_range = idle_vision_range
+ taunt_chance = initial(taunt_chance)
/mob/living/simple_animal/hostile/proc/LoseTarget()
target = null
walk(src, 0)
LoseAggro()
-/mob/living/simple_animal/hostile/proc/LostTarget()
- walk(src, 0)
- LoseAggro()
-
//////////////END HOSTILE MOB TARGETTING AND AGGRESSION////////////
/mob/living/simple_animal/hostile/death(gibbed)
- LoseAggro()
- ..()
- walk(src, 0)
+ LoseTarget()
+ ..(gibbed)
/mob/living/simple_animal/hostile/proc/summon_backup(distance)
do_alert_animation(src)
@@ -275,7 +301,7 @@
/mob/living/simple_animal/hostile/proc/OpenFire(atom/A)
if(check_friendly_fire)
- for(var/turf/T in getline(src, target)) // Not 100% reliable but this is faster than simulating actual trajectory
+ for(var/turf/T in getline(src,A)) // Not 100% reliable but this is faster than simulating actual trajectory
for(var/mob/living/L in T)
if(L == src || L == A)
continue
@@ -293,7 +319,6 @@
else
Shoot(A)
ranged_cooldown = world.time + ranged_cooldown_time
- return
/mob/living/simple_animal/hostile/proc/Shoot(atom/targeted_atom)
if(targeted_atom == targets_from.loc || targeted_atom == targets_from)
@@ -304,18 +329,19 @@
var/obj/item/ammo_casing/casing = new casingtype(startloc)
playsound(src, projectilesound, 100, 1)
casing.fire(targeted_atom, src, zone_override = ran_zone())
- else
- var/obj/item/projectile/A = new projectiletype(loc)
+ else if(projectiletype)
+ var/obj/item/projectile/P = new projectiletype(startloc)
playsound(src, projectilesound, 100, 1)
- A.current = target
- A.firer = src
- A.yo = targeted_atom.y - startloc.y
- A.xo = targeted_atom.x - startloc.x
- if(AIStatus == AI_OFF)//Don't want mindless mobs to have their movement screwed up firing in space
- newtonian_move(get_dir(target, targets_from))
- A.original = target
- A.fire()
- return A
+ P.current = startloc
+ P.starting = startloc
+ P.firer = src
+ P.yo = targeted_atom.y - startloc.y
+ P.xo = targeted_atom.x - startloc.x
+ if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space
+ newtonian_move(get_dir(targeted_atom, targets_from))
+ P.original = targeted_atom
+ P.fire()
+ return P
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
if(environment_smash)
@@ -325,7 +351,8 @@
if(istype(T, /turf/simulated/wall) || istype(T, /turf/simulated/mineral))
if(T.Adjacent(targets_from))
T.attack_animal(src)
- for(var/atom/A in T)
+ for(var/a in T)
+ var/atom/A = a
if(!A.Adjacent(targets_from))
continue
if(is_type_in_typecache(A, environment_target_typecache))
@@ -348,7 +375,7 @@
A.attack_animal(src)
return 1
-/mob/living/simple_animal/hostile/RangedAttack(var/atom/A, var/params) //Player firing
+/mob/living/simple_animal/hostile/RangedAttack(atom/A, params) //Player firing
if(ranged && ranged_cooldown <= world.time)
target = A
OpenFire(A)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
new file mode 100644
index 00000000000..b9f6f97f864
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
@@ -0,0 +1,196 @@
+#define MEDAL_PREFIX "Legion"
+/*
+
+LEGION
+
+Legion spawns from the necropolis gate in the far north of lavaland. It is the guardian of the Necropolis and emerges from within whenever an intruder tries to enter through its gate.
+Whenever Legion emerges, everything in lavaland will receive a notice via color, audio, and text. This is because Legion is powerful enough to slaughter the entirety of lavaland with little effort.
+
+It has two attack modes that it constantly rotates between.
+
+In ranged mode, it will behave like a normal legion - retreating when possible and firing legion skulls at the target.
+In charge mode, it will spin and rush its target, attacking with melee whenever possible.
+
+When Legion dies, it drops a staff of storms, which allows its wielder to call and disperse ash storms at will and functions as a powerful melee weapon.
+
+Difficulty: Medium
+
+*/
+
+/mob/living/simple_animal/hostile/megafauna/legion
+ name = "Legion"
+ health = 800
+ maxHealth = 800
+ icon_state = "legion"
+ icon_living = "legion"
+ desc = "One of many."
+ icon = 'icons/mob/lavaland/legion.dmi'
+ attacktext = "chomps"
+ attack_sound = 'sound/misc/demon_attack1.ogg'
+ speak_emote = list("echoes")
+ armour_penetration = 50
+ melee_damage_lower = 25
+ melee_damage_upper = 25
+ speed = 2
+ ranged = 1
+ del_on_death = 1
+ retreat_distance = 5
+ minimum_distance = 5
+ ranged_cooldown_time = 20
+ var/size = 5
+ var/charging = 0
+ medal_type = MEDAL_PREFIX
+ score_type = LEGION_SCORE
+ pixel_y = -90
+ pixel_x = -75
+ loot = list(/obj/item/stack/sheet/bone = 3)
+ vision_range = 13
+ elimination = 1
+ idle_vision_range = 13
+ appearance_flags = 0
+ mouse_opacity = 1
+ stat_attack = 1 // Overriden from /tg/ - otherwise Legion starts chasing its minions
+
+/mob/living/simple_animal/hostile/megafauna/legion/New()
+ ..()
+ internal_gps = new/obj/item/device/gps/internal/legion(src)
+
+/mob/living/simple_animal/hostile/megafauna/legion/AttackingTarget()
+ ..()
+ if(ishuman(target))
+ var/mob/living/L = target
+ if(L.stat == UNCONSCIOUS)
+ var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
+ A.infest(L)
+
+/mob/living/simple_animal/hostile/megafauna/legion/OpenFire(the_target)
+ if(world.time >= ranged_cooldown && !charging)
+ if(prob(75))
+ var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
+ A.GiveTarget(target)
+ A.friends = friends
+ A.faction = faction
+ ranged_cooldown = world.time + ranged_cooldown_time
+ else
+ visible_message("[src] charges!")
+ SpinAnimation(speed = 20, loops = 5)
+ ranged = 0
+ retreat_distance = 0
+ minimum_distance = 0
+ speed = 0
+ charging = 1
+ addtimer(src, "reset_charge", 50)
+
+/mob/living/simple_animal/hostile/megafauna/legion/proc/reset_charge()
+ ranged = 1
+ retreat_distance = 5
+ minimum_distance = 5
+ speed = 2
+ charging = 0
+
+/mob/living/simple_animal/hostile/megafauna/legion/death()
+ if(health > 0)
+ return
+ if(size > 1)
+ adjustHealth(-maxHealth) //heal ourself to full in prep for splitting
+ var/mob/living/simple_animal/hostile/megafauna/legion/L = new(loc)
+
+ L.maxHealth = maxHealth * 0.6
+ maxHealth = L.maxHealth
+
+ L.health = L.maxHealth
+ health = maxHealth
+
+ size--
+ L.size = size
+
+ L.resize = L.size * 0.2
+ transform = initial(transform)
+ resize = size * 0.2
+
+ L.update_transform()
+ update_transform()
+
+ L.faction = faction.Copy()
+
+ L.GiveTarget(target)
+
+ visible_message("[src] splits in twain!")
+ else
+ var/last_legion = TRUE
+ for(var/mob/living/simple_animal/hostile/megafauna/legion/other in mob_list)
+ if(other != src)
+ last_legion = FALSE
+ break
+ if(last_legion)
+ loot = list(/obj/item/weapon/staff/storm)
+ elimination = 0
+ else if(prob(5))
+ loot = list(/obj/structure/closet/crate/necropolis/tendril)
+ ..()
+
+/mob/living/simple_animal/hostile/megafauna/legion/Process_Spacemove(movement_dir = 0)
+ return 1
+
+/obj/item/device/gps/internal/legion
+ icon_state = null
+ gpstag = "Echoing Signal"
+ desc = "The message repeats."
+ invisibility = 100
+
+
+//Loot
+
+/obj/item/weapon/staff/storm
+ name = "staff of storms"
+ desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it."
+ icon_state = "staffofstorms"
+ item_state = "staffofstorms"
+ icon = 'icons/obj/guns/magic.dmi'
+ slot_flags = SLOT_BACK
+ item_state = "staffofstorms"
+ w_class = 4
+ force = 25
+ damtype = BURN
+ hitsound = 'sound/weapons/sear.ogg'
+ var/storm_type = /datum/weather/ash_storm
+ var/storm_cooldown = 0
+
+/obj/item/weapon/staff/storm/attack_self(mob/user)
+ if(storm_cooldown > world.time)
+ user << "The staff is still recharging!"
+ return
+
+ var/area/user_area = get_area(user)
+ var/datum/weather/A
+ for(var/V in weather_master.existing_weather)
+ var/datum/weather/W = V
+ if(W.target_z == user.z && W.area_type == user_area.type)
+ A = W
+ break
+ if(A)
+
+ if(A.stage != END_STAGE)
+ if(A.stage == WIND_DOWN_STAGE)
+ user << "The storm is already ending! It would be a waste to use the staff now."
+ return
+ user.visible_message("[user] holds [src] skywards as an orange beam travels into the sky!", \
+ "You hold [src] skyward, dispelling the storm!")
+ playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0)
+ A.wind_down()
+ return
+ else
+ A = new storm_type
+ A.name = "staff storm"
+ A.area_type = user_area.type
+ A.target_z = user.z
+ A.telegraph_duration = 100
+ A.end_duration = 100
+
+ user.visible_message("[user] holds [src] skywards as red lightning crackles into the sky!", \
+ "You hold [src] skyward, calling down a terrible storm!")
+ playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0)
+ A.telegraph()
+ storm_cooldown = world.time + 200
+
+#undef MEDAL_PREFIX
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm
index ac9b8562681..87754e1428a 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimic.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm
@@ -91,10 +91,6 @@
..()
icon_state = initial(icon_state)
-/mob/living/simple_animal/hostile/mimic/crate/LostTarget()
- ..()
- icon_state = initial(icon_state)
-
/mob/living/simple_animal/hostile/mimic/crate/death(gibbed)
var/obj/structure/closet/crate/C = new(get_turf(src))
// Put loot in crate
diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
new file mode 100644
index 00000000000..4f12bb92270
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
@@ -0,0 +1,319 @@
+/mob/living/simple_animal/hostile/asteroid/hivelord
+ name = "hivelord"
+ desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original."
+ icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
+ icon_state = "Hivelord"
+ icon_living = "Hivelord"
+ icon_aggro = "Hivelord_alert"
+ icon_dead = "Hivelord_dead"
+ icon_gib = "syndicate_gib"
+ mouse_opacity = 2
+ move_to_delay = 14
+ ranged = 1
+ vision_range = 5
+ aggro_vision_range = 9
+ idle_vision_range = 5
+ speed = 3
+ maxHealth = 75
+ health = 75
+ harm_intent_damage = 5
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ attacktext = "lashes out at"
+ speak_emote = list("telepathically cries")
+ attack_sound = 'sound/weapons/pierce.ogg'
+ throw_message = "falls right through the strange body of the"
+ ranged_cooldown = 0
+ ranged_cooldown_time = 20
+ environment_smash = 0
+ retreat_distance = 3
+ minimum_distance = 3
+ pass_flags = PASSTABLE
+ loot = list(/obj/item/organ/internal/hivelord_core)
+ var/brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood
+
+/mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(the_target)
+ if(world.time >= ranged_cooldown)
+ var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new brood_type(src.loc)
+ A.admin_spawned = admin_spawned
+ A.GiveTarget(target)
+ A.friends = friends
+ A.faction = faction.Copy()
+ ranged_cooldown = world.time + ranged_cooldown_time
+
+/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
+ OpenFire()
+
+/mob/living/simple_animal/hostile/asteroid/hivelord/death(gibbed)
+ mouse_opacity = 1
+ ..(gibbed)
+
+/obj/item/organ/internal/hivelord_core
+ name = "hivelord remains"
+ desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly."
+ icon_state = "roro core 2"
+ flags = NOBLUDGEON
+ slot = "hivecore"
+ force = 0
+ actions_types = list(/datum/action/item_action/organ_action/use)
+ var/inert = 0
+ var/preserved = 0
+
+/obj/item/organ/internal/hivelord_core/New()
+ ..()
+ addtimer(src, "inert_check", 2400)
+
+/obj/item/organ/internal/hivelord_core/proc/inert_check()
+ if(!owner && !preserved)
+ go_inert()
+ else
+ preserved(implanted = 1)
+
+/obj/item/organ/internal/hivelord_core/proc/preserved(implanted = 0)
+ inert = FALSE
+ preserved = TRUE
+ update_icon()
+
+ if(implanted)
+ feedback_add_details("hivelord_core", "[type]|implanted")
+ else
+ feedback_add_details("hivelord_core", "[type]|stabilizer")
+
+
+/obj/item/organ/internal/hivelord_core/proc/go_inert()
+ inert = TRUE
+ desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested."
+ feedback_add_details("hivelord_core", "[src.type]|inert")
+ update_icon()
+
+/obj/item/organ/internal/hivelord_core/ui_action_click()
+ owner.revive()
+ qdel(src)
+
+/obj/item/organ/internal/hivelord_core/on_life()
+ ..()
+ if(owner.health < config.health_threshold_crit)
+ ui_action_click()
+
+/obj/item/organ/internal/hivelord_core/afterattack(atom/target, mob/user, proximity_flag)
+ if(proximity_flag && ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(inert)
+ user << "[src] has become inert, its healing properties are no more."
+ return
+ else
+ if(H.stat == DEAD)
+ user << "[src] are useless on the dead."
+ return
+ if(H != user)
+ H.visible_message("[user] forces [H] to apply [src]... They quickly regenerate all injuries!")
+ feedback_add_details("hivelord_core","[src.type]|used|other")
+ else
+ user << "You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments."
+ feedback_add_details("hivelord_core","[src.type]|used|self")
+ playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
+ H.revive()
+ qdel(src)
+ ..()
+
+/obj/item/organ/internal/hivelord_core/prepare_eat()
+ return null
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood
+ name = "hivelord brood"
+ desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..."
+ icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
+ icon_state = "Hivelordbrood"
+ icon_living = "Hivelordbrood"
+ icon_aggro = "Hivelordbrood"
+ icon_dead = "Hivelordbrood"
+ icon_gib = "syndicate_gib"
+ mouse_opacity = 2
+ move_to_delay = 1
+ friendly = "buzzes near"
+ vision_range = 10
+ speed = 3
+ maxHealth = 1
+ health = 1
+ flying = 1
+ harm_intent_damage = 5
+ melee_damage_lower = 2
+ melee_damage_upper = 2
+ attacktext = "slashes"
+ speak_emote = list("telepathically cries")
+ attack_sound = 'sound/weapons/pierce.ogg'
+ throw_message = "falls right through the strange body of the"
+ environment_smash = 0
+ pass_flags = PASSTABLE
+ del_on_death = 1
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New()
+ ..()
+ addtimer(src, "death", 100)
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood
+ name = "blood brood"
+ desc = "A living string of blood and alien materials."
+ icon_state = "bloodbrood"
+ icon_living = "bloodbrood"
+ icon_aggro = "bloodbrood"
+ attacktext = "pierces"
+ color = "#C80000"
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/death()
+ if(loc) // Splash the turf we are on with blood
+ reagents.reaction(get_turf(src))
+ ..()
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/New()
+ create_reagents(30)
+ ..()
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/AttackingTarget()
+ ..()
+ if(iscarbon(target))
+ transfer_reagents(target, 1)
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_hand(mob/living/carbon/human/M)
+ if("\ref[M]" in faction)
+ reabsorb_host(M)
+ else
+ return ..()
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if("\ref[M]" in faction)
+ reabsorb_host(M)
+ else
+ return ..()
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/reabsorb_host(mob/living/carbon/C)
+ C.visible_message("[src] is reabsorbed by [C]'s body.", \
+ "[src] is reabsorbed by your body.")
+ transfer_reagents(C)
+ death()
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/transfer_reagents(mob/living/carbon/C, volume = 30)
+ if(!reagents.total_volume)
+ return
+
+ volume = min(volume, reagents.total_volume)
+
+ var/fraction = min(volume/reagents.total_volume, 1)
+ reagents.reaction(C, INGEST, fraction)
+ reagents.trans_to(C, volume)
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/link_host(mob/living/carbon/human/H)
+ faction = list("\ref[src]", "\ref[H]") // Hostile to everyone except the host.
+ H.vessel.trans_to(src, 30)
+ color = mix_color_from_reagents(reagents.reagent_list)
+
+// Legion
+/mob/living/simple_animal/hostile/asteroid/hivelord/legion
+ name = "legion"
+ desc = "You can still see what was once a human under the shifting mass of corruption."
+ icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
+ icon_state = "legion"
+ icon_living = "legion"
+ icon_aggro = "legion"
+ icon_dead = "legion"
+ icon_gib = "syndicate_gib"
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ attacktext = "lashes out at"
+ speak_emote = list("echoes")
+ attack_sound = 'sound/weapons/pierce.ogg'
+ throw_message = "bounces harmlessly off of"
+ loot = list(/obj/item/organ/internal/hivelord_core/legion)
+ brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion
+ del_on_death = 1
+ stat_attack = 1
+ robust_searching = 1
+ var/mob/living/carbon/human/stored_mob
+
+/mob/living/simple_animal/hostile/asteroid/hivelord/legion/death(gibbed)
+ visible_message("The skulls on [src] wail in anger as they flee from their dying host!")
+ var/turf/T = get_turf(src)
+ if(T)
+ if(stored_mob)
+ stored_mob.forceMove(get_turf(src))
+ stored_mob = null
+ else
+ new /obj/effect/landmark/corpse/damaged(T)
+ ..(gibbed)
+
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion
+ name = "legion"
+ desc = "One of many."
+ icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
+ icon_state = "legion_head"
+ icon_living = "legion_head"
+ icon_aggro = "legion_head"
+ icon_dead = "legion_head"
+ icon_gib = "syndicate_gib"
+ friendly = "buzzes near"
+ vision_range = 10
+ maxHealth = 1
+ health = 5
+ harm_intent_damage = 5
+ melee_damage_lower = 12
+ melee_damage_upper = 12
+ attacktext = "bites"
+ speak_emote = list("echoes")
+ attack_sound = 'sound/weapons/pierce.ogg'
+ throw_message = "is shrugged off by"
+ pass_flags = PASSTABLE
+ del_on_death = 1
+ stat_attack = 1
+ robust_searching = 1
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/Life()
+ if(isturf(loc))
+ for(var/mob/living/carbon/human/H in view(src,1)) //Only for corpse right next to/on same tile
+ if(H.stat == UNCONSCIOUS)
+ infest(H)
+ ..()
+
+/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H)
+ visible_message("[name] burrows into the flesh of [H]!")
+ var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L = new(H.loc)
+ visible_message("[L] staggers to their feet!")
+ H.death()
+ H.adjustBruteLoss(1000)
+ L.stored_mob = H
+ H.forceMove(L)
+ qdel(src)
+
+/obj/item/organ/internal/hivelord_core/legion
+ name = "legion's soul"
+ desc = "A strange rock that still crackles with power... its \
+ healing properties will soon become inert if not used quickly."
+ icon_state = "legion_soul"
+
+/obj/item/organ/internal/hivelord_core/legion/New()
+ ..()
+ update_icon()
+
+/obj/item/organ/internal/hivelord_core/legion/update_icon()
+ icon_state = inert ? "legion_soul_inert" : "legion_soul"
+ overlays.Cut()
+ if(!inert && !preserved)
+ overlays += image(icon, "legion_soul_crackle")
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+
+/obj/item/organ/internal/hivelord_core/legion/go_inert()
+ . = ..()
+ desc = "[src] has become inert, it crackles no more and is useless for \
+ healing injuries."
+
+/obj/item/organ/internal/hivelord_core/legion/preserved(implanted = 0)
+ ..()
+ desc = "[src] has been stabilized. It no longer crackles with power, but it's healing properties are preserved indefinitely."
+
+/obj/item/weapon/legion_skull
+ name = "legion's head"
+ desc = "The once living, now empty eyes of the former human's skull cut deep into your soul."
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "skull"
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
index cbf8490c827..ceac9068e79 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
@@ -204,131 +204,6 @@
idle_vision_range = 9
..()
-/mob/living/simple_animal/hostile/asteroid/hivelord
- name = "hivelord"
- desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original."
- icon = 'icons/mob/animal.dmi'
- icon_state = "Hivelord"
- icon_living = "Hivelord"
- icon_aggro = "Hivelord_alert"
- icon_dead = "Hivelord_dead"
- icon_gib = "syndicate_gib"
- mouse_opacity = 2
- move_to_delay = 14
- ranged = 1
- vision_range = 5
- aggro_vision_range = 9
- idle_vision_range = 5
- speed = 3
- maxHealth = 75
- health = 75
- harm_intent_damage = 5
- melee_damage_lower = 0
- melee_damage_upper = 0
- attacktext = "lashes out at"
- speak_emote = list("telepathically cries")
- attack_sound = 'sound/weapons/pierce.ogg'
- throw_message = "falls right through the strange body of the"
- ranged_cooldown = 0
- ranged_cooldown_time = 20
- environment_smash = 0
- retreat_distance = 3
- minimum_distance = 3
- pass_flags = PASSTABLE
- loot = list(/obj/item/organ/internal/hivelord_core)
-
-/mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(var/the_target)
- var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood(src.loc)
- A.GiveTarget(target)
- A.friends = friends
- A.faction = faction
- return
-
-/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
- OpenFire()
-
-/obj/item/organ/internal/hivelord_core
- name = "hivelord remains"
- desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly. Try not to think about what you're eating."
- icon = 'icons/obj/food/food.dmi'
- icon_state = "boiledrorocore"
- slot = "hivecore"
- var/inert = 0
- var/preserved = 0
-
-/obj/item/organ/internal/hivelord_core/New()
- spawn(2400)
- if(!preserved)
- inert = 1
- desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested."
-
-/obj/item/organ/internal/hivelord_core/on_life()
- ..()
- if(owner)
- owner.adjustBruteLoss(-1)
- owner.adjustFireLoss(-1)
- owner.adjustOxyLoss(-2)
- if(ishuman(owner))
- var/mob/living/carbon/human/H = owner
- var/datum/reagent/blood/B = locate() in H.vessel.reagent_list //Grab some blood
- var/blood_volume = round(H.vessel.get_reagent_amount("blood"))
- if(B && blood_volume < H.max_blood && blood_volume)
- B.volume += 2 // Fast blood regen
-
-/obj/item/organ/internal/hivelord_core/attack(mob/living/M as mob, mob/living/user as mob)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(inert)
- to_chat(user, "[src] have become inert, its healing properties are no more.")
- return
- else
- if(H.stat == DEAD)
- to_chat(user, "[src] are useless on the dead.")
- return
- if(H != user)
- H.visible_message("[user] forces [H] to eat [src]... they quickly regenerate all injuries!")
- else
- to_chat(user, "You chomp into [src], barely managing to hold it down, but feel amazingly refreshed in mere moments.")
- playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
- H.revive()
- qdel(src)
- ..()
-
-/obj/item/organ/internal/hivelord_core/prepare_eat()
- return null
-
-/mob/living/simple_animal/hostile/asteroid/hivelordbrood
- name = "hivelord brood"
- desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..."
- icon = 'icons/mob/animal.dmi'
- icon_state = "Hivelordbrood"
- icon_living = "Hivelordbrood"
- icon_aggro = "Hivelordbrood"
- icon_dead = "Hivelordbrood"
- icon_gib = "syndicate_gib"
- mouse_opacity = 2
- move_to_delay = 1
- friendly = "buzzes near"
- vision_range = 10
- speed = 3
- maxHealth = 1
- health = 1
- harm_intent_damage = 5
- melee_damage_lower = 2
- melee_damage_upper = 2
- attacktext = "slashes"
- speak_emote = list("telepathically cries")
- attack_sound = 'sound/weapons/pierce.ogg'
- throw_message = "falls right through the strange body of the"
- environment_smash = 0
- pass_flags = PASSTABLE
- del_on_death = 1
-
-/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New()
- ..()
- spawn(100)
- death()
-
/mob/living/simple_animal/hostile/asteroid/goliath
name = "goliath"
desc = "A massive beast that uses long tentacles to ensare its prey, threatening them is not advised under any conditions."
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 06160dca1fd..90cb13de26b 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -301,6 +301,9 @@
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
attack_threshold_check(damage,M.melee_damage_type)
+/mob/living/simple_animal/proc/attacked_by(obj/item/I, mob/living/user) // Handled in _onclick/click.dm
+ return
+
/mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
if(!Proj)
return
diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi
index 34f1d493040..d6cb7a676c4 100644
Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 88161a20b5c..033446d49d3 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/paradise.dme b/paradise.dme
index b5fde57ce71..b094b194f01 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1656,7 +1656,9 @@
#include "code\modules\mob\living\simple_animal\hostile\tree.dm"
#include "code\modules\mob\living\simple_animal\hostile\winter_mobs.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\dragon.dm"
+#include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\megafauna.dm"
+#include "code\modules\mob\living\simple_animal\hostile\mining\hivelord.dm"
#include "code\modules\mob\living\simple_animal\hostile\retaliate\clown.dm"
#include "code\modules\mob\living\simple_animal\hostile\retaliate\drone.dm"
#include "code\modules\mob\living\simple_animal\hostile\retaliate\fish.dm"