diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index 0da4f75e1bf..33d02d6e06e 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -77,4 +77,5 @@
#define ALIEN 4
#define ROBOT 8
#define SLIME 16
-#define DRONE 32
\ No newline at end of file
+#define DRONE 32
+#define SWARMER 64
\ No newline at end of file
diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm
index 2ec7b4c407f..66ae50cf852 100644
--- a/code/__HELPERS/lists.dm
+++ b/code/__HELPERS/lists.dm
@@ -342,4 +342,10 @@
for(var/datum/D in L)
if(D.vars.Find(varname))
if(D.vars[varname] == value)
- return D
\ No newline at end of file
+ return D
+
+//remove all nulls from a list
+/proc/removeNullsFromList(list/L)
+ while(L.Remove(null))
+ continue
+ return L
\ No newline at end of file
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index fb209d087e7..d947bfa6553 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -197,6 +197,8 @@ var/datum/global_hud/global_hud = new()
blob_hud()
else if(isdrone(mymob))
drone_hud(ui_style)
+ else if(isswarmer(mymob))
+ swarmer_hud()
//Version denotes which style should be displayed. blank or 0 means "next version"
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 82a66b848e1..fbf9c5b26f3 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -235,10 +235,8 @@
return
var/mob/living/simple_animal/M = user
M.do_attack_animation(src)
- if(M.melee_damage_upper <= 0)
- return
- attack_generic(M, M.melee_damage_upper)
-
+ if(M.melee_damage_upper > 0 && (M.melee_damage_type == BRUTE || M.melee_damage_type == BURN))
+ attack_generic(M, M.melee_damage_upper)
/obj/machinery/door/window/attack_slime(mob/living/simple_animal/slime/user)
user.do_attack_animation(src)
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index f0a2c610a61..499198a49e3 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -311,7 +311,7 @@
/obj/machinery/porta_turret/attack_animal(mob/living/simple_animal/M)
M.changeNext_move(CLICK_CD_MELEE)
M.do_attack_animation(src)
- if(M.melee_damage_upper == 0)
+ if(M.melee_damage_upper == 0 || (M.melee_damage_type != BRUTE && M.melee_damage_type != BURN))
return
if(!(stat & BROKEN))
visible_message("[M] [M.attacktext] [src]!")
diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm
index f1347bcd07e..65e2b67e0b3 100644
--- a/code/game/objects/items/weapons/storage/firstaid.dm
+++ b/code/game/objects/items/weapons/storage/firstaid.dm
@@ -45,8 +45,8 @@
new /obj/item/weapon/reagent_containers/pill/patch/silver_sulf(src)
new /obj/item/weapon/reagent_containers/pill/patch/silver_sulf(src)
new /obj/item/weapon/reagent_containers/pill/patch/silver_sulf(src)
- new /obj/item/weapon/reagent_containers/pill/salicyclic(src)
- new /obj/item/weapon/reagent_containers/pill/salicyclic(src)
+ new /obj/item/weapon/reagent_containers/pill/oxandrolone(src)
+ new /obj/item/weapon/reagent_containers/pill/oxandrolone(src)
new /obj/item/weapon/reagent_containers/hypospray/medipen(src)
new /obj/item/device/healthanalyzer(src)
return
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index bb209cb9515..8fa1375a480 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -166,6 +166,7 @@
/obj/structure/closet/ex_act(severity, target)
contents_explosion(severity, target)
+ new /obj/item/stack/sheet/metal(loc)
dump_contents()
qdel(src)
..()
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 355938166f5..e8775daf133 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -239,7 +239,7 @@
qdel(src)
return
if(3.0)
- if (prob(15))
+ if (prob(40))
var/remains = pick(/obj/item/stack/rods,/obj/item/stack/sheet/metal)
new remains(loc)
qdel(src)
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 488932acaa4..d6c56c34a34 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -79,7 +79,8 @@
/obj/structure/grille/attack_animal(var/mob/living/simple_animal/M)
M.changeNext_move(CLICK_CD_MELEE)
- if(M.melee_damage_upper == 0) return
+ if(M.melee_damage_upper == 0 || (M.melee_damage_type != BRUTE && M.melee_damage_type != BURN))
+ return
M.do_attack_animation(src)
playsound(loc, 'sound/effects/grillehit.ogg', 80, 1)
M.visible_message("[M] smashes against [src].", \
diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm
index 696ed292eb9..b7862562752 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm
@@ -11,11 +11,13 @@
qdel(src)
return
if(2.0)
- if (prob(50))
+ if (prob(70))
+ new /obj/item/stack/sheet/metal(loc)
qdel(src)
return
if(3.0)
- if (prob(5))
+ if (prob(50))
+ new /obj/item/stack/sheet/metal(loc)
qdel(src)
return
return
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 6c02cd7e7d0..9dc8d6631e9 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -168,7 +168,7 @@
var/mob/living/simple_animal/M = user
M.do_attack_animation(src)
- if(M.melee_damage_upper <= 0)
+ if(M.melee_damage_upper <= 0 || (M.melee_damage_type != BRUTE && M.melee_damage_type != BURN))
return
attack_generic(M, M.melee_damage_upper)
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index 9a55d77b4ad..f373fad4af6 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -7,7 +7,6 @@
/datum/round_event/brand_intelligence
announceWhen = 21
endWhen = 1000 //Ends when all vending machines are subverted anyway.
-
var/list/obj/machinery/vending/vendingMachines = list()
var/list/obj/machinery/vending/infectedMachines = list()
var/obj/machinery/vending/originMachine
@@ -28,11 +27,9 @@
for(var/obj/machinery/vending/V in machines)
if(V.z != 1) continue
vendingMachines.Add(V)
-
if(!vendingMachines.len)
kill()
return
-
originMachine = pick(vendingMachines)
vendingMachines.Remove(originMachine)
originMachine.shut_up = 0
@@ -48,7 +45,7 @@
originMachine.visible_message("[originMachine] beeps and seems lifeless.")
kill()
return
-
+ vendingMachines = removeNullsFromList(vendingMachines)
if(!vendingMachines.len) //if every machine is infected
for(var/obj/machinery/vending/upriser in infectedMachines)
if(prob(70) && !upriser.gc_destroyed)
@@ -62,7 +59,6 @@
kill()
return
-
if(IsMultiple(activeFor, 4))
var/obj/machinery/vending/rebel = pick(vendingMachines)
vendingMachines.Remove(rebel)
diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm
index fd3fff64a4b..20577531b27 100644
--- a/code/modules/mob/living/carbon/alien/alien_defense.dm
+++ b/code/modules/mob/living/carbon/alien/alien_defense.dm
@@ -73,7 +73,19 @@ In all, this is a lot like the monkey code. /N
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
if(..())
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- adjustBruteLoss(damage)
+ switch(M.melee_damage_type)
+ if(BRUTE)
+ adjustBruteLoss(damage)
+ if(BURN)
+ adjustFireLoss(damage)
+ if(TOX)
+ adjustToxLoss(damage)
+ if(OXY)
+ adjustOxyLoss(damage)
+ if(CLONE)
+ adjustCloneLoss(damage)
+ if(STAMINA)
+ adjustStaminaLoss(damage)
updatehealth()
/mob/living/carbon/alien/attack_slime(mob/living/simple_animal/slime/M)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 8fdb1c39ccf..283c745d796 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -74,9 +74,9 @@
. = ..()
-/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0)
+/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, override = 0)
shock_damage *= siemens_coeff
- if (shock_damage<1)
+ if(shock_damage<1 && !override)
return 0
take_overall_damage(0,shock_damage)
//src.burn_skin(shock_damage)
@@ -95,7 +95,10 @@
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
Stun(3)
Weaken(3)
- return shock_damage
+ if(override)
+ return override
+ else
+ return shock_damage
/mob/living/carbon/swap_hand()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index ec19362de9b..a6dbd65bfca 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -270,7 +270,7 @@
spreadFire(AM)
//Added a safety check in case you want to shock a human mob directly through electrocute_act.
-/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, safety = 0)
+/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, safety = 0, override = 0)
if(!safety)
if(gloves)
var/obj/item/clothing/gloves/G = gloves
@@ -280,8 +280,7 @@
heart_attack = 0
if(stat == CONSCIOUS)
src << "You feel your heart beating again!"
-
- . = ..(shock_damage,source,siemens_coeff)
+ . = ..(shock_damage,source,siemens_coeff,safety,override)
if(.)
electrocution_animation(40)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 7a39b9969fe..98a8c3b6eed 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -389,7 +389,7 @@ emp_act
var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
var/obj/item/organ/limb/affecting = get_organ(ran_zone(dam_zone))
var/armor = run_armor_check(affecting, "melee")
- apply_damage(damage, BRUTE, affecting, armor)
+ apply_damage(damage, M.melee_damage_type, affecting, armor)
updatehealth()
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 5f721ecb512..bd9a1af5f52 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -155,7 +155,19 @@
/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M)
if(..())
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- adjustBruteLoss(damage)
+ switch(M.melee_damage_type)
+ if(BRUTE)
+ adjustBruteLoss(damage)
+ if(BURN)
+ adjustFireLoss(damage)
+ if(TOX)
+ adjustToxLoss(damage)
+ if(OXY)
+ adjustOxyLoss(damage)
+ if(CLONE)
+ adjustCloneLoss(damage)
+ if(STAMINA)
+ adjustStaminaLoss(damage)
updatehealth()
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 83b20b450cb..1a42c2e82f2 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -381,7 +381,19 @@
/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
if(..())
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- adjustBruteLoss(damage)
+ switch(M.melee_damage_type)
+ if(BRUTE)
+ adjustBruteLoss(damage)
+ if(BURN)
+ adjustFireLoss(damage)
+ if(TOX)
+ adjustToxLoss(damage)
+ if(OXY)
+ adjustOxyLoss(damage)
+ if(CLONE)
+ adjustCloneLoss(damage)
+ if(STAMINA)
+ adjustStaminaLoss(damage)
updatehealth()
/mob/living/silicon/attack_paw(mob/living/user)
diff --git a/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm b/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm
new file mode 100644
index 00000000000..bbed56a6962
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm
@@ -0,0 +1,513 @@
+////Deactivated swarmer shell////
+/obj/item/unactivated_swarmer
+ name = "unactivated swarmer"
+ desc = "A currently unactivated swarmer. Swarmers can self activate at any time, it would be wise to immediately dispose of this."
+ icon = 'icons/mob/swarmer.dmi'
+ icon_state = "swarmer_unactivated"
+
+/obj/item/unactivated_swarmer/attack_ghost(mob/user)
+ var/be_swarmer = alert("Become a swarmer? (Warning, You can no longer be cloned!)",,"Yes","No")
+ if(be_swarmer == "No" || qdeleted())
+ return
+ var/mob/living/simple_animal/hostile/swarmer/S = new /mob/living/simple_animal/hostile/swarmer(get_turf(loc))
+ S.key = user.key
+ qdel(src)
+
+////The Mob itself////
+
+/mob/living/simple_animal/hostile/swarmer
+ name = "Swarmer"
+ unique_name = 1
+ icon = 'icons/mob/swarmer.dmi'
+ desc = "A robot of unknown design, they seek only to consume materials and replicate themselves indefinitely."
+ speak_emote = list("tones")
+ health = 40
+ maxHealth = 40
+ status_flags = CANPUSH
+ icon_state = "swarmer"
+ icon_living = "swarmer"
+ icon_dead = "swarmer_unactivated"
+ icon_gib = null
+ wander = 0
+ harm_intent_damage = 5
+ minbodytemp = 0
+ maxbodytemp = 500
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ unsuitable_atmos_damage = 0
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ melee_damage_type = STAMINA
+ ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1)
+ languages = SWARMER
+ environment_smash = 0
+ attacktext = "shocks"
+ attack_sound = 'sound/effects/EMPulse.ogg'
+ friendly = "pinches"
+ speed = 0
+ faction = list("swarmer")
+ AIStatus = AI_OFF
+ projectiletype = /obj/item/projectile/beam/disabler
+ pass_flags = PASSTABLE | PASSMOB
+ ventcrawler = 2
+ ranged = 1
+ projectiletype = /obj/item/projectile/beam/disabler
+ ranged_cooldown_cap = 2
+ projectilesound = 'sound/weapons/taser2.ogg'
+ var/resources = 0 //Resource points, generated by consuming metal/glass
+
+/mob/living/simple_animal/hostile/swarmer/Login()
+ ..()
+ src << "You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate."
+ src << "Ctrl + Click provides most of your swarmer specific interactions, such as cannibalizing metal or glass, destroying the environment, or teleporting mobs away from you."
+ src << "Objectives:"
+ src << "1. Consume resources and replicate until there are no more resources left."
+ src << "2. Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable."
+ src << "3. Biological resources will be harvested at a later date, do not harm them."
+
+/mob/living/simple_animal/hostile/swarmer/New()
+ ..()
+ verbs -= /mob/living/verb/pulled
+
+/mob/living/simple_animal/hostile/swarmer/Stat()
+ ..()
+ if(statpanel("Status"))
+ stat("Resources:",resources)
+
+/mob/living/simple_animal/hostile/swarmer/death(gibbed)
+ ..(gibbed)
+ new /obj/effect/decal/cleanable/robot_debris(src.loc)
+ ghostize()
+ qdel(src)
+
+/mob/living/simple_animal/hostile/swarmer/emp_act()
+ if(health > 1)
+ health = 1
+ ..()
+ health = 0
+
+/mob/living/simple_animal/hostile/swarmer/CanPass(atom/movable/O)
+ if(istype(O, /obj/item/projectile/beam/disabler))//Allows for swarmers to fight as a group without wasting their shots hitting each other
+ return 1
+ if(isswarmer(O))
+ return 1
+ ..()
+
+////CTRL CLICK FOR SWARMERS AND SWARMER_ACT()'S////
+/mob/living/simple_animal/hostile/swarmer/CtrlClickOn(atom/A)
+ face_atom(A)
+ if(!isturf(loc))
+ return
+ if(next_move > world.time)
+ return
+ if(!A.Adjacent(src))
+ return
+ A.swarmer_act(src)
+ return
+
+/atom/proc/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+
+/obj/item/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.Integrate(src)
+
+/obj/item/weapon/gun/swarmer_act()//Stops you from eating the entire armory
+ return
+
+/turf/simulated/floor/swarmer_act()//ex_act() on turf calls it on its contents, this is to prevent attacking mobs by DisIntegrate()'ing the floor
+ return
+
+/obj/machinery/atmospherics/swarmer_act()
+ return
+
+/obj/structure/disposalpipe/swarmer_act()
+ return
+
+/obj/machinery/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DismantleMachine(src)
+
+/obj/machinery/light/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+
+/obj/machinery/door/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+
+/obj/machinery/camera/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+ deactivate(S, 0)
+
+/obj/machinery/particle_accelerator/control_box/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+
+/obj/machinery/field/generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+
+/obj/machinery/gravity_generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+
+/obj/machinery/vending/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)//It's more visually interesting than dismantling the machine
+ S.DisIntegrate(src)
+
+/obj/machinery/turretid/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisIntegrate(src)
+
+/obj/machinery/chem_dispenser/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "The volatile chemicals in this machine would destroy us. Aborting."
+
+/obj/machinery/nuclearbomb/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "This device's destruction would result in the extermination of everything in the area. Aborting."
+
+/obj/structure/reagent_dispensers/fueltank/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "Destroying this object would cause a chain reaction. Aborting."
+
+/obj/structure/cable/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "Disrupting the power grid would bring no benefit to us. Aborting."
+
+/obj/machinery/portable_atmospherics/canister/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "An inhospitable area may be created as a result of destroying this object. Aborting."
+
+/obj/machinery/power/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "Disrupting the power grid would bring no benefit to us. Aborting."
+
+/obj/machinery/gateway/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "This bluespace source will be important to us later. Aborting."
+
+/turf/simulated/wall/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ if(locate(/turf/space) in range(1, src))
+ S << "Destroying this object has the potential to cause a hull breach. Aborting."
+ return
+ ..()
+
+/obj/structure/window/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ if(locate(/turf/space) in range(1, src))
+ S << "Destroying this object has the potential to cause a hull breach. Aborting."
+ return
+ ..()
+
+/obj/item/stack/cable_coil/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)//Wiring would be too effective as a resource
+ S << "This object does not contain enough materials to work with."
+
+/obj/machinery/porta_turret/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "Attempting to dismantle this machine would result in an immediate counterattack. Aborting."
+
+/mob/living/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S.DisperseTarget(src)
+
+/mob/living/simple_animal/slime/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "This biological resource is somehow resisting our bluespace transceiver. Aborting."
+
+
+////END CTRL CLICK FOR SWARMERS////
+
+/mob/living/simple_animal/hostile/swarmer/proc/Fabricate(var/atom/fabrication_object,var/fabrication_cost = 0)
+ if(!isturf(loc))
+ src << "This is not a suitable location for fabrication. We need more space."
+ if(resources >= fabrication_cost)
+ resources -= fabrication_cost
+ else
+ src << "You do not have the necessary resources to fabricate this object."
+ return 0
+ new fabrication_object(loc)
+ return 1
+
+/mob/living/simple_animal/hostile/swarmer/proc/Integrate(var/obj/item/target)
+ if(resources >= 100)
+ src << "We cannot hold more materials!"
+ return
+ if((target.materials[MAT_METAL]) || (target.materials[MAT_GLASS]))
+ resources++
+ do_attack_animation(target)
+ changeNext_move(CLICK_CD_MELEE)
+ if(istype(target, /obj/item/stack))
+ var/obj/item/stack/S = target
+ S.use(1)
+ if(S.amount)
+ return
+ qdel(target)
+ else
+ src << "\the [target] is incompatible with our internal matter recycler."
+ return
+
+/mob/living/simple_animal/hostile/swarmer/proc/DisIntegrate(var/atom/movable/target)
+ new /obj/effect/effect/sparks(get_turf(target))
+ do_attack_animation(target)
+ changeNext_move(CLICK_CD_MELEE)
+ target.ex_act(3)
+ return
+
+/mob/living/simple_animal/hostile/swarmer/proc/DisperseTarget(var/mob/living/target)
+ if(target != src)
+ src << "Attempting to remove this being from our presence."
+ if(src.z != ZLEVEL_STATION)
+ src << "Our bluespace transceiver cannot locate a viable bluespace link, our teleportation abilities are useless in this area."
+ return
+ if(do_mob(src, target, 30))
+ var/cycle
+ for(cycle=0,cycle<100,cycle++)
+ var/random_location = locate(rand(37,202),rand(75,192),ZLEVEL_STATION)//Drunk dial a turf in the general ballpark of the station
+ if(istype(random_location, /turf/simulated/floor))
+ var/turf/simulated/floor/F = random_location
+ if(F.air)
+ var/datum/gas_mixture/A = F.air
+ if(A.oxygen >= 16 && !A.toxins && A.carbon_dioxide < 10 && !A.trace_gases.len)//Can most things breathe in this location?
+ if((A.temperature > 270) && (A.temperature < 360))//Not too hot, not too cold
+ var/pressure = A.return_pressure()
+ if((pressure > 20) && (pressure < 550))//Account for crushing pressure or vaccuums
+ if(ishuman(target))//If we're getting rid of a human, slap some zipties on them to keep them away from us a little longer
+ var/obj/item/weapon/restraints/handcuffs/cable/zipties/Z = new /obj/item/weapon/restraints/handcuffs/cable/zipties(src)
+ var/mob/living/carbon/human/H = target
+ Z.apply_cuffs(H, src)
+ do_teleport(target, F, 0)
+ playsound(src,'sound/effects/sparks4.ogg',50,1)
+ break
+ return
+
+/mob/living/simple_animal/hostile/swarmer/proc/DismantleMachine(var/obj/machinery/target)
+ do_attack_animation(target)
+ src << "We begin to dismantle this machine. We will need to be uninterrupted."
+ new /obj/effect/effect/sparks(get_turf(target))
+ if(do_mob(src, target, 100))
+ src << "Dismantling complete."
+ var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(target.loc)
+ M.amount = 5
+ for(var/obj/item/I in target.component_parts)
+ I.loc = M.loc
+ new /obj/effect/effect/sparks(get_turf(target))
+ target.dropContents()
+ if(istype(target, /obj/machinery/computer))
+ var/obj/machinery/computer/C = target
+ if(C.circuit)
+ C.circuit.loc = M.loc
+ qdel(target)
+
+/obj/effect/swarmer //Default destroyable object for swarmer constructions
+ name = "swarmer construction"
+ desc = "Debug swarmer item, this shouldn't be here. Yell at a coder."
+ gender = NEUTER
+ icon = 'icons/mob/swarmer.dmi'
+ icon_state = "ui_light"
+ luminosity = 1
+ var/health = 30
+
+/obj/effect/swarmer/proc/TakeDamage(damage)
+ health -= damage
+ if(health <= 0)
+ qdel(src)
+
+/obj/effect/swarmer/bullet_act(obj/item/projectile/Proj)
+ if(Proj.damage)
+ if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
+ TakeDamage(Proj.damage)
+ ..()
+
+/obj/effect/swarmer/attackby(obj/item/weapon/I, mob/living/user, params)
+ if(istype(I, /obj/item/weapon))
+ user.changeNext_move(CLICK_CD_MELEE)
+ user.do_attack_animation(src)
+ TakeDamage(I.force)
+ return
+
+/obj/effect/swarmer/ex_act()
+ qdel(src)
+ return
+
+/obj/effect/swarmer/blob_act()
+ qdel(src)
+ return
+
+/obj/effect/swarmer/attack_animal(mob/living/user)
+ if(isanimal(user))
+ var/mob/living/simple_animal/S = user
+ S.do_attack_animation(src)
+ user.changeNext_move(CLICK_CD_MELEE)
+ if(S.melee_damage_type == BRUTE || S.melee_damage_type == BURN)
+ TakeDamage(rand(S.melee_damage_lower, S.melee_damage_upper))
+ return
+
+/mob/living/simple_animal/hostile/swarmer/proc/CreateTrap()
+ set name = "Create trap"
+ set category = "Swarmer"
+ set desc = "Creates a simple trap that will non-lethally electrocute anything that steps on it. Costs 5 resources"
+ if(/obj/effect/swarmer/trap in loc)
+ src << "There is already a trap here. Aborting."
+ return
+ Fabricate(/obj/effect/swarmer/trap, 5)
+ return
+
+/obj/effect/swarmer/trap
+ name = "swarmer trap"
+ desc = "A quickly assembled electric trap. Will not retain its form if damaged enough."
+ icon_state = "trap"
+ luminosity = 1
+ health = 10
+
+/obj/effect/swarmer/trap/Crossed(var/atom/movable/AM)
+ if(isliving(AM))
+ var/mob/living/L = AM
+ if(!istype(L, /mob/living/simple_animal/hostile/swarmer))
+ L.electrocute_act(0, src, 1, 1)
+ qdel(src)
+ ..()
+
+/mob/living/simple_animal/hostile/swarmer/proc/CreateBarricade()
+ set name = "Create barricade"
+ set category = "Swarmer"
+ set desc = "Creates a barricade that will stop anything but swarmers and disabler beams from passing through."
+ if(/obj/effect/swarmer/blockade in loc)
+ src << "There is already a blockade here. Aborting."
+ return
+ Fabricate(/obj/effect/swarmer/blockade, 5)
+ return
+
+/obj/effect/swarmer/blockade
+ name = "swarmer blockade"
+ desc = "A quickly assembled energy blockade. Will not retain its form if damaged enough, but disabler beams and swarmers pass right through."
+ icon_state = "barricade"
+ luminosity = 1
+ health = 50
+ density = 1
+ anchored = 1
+
+/obj/effect/swarmer/blockade/CanPass(atom/movable/O)
+ if(isswarmer(O))
+ return 1
+ if(istype(O, /obj/item/projectile/beam/disabler))
+ return 1
+
+/mob/living/simple_animal/hostile/swarmer/proc/CreateSwarmer()
+ set name = "Replicate"
+ set category = "Swarmer"
+ set desc = "Creates a shell for a new swarmer. Swarmers will self activate."
+ src << "We are attempting to replicate ourselves. We will need to stand still until the process is complete."
+ if(resources < 50)
+ src << "We do not have the resources for this!"
+ return
+ if(!isturf(loc))
+ src << "This is not a suitable location for replicating ourselves. We need more room."
+ return
+ if(do_mob(src, src, 100))
+ if(Fabricate(/obj/item/unactivated_swarmer, 50))
+ playsound(loc,'sound/items/poster_being_created.ogg',50, 1, -1)
+
+/mob/living/simple_animal/hostile/swarmer/proc/RepairSelf()
+ set name = "Self Repair"
+ set category = "Swarmer"
+ set desc = "Attempts to repair damage to our body. You will have to remain motionless until repairs are complete."
+ if(!isturf(loc))
+ return
+ src << "Attempting to repair damage to our body, stand by..."
+ if(do_mob(src, src, 100))
+ adjustBruteLoss(-100)
+ src << "We successfully repaired ourselves."
+
+/mob/living/simple_animal/hostile/swarmer/proc/ToggleLight()
+ if(!luminosity)
+ SetLuminosity(3)
+ else
+ SetLuminosity(0)
+
+/mob/living/simple_animal/hostile/swarmer/proc/ContactSwarmers()
+ var/message = input(src, "Announce to other swarmers", "Swarmer contact")
+ if(message)
+ for(var/mob/M in mob_list)
+ if(isswarmer(M) || (M in dead_mob_list))
+ M << "Swarm communication - [M] states: [message]"
+
+
+
+////HUD NONSENSE////
+/obj/screen/swarmer
+ icon = 'icons/mob/swarmer.dmi'
+
+/obj/screen/swarmer/FabricateTrap
+ icon_state = "ui_trap"
+ name = "Create trap"
+ desc = "Creates a trap that will nonlethally shock any non-swarmer that attempts to cross it. (Costs 5 resources)"
+
+/obj/screen/swarmer/FabricateTrap/Click()
+ if(isswarmer(usr))
+ var/mob/living/simple_animal/hostile/swarmer/S = usr
+ S.CreateTrap()
+
+/obj/screen/swarmer/Barricade
+ icon_state = "ui_barricade"
+ name = "Create barricade"
+ desc = "Creates a destructible barricade that will stop any non swarmer from passing it. Also allows disabler beams to pass through. (Costs 5 resources)"
+
+/obj/screen/swarmer/Barricade/Click()
+ if(isswarmer(usr))
+ var/mob/living/simple_animal/hostile/swarmer/S = usr
+ S.CreateBarricade()
+
+/obj/screen/swarmer/Replicate
+ icon_state = "ui_replicate"
+ name = "Replicate"
+ desc = "Creates a another of our kind. (Costs 50 resources)"
+
+/obj/screen/swarmer/Replicate/Click()
+ if(isswarmer(usr))
+ var/mob/living/simple_animal/hostile/swarmer/S = usr
+ S.CreateSwarmer()
+
+/obj/screen/swarmer/RepairSelf
+ icon_state = "ui_self_repair"
+ name = "Repair self"
+ desc = "Repairs damage to our body."
+
+/obj/screen/swarmer/RepairSelf/Click()
+ if(isswarmer(usr))
+ var/mob/living/simple_animal/hostile/swarmer/S = usr
+ S.RepairSelf()
+
+/obj/screen/swarmer/ToggleLight
+ icon_state = "ui_light"
+ name = "Toggle light"
+ desc = "Toggles our inbuilt light on or off."
+
+/obj/screen/swarmer/ToggleLight/Click()
+ if(isswarmer(usr))
+ var/mob/living/simple_animal/hostile/swarmer/S = usr
+ S.ToggleLight()
+
+/obj/screen/swarmer/ContactSwarmers
+ icon_state = "ui_contact_swarmers"
+ name = "Contact swarmers"
+ desc = "Sends a message to all other swarmers, should they exist."
+
+/obj/screen/swarmer/ContactSwarmers/Click()
+ if(isswarmer(usr))
+ var/mob/living/simple_animal/hostile/swarmer/S = usr
+ S.ContactSwarmers()
+
+/datum/hud/proc/swarmer_hud(ui_style = 'icons/mob/screen_midnight.dmi')
+ adding = list()
+
+ var/obj/screen/using
+
+ using = new /obj/screen/swarmer/FabricateTrap()
+ using.screen_loc = ui_rhand
+ adding += using
+
+ using = new /obj/screen/swarmer/Barricade()
+ using.screen_loc = ui_lhand
+ adding += using
+
+ using = new /obj/screen/swarmer/Replicate()
+ using.screen_loc = ui_zonesel
+ adding += using
+
+ using = new /obj/screen/swarmer/RepairSelf()
+ using.screen_loc = ui_storage1
+ adding += using
+
+ using = new /obj/screen/swarmer/ToggleLight()
+ using.screen_loc = ui_back
+ adding += using
+
+ using = new /obj/screen/swarmer/ContactSwarmers()
+ using.screen_loc = ui_inventory
+ adding += using
+
+ mymob.client.screen = list()
+ mymob.client.screen += mymob.client.void
+ mymob.client.screen += adding
+
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index f3910d8af2d..f41c7847b90 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -41,6 +41,8 @@
//LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly
var/melee_damage_lower = 0
var/melee_damage_upper = 0
+ var/melee_damage_type = BRUTE //Damage type of a simple mob's melee attack, should it do damage.
+ var/list/ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 0, CLONE = 0, STAMINA = 1, OXY = 0) //Set 0 to receive that damage type, 1 to ignore
var/attacktext = "attacks"
var/attack_sound = null
var/friendly = "nuzzles" //If the mob does no damage with it's attack
@@ -253,7 +255,7 @@
/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M)
if(..())
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- attack_threshold_check(damage)
+ attack_threshold_check(damage,M.melee_damage_type)
return 1
/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj)
@@ -263,8 +265,21 @@
Proj.on_hit(src)
return 0
+/mob/living/simple_animal/adjustBruteLoss(amount)
+ if(!ignored_damage_types[BRUTE])
+ ..()
+
/mob/living/simple_animal/adjustFireLoss(amount)
- adjustBruteLoss(amount)
+ if(!ignored_damage_types[BURN])
+ adjustBruteLoss(amount)
+
+/mob/living/simple_animal/adjustToxLoss(amount)
+ if(!ignored_damage_types[TOX])
+ ..(amount)
+
+/mob/living/simple_animal/adjustCloneLoss(amount)
+ if(!ignored_damage_types[CLONE])
+ ..(amount)
/mob/living/simple_animal/adjustStaminaLoss(amount)
return
@@ -334,8 +349,8 @@
attack_threshold_check(damage)
return 1
-/mob/living/simple_animal/proc/attack_threshold_check(damage)
- if(damage <= force_threshold)
+/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE)
+ if(damage <= force_threshold || ignored_damage_types[damagetype])
visible_message("[src] looks unharmed.")
else
adjustBruteLoss(damage)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 857b7f35181..c53fa9b1d3a 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -125,6 +125,11 @@
return 1
return 0
+/proc/isswarmer(A)
+ if(istype(A, /mob/living/simple_animal/hostile/swarmer))
+ return 1
+ return 0
+
/proc/islimb(A)
if(istype(A, /obj/item/organ/limb))
return 1
diff --git a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
index a8999d8ddac..14213840918 100644
--- a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
@@ -173,13 +173,36 @@
if(method == INGEST)
M.adjustToxLoss(0.5*reac_volume)
if(show_message)
- M << "You probably shouldn't have eaten that. Maybe you should of splashed it on, or applied a patch?"
+ M << "You probably shouldn't have eaten that. Maybe you should have splashed it on, or applied a patch?"
..()
/datum/reagent/medicine/silver_sulfadiazine/on_mob_life(mob/living/M)
M.adjustFireLoss(-2*REM)
..()
+/datum/reagent/medicine/oxandrolone
+ name = "Oxandrolone"
+ id = "oxandrolone"
+ description = "Stimulates healing of severe burns. If you have more than 50 burn damage, it heals 2 units; otherwise, 0.5. If overdosed it will exacerbate existing burns, causing burn and brute damage."
+ reagent_state = LIQUID
+ color = "#f7ffa5"
+ metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ overdose_threshold = 25
+
+/datum/reagent/medicine/oxandrolone/on_mob_life(mob/living/M)
+ if(M.getFireLoss() > 50)
+ M.adjustFireLoss(-2*REM)
+ else
+ M.adjustFireLoss(-0.5*REM)
+ ..()
+ return
+
+/datum/reagent/medicine/oxandrolone/overdose_process(mob/living/M)
+ M.adjustFireLoss(2.5*REM) // it's going to be healing either 2 or 0.5
+ M.adjustBruteLoss(0.5*REM)
+ ..()
+ return
+
/datum/reagent/medicine/styptic_powder
name = "Styptic Powder"
id = "styptic_powder"
diff --git a/code/modules/reagents/Chemistry-Recipes/Medicine.dm b/code/modules/reagents/Chemistry-Recipes/Medicine.dm
index 60e80923400..3ccc5753cc2 100644
--- a/code/modules/reagents/Chemistry-Recipes/Medicine.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Medicine.dm
@@ -116,6 +116,12 @@
required_reagents = list("sodium" = 1, "phenol" = 1, "carbon" = 1, "oxygen" = 1, "sacid" = 1)
result_amount = 5
+/datum/chemical_reaction/oxandrolone
+ name = "Oxandrolone"
+ id = "oxandrolone"
+ result = "oxandrolone"
+ required_reagents = list("carbon" = 3, "phenol" = 1, "hydrogen" = 1, "oxygen" = 1)
+ result_amount = 6
/datum/chemical_reaction/salbutamol
name = "Salbutamol"
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 2a99e768c75..94ece6ee2c0 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -133,6 +133,12 @@
icon_state = "pill5"
list_reagents = list("sal_acid" = 24)
roundstart = 1
+/obj/item/weapon/reagent_containers/pill/oxandrolone
+ name = "oxandrolone pill"
+ desc = "Used to stimulate burn healing."
+ icon_state = "pill5"
+ list_reagents = list("oxandrolone" = 24)
+ roundstart = 1
/obj/item/weapon/reagent_containers/pill/insulin
name = "insulin pill"
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index e57a3762319..acb72b88205 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -703,7 +703,8 @@
R.realProc = realProc
R.revealed = TRUE
dupes |= R
- R.throw_at(pick(oview(7,get_turf(src))),10,1)
+ spawn()
+ R.throw_at(pick(oview(7,get_turf(src))),10,1)
counter = 0
spawn(rand(10,100))
for(counter = 1; counter <= dupes.len; counter++)
diff --git a/html/changelog.html b/html/changelog.html
index 74b09bfbaa3..821377b3ad1 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -55,6 +55,13 @@
-->
+
28 August 2015
+
bgobandit updated:
+
+ - Overheard at CentComm: 'This burn kit said salicyclic acid would heal my burns! WHO MADE THIS SHIT?' A muffled honking is heard in the background. (Burn first-aid kits now contain an appropriate burn pill.)
+ - Oxandrolone, a new burn healing medication, has been added to burn first-aid kits and to chemistry. Ingesting 25 units or more causes burn and brute damage.
+
+
19 August 2015
Joan updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index eac761cfbc9..b84356a720c 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -1646,3 +1646,10 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscdel: Splashing someone with chemicals no longer injects those chemicals in
their body.
- bugfix: Fixes splashing acid on items or floor with items not having any effect.
+2015-08-28:
+ bgobandit:
+ - bugfix: 'Overheard at CentComm: ''This burn kit said salicyclic acid would heal
+ my burns! WHO MADE THIS SHIT?'' A muffled honking is heard in the background.
+ (Burn first-aid kits now contain an appropriate burn pill.)'
+ - rscadd: Oxandrolone, a new burn healing medication, has been added to burn first-aid
+ kits and to chemistry. Ingesting 25 units or more causes burn and brute damage.
diff --git a/icons/mob/swarmer.dmi b/icons/mob/swarmer.dmi
new file mode 100644
index 00000000000..96a9f9ae09e
Binary files /dev/null and b/icons/mob/swarmer.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 4b0e32905e0..e89d43409bb 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1229,6 +1229,7 @@
#include "code\modules\mob\living\simple_animal\parrot.dm"
#include "code\modules\mob\living\simple_animal\shade.dm"
#include "code\modules\mob\living\simple_animal\simple_animal.dm"
+#include "code\modules\mob\living\simple_animal\bot_swarm\swarmer.dm"
#include "code\modules\mob\living\simple_animal\friendly\butterfly.dm"
#include "code\modules\mob\living\simple_animal\friendly\cat.dm"
#include "code\modules\mob\living\simple_animal\friendly\crab.dm"