Takeover In Progress: [gang.dom_timer] seconds remain
"
- var/isboss = (user.mind in ticker.mode.get_gang_bosses())
+ var/isboss = (user.mind == gang.bosses[1])
var/points = gang.points
dat += "Registration: [gang.name] Gang [isboss ? "Boss" : "Lieutenant"] "
dat += "Organization Size: [gang.gangsters.len + gang.bosses.len] | Station Control: [round((gang.territory.len/start_state.num_territories)*100, 1)]% "
@@ -57,7 +57,7 @@
dat += "Create Armored Gang Outfit "
else
dat += "Create Gang Outfit (Restocking) "
- if(user.mind in ticker.mode.get_gang_bosses())
+ if(isboss)
dat += "Recall Emergency Shuttle "
dat += " "
@@ -158,7 +158,7 @@
dat += "Recruitment Pen "
var/gangtooltext = "Spare Gangtool"
- if((user.mind in ticker.mode.get_gang_bosses()) && gang.bosses.len < 3)
+ if(isboss && gang.bosses.len < 3)
gangtooltext = "Promote a Gangster"
dat += "(10 Influence) "
if(points >= 10)
@@ -258,7 +258,7 @@
pointcost = 10
if("gangtool")
if(gang.points >= 10)
- if(usr.mind in ticker.mode.get_gang_bosses())
+ if(usr.mind == gang.bosses[1])
item_type = /obj/item/device/gangtool/spare/lt
if(gang.bosses.len < 3)
usr << "Gangtools allow you to promote a gangster to be your Lieutenant, enabling them to recruit and purchase items like you. Simply have them register the gangtool. You may promote up to [3-gang.bosses.len] more Lieutenants"
@@ -301,7 +301,7 @@
else if(href_list["choice"])
switch(href_list["choice"])
if("recall")
- if(usr.mind in ticker.mode.get_gang_bosses())
+ if(usr.mind == gang.bosses[1])
recall(usr)
if("outfit")
if(outfits > 0)
@@ -326,7 +326,19 @@
members += gang.gangsters
members += gang.bosses
if(members.len)
- var/ping = "[gang.name] [(user.mind in ticker.mode.get_gang_bosses()) ? "Gang Boss" : "Lieutenant"]: [message]"
+ var/gang_rank = gang.bosses.Find(user.mind)
+ switch(gang_rank)
+ if(1)
+ gang_rank = "Gang Boss"
+ if(2)
+ gang_rank = "1st Lieutenant"
+ if(3)
+ gang_rank = "2nd Lieutenant"
+ if(4)
+ gang_rank = "3rd Lieutenant"
+ else
+ gang_rank = "[gang_rank - 1]th Lieutenant"
+ var/ping = "[gang.name] [gang_rank]: [message]"
for(var/datum/mind/ganger in members)
if(ganger.current && (ganger.current.z <= 2) && (ganger.current.stat == CONSCIOUS))
ganger.current << ping
diff --git a/code/game/gamemodes/intercept_report.dm b/code/game/gamemodes/intercept_report.dm
index 2b16b298975..84da89a5570 100644
--- a/code/game/gamemodes/intercept_report.dm
+++ b/code/game/gamemodes/intercept_report.dm
@@ -89,6 +89,10 @@
src.text = ""
src.build_changeling(correct_person)
return src.text
+ if("shadowling")
+ src.text = ""
+ src.build_shadowling(correct_person)
+ return src.text
else
return null
@@ -289,4 +293,10 @@
*/
src.text += "These lifeforms are associated with the [orgname1] [orgname2] and may be attempting to acquire sensitive materials on their behalf. "
src.text += "Please take care not to alarm the crew, as [cname] may take advantage of a panic situation. Remember, they can be anybody, suspect everybody!"
- src.text += " "
\ No newline at end of file
+ src.text += " "
+
+/datum/intercept_text/proc/build_shadowling(datum/mind/correct_person)
+ src.text += "
Sightings of strange alien creatures have been observed in your area. These aliens supposedly possess the ability to enslave unwitting personnel and leech from their power. \
+ Be wary of dark areas and ensure all lights are kept well-maintained. Closely monitor all crew for suspicious behavior and perform dethralling surgery if they have obvious tells. Investigate all \
+ reports of odd or suspicious sightings in maintenance."
+ src.text += "
"
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index ae618f0be1b..8f90c400ae9 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -371,81 +371,86 @@
src << "Overcurrent applied to the powernet."
else src << "Out of uses."
-/datum/AI_Module/small/reactivate_camera
- module_name = "Reactivate camera"
+/datum/AI_Module/small/reactivate_cameras
+ module_name = "Reactivate Camera Network"
mod_pick_name = "recam"
- description = "Reactivates a currently disabled camera. 5 uses."
- uses = 5
- cost = 5
+ description = "Runs a network-wide diagnostic on the camera network, resetting focus and re-routing power to failed cameras. Can be used to repair up to 30 cameras."
+ uses = 30
+ cost = 10
+ one_time = 1
- power_type = /mob/living/silicon/ai/proc/reactivate_camera
+ power_type = /mob/living/silicon/ai/proc/reactivate_cameras
-/mob/living/silicon/ai/proc/reactivate_camera(obj/machinery/camera/C in cameranet.cameras)
- set name = "Reactivate Camera"
+/mob/living/silicon/ai/proc/reactivate_cameras()
+ set name = "Reactivate Cameranet"
set category = "Malfunction"
- if(!canUseTopic())
+ if(!canUseTopic() || malf_cooldown)
return
+ var/fixedcams = 0 //Tells the AI how many cams it fixed. Stats are fun.
- if (istype (C, /obj/machinery/camera))
- for(var/datum/AI_Module/small/reactivate_camera/camera in current_modules)
+ for(var/datum/AI_Module/small/reactivate_cameras/camera in current_modules)
+ for(var/obj/machinery/camera/C in cameranet.cameras)
+ var/initial_range = initial(C.view_range) //To prevent calling the proc twice
if(camera.uses > 0)
if(!C.status)
- C.deactivate(src)
- camera.uses --
- src << "Camera reactivated."
- else
- src << "This camera is either active, or not repairable."
- else src << "Out of uses."
- else src << "That's not a camera."
+ C.deactivate(src, 0) //Reactivates the camera based on status. Badly named proc.
+ fixedcams++
+ camera.uses--
+ if(C.view_range != initial_range)
+ C.view_range = initial_range //Fixes cameras with bad focus.
+ camera.uses--
+ fixedcams++
+ //If a camera is both deactivated and has bad focus, it will cost two uses to fully fix!
+ else
+ src << "Out of uses."
+ verbs -= /mob/living/silicon/ai/proc/reactivate_cameras //It is useless now, clean it up.
+ break
+ src << "Diagnostic complete! Operations completed: [fixedcams]."
-/datum/AI_Module/small/upgrade_camera
- module_name = "Upgrade Camera"
+ malf_cooldown = 1
+ spawn(30) //Lag protection
+ malf_cooldown = 0
+
+/datum/AI_Module/large/upgrade_cameras
+ module_name = "Upgrade Camera Network"
mod_pick_name = "upgradecam"
- description = "Upgrades a camera to have X-ray vision, motion sensing and be EMP-Proof. 5 uses."
- uses = 5
- cost = 5
+ description = "Install broad-spectrum scanning and electrical redundancy firmware to the camera network, enabling EMP-Proofing and light-amplified X-ray vision." //I <3 pointless technobabble
+ //This used to have motion sensing as well, but testing quickly revealed that giving it to the whole cameranet is PURE HORROR.
+ one_time = 1
+ cost = 35 //Decent price for omniscience!
- power_type = /mob/living/silicon/ai/proc/upgrade_camera
+ power_type = /mob/living/silicon/ai/proc/upgrade_cameras
-/mob/living/silicon/ai/proc/upgrade_camera(obj/machinery/camera/C in cameranet.cameras)
- set name = "Upgrade Camera"
+/mob/living/silicon/ai/proc/upgrade_cameras()
+ set name = "Upgrade Cameranet"
set category = "Malfunction"
if(!canUseTopic())
return
- if(istype(C))
- var/datum/AI_Module/small/upgrade_camera/UC = locate(/datum/AI_Module/small/upgrade_camera) in current_modules
- if(UC)
- if(UC.uses > 0)
- if(C.assembly)
- var/upgraded = 0
+ var/upgradedcams = 0
+ see_override = SEE_INVISIBLE_MINIMUM //Night-vision, without which X-ray would be very limited in power.
- if(!C.isXRay())
- C.upgradeXRay()
- //Update what it can see.
- cameranet.updateVisibility(C, 0)
- upgraded = 1
+ for(var/obj/machinery/camera/C in cameranet.cameras)
+ if(C.assembly)
+ var/upgraded = 0
- if(!C.isEmpProof())
- C.upgradeEmpProof()
- upgraded = 1
+ if(!C.isXRay())
+ C.upgradeXRay()
+ //Update what it can see.
+ cameranet.updateVisibility(C, 0)
+ upgraded = 1
- if(!C.isMotion())
- C.upgradeMotion()
- upgraded = 1
- // Add it to machines that process
- SSmachine.processing |= C//machines |= C
+ if(!C.isEmpProof())
+ C.upgradeEmpProof()
+ upgraded = 1
- if(upgraded)
- UC.uses --
- C.visible_message("\icon[C] *beep*")
- src << "You successully upgrade the camera."
- else
- src << "This camera is already upgraded!"
- else
- src << "Out of uses!"
+ if(upgraded)
+ upgradedcams++
+
+ src << "OTA firmware distribution complete! Cameras upgraded: [upgradedcams]. Light amplification system online."
+ verbs -= /mob/living/silicon/ai/proc/upgrade_cameras
/datum/module_picker
var/temp = null
diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm
index e6b7500a866..3b453e491cc 100644
--- a/code/game/gamemodes/malfunction/malfunction.dm
+++ b/code/game/gamemodes/malfunction/malfunction.dm
@@ -302,4 +302,4 @@
text += " "
world << text
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 1cb47606530..ceb70737d79 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -181,13 +181,9 @@
synd_mob.equip_to_slot_or_del(U, slot_in_backpack)
var/obj/item/weapon/implant/weapons_auth/W = new/obj/item/weapon/implant/weapons_auth(synd_mob)
- W.imp_in = synd_mob
- W.implanted = 1
- W.implanted(synd_mob)
+ W.implant(synd_mob)
var/obj/item/weapon/implant/explosive/E = new/obj/item/weapon/implant/explosive(synd_mob)
- E.imp_in = synd_mob
- E.implanted = 1
- E.implanted(synd_mob)
+ E.implant(synd_mob)
synd_mob.faction |= "syndicate"
synd_mob.update_icons()
return 1
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 452288e8ffd..dd3b338b299 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -186,7 +186,7 @@
/datum/objective/hijack
- explanation_text = "Hijack the emergency shuttle by escaping alone."
+ explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive and out of custody."
dangerrating = 25
martyr_compatible = 0 //Technically you won't get both anyway.
@@ -462,6 +462,7 @@ var/global/list/possible_items_special = list()
/datum/objective/steal/exchange
dangerrating = 10
+ martyr_compatible = 0
/datum/objective/steal/exchange/proc/set_faction(faction,otheragent)
target = otheragent
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index 430b4c405f7..1330cdc6f06 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -77,7 +77,7 @@
difficulty = 5
/datum/objective_item/steal/nuke_core
- name = "the plutonium core from the onboard self-destruct"
+ name = "the heavily radioactive plutonium core from the onboard self-destruct. Take care to wear the proper safety equipment when extracting the core"
targetitem = /obj/item/nuke_core
difficulty = 15
diff --git a/code/game/gamemodes/shadowling/ascendant_shadowling.dm b/code/game/gamemodes/shadowling/ascendant_shadowling.dm
index c0dc989a7b3..9b51955136e 100644
--- a/code/game/gamemodes/shadowling/ascendant_shadowling.dm
+++ b/code/game/gamemodes/shadowling/ascendant_shadowling.dm
@@ -1,6 +1,6 @@
/mob/living/simple_animal/ascendant_shadowling
name = "ascendant shadowling"
- desc = "A large, floating eldritch horror. It has pulsing markings all about its body and large horns. It seems to be floating without any form of support."
+ desc = "HOLY SHIT RUN THE FUCK AWAY"
icon = 'icons/mob/mob.dmi'
icon_state = "shadowling_ascended"
icon_living = "shadowling_ascended"
@@ -16,14 +16,14 @@
see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
- response_help = "stares at"
+ response_help = "pokes"
response_disarm = "flails at"
response_harm = "flails at"
harm_intent_damage = 0
- melee_damage_lower = 35
- melee_damage_upper = 35
- attacktext = "claws at"
+ melee_damage_lower = 60 //Was 35, buffed
+ melee_damage_upper = 60
+ attacktext = "rends"
attack_sound = 'sound/weapons/slash.ogg'
minbodytemp = 0
@@ -36,4 +36,10 @@
return 1 //copypasta from carp code
/mob/living/simple_animal/ascendant_shadowling/get_spans()
- return ..() | list(SPAN_REALLYBIG, SPAN_YELL)
+ return ..() | list(SPAN_REALLYBIG, SPAN_YELL) //MAKES THEM SHOUT WHEN THEY TALK
+
+/mob/living/simple_animal/ascendant_shadowling/ex_act(severity)
+ return 0 //You think an ascendant can be hurt by bombs? HA
+
+/mob/living/simple_animal/ascendant_shadowling/singularity_act()
+ return 0 //Well hi, fellow god! How are you today?
diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm
index 52fb5a2899e..37223bac1d2 100644
--- a/code/game/gamemodes/shadowling/shadowling.dm
+++ b/code/game/gamemodes/shadowling/shadowling.dm
@@ -131,27 +131,61 @@ Made by Xhuis
/datum/game_mode/proc/finalize_shadowling(datum/mind/shadow_mind)
var/mob/living/carbon/human/S = shadow_mind.current
- shadow_mind.current.verbs += /mob/living/carbon/human/proc/shadowling_hatch
- shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/enthrall
+ shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_hatch(null))
+ shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/enthrall(null))
+ shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind(null))
spawn(0)
- shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
update_shadow_icons_added(shadow_mind)
if(shadow_mind.assigned_role == "Clown")
S << "Your alien nature has allowed you to overcome your clownishness."
S.dna.remove_mutation(CLOWNMUT)
/datum/game_mode/proc/add_thrall(datum/mind/new_thrall_mind)
- if (!istype(new_thrall_mind))
+ if(!istype(new_thrall_mind))
return 0
if(!(new_thrall_mind in thralls))
update_shadow_icons_added(new_thrall_mind)
thralls += new_thrall_mind
+ new_thrall_mind.special_role = "thrall"
new_thrall_mind.current.attack_log += "\[[time_stamp()]\] Became a thrall"
- new_thrall_mind.memory += "The Shadowlings' Objectives: [objective_explanation]"
- new_thrall_mind.current << "The objectives of the shadowlings: [objective_explanation]"
- new_thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
+ new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_shadowling_hivemind(null))
+ new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_glare(null))
+ new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_shadow_walk(null))
+ new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/thrall_vision(null))
+ new_thrall_mind.current << "You see the truth. Reality has been torn away and you realize what a fool you've been."
+ new_thrall_mind.current << "The shadowlings are your masters. Serve them above all else and ensure they complete their goals."
+ new_thrall_mind.current << "You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls."
+ new_thrall_mind.current << "Your body has been irreversibly altered. The attentive can see this - you may conceal it by wearing a mask."
+ new_thrall_mind.current << "Though not nearly as powerful as your masters, you possess some weak powers. These can be found in the Thrall Abilities tab."
+ new_thrall_mind.current << "You may communicate with your allies by using the Lesser Commune ability."
return 1
+/datum/game_mode/proc/remove_thrall(datum/mind/thrall_mind, var/kill = 0)
+ if(!istype(thrall_mind) || !(thrall_mind in thralls) || !isliving(thrall_mind.current)) return 0 //If there is no mind, the mind isn't a thrall, or the mind's mob isn't alive, return
+ update_shadow_icons_removed(thrall_mind)
+ thralls.Remove(thrall_mind)
+ thrall_mind.current.attack_log += "\[[time_stamp()]\] Dethralled"
+ thrall_mind.special_role = null
+ thrall_mind.remove_spell(/obj/effect/proc_holder/spell/targeted/lesser_shadowling_hivemind)
+ thrall_mind.remove_spell(/obj/effect/proc_holder/spell/targeted/lesser_glare)
+ thrall_mind.remove_spell(/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk)
+ thrall_mind.remove_spell(/obj/effect/proc_holder/spell/targeted/thrall_vision)
+ if(kill && ishuman(thrall_mind.current)) //If dethrallization surgery fails, kill the mob as well as dethralling them
+ var/mob/living/carbon/human/H = thrall_mind.current
+ H.visible_message("[H] jerks violently and falls still.", \
+ "A piercing white light floods your mind, banishing your memories as a thrall and--")
+ H.death()
+ return 1
+ var/mob/living/M = thrall_mind.current
+ if(issilicon(M))
+ M.audible_message("[M] lets out a short blip.", \
+ "You have been turned into a robot! You are no longer a thrall! Though you try, you cannot remember anything about your servitude...")
+ else
+ M.visible_message("[M] looks like their mind is their own again!", \
+ "A piercing white light floods your eyes. Your mind is your own again! Though you try, you cannot remember anything about the shadowlings or your time \
+ under their command...")
+ return 1
+
/datum/game_mode/shadowling/proc/check_shadow_victory()
var/success = 0 //Did they win?
if(shadow_objectives.Find("enthrall"))
@@ -165,7 +199,7 @@ Made by Xhuis
else if(shadowling_dead && !check_shadow_victory()) //If the shadowlings have ascended, they can not lose the round
world << "The shadowlings have been killed by the crew!"
else if(!check_shadow_victory() && SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
- world << "The crew has escaped the station before the shadowlings could ascend!"
+ world << "The crew escaped the station before the shadowlings could ascend!"
else
world << "The shadowlings have failed!"
..()
@@ -202,23 +236,20 @@ Made by Xhuis
heatmod = 2
/datum/species/shadow/ling/spec_life(mob/living/carbon/human/H)
- //H.shadowling_status = 1 //If they are affected more strongly by flashes and stuff
+ if(!H.weakeyes) H.weakeyes = 1 //Makes them more vulnerable to flashes and flashbangs
var/light_amount = 0
H.nutrition = NUTRITION_LEVEL_WELL_FED //i aint never get hongry
- if(isturf(H.loc)) //Copypasta
+ if(isturf(H.loc))
var/turf/T = H.loc
- var/area/A = T.loc
- if(A)
- if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount
- else light_amount = 10
- if(light_amount > LIGHT_DAM_THRESHOLD) //Not complete blackness - they can live in very small light levels plus starlight
+ light_amount = T.get_lumcount()
+ if(light_amount > LIGHT_DAM_THRESHOLD && !H.incorporeal_move) //Can survive in very small light levels. Also doesn't take damage while incorporeal, for shadow walk purposes
H.take_overall_damage(0, LIGHT_DAMAGE_TAKEN)
H << "The light burns you!"
H << 'sound/weapons/sear.ogg'
else if (light_amount < LIGHT_HEAL_THRESHOLD)
H.heal_overall_damage(5,5)
H.adjustToxLoss(-5)
- H.adjustBrainLoss(-25) //gibbering shadowlings are hilarious but also bad to have
+ H.adjustBrainLoss(-25) //Shad O. Ling gibbers, "CAN U BE MY THRALL?!!"
H.adjustCloneLoss(-1)
H.SetWeakened(0)
H.SetStunned(0)
@@ -232,3 +263,12 @@ Made by Xhuis
var/datum/atom_hud/antag/shadow_hud = huds[ANTAG_HUD_SHADOW]
shadow_hud.leave_hud(shadow_mind.current)
set_antag_hud(shadow_mind.current, null)
+
+/turf/proc/get_lumcount()
+ var/light_amount
+ if(!src || !istype(src)) return
+ var/area/A = src.loc
+ if(!A || !istype(src)) return
+ if(A.lighting_use_dynamic) light_amount = src.lighting_lumcount
+ else light_amount = 10
+ return light_amount
diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm
index 06a7747b2bb..9a8b8ab9482 100644
--- a/code/game/gamemodes/shadowling/shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm
@@ -1,15 +1,28 @@
-/obj/effect/proc_holder/spell/targeted/glare
+/obj/effect/proc_holder/spell/proc/shadowling_check(var/mob/living/carbon/human/H)
+ if(!H || !istype(H)) return
+ if(H.dna.species.id == "shadowling" && is_shadow(H)) return 1
+ if(!is_shadow_or_thrall(usr)) usr << "You can't wrap your head around how to do this."
+ else if(is_thrall(usr)) usr << "You aren't powerful enough to do this."
+ else if(is_shadow(usr)) usr << "Your telepathic ability is suppressed. Hatch or regenerate first."
+ return 0
+
+
+/obj/effect/proc_holder/spell/targeted/glare //Stuns and mutes a human target for 10 seconds
name = "Glare"
desc = "Stuns and mutes a target for a decent duration."
panel = "Shadowling Abilities"
charge_max = 300
clothes_req = 0
+ action_icon_state = "glare"
/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
if(!ishuman(target))
charge_counter = charge_max
return
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
if(target.stat)
charge_counter = charge_max
return
@@ -28,22 +41,22 @@
M.silent += 10
-
-/obj/effect/proc_holder/spell/aoe_turf/veil
+/obj/effect/proc_holder/spell/aoe_turf/veil //Puts out most nearby lights except for flares and yellow slime cores
name = "Veil"
desc = "Extinguishes most nearby light sources."
panel = "Shadowling Abilities"
charge_max = 250 //Short cooldown because people can just turn the lights back on
clothes_req = 0
range = 5
+ action_icon_state = "veil"
var/blacklisted_lights = list(/obj/item/device/flashlight/flare, /obj/item/device/flashlight/slime)
-/obj/effect/proc_holder/spell/aoe_turf/veil/proc/extinguishItem(obj/item/I) //WARNING NOT SUFFICIENT TO EXTINGUISH AN ITEM HELD BY A MOB
+/obj/effect/proc_holder/spell/aoe_turf/veil/proc/extinguishItem(obj/item/I) //Does not darken items held by mobs due to mobs having separate luminosity, use extinguishMob() or write your own proc.
if(istype(I, /obj/item/device/flashlight))
var/obj/item/device/flashlight/F = I
if(F.on)
if(is_type_in_list(I, blacklisted_lights))
- I.visible_message("[I] dims slightly, before the shadows around it scatter.")
+ I.visible_message("[I] dims slightly before scattering the shadows around it.")
return F.brightness_on //Necessary because flashlights become 0-luminosity when held. I don't make the rules of lightcode.
F.on = 0
F.update_brightness()
@@ -60,19 +73,22 @@
H.SetLuminosity(blacklistLuminosity) //I hate lightcode for making me do it this way
/obj/effect/proc_holder/spell/aoe_turf/veil/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
usr << "You silently disable all nearby lights."
for(var/turf/T in targets)
for(var/obj/item/F in T.contents)
extinguishItem(F)
for(var/obj/machinery/light/L in T.contents)
L.on = 0
- L.visible_message("[L] flickers and falls dark.")
+ L.visible_message("[L] flickers and falls dark.")
L.update(0)
for(var/obj/machinery/computer/C in T.contents)
C.SetLuminosity(0)
- C.visible_message("[C] grows dim, its screen barely readable.")
+ C.visible_message("[C] grows dim, its screen barely readable.")
for(var/obj/effect/glowshroom/G in orange(2, usr)) //Very small radius
- G.visible_message("\The [G] withers away!")
+ G.visible_message("[G] withers away!")
qdel(G)
for(var/mob/living/H in T.contents)
extinguishMob(H)
@@ -80,8 +96,7 @@
borgie.update_headlamp(1)
-
-/obj/effect/proc_holder/spell/targeted/shadow_walk
+/obj/effect/proc_holder/spell/targeted/shadow_walk //Grants the shadowling invisibility and phasing for 4 seconds
name = "Shadow Walk"
desc = "Phases you into the space between worlds for a short time, allowing movement through walls and invisbility."
panel = "Shadowling Abilities"
@@ -89,11 +104,16 @@
clothes_req = 0
range = -1
include_user = 1
+ action_icon_state = "shadow_walk"
+ sound = 'sound/effects/bamf.ogg'
/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets)
for(var/mob/living/user in targets)
- playsound(user.loc, 'sound/effects/bamf.ogg', 50, 1)
- user.visible_message("[user] vanishes in a puff of black mist!", "You enter the space between worlds as a passageway.")
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
+ playMagSound()
+ user.visible_message("[user] vanishes in a puff of black mist!", "You enter the space between worlds as a tunnel.")
user.SetStunned(0)
user.SetWeakened(0)
user.incorporeal_move = 1
@@ -101,64 +121,68 @@
if(user.buckled)
user.buckled.unbuckle_mob()
sleep(40) //4 seconds
- user.visible_message("[user] suddenly manifests!", "The pressure becomes too much and you vacate the interdimensional darkness.")
+ user.visible_message("[user] suddenly manifests!", "The pressure becomes too much and you exit the rift.")
user.incorporeal_move = 0
user.alpha = 255
-
-/obj/effect/proc_holder/spell/aoe_turf/flashfreeze
- name = "Flash Freeze"
+/obj/effect/proc_holder/spell/aoe_turf/flashfreeze //Stuns and freezes nearby people - a bit more effective than a changeling's cryosting
+ name = "Icy Veins"
desc = "Instantly freezes the blood of nearby people, stunning them and causing burn damage."
panel = "Shadowling Abilities"
range = 5
charge_max = 1200
clothes_req = 0
+ action_icon_state = "icy_veins"
+ sound = 'sound/effects/ghost2.ogg'
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
usr << "You freeze the nearby air."
- playsound(usr.loc, 'sound/effects/ghost2.ogg', 50, 1)
-
+ playMagSound()
for(var/turf/T in targets)
- for(var/mob/living/carbon/human/target in T.contents)
- if(is_shadow_or_thrall(target))
- if(target == usr) //No message for the user, of course
+ for(var/mob/living/carbon/M in T.contents)
+ if(is_shadow_or_thrall(M))
+ if(M == usr) //No message for the user, of course
continue
else
- target << "You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!"
+ M << "You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!"
continue
- target << "You are hit by a blast of paralyzingly cold air and feel goosebumps break out across your body!"
- target.Stun(2)
- if(target.bodytemperature)
- target.bodytemperature -= 200 //Extreme amount of initial cold
- if(target.reagents)
- target.reagents.add_reagent("frostoil", 15) //Half of a cryosting
+ M << "A wave of shockingly cold air engulfs you!"
+ M.Stun(2)
+ if(M.bodytemperature)
+ M.bodytemperature -= 200 //Extreme amount of initial cold
+ if(M.reagents)
+ M.reagents.add_reagent("frostoil", 15) //Half of a cryosting
-
-//Enthrall is the single most important spell
-/obj/effect/proc_holder/spell/targeted/enthrall
+/obj/effect/proc_holder/spell/targeted/enthrall //Turns a target into the shadowling's slave. This overrides all previous loyalties
name = "Enthrall"
desc = "Allows you to enslave a conscious, non-braindead, non-catatonic human to your will. This takes some time to cast."
panel = "Shadowling Abilities"
- charge_max = 450
+ charge_max = 0
clothes_req = 0
range = 1 //Adjacent to user
+ action_icon_state = "enthrall"
var/enthralling = 0
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets)
var/mob/living/carbon/human/user = usr
listclearnulls(ticker.mode.thralls)
- if(ticker.mode.thralls.len >= 5 && (user.dna.species.id != "shadowling"))
- user << "With your telepathic abilities suppressed, your human form will not allow you to enthrall any others. Hatch first."
- charge_counter = charge_max
- return
+ if(!shadowling_check(usr)) return
+ if(user.dna.species.id != "shadowling")
+ if(ticker.mode.thralls.len >= 5)
+ user << "With your telepathic abilities suppressed, your human form will not allow you to enthrall any others. Hatch first."
+ charge_counter = charge_max
+ return
for(var/mob/living/carbon/human/target in targets)
if(!in_range(usr, target))
usr << "You need to be closer to enthrall [target]."
charge_counter = charge_max
return
- if(!target.key)
+ if(!target.key || !target.mind)
usr << "The target has no mind."
charge_counter = charge_max
return
@@ -179,7 +203,7 @@
charge_counter = charge_max
return
if(!target.client)
- usr << "[target]'s mind is vacant of activity. Still, you may rearrange their memories in the case of their return."
+ usr << "[target]'s mind is vacant of activity."
enthralling = 1
usr << "This target is valid. You begin the enthralling."
target << "[usr] stares at you. You feel your head begin to pulse."
@@ -208,28 +232,24 @@
target << "Your unwavering loyalty to Nanotrasen unexpectedly falters, dims, dies. You feel a sense of liberation which is quickly stifled by terror."
if(3)
usr << "You begin rearranging [target]'s memories."
- usr.visible_message("[usr]'s eyes flare brightly, their unflinching gaze staring constantly at [target].")
+ usr.visible_message("[usr]'s eyes flare brightly.")
target << "Your head cries out. The veil of reality begins to crumple and something evil bleeds through." //Ow the edge
if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a loyalty implant
usr << "The enthralling has been interrupted - your target's mind returns to its previous state."
- target << "A spike of pain drives into your head. You aren't sure what's happened, but you feel a faint sense of revulsion."
+ target << "A spike of pain drives into your head, wiping your memory. You aren't sure what's happened, but you feel a faint sense of revulsion."
enthralling = 0
return
enthralling = 0
usr << "You have enthralled [target]!"
- target.visible_message("[target]'s expression appears as if they have experienced a revelation!", \
- "You see the Truth. Reality has been torn away and you realize what a fool you've been.")
- target << "The shadowlings are your masters. Serve them above all else and ensure they complete their goals."
- target << "You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls."
- target << "You can communicate with the other enlightened ones by using the Hivemind Commune ability."
+ target.visible_message("[target] looks to have experienced a revelation!", \
+ "False faces all dark not real not real not--")
target.setOxyLoss(0) //In case the shadowling was choking them out
ticker.mode.add_thrall(target.mind)
- target.mind.special_role = "Thrall"
+ target.mind.special_role = "thrall"
-
-/obj/effect/proc_holder/spell/targeted/shadowling_hivemind
+/obj/effect/proc_holder/spell/targeted/shadowling_hivemind //Lets a shadowling talk to its allies
name = "Hivemind Commune"
desc = "Allows you to silently communicate with all other shadowlings and thralls."
panel = "Shadowling Abilities"
@@ -237,19 +257,23 @@
clothes_req = 0
range = -1
include_user = 1
+ action_icon_state = "commune"
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind/cast(list/targets)
for(var/mob/living/user in targets)
- var/text = stripped_input(user, "What do you want to say to fellow thralls and shadowlings?.", "Hive Chat", "")
+ if(!is_shadow(user))
+ user << "As you attempt to commune with the others, an agonizing spike of pain drives itself into your head!"
+ user.apply_damage(10, BRUTE, "head")
+ return
+ var/text = stripped_input(user, "What do you want to say your thralls and fellow shadowlings?.", "Hive Chat", "")
if(!text)
return
for(var/mob/M in mob_list)
if(is_shadow_or_thrall(M) || (M in dead_mob_list))
- M << "\[Hive Chat\] [usr.real_name]: [text]"
+ M << "\[Shadowling\] [usr.real_name]: [text]"
-
-/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor
+/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor //Resets a shadowling's species to normal, removes genetic defects, and re-equips their armor
name = "Regenerate Chitin"
desc = "Re-forms protective chitin that may be lost during cloning or similar processes."
panel = "Shadowling Abilities"
@@ -257,10 +281,11 @@
clothes_req = 0
range = -1
include_user = 1
+ action_icon_state = "regen_armor"
/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor/cast(list/targets)
for(var/mob/living/user in targets)
- user.visible_message("[user]'s skin suddenly bubbles and begins to shift around their body!", \
+ user.visible_message("[user]'s skin suddenly bubbles and shifts around their body!", \
"You regenerate your protective armor and cleanse your form of defects.")
user.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(usr), slot_w_uniform)
user.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(usr), slot_shoes)
@@ -269,11 +294,10 @@
user.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves)
user.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask)
user.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/shadowling(usr), slot_glasses)
- hardset_dna(user, null, null, null, null, /datum/species/shadow/ling) //can't be a shadowling without being a shadowling
+ hardset_dna(user, null, null, null, null, /datum/species/shadow/ling)
-
-/obj/effect/proc_holder/spell/targeted/collective_mind
+/obj/effect/proc_holder/spell/targeted/collective_mind //Lets a shadowling bring together their thralls' strength, granting new abilities and a headcount
name = "Collective Hivemind"
desc = "Gathers the power of all of your thralls and compares it to what is needed for ascendance. Also gains you new abilities."
panel = "Shadowling Abilities"
@@ -281,6 +305,7 @@
clothes_req = 0
range = -1
include_user = 1
+ action_icon_state = "collective_mind"
var/blind_smoke_acquired
var/screech_acquired
var/drainLifeAcquired
@@ -288,6 +313,9 @@
/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets)
for(var/mob/living/user in targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
var/thralls = 0
var/victory_threshold = 15
var/mob/M
@@ -312,7 +340,7 @@
if(thralls >= 5 && !drainLifeAcquired)
drainLifeAcquired = 1
user << "The power of your thralls has granted you the Drain Life ability. You can now drain the health of nearby humans to heal yourself."
- user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/drainLife
+ user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/drain_life
if(thralls >= 7 && !screech_acquired)
screech_acquired = 1
@@ -323,7 +351,7 @@
reviveThrallAcquired = 1
user << "The power of your thralls has granted you the Black Recuperation ability. This will, after a short time, bring a dead thrall completely back to life \
with no bodily defects."
- user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/reviveThrall
+ user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/revive_thrall
if(thralls < victory_threshold)
user << "You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present."
@@ -333,17 +361,19 @@
usr << "You may find Ascendance in the Shadowling Evolution tab."
for(M in living_mob_list)
if(is_shadow(M))
- M.mind.spell_list -= /obj/effect/proc_holder/spell/targeted/collective_mind
- M.mind.current.verbs -= /mob/living/carbon/human/proc/shadowling_hatch //In case a shadowling hasn't hatched
- M.mind.current.verbs += /mob/living/carbon/human/proc/shadowling_ascendance
+ var/obj/effect/proc_holder/spell/targeted/collective_mind/CM
+ if(CM in M.mind.spell_list)
+ M.mind.spell_list -= CM
+ qdel(CM)
+ M.mind.remove_spell(/obj/effect/proc_holder/spell/targeted/shadowling_hatch)
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_ascend(null))
if(M == usr)
M << "You project this power to the rest of the shadowlings."
else
M << "[user.real_name] has coalesced the strength of the thralls. You can draw upon it at any time to ascend. (Shadowling Evolution Tab)" //Tells all the other shadowlings
-
-/obj/effect/proc_holder/spell/targeted/blindness_smoke
+/obj/effect/proc_holder/spell/targeted/blindness_smoke //Spawns a cloud of smoke that blinds non-thralls/shadows and grants slight healing to shadowlings and their allies
name = "Blindness Smoke"
desc = "Spews a cloud of smoke which will blind enemies."
panel = "Shadowling Abilities"
@@ -351,13 +381,18 @@
clothes_req = 0
range = -1
include_user = 1
+ action_icon_state = "black_smoke"
+ sound = 'sound/effects/bamf.ogg'
/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets) //Extremely hacky
for(var/mob/living/user in targets)
- user.visible_message("[user] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!")
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
+ playMagSound()
+ user.visible_message("[user] bends over and coughs out a cloud of black smoke!")
user << "You regurgitate a vast cloud of blinding smoke."
- playsound(user, 'sound/effects/bamf.ogg', 50, 1)
- var/obj/item/weapon/reagent_containers/glass/beaker/large/B = new /obj/item/weapon/reagent_containers/glass/beaker/large(user.loc)
+ var/obj/item/weapon/reagent_containers/glass/beaker/large/B = new /obj/item/weapon/reagent_containers/glass/beaker/large(user.loc) //hacky
B.reagents.clear_reagents() //Just in case!
B.icon_state = null //Invisible
B.reagents.add_reagent("blindness_smoke", 10)
@@ -370,7 +405,7 @@
S.start()
qdel(B)
-datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowlings/thralls
+datum/reagent/shadowling_blindness_smoke //Reagent used for above spell
name = "odd black liquid"
id = "blindness_smoke"
description = "<::ERROR::> CANNOT ANALYZE REAGENT <::ERROR::>"
@@ -394,19 +429,22 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
return
-
-/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech
+/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech //Damages nearby windows, confuses nearby carbons, and outright stuns silly cones
name = "Sonic Screech"
desc = "Deafens, stuns, and confuses nearby people. Also shatters windows."
panel = "Shadowling Abilities"
range = 7
charge_max = 300
clothes_req = 0
+ action_icon_state = "screech"
+ sound = 'sound/effects/screech.ogg'
/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
usr.audible_message("[usr] lets out a horrible scream!")
- playsound(usr.loc, 'sound/effects/screech.ogg', 100, 1)
-
+ playMagSound()
for(var/turf/T in targets)
for(var/mob/target in T.contents)
if(is_shadow_or_thrall(target))
@@ -421,7 +459,7 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
M.setEarDamage(M.ear_damage + 3)
else if(issilicon(target))
var/mob/living/silicon/S = target
- S << "ERROR $!(@ ERROR )#^! SENSOR OVERLOAD \[$(!@#"
+ S << "ERROR $!(@ ERROR )#^! SENSORY OVERLOAD \[$(!@#"
S << 'sound/misc/interference.ogg'
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
var/datum/effect/effect/system/spark_spread/sp = new /datum/effect/effect/system/spark_spread
@@ -432,22 +470,26 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
W.hit(rand(80, 100))
-
-/obj/effect/proc_holder/spell/aoe_turf/drainLife
+/obj/effect/proc_holder/spell/aoe_turf/drain_life //Deals stamina and oxygen damage to nearby humans and heals the shadowling. On a short cooldown because of the small range and situational usefulness
name = "Drain Life"
desc = "Damages nearby humans, draining their life and healing your own wounds."
panel = "Shadowling Abilities"
range = 3
charge_max = 100
clothes_req = 0
+ action_icon_state = "drain_life"
var/targetsDrained
var/list/nearbyTargets
-/obj/effect/proc_holder/spell/aoe_turf/drainLife/cast(list/targets, mob/living/carbon/human/U = usr)
+/obj/effect/proc_holder/spell/aoe_turf/drain_life/cast(list/targets, mob/living/carbon/human/U = usr)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
targetsDrained = 0
nearbyTargets = list()
for(var/turf/T in targets)
for(var/mob/living/carbon/M in T.contents)
+ if(M == src) continue
targetsDrained++
nearbyTargets.Add(M)
if(!targetsDrained)
@@ -467,8 +509,7 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
usr << "You draw life from those around you to heal your wounds."
-
-/obj/effect/proc_holder/spell/targeted/reviveThrall
+/obj/effect/proc_holder/spell/targeted/revive_thrall //Completely revives a dead thrall
name = "Black Recuperation"
desc = "Brings a dead thrall back to life."
panel = "Shadowling Abilities"
@@ -476,15 +517,13 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
charge_max = 3000
clothes_req = 0
include_user = 0
+ action_icon_state = "revive_thrall"
var/list/thralls_in_world = list()
-/obj/effect/proc_holder/spell/targeted/reviveThrall/Topic(href, href_list)
- if(href_list["reenter"])
- var/mob/dead/observer/ghost = usr
- if(istype(ghost))
- ghost.reenter_corpse(ghost)
-
-/obj/effect/proc_holder/spell/targeted/reviveThrall/cast(list/targets)
+/obj/effect/proc_holder/spell/targeted/revive_thrall/cast(list/targets)
+ if(!shadowling_check(usr))
+ charge_counter = charge_max
+ return
for(var/mob/living/carbon/human/thrallToRevive in targets)
if(!is_thrall(thrallToRevive))
usr << "[thrallToRevive] is not a thrall."
@@ -496,19 +535,16 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
return
usr.visible_message("[usr] kneels over [thrallToRevive], placing their hands on \his chest.", \
"You crouch over the body of your thrall and begin gathering energy...")
- var/mob/dead/observer/ghost = thrallToRevive.get_ghost()
- if(ghost)
- ghost << "Your masters are resuscitating you! Re-enter your corpse if you wish to be brought to life.(Click to re-enter)"
- ghost << 'sound/effects/genetics.ogg'
- if(!do_mob(usr, thrallToRevive, 100))
+ thrallToRevive.notify_ghost_cloning("Your masters are resuscitating you! Re-enter your corpse if you wish to be brought to life.")
+ if(!do_mob(usr, thrallToRevive, 30))
usr << "Your concentration snaps. The flow of energy ebbs."
charge_counter= charge_max
return
- usr << "You release a massive surge of energy into [thrallToRevive]!"
+ usr << "You release a massive surge of power into [thrallToRevive]!"
usr.visible_message("Red lightning surges from [usr]'s hands into [thrallToRevive]'s chest!")
playsound(thrallToRevive, 'sound/weapons/Egloves.ogg', 50, 1)
playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
- sleep(20)
+ sleep(10)
thrallToRevive.revive()
thrallToRevive.visible_message("[thrallToRevive] draws in a huge breath, blinding violet light shining from their eyes.", \
"You have returned. One of your masters has brought you from the darkness beyond.")
@@ -516,15 +552,129 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
thrallToRevive.emote("gasp")
playsound(thrallToRevive, "bodyfall", 50, 1)
+
+// THRALL ABILITIES BEYOND THIS POINT //
+
+
+/obj/effect/proc_holder/spell/targeted/lesser_glare //Thrall version of Glare - same effects but for 3 seconds
+ name = "Lesser Glare"
+ desc = "Stuns and mutes a target for a short duration."
+ panel = "Thrall Abilities"
+ charge_max = 450
+ clothes_req = 0
+ action_icon_state = "glare"
+
+/obj/effect/proc_holder/spell/targeted/lesser_glare/cast(list/targets)
+ for(var/mob/living/carbon/human/target in targets)
+ if(!ishuman(target) || !target)
+ charge_counter = charge_max
+ return
+ if(target.stat)
+ charge_counter = charge_max
+ return
+ if(is_shadow_or_thrall(target))
+ usr << "You don't see why you would want to paralyze an ally."
+ charge_counter = charge_max
+ return
+ var/mob/living/carbon/human/M = target
+ usr.visible_message("[usr]'s eyes flash a bright red!")
+ target.visible_message("[target] freezes in place, their eyes clouding...")
+ if(in_range(target, usr))
+ target << "Your gaze is forcibly drawn into [usr]'s eyes, and you are starstruck by the heavenly lights..."
+ else //Only alludes to the shadowling if the target is close by
+ target << "Red lights suddenly dance in your vision, and you are starstruck by their heavenly beauty..."
+ target.Stun(3) //Roughly 30% as long as the normal one
+ M.silent += 3
+
+
+/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk //Thrall version of Shadow Walk, only works in darkness, doesn't grant phasing, but gives near-invisibility
+ name = "Guise"
+ desc = "Wraps your form in shadows, making you harder to see."
+ panel = "Thrall Abilities"
+ charge_max = 1200
+ clothes_req = 0
+ range = -1
+ include_user = 1
+ action_icon_state = "shadow_walk"
+
+/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk/cast(list/targets)
+ for(var/mob/living/user in targets)
+ var/lumcount = 0
+ var/turf/T = user.loc
+ lumcount = T.get_lumcount()
+ if(lumcount > LIGHT_DAM_THRESHOLD)
+ user << "It's too bright to do that!"
+ charge_counter = charge_max
+ return
+ user.visible_message("[user] suddenly fades away!", "You veil yourself in darkness, making you harder to see.")
+ user.alpha = 20
+ sleep(40)
+ user.visible_message("[user] appears from nowhere!", "Your shadowy guise slips away.")
+ user.alpha = initial(user.alpha)
+
+
+/obj/effect/proc_holder/spell/targeted/thrall_vision //Toggleable night vision for thralls
+ name = "Darksight"
+ desc = "Gives you night vision."
+ panel = "Thrall Abilities"
+ charge_max = 0
+ range = -1
+ include_user = 1
+ clothes_req = 0
+ action_icon_state = "collective_mind"
+ var/active = 0
+
+/obj/effect/proc_holder/spell/targeted/thrall_vision/cast(list/targets)
+ for(var/mob/living/user in targets)
+ if(!istype(user) || !ishuman(user)) return
+ var/mob/living/carbon/human/H = user
+ active = !active
+ if(active)
+ user << "You shift the nerves in your eyes, allowing you to see in the dark."
+ H.see_in_dark = 8
+ H.dna.species.invis_sight = SEE_INVISIBLE_MINIMUM
+ else
+ user << "You return your vision to normal."
+ H.see_in_dark = 0
+ H.dna.species.invis_sight = initial(H.dna.species.invis_sight)
+
+
+/obj/effect/proc_holder/spell/targeted/lesser_shadowling_hivemind //Lets a thrall talk with their allies
+ name = "Lesser Commune"
+ desc = "Allows you to silently communicate with all other shadowlings and thralls."
+ panel = "Thrall Abilities"
+ charge_max = 50
+ clothes_req = 0
+ range = -1
+ include_user = 1
+ action_icon_state = "commune"
+
+/obj/effect/proc_holder/spell/targeted/lesser_shadowling_hivemind/cast(list/targets)
+ for(var/mob/living/user in targets)
+ if(!is_shadow_or_thrall(user))
+ user << "As you attempt to commune with the others, an agonizing spike of pain drives itself into your head!"
+ user.apply_damage(10, BRUTE, "head")
+ return
+ var/text = stripped_input(user, "What do you want to say your masters and fellow thralls?.", "Lesser Commune", "")
+ if(!text)
+ return
+ for(var/mob/M in mob_list)
+ if(is_shadow_or_thrall(M) || (M in dead_mob_list))
+ M << "\[Thrall\] [usr.real_name]: [text]"
+
+
// ASCENDANT ABILITIES BEYOND THIS POINT //
-/obj/effect/proc_holder/spell/targeted/annihilate
+
+/obj/effect/proc_holder/spell/targeted/annihilate //Gibs someone instantly.
name = "Annihilate"
- desc = "Gibs a human after a short time."
+ desc = "Gibs someone instantly."
panel = "Ascendant"
range = 7
charge_max = 0
clothes_req = 0
+ action_icon_state = "annihilate"
+ sound = 'sound/magic/Staff_Chaos.ogg'
/obj/effect/proc_holder/spell/targeted/annihilate/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
@@ -533,30 +683,29 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
charge_counter = charge_max
return
- for(var/mob/living/carbon/human/boom in targets)
+ for(var/mob/living/boom in targets)
if(is_shadow_or_thrall(boom))
usr << "Making an ally explode seems unwise."
charge_counter = charge_max
return
- usr.visible_message("[usr]'s eyes flare as they gesture at [boom]!", \
- "You direct a lance of telekinetic energy at [boom].")
- boom << "You feel an immense pressure building all across your body!"
- boom.Stun(10)
- boom.audible_message("[boom] screams!")
- sleep(20)
- playsound(boom, 'sound/effects/splat.ogg', 100, 1)
+ usr.visible_message("[usr]'s markings flare as they gesture at [boom]!", \
+ "You direct a lance of telekinetic energy into [boom].")
+ playMagSound()
+ sleep(4)
+ if(iscarbon(boom))
+ playsound(boom, 'sound/magic/Disintegrate.ogg', 100, 1)
boom.visible_message("[boom] explodes!")
boom.gib()
-
-/obj/effect/proc_holder/spell/targeted/hypnosis
+/obj/effect/proc_holder/spell/targeted/hypnosis //Enthralls someone instantly. Nonlethal alternative to Annihilate
name = "Hypnosis"
desc = "Instantly enthralls a human."
panel = "Ascendant"
range = 7
charge_max = 0
clothes_req = 0
+ action_icon_state = "enthrall"
/obj/effect/proc_holder/spell/targeted/hypnosis/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
@@ -570,7 +719,7 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
usr << "You cannot enthrall an ally."
charge_counter = charge_max
return
- if(!target.ckey)
+ if(!target.ckey || !target.mind)
usr << "The target has no mind."
charge_counter = charge_max
return
@@ -585,18 +734,13 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
usr << "You instantly rearrange [target]'s memories, hyptonitizing them into a thrall."
target << "An agonizing spike of pain drives into your mind, and--"
- target << "And you see the Truth. Reality has been torn away and you realize what a fool you've been."
- target << "The shadowlings are your masters. Serve them above all else and ensure they complete their goals."
- target << "You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls."
- target << "You can communicate with the other enlightened ones by using the Hivemind Commune ability."
ticker.mode.add_thrall(target.mind)
- target.mind.special_role = "Thrall"
+ target.mind.special_role = "thrall"
var/datum/mind/thrall_mind = target.mind
thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
-
-/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
+/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift //Permanent version of shadow walk with no drawback. Toggleable.
name = "Phase Shift"
desc = "Phases you into the space between worlds at will, allowing you to move through walls and become invisible."
panel = "Ascendant"
@@ -604,6 +748,7 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
include_user = 1
charge_max = 15
clothes_req = 0
+ action_icon_state = "shadow_walk"
/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
@@ -621,41 +766,39 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
SHA.alpha = 255
-
-/obj/effect/proc_holder/spell/aoe_turf/glacial_blast
- name = "Glacial Blast"
- desc = "Extremely empowered version of Flash Freeze."
+/obj/effect/proc_holder/spell/aoe_turf/ascendant_storm //Releases bolts of lightning to everyone nearby
+ name = "Lightning Storm"
+ desc = "Shocks everyone nearby."
panel = "Ascendant"
- range = 5
+ range = 6
charge_max = 100
clothes_req = 0
+ action_icon_state = "lightning_storm"
+ sound = 'sound/magic/lightningbolt.ogg'
-/obj/effect/proc_holder/spell/aoe_turf/glacial_blast/cast(list/targets)
+/obj/effect/proc_holder/spell/aoe_turf/ascendant_storm/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
usr << "You are not in the same plane of existence. Unphase first."
+ charge_counter = charge_max
return
-
- usr << "You freeze the nearby air."
- playsound(usr.loc, 'sound/effects/ghost2.ogg', 100, 1)
+ playMagSound()
+ usr.visible_message("A massive ball of lightning appears in [usr]'s hands and flares out!", \
+ "You conjure a ball of lightning and release it.")
for(var/turf/T in targets)
for(var/mob/living/carbon/human/target in T.contents)
if(is_shadow_or_thrall(target))
if(target == usr) //No message for the user, of course
continue
- else
- target << "You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!"
- continue
- target << "You are hit by a blast of cold unlike anything you have ever felt. Your limbs instantly lock in place and you feel ice burns across your body!"
- target.Weaken(15)
- if(target.bodytemperature)
- target.bodytemperature -= INFINITY //:^)
- target.take_organ_damage(0,80)
+ target << "You are struck by a bolt of lightning!"
+ playsound(target, 'sound/magic/LightningShock.ogg', 50, 1)
+ target.Weaken(8)
+ target.take_organ_damage(0,50)
+ usr.Beam(target,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
-
-/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant
+/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant //Large, all-caps text in shadowling chat
name = "Ascendant Commune"
desc = "Allows you to LOUDLY communicate with all other shadowlings and thralls."
panel = "Ascendant"
@@ -663,6 +806,7 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
clothes_req = 0
range = -1
include_user = 1
+ action_icon_state = "commune"
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant/cast(list/targets)
for(var/mob/living/user in targets)
@@ -672,11 +816,10 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
text = "[text]"
for(var/mob/M in mob_list)
if(is_shadow_or_thrall(M) || (M in dead_mob_list))
- M << "\[Hive Chat\] [usr.real_name] (ASCENDANT): [text]" //Bigger text for ascendants.
+ M << "\[Ascendant\] [usr.real_name]: [text]" //Bigger text for ascendants.
-
-/obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit
+/obj/effect/proc_holder/spell/targeted/ascendant_transmit //Sends a message to the entire world. If this gets abused too much it can be removed safely
name = "Ascendant Broadcast"
desc = "Sends a message to the whole wide world."
panel = "Ascendant"
@@ -684,8 +827,9 @@ datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowl
clothes_req = 0
range = -1
include_user = 1
+ action_icon_state = "transmit"
-/obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit/cast(list/targets)
+/obj/effect/proc_holder/spell/targeted/ascendant_transmit/cast(list/targets)
for(var/mob/living/user in targets)
var/text = stripped_input(user, "What do you want to say to everything on and near [world.name]?.", "Transmit to World", "")
if(!text)
diff --git a/code/game/gamemodes/shadowling/shadowling_items.dm b/code/game/gamemodes/shadowling/shadowling_items.dm
index 3d35167214f..5d5de93e57b 100644
--- a/code/game/gamemodes/shadowling/shadowling_items.dm
+++ b/code/game/gamemodes/shadowling/shadowling_items.dm
@@ -97,7 +97,6 @@
/obj/structure/shadow_vortex/Crossed(td)
..()
if(ismob(td))
- td << "You enter the rift. Sickening chimes begin to jangle in your ears. \
- All around you is endless blackness. After you see something moving, you realize it isn't entirely lifeless." //A bit of spooking before they die
+ td << "You enter the rift. Deafening chimes jingle in your ears. You are swallowed in darkness."
playsound(loc, 'sound/effects/EMPulse.ogg', 25, 1)
qdel(td)
diff --git a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
index 8953b771466..0a047b152a8 100644
--- a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
@@ -1,167 +1,177 @@
//In here: Hatch and Ascendance
-var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "Noaey'gief", "Mii`mahza", "Amerziox", "Gyrg-mylin", "Kanet'pruunance", "Vigistaezian")
-/mob/living/carbon/human/proc/shadowling_hatch()
- set category = "Shadowling Evolution"
- set name = "Hatch"
+var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "Noaey'gief", "Mii`mahza", "Amerziox", "Gyrg-mylin", "Kanet'pruunance", "Vigistaezian") //Unpronouncable 2: electric boogalo
+/obj/effect/proc_holder/spell/targeted/shadowling_hatch
+ name = "Hatch"
+ desc = "Casts off your disguise."
+ panel = "Shadowling Evolution"
+ charge_max = 3000
+ clothes_req = 0
+ range = -1
+ include_user = 1
+ action_icon_state = "hatch"
- if(usr.stat)
- return
- usr.verbs -= /mob/living/carbon/human/proc/shadowling_hatch
- switch(alert("Are you sure you want to hatch? You cannot undo this!",,"Yes","No"))
- if("No")
- usr << "You decide against hatching for now."
- usr.verbs += /mob/living/carbon/human/proc/shadowling_hatch
- return
- if("Yes")
- usr.Stun(INFINITY) //This is bad but notransform won't work.
- usr.visible_message("[usr]'s things suddenly slip off. They hunch over and vomit up a copious amount of purple goo which begins to shape around them!", \
- "You remove any equipment which would hinder your hatching and begin regurgitating the resin which will protect you.")
+/obj/effect/proc_holder/spell/targeted/shadowling_hatch/cast(list/targets)
+ if(usr.stat || !ishuman(usr) || !usr || !is_shadow(usr)) return
+ for(var/mob/living/carbon/human/H in targets)
+ var/hatch_or_no = alert(H,"Are you sure you want to hatch? You cannot undo this!",,"Yes","No")
+ switch(hatch_or_no)
+ if("No")
+ H << "You decide against hatching for now."
+ charge_counter = charge_max
+ return
+ if("Yes")
+ H.Stun(INFINITY) //This is bad but notransform won't work.
+ H.visible_message("[H]'s things suddenly slip off. They hunch over and vomit up a copious amount of purple goo which begins to shape around them!", \
+ "You remove any equipment which would hinder your hatching and begin regurgitating the resin which will protect you.")
- for(var/obj/item/I in usr) //drops all items
- usr.unEquip(I)
+ for(var/obj/item/I in H) //drops all items
+ H.unEquip(I)
- sleep(50)
- var/turf/simulated/floor/F
- var/turf/shadowturf = get_turf(usr)
- for(F in orange(1, usr))
- new /obj/structure/alien/resin/wall/shadowling(F)
- for(var/obj/structure/alien/resin/wall/shadowling/R in shadowturf) //extremely hacky
- qdel(R)
- new /obj/structure/alien/weeds/node(shadowturf) //Dim lighting in the chrysalis -- removes itself with the chrysalis
+ sleep(50)
+ var/turf/simulated/floor/F
+ var/turf/shadowturf = get_turf(usr)
+ for(F in orange(1, usr))
+ new /obj/structure/alien/resin/wall/shadowling(F)
+ for(var/obj/structure/alien/resin/wall/shadowling/R in shadowturf) //extremely hacky
+ qdel(R)
+ new /obj/structure/alien/weeds/node(shadowturf) //Dim lighting in the chrysalis -- removes itself afterwards
- usr.visible_message("A chrysalis forms around [usr], sealing them inside.", \
- "You create your chrysalis and begin to contort within.")
+ H.visible_message("A chrysalis forms around [H], sealing them inside.", \
+ "You create your chrysalis and begin to contort within.")
- sleep(100)
- usr.visible_message("The skin on [usr]'s back begins to split apart. Black spines slowly emerge from the divide.", \
- "Spines pierce your back. Your claws break apart your fingers. You feel excruciating pain as your true form begins its exit.")
+ sleep(100)
+ H.visible_message("The skin on [H]'s back begins to split apart. Black spines slowly emerge from the divide.", \
+ "Spines pierce your back. Your claws break apart your fingers. You feel excruciating pain as your true form begins its exit.")
- sleep(90)
- usr.visible_message("[usr], skin shifting, begins tearing at the walls around them.", \
- "Your false skin slips away. You begin tearing at the fragile membrane protecting you.")
+ sleep(90)
+ H.visible_message("[H], skin shifting, begins tearing at the walls around them.", \
+ "Your false skin slips away. You begin tearing at the fragile membrane protecting you.")
- sleep(80)
- playsound(usr.loc, 'sound/weapons/slash.ogg', 25, 1)
- usr << "You rip and slice."
- sleep(10)
- playsound(usr.loc, 'sound/weapons/slashmiss.ogg', 25, 1)
- usr << "The chrysalis falls like water before you."
- sleep(10)
- playsound(usr.loc, 'sound/weapons/slice.ogg', 25, 1)
- usr << "You are free!"
+ sleep(80)
+ playsound(H.loc, 'sound/weapons/slash.ogg', 25, 1)
+ H << "You rip and slice."
+ sleep(10)
+ playsound(H.loc, 'sound/weapons/slashmiss.ogg', 25, 1)
+ H << "The chrysalis falls like water before you."
+ sleep(10)
+ playsound(H.loc, 'sound/weapons/slice.ogg', 25, 1)
+ H << "You are free!"
- sleep(10)
- playsound(usr.loc, 'sound/effects/ghost.ogg', 100, 1)
- var/newNameId = pick(possibleShadowlingNames)
- possibleShadowlingNames.Remove(newNameId)
- usr.real_name = newNameId
- usr.name = usr.real_name
- usr.SetStunned(0)
- usr << "YOU LIVE!!!"
+ sleep(10)
+ playsound(H.loc, 'sound/effects/ghost.ogg', 100, 1)
+ var/newNameId = pick(possibleShadowlingNames)
+ possibleShadowlingNames.Remove(newNameId)
+ H.real_name = newNameId
+ H.name = usr.real_name
+ H.SetStunned(0)
+ H << "YOU LIVE!!!"
- for(var/obj/structure/alien/resin/wall/shadowling/W in orange(usr, 1))
- playsound(W, 'sound/effects/splat.ogg', 50, 1)
- qdel(W)
- for(var/obj/structure/alien/weeds/node/N in shadowturf)
- qdel(N)
- usr.visible_message("The chrysalis explodes in a shower of purple flesh and fluid!")
- var/mob/living/carbon/human/M = usr
- M.underwear = "Nude"
- M.undershirt = "Nude"
- M.socks = "Nude"
- M.faction |= "faithless"
+ for(var/obj/structure/alien/resin/wall/shadowling/W in orange(H, 1))
+ playsound(W, 'sound/effects/splat.ogg', 50, 1)
+ qdel(W)
+ for(var/obj/structure/alien/weeds/node/N in shadowturf)
+ qdel(N)
+ H.visible_message("The chrysalis explodes in a shower of purple flesh and fluid!")
+ H.underwear = "Nude"
+ H.undershirt = "Nude"
+ H.socks = "Nude"
+ H.faction |= "faithless"
- usr.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(usr), slot_w_uniform)
- usr.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(usr), slot_shoes)
- usr.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(usr), slot_wear_suit)
- usr.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(usr), slot_head)
- usr.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves)
- usr.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask)
- usr.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/shadowling(usr), slot_glasses)
- hardset_dna(usr, null, null, null, null, /datum/species/shadow/ling) //can't be a shadowling without being a shadowling
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(H), slot_w_uniform)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(H), slot_shoes)
+ H.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(H), slot_wear_suit)
+ H.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(H), slot_head)
+ H.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(H), slot_gloves)
+ H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(H), slot_wear_mask)
+ H.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/shadowling(H), slot_glasses)
+ hardset_dna(H, null, null, null, null, /datum/species/shadow/ling) //can't be a shadowling without being a shadowling
- sleep(10)
- usr << "Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies."
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/glare
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/veil
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadow_walk
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/collective_mind
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_regenarmor
+ sleep(10)
+ H << "Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies."
+ H.mind.remove_spell(/obj/effect/proc_holder/spell/targeted/shadowling_hatch)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/glare(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/veil(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/collective_mind(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_regenarmor(null))
-/mob/living/carbon/human/proc/shadowling_ascendance()
- set category = "Shadowling Evolution"
- set name = "Ascendance"
+/obj/effect/proc_holder/spell/targeted/shadowling_ascend
+ name = "Ascend"
+ desc = "Enters your true form."
+ panel = "Shadowling Evolution"
+ charge_max = 3000
+ clothes_req = 0
+ range = -1
+ include_user = 1
+ action_icon_state = "ascend"
- if(usr.stat)
- return
- usr.verbs -= /mob/living/carbon/human/proc/shadowling_ascendance
- switch(alert("It is time to ascend. Are you completely sure about this? You cannot undo this!",,"Yes","No"))
- if("No")
- usr << "You decide against ascending for now."
- usr.verbs += /mob/living/carbon/human/proc/shadowling_ascendance
- return
- if("Yes")
- usr.Stun(INFINITY)
- usr.visible_message("[usr] rapidly bends and contorts, their eyes flaring a deep crimson!", \
- "You begin unlocking the genetic vault within you and prepare yourself for the power to come.")
+/obj/effect/proc_holder/spell/targeted/shadowling_ascend/cast(list/targets)
+ if(usr.stat || !ishuman(usr) || !usr || !shadowling_check(usr)) return
+ for(var/mob/living/carbon/human/H in targets)
+ var/hatch_or_no = alert(H,"It is time to ascend. Are you sure about this?",,"Yes","No")
+ switch(hatch_or_no)
+ if("No")
+ H << "You decide against ascending for now."
+ charge_counter = charge_max
+ return
+ if("Yes")
+ H.notransform = 1
+ H.visible_message("[H]'s things suddenly slip off. They gently rise into the air, red light glowing in their eyes.", \
+ "You rise into the air and get ready for your transformation.")
- sleep(30)
- usr.visible_message("[usr] suddenly shoots up a few inches in the air and begins hovering there, still twisting.", \
- "You hover into the air to make room for your new form.")
+ for(var/obj/item/I in H) //drops all items
+ H.unEquip(I)
- sleep(60)
- usr.visible_message("[usr]'s skin begins to pulse red in sync with their eyes. Their form slowly expands outward.", \
- "You feel yourself beginning to mutate.")
+ sleep(50)
- sleep(20)
- if(!ticker.mode.shadowling_ascended)
- usr << "It isn't enough. Time to draw upon your thralls."
- else
- usr << "After some telepathic searching, you find the reservoir of life energy from the thralls and tap into it."
+ H.visible_message("[H]'s skin begins to crack and harden.", \
+ "Your flesh begins creating a shield around yourself.")
- sleep(50)
- for(var/mob/M in mob_list)
- if(is_thrall(M) && !ticker.mode.shadowling_ascended)
- M.visible_message("[M] trembles minutely as they collapse, black smoke pouring from their disintegrating face.", \
- "It's time! Your masters are ascending! Your last thoughts are happy as your body is drained of life.")
+ sleep(100)
+ H.visible_message("The small horns on [H]'s head slowly grow and elongate.", \
+ "Your body continues to mutate. Your telepathic abilities grow.") //y-your horns are so big, senpai...!~
- ticker.mode.thralls -= M.mind //To prevent message spam
- M.death(0)
+ sleep(90)
+ H.visible_message("[H]'s body begins to violently stretch and contort.", \
+ "You begin to rend apart the final barries to godhood.")
- usr << "Drawing upon your thralls, you find the strength needed to finish and rend apart the final barriers to godhood."
- sleep(20)
- usr << "Yes!"
- sleep(10)
- usr << "YES!"
- sleep(10)
- usr << "YE--"
- sleep(1)
- for(var/mob/living/M in orange(7, src))
- M.Weaken(10)
- M << "An immense pressure slams you onto the ground!"
- world << "\"VYSHA NERADA YEKHEZET U'RUU!!\""
- world << 'sound/hallucinations/veryfar_noise.ogg'
- for(var/obj/machinery/power/apc/A in world)
- A.overload_lighting()
- var/mob/A = new /mob/living/simple_animal/ascendant_shadowling(usr.loc)
- usr.mind.spell_list = list()
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/annihilate
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/hypnosis
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/glacial_blast
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant
- usr.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit
- usr.mind.transfer_to(A)
- A.name = usr.real_name
- if(A.real_name)
- A.real_name = usr.real_name
- usr.invisibility = 60 //This is pretty bad, but is also necessary for the shuttle call to function properly
- usr.flags |= GODMODE
- sleep(50)
- if(!ticker.mode.shadowling_ascended)
- SSshuttle.emergency.request(null, 0.3)
- ticker.mode.shadowling_ascended = 1
- qdel(usr)
+ sleep(40)
+ H << "Yes!"
+ sleep(10)
+ H << "YES!!"
+ sleep(10)
+ H << "YE--"
+ sleep(1)
+ for(var/mob/living/M in orange(7, H))
+ M.Weaken(10)
+ M << "An immense pressure slams you onto the ground!"
+ world << "\"VYSHA NERADA YEKHEZET U'RUU!!\""
+ world << 'sound/hallucinations/veryfar_noise.ogg'
+ for(var/obj/machinery/power/apc/A in apcs_list)
+ A.overload_lighting()
+ var/mob/A = new /mob/living/simple_animal/ascendant_shadowling(H.loc)
+ for(var/obj/effect/proc_holder/spell/S in H.mind.spell_list)
+ if(S == src) continue
+ H.mind.remove_spell(S)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/annihilate(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/hypnosis(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/ascendant_storm(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ascendant_transmit(null))
+ H.mind.transfer_to(A)
+ A.name = H.real_name
+ if(A.real_name)
+ A.real_name = H.real_name
+ H.invisibility = 60 //This is pretty bad, but is also necessary for the shuttle call to function properly
+ H.flags |= GODMODE
+ H.loc = A
+ sleep(50)
+ if(!ticker.mode.shadowling_ascended)
+ SSshuttle.emergency.request(null, 0.3)
+ ticker.mode.shadowling_ascended = 1
+ A.mind.remove_spell(src)
+ qdel(H)
diff --git a/code/game/gamemodes/traitor/double_agents.dm b/code/game/gamemodes/traitor/double_agents.dm
index 78deaacba09..af284603f6a 100644
--- a/code/game/gamemodes/traitor/double_agents.dm
+++ b/code/game/gamemodes/traitor/double_agents.dm
@@ -35,11 +35,13 @@
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = traitor
destroy_objective.target = target_mind
+ destroy_objective.update_explanation_text()
traitor.objectives += destroy_objective
else
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = traitor
kill_objective.target = target_mind
+ kill_objective.update_explanation_text()
traitor.objectives += kill_objective
// Escape
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index d222919684c..c053983d4c0 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -458,3 +458,118 @@ var/global/list/multiverse = list()
W.registered_name = M.real_name
W.update_label(M.real_name)
M.equip_to_slot_or_del(W, slot_wear_id)
+
+
+/obj/item/voodoo
+ name = "wicker doll"
+ desc = "Something creepy about it."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state = "voodoo"
+ item_state = "electronic"
+ var/mob/living/carbon/human/target = null
+ var/list/mob/living/carbon/human/possible = list()
+ var/obj/item/link = null
+ var/cooldown_time = 30 //3s
+ var/cooldown = 0
+ burntime = 0
+ burn_state = 0
+
+/obj/item/voodoo/attackby(obj/item/I, mob/user, params)
+ if(target && cooldown < world.time)
+ if(is_hot(I))
+ target << "You suddenly feel very hot"
+ target.bodytemperature += 50
+ GiveHint(target)
+ else if(is_pointed(I))
+ target << "You feel a stabbing pain in [parse_zone(user.zone_sel.selecting)]!"
+ target.Weaken(2)
+ GiveHint(target)
+ else if(istype(I,/obj/item/weapon/bikehorn))
+ target << "HONK"
+ target << 'sound/items/AirHorn.ogg'
+ target.adjustEarDamage(0,3)
+ GiveHint(target)
+ cooldown = world.time +cooldown_time
+ return
+
+ if(!link)
+ if(I.loc == user && istype(I) && I.w_class <= 2)
+ user.drop_item()
+ I.loc = src
+ link = I
+ user << "You attach [I] to the doll."
+ update_targets()
+ ..()
+
+/obj/item/voodoo/check_eye(mob/user)
+ return src.loc == user
+
+/obj/item/voodoo/attack_self(mob/user)
+ if(!target)
+ target = input(user, "Select your victim!", "Voodoo") as null|anything in possible
+ return
+ if(target && cooldown < world.time)
+ switch(user.zone_sel.selecting)
+ if("mouth")
+ var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text)
+ target.say(wgw)
+ log_game("[user][user.key] made [target][target.key] say [wgw] with a voodoo doll.")
+ if("eyes")
+ user.set_machine(src)
+ if(user.client)
+ user.client.eye = target
+ user.client.perspective = EYE_PERSPECTIVE
+ spawn(100)
+ user.reset_view()
+ user.unset_machine()
+ if("r_leg","l_leg")
+ user << "You move the doll's legs around."
+ var/turf/T = get_step(target,pick(cardinal))
+ target.Move(T)
+ if("r_arm","l_arm")
+ //use active hand on random nearby mob
+ var/list/nearby_mobs = list()
+ for(var/mob/living/L in range(target,1))
+ if(L!=target)
+ nearby_mobs |= L
+ if(nearby_mobs.len)
+ var/mob/living/T = pick(nearby_mobs)
+ log_game("[user][user.key] made [target][target.key] click on [T] with a voodoo doll.")
+ target.ClickOn(T)
+ GiveHint(target)
+ if("head")
+ user << "You smack the doll's head with your hand."
+ target.Dizzy(10)
+ target << "You suddenly feel as if your head was hit with a hammer!"
+ GiveHint(target,user)
+ if("chest")
+ if(link)
+ target = null
+ link.loc = get_turf(src)
+ user << "You remove the [link] from the doll."
+ link = null
+ update_targets()
+ cooldown = world.time + cooldown_time
+
+/obj/item/voodoo/proc/update_targets()
+ possible = list()
+ if(!link)
+ return
+ for(var/mob/living/carbon/human/H in living_mob_list)
+ if(md5(H.dna.uni_identity) in link.fingerprints)
+ possible |= H
+
+/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
+ if(prob(50) || force)
+ var/way = dir2text(get_dir(victim,get_turf(src)))
+ victim << "You feel a dark presence from [way]"
+ if(prob(20) || force)
+ var/area/A = get_area(src)
+ victim << "You feel a dark presence from [A.name]"
+
+/obj/item/voodoo/fire_act()
+ if(target)
+ target.adjust_fire_stacks(20)
+ target.IgniteMob()
+ GiveHint(target,1)
+ return ..()
\ No newline at end of file
diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm
index d7f0cfc38e8..df515f88db8 100644
--- a/code/game/gamemodes/wizard/rightandwrong.dm
+++ b/code/game/gamemodes/wizard/rightandwrong.dm
@@ -2,7 +2,7 @@
/proc/rightandwrong(summon_type, mob/user, survivor_probability) //0 = Summon Guns, 1 = Summon Magic
var/list/gunslist = list("taser","egun","laser","revolver","detective","c20r","nuclear","deagle","gyrojet","pulse","suppressed","cannon","doublebarrel","shotgun","combatshotgun","bulldog","mateba","sabr","crossbow","saw","car","boltaction","speargun","arg","uzi")
- var/list/magiclist = list("fireball","smoke","blind","mindswap","forcewall","knock","horsemask","charge", "summonitem", "wandnothing", "wanddeath", "wandresurrection", "wandpolymorph", "wandteleport", "wanddoor", "wandfireball", "staffchange", "staffhealing", "armor", "scrying","staffdoor", "special")
+ var/list/magiclist = list("fireball","smoke","blind","mindswap","forcewall","knock","horsemask","charge", "summonitem", "wandnothing", "wanddeath", "wandresurrection", "wandpolymorph", "wandteleport", "wanddoor", "wandfireball", "staffchange", "staffhealing", "armor", "scrying","staffdoor","voodoo", "special")
var/list/magicspeciallist = list("staffchange","staffanimation", "wandbelt", "contract", "staffchaos", "necromantic")
if(user) //in this case either someone holding a spellbook or a badmin
@@ -139,6 +139,8 @@
if (!(H.dna.check_mutation(XRAY)))
H.dna.add_mutation(XRAY)
H << "The walls suddenly disappear."
+ if("voodoo")
+ new /obj/item/voodoo(get_turf(H))
if("special")
magiclist -= "special" //only one super OP item per summoning max
switch (randomizemagicspecial)
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index 00a3306e3e1..0f3fe47fac3 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -115,8 +115,10 @@
for(var/obj/item/W in T)
T.unEquip(W)
init_shade(C, T, U)
- //qdel T //Gib instead
return 1
+ else
+ U << "Capture failed!: The soul has already fled it's mortal frame. You attempt to bring it back..."
+ getCultGhost(C,T,U)
return 0
if("VICTIM")
var/mob/living/carbon/human/T = target
@@ -134,7 +136,8 @@
U << "Capture failed!: Kill or maim the victim first!"
else
if(T.client == null)
- U << "Capture failed!: The soul has already fled it's mortal frame."
+ U << "Capture failed!: The soul has already fled it's mortal frame. You attempt to bring it back..."
+ getCultGhost(C,T,U)
else
if(C.contents.len)
U << "Capture failed!: The soul stone is full! Use or free an existing soul to make room."
@@ -237,3 +240,37 @@
if(vic)
U << "Capture successful!: [T.real_name]'s soul has been ripped from their body and stored within the soul stone."
U << "The soulstone has been imprinted with [S.real_name]'s mind, it will no longer react to other souls."
+
+
+/obj/item/device/soulstone/proc/getCultGhost(obj/item/device/soulstone/C, mob/living/carbon/human/T, mob/U)
+ var/list/candidates = get_candidates(BE_CULTIST)
+
+ shuffle(candidates)
+
+ var/time_passed = world.time
+ var/list/consenting_candidates = list()
+
+ for(var/candidate in candidates)
+
+ spawn(0)
+ switch(alert(candidate, "Would you like to play as a Shade? Please choose quickly!","Confirmation","Yes","No"))
+ if("Yes")
+ if((world.time-time_passed)>=50 || !src)
+ return
+ consenting_candidates += candidate
+
+ sleep(50)
+
+ if(consenting_candidates.len)
+ var/client/ghost = null
+ ghost = pick(consenting_candidates)
+ if(C.contents.len) //If they used the soulstone on someone else in the meantime
+ return 0
+ if(!T.client) //If the original returns in the alloted time
+ T.client = ghost
+ for(var/obj/item/W in T)
+ T.unEquip(W)
+ init_shade(C, T, U)
+ qdel(T)
+ else
+ U << "The ghost has fled beyond your grasp."
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index 932e6a8c63b..6ed742e75a4 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -248,6 +248,13 @@
qdel(spell_to_remove)
mind.spell_list -= spell_to_remove
+/datum/mind/proc/remove_spell(var/obj/effect/proc_holder/spell/spell) //To remove a specific spell from a mind - use AddSpell to add one
+ if(!spell) return
+ for(var/obj/effect/proc_holder/spell/S in spell_list)
+ if(istype(S, spell))
+ qdel(S)
+ spell_list -= S
+
/*Checks if the wizard can cast spells.
Made a proc so this is not repeated 14 (or more) times.*/
/mob/proc/casting()
diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm
index 3d97869a1ca..2af85ca36ba 100644
--- a/code/game/jobs/job/captain.dm
+++ b/code/game/jobs/job/captain.dm
@@ -89,3 +89,5 @@ Head of Personnel
//Equip ID box & telebaton
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/ids(H.back), slot_in_backpack)
H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack)
+
+ announce_head(H.mind, list("Supply", "Service")) //tell underlings (suuply/service) they have a head
diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm
index e686d1e9593..fa8f10f9eff 100644
--- a/code/game/jobs/job/engineering.dm
+++ b/code/game/jobs/job/engineering.dm
@@ -41,6 +41,8 @@ Chief Engineer
//Equip telebaton
H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack)
+ announce_head(H.mind, list("Engineering")) //tell underlings (engineering radio) they have a head
+
/*
Station Engineer
*/
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index e77878cd7f0..fe7638427f8 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -167,4 +167,10 @@
return max(0, minimal_player_age - C.player_age)
/datum/job/proc/config_check()
- return 1
\ No newline at end of file
+ return 1
+
+/datum/job/proc/announce_head(var/datum/mind/o_mind, var/channels) //tells the given channel that the given mind is the new department head. See communications.dm for valid channels.
+ spawn(4) //to allow some initialization
+ if(announcement_systems.len)
+ var/obj/machinery/announcement_system/announcer = pick(announcement_systems)
+ announcer.announce("NEWHEAD", o_mind.name, o_mind.assigned_role, channels)
diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm
index 083aedb3ac2..7485f8442ca 100644
--- a/code/game/jobs/job/medical.dm
+++ b/code/game/jobs/job/medical.dm
@@ -35,6 +35,8 @@ Chief Medical Officer
H.equip_to_slot_or_del(new /obj/item/device/flashlight/pen(H), slot_s_store)
H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack)
+ announce_head(H.mind, list("Medical")) //tell underlings (medical radio) they have a head
+
/*
Medical Doctor
*/
diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm
index 518813f2990..9f571c85ea2 100644
--- a/code/game/jobs/job/science.dm
+++ b/code/game/jobs/job/science.dm
@@ -37,6 +37,8 @@ Research Director
H.equip_to_slot_or_del(new /obj/item/device/laser_pointer(H), slot_l_store)
H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack)
+ announce_head(H.mind, list("Science")) //tell underlings (science radio) they have a head
+
/*
Scientist
*/
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index 9adfaef00ca..2d8bdefcbde 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -52,6 +52,8 @@ Head of Security
L.implanted = 1
H.sec_hud_set_implants()
+ announce_head(H.mind, list("Security")) //tell underlings (security radio) they have a head
+
/*
Warden
*/
diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm
new file mode 100644
index 00000000000..e69df9c883c
--- /dev/null
+++ b/code/game/machinery/announcement_system.dm
@@ -0,0 +1,196 @@
+var/list/announcement_systems = list()
+
+/obj/machinery/announcement_system
+ density = 1
+ anchored = 1
+ name = "\improper Automated Announcement System"
+ desc = "An automated announcement system that handles minor announcements over the radio."
+ icon = 'icons/obj/machines/telecomms.dmi'
+ icon_state = "AAS_On"
+ var/obj/item/device/radio/headset/radio
+
+ verb_say = "coldly states"
+ verb_ask = "queries"
+ verb_exclaim = "alarms"
+
+ var/broken = 0
+
+ idle_power_usage = 20
+ active_power_usage = 50
+
+ var/arrival = "%PERSON has signed up as %RANK"
+ var/arrivalToggle = 1
+ var/newhead = "%PERSON, %RANK, is the department head."
+ var/newheadToggle = 1
+
+ var/greenlight = "Light_Green"
+ var/pinklight = "Light_Pink"
+ var/errorlight = "Error_Red"
+
+/obj/machinery/announcement_system/New()
+ ..()
+ announcement_systems += src
+ radio = new /obj/item/device/radio/headset/ai(src)
+
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/announcement_system(null)
+ component_parts += new /obj/item/stack/cable_coil(null, 2)
+ component_parts += new /obj/item/weapon/stock_parts/console_screen(null)
+ RefreshParts()
+
+ update_icon()
+
+/obj/machinery/announcement_system/update_icon()
+ if(is_operational())
+ icon_state = (panel_open ? "AAS_On_Open" : "AAS_On")
+ else
+ icon_state = (panel_open ? "AAS_Off_Open" : "AAS_Off")
+
+
+ overlays.Cut()
+ if(arrivalToggle)
+ overlays |= greenlight
+ else
+ overlays -= greenlight
+
+ if(newheadToggle)
+ overlays |= pinklight
+ else
+ overlays -= pinklight
+
+ if(broken)
+ overlays |= errorlight
+ else
+ overlays -= errorlight
+
+/obj/machinery/announcement_system/Destroy()
+ announcement_systems -= src //"OH GOD WHY ARE THERE 100,000 LISTED ANNOUNCEMENT SYSTEMS?!!"
+
+/obj/machinery/announcement_system/power_change()
+ ..()
+ update_icon()
+
+/obj/machinery/announcement_system/attackby(obj/item/P, mob/user, params)
+ if(istype(P, /obj/item/weapon/screwdriver))
+ if(!panel_open)
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You open the maintenance hatch of [src]."
+ panel_open = 1
+ else
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You close the maintenance hatch of [src]."
+ panel_open = 0
+ update_icon()
+ return
+
+ if(panel_open)
+ default_deconstruction_crowbar(P)
+ if(istype(P, /obj/item/device/multitool) && broken)
+ user << "You reset [src]'s firmware."
+ broken = 0
+ update_icon()
+
+/obj/machinery/announcement_system/attack_hand(mob/user)
+ if(can_be_used_by(user))
+ Interact(user)
+
+/obj/machinery/announcement_system/proc/CompileText(str, user, rank) //replaces user-given variables with actual thingies.
+ str = replacetext(str, "%PERSON", "[user]")
+ str = replacetext(str, "%RANK", "[rank]")
+ return str
+
+/obj/machinery/announcement_system/proc/announce(message_type, user, rank, list/channels)
+ if(!is_operational())
+ return
+
+ var/message
+
+ if(message_type == "ARRIVAL" && arrivalToggle)
+ message = CompileText(arrival, user, rank)
+
+ else if(message_type == "NEWHEAD" && newheadToggle)
+ message = CompileText(newhead, user, rank)
+
+ if(channels.len == 0)
+ radio.talk_into(src, message, null, list(SPAN_ROBOT))
+ else
+ for(var/channel in channels)
+ radio.talk_into(src, message, channel, list(SPAN_ROBOT))
+
+//config stuff
+
+/obj/machinery/announcement_system/proc/Interact(mob/user)
+ if(!can_be_used_by(user))
+ return
+
+ if(broken)
+ visible_message("[src] buzzes.", "You hear a faint buzz.")
+ playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1)
+ return
+
+
+ var/contents = "Arrival Announcement: ([(arrivalToggle ? "On" : "Off")]) \n[arrival]
\n"
+
+ var/datum/browser/popup = new(user, "announcement_config", "Automated Announcement Configuration", 370, 220)
+ popup.set_content(contents)
+ popup.open()
+
+/obj/machinery/announcement_system/Topic(href, href_list)
+ if(!can_be_used_by(usr) || usr.lying || usr.stat || usr.stunned)
+ return
+ if(broken)
+ visible_message("[src] buzzes.", "You hear a faint buzz.")
+ playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1)
+ return
+
+ if(href_list["ArrivalTopic"])
+ var/NewMessage = stripped_input(usr, "Enter in the arrivals announcement configuration.", "Arrivals Announcement Config", arrival)
+ if(!in_range(src, usr) && src.loc != usr && !isAI(usr))
+ return
+ if(NewMessage)
+ arrival = NewMessage
+ else if(href_list["NewheadTopic"])
+ var/NewMessage = stripped_input(usr, "Enter in the departmental head announcement configuration.", "Head Departmental Announcement Config", newhead)
+ if(!in_range(src, usr) && src.loc != usr && !isAI(usr))
+ return
+ if(NewMessage)
+ newhead = NewMessage
+
+ else if(href_list["NewheadT-Topic"])
+ newheadToggle = !newheadToggle
+ update_icon()
+ else if(href_list["ArrivalT-Topic"])
+ arrivalToggle = !arrivalToggle
+ update_icon()
+
+ add_fingerprint(usr)
+ Interact(usr)
+ return
+
+/obj/machinery/announcement_system/attack_ai(mob/living/silicon/ai/user)
+ if(!isAI(user))
+ return
+ if(broken)
+ user << "[src]'s firmware appears to be malfunctioning!"
+ return
+ Interact(user)
+
+/obj/machinery/announcement_system/proc/act_up() //does funny breakage stuff
+ broken = 1
+ update_icon()
+
+ arrival = pick("#!@%ERR-34%2 CANNOT LOCAT@# JO# F*LE!", "CRITICAL ERROR 99.", "ERR)#: DA#AB@#E NOT F(*ND!")
+ newhead = pick("OV#RL()D: \[UNKNOWN??\] DET*#CT)D!", "ER)#R - B*@ TEXT F*O(ND!", "AAS.exe is not responding. NanoOS is searching for a solution to the problem.")
+
+/obj/machinery/announcement_system/emp_act(severity)
+ if(stat & (NOPOWER|BROKEN))
+ ..(severity)
+ return
+ act_up()
+ ..(severity)
+
+/obj/machinery/announcement_system/emag_act()
+ ..()
+ emagged = 1
+ act_up()
\ No newline at end of file
diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm
index 47d32366084..5f6835bff24 100644
--- a/code/game/machinery/atmoalter/meter.dm
+++ b/code/game/machinery/atmoalter/meter.dm
@@ -119,6 +119,11 @@
usr << status()
return 1
+/obj/machinery/meter/singularity_pull(S, current_size)
+ if(current_size >= STAGE_FIVE)
+ new /obj/item/pipe_meter(loc)
+ qdel(src)
+
// TURF METER - REPORTS A TILE'S AIR CONTENTS
// why are you yelling?
diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm
index cb21aa88feb..9c6639c3bd7 100644
--- a/code/game/machinery/bots/bots.dm
+++ b/code/game/machinery/bots/bots.dm
@@ -702,6 +702,7 @@ obj/machinery/bot/proc/bot_reset()
/obj/machinery/bot/Bump(M as mob|obj) //Leave no door unopened!
+ . = ..()
if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(botcard)))
var/obj/machinery/door/D = M
if(D.check_access(botcard))
@@ -711,4 +712,3 @@ obj/machinery/bot/proc/bot_reset()
var/mob/living/Mb = M
loc = Mb.loc
frustration = 0
- return
\ No newline at end of file
diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm
index e8a4b1ce2eb..620b163560a 100644
--- a/code/game/machinery/bots/medbot.dm
+++ b/code/game/machinery/bots/medbot.dm
@@ -485,7 +485,7 @@
"[src] is trying to inject you!")
spawn(30)
- if ((get_dist(src, patient) <= 1) && (on))
+ if ((get_dist(src, patient) <= 1) && (on) && assess_patient(patient))
if(reagent_id == "internal_beaker")
if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1)
@@ -496,6 +496,8 @@
C.visible_message("[src] injects [patient] with its syringe!", \
"[src] injects you with its syringe!")
patient = null
+ else
+ visible_message("[src] retracts its syringe.")
mode = BOT_IDLE
updateicon()
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
index f7b2e0c8010..68643c28cb6 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/game/machinery/bots/mulebot.dm
@@ -14,11 +14,11 @@ var/global/mulebot_count = 0
density = 1
anchored = 1
animate_movement=1
- health = 150 //yeah, it's tougher than ed209 because it is a big metal box with wheels --rastaf0
+ health = 150
maxhealth = 150
fire_dam_coeff = 0.7
brute_dam_coeff = 0.5
- var/atom/movable/load = null // the loaded crate (usually)
+ var/atom/movable/load = null
bot_type = MULE_BOT
model = "MULE"
blood_DNA = list()
@@ -28,7 +28,7 @@ var/global/mulebot_count = 0
var/turf/target // this is turf to navigate to (location of beacon)
var/loaddir = 0 // this the direction to unload onto/load from
var/home_destination = "" // tag of home beacon
- req_access = list(access_cargo) // added robotics access so assembly line drop-off works properly -veyveyr //I don't think so, Tim. You need to add it to the MULE's hidden robot ID card. -NEO
+ req_access = list(access_cargo)
mode = BOT_IDLE
@@ -62,7 +62,6 @@ var/global/mulebot_count = 0
var/datum/job/cargo_tech/J = new/datum/job/cargo_tech
botcard.access = J.get_access()
prev_access = botcard.access
-// botcard.access += access_robotics //Why --Ikki
cell = new(src)
cell.charge = 2000
cell.maxcharge = 2000
@@ -747,7 +746,7 @@ obj/machinery/bot/mulebot/bot_reset()
M.stop_pulling()
M.Stun(8)
M.Weaken(5)
- ..()
+ return ..()
/obj/machinery/bot/mulebot/alter_health()
return get_turf(src)
diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm
index e446fe82255..4ec583172e6 100644
--- a/code/game/machinery/computer/Operating.dm
+++ b/code/game/machinery/computer/Operating.dm
@@ -60,8 +60,10 @@
"}
if(patient.surgeries.len)
- dat += " Initiated Procedures
"
+ dat += "
Initiated Procedures
"
for(var/datum/surgery/procedure in patient.surgeries)
dat += "[capitalize(procedure.name)] "
+ var/datum/surgery_step/surgery_step = procedure.get_surgery_step()
+ dat += "Next step: [capitalize(surgery_step.name)] "
dat += "
"
return dat
\ No newline at end of file
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 661a8d78fe5..860d26968e1 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -80,6 +80,9 @@
explosion(src.loc, -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes)
+// ** BATTLE ** //
+
+
/obj/machinery/computer/arcade/battle
name = "arcade machine"
desc = "Does not support Pinball."
@@ -292,7 +295,7 @@
src.updateUsrDialog()
-
+// *** THE ORION TRAIL ** //
/obj/machinery/computer/arcade/orion_trail
@@ -722,4 +725,4 @@
sleep(3.6)
src.visible_message("[src] explodes!")
explosion(src.loc, 1,2,4, flame_range = 3)
- qdel(src)
+ qdel(src)
\ No newline at end of file
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index d49f0c1cee5..4d30422e833 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -128,7 +128,7 @@
build_path = /obj/machinery/computer/arcade/battle
origin_tech = "programming=1"
/obj/item/weapon/circuitboard/arcade/orion_trail
- name = "circuit board (Orion_Trail)"
+ name = "circuit board (Orion Trail)"
build_path = /obj/machinery/computer/arcade/orion_trail
/obj/item/weapon/circuitboard/turbine_control
name = "circuit board (Turbine control)"
diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm
index 3f2c3d52e75..cbbe3ed233f 100644
--- a/code/game/machinery/computer/crew.dm
+++ b/code/game/machinery/computer/crew.dm
@@ -256,7 +256,7 @@ var/global/datum/crewmonitor/crewmonitor = new
spawn
for (var/z = 1 to world.maxz) src.generateMiniMap(z)
- NOTICE("MINIMAP: All minimaps have been generated.")
+ world << "All minimaps have been generated."
for (var/client/C in clients)
src.sendResources(C)
@@ -345,7 +345,6 @@ var/global/datum/crewmonitor/crewmonitor = new
ASSERT(map_icon.Width() == MAX_ICON_DIMENSION && map_icon.Height() == MAX_ICON_DIMENSION)
- NOTICE("MINIMAP: Generating minimap for z-level [z].")
var/i = 0
var/icon/turf_icon
@@ -411,12 +410,9 @@ var/global/datum/crewmonitor/crewmonitor = new
if ((++i) % 512 == 0) sleep(1) // deliberate delay to avoid lag spikes
- if ((i % 1024) == 0) NOTICE("MINIMAP: Generated [i] of [tiles.len] tiles.")
else
sleep(-1) // avoid sleeping if possible: prioritize pending procs
- NOTICE("MINIMAP: Generated [tiles.len] of [tiles.len] tiles.")
-
// BYOND BUG: map_icon now contains 4 directions? Create a new icon with only a single state.
var/icon/result_icon = new/icon()
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index d351c5f7ec4..4288620d25e 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -254,6 +254,15 @@ to destroy them and players will be able to make replacements.
user << "You set the board to [names_paths[build_path]]."
req_components = list(text2path("/obj/item/weapon/vending_refill/[copytext("[build_path]", 24)]") = 3) //Never before has i used a method as horrible as this one, im so sorry
+/obj/item/weapon/circuitboard/announcement_system
+ name = "circuit board (Announcement System)"
+ build_path = /obj/machinery/announcement_system
+ board_type = "machine"
+ origin_tech = "programming=3;bluespace=2"
+ req_components = list(
+ /obj/item/stack/cable_coil = 2,
+ /obj/item/weapon/stock_parts/console_screen = 1)
+
/obj/item/weapon/circuitboard/smes
name = "circuit board (SMES)"
build_path = /obj/machinery/power/smes
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index e023131b2f6..245b949cb79 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -86,7 +86,7 @@
/obj/machinery/door/airlock/centcom
icon = 'icons/obj/doors/Doorele.dmi'
opacity = 1
- doortype = null //(centcom) there's no door assembly sprites for this one.
+ doortype = /obj/structure/door_assembly/door_assembly_centcom
/obj/machinery/door/airlock/vault
name = "vault door"
@@ -980,6 +980,9 @@ About the new airlock wires panel:
if(src.doortype)
var/obj/structure/door_assembly/A = new src.doortype(src.loc)
A.heat_proof_finished = src.heat_proof //tracks whether there's rglass in
+ else
+ new /obj/structure/door_assembly/door_assembly_0(src.loc)
+ //If you come across a null doortype, it will produce the default assembly instead of disintegrating.
if(emagged)
user << "You discard the damaged electronics."
diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm
index 218c4c50ddc..bba22799b5f 100644
--- a/code/game/machinery/embedded_controller/access_controller.dm
+++ b/code/game/machinery/embedded_controller/access_controller.dm
@@ -21,6 +21,14 @@
/obj/machinery/doorButtons/initialize()
findObjsByTag()
+/obj/machinery/doorButtons/emag_act(mob/user)
+ if(!emagged)
+ emagged = 1
+ req_access = list()
+ req_one_access = list()
+ playsound(src.loc, "sparks", 100, 1)
+ user << "You short out the access controller."
+
/obj/machinery/doorButtons/proc/removeMe()
diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm
index 7029c01bfbe..004c1cf5383 100644
--- a/code/game/machinery/requests_console.dm
+++ b/code/game/machinery/requests_console.dm
@@ -431,7 +431,7 @@ var/list/obj/machinery/requests_console/allConsoles = list()
/obj/machinery/say_quote(input, list/spans)
var/ending = copytext(input, length(input) - 2)
if (ending == "!!!")
- return "blares, \"attach_spans(input, spans)\""
+ return "blares, \"[attach_spans(input, spans)]\""
return ..()
diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm
index a3f27aa2759..0eb7cf4e577 100644
--- a/code/game/mecha/combat/phazon.dm
+++ b/code/game/mecha/combat/phazon.dm
@@ -21,7 +21,7 @@
var/datum/action/mecha/mech_toggle_phasing/phasing_action = new
/obj/mecha/combat/phazon/Bump(atom/obstacle)
- if(phasing && get_charge()>=phasing_energy_drain)
+ if(phasing && get_charge()>=phasing_energy_drain && !throwing)
spawn()
if(can_move)
can_move = 0
diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index 337dd01132e..6ce6246dbad 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -29,9 +29,6 @@
return 0
set_ready_state(0)
- chassis.can_move = 0
- spawn(shot_delay*projectiles_per_shot)
- chassis.can_move = 1
for(var/i=1 to get_shot_amount())
var/obj/item/projectile/A = new projectile(curloc)
A.firer = chassis.occupant
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 757497403de..0e178a4218e 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -445,23 +445,17 @@
playsound(src,stepsound,40,1)
return result
-/obj/mecha/Bump(var/atom/obstacle)
-// src.inertia_dir = null
- if(istype(obstacle, /obj))
- var/obj/O = obstacle
- if(istype(O, /obj/effect/portal)) //derpfix
- anchored = 0
- O.Crossed(src)
- src.anchored = 1
- else if(!O.anchored)
+/obj/mecha/Bump(var/atom/obstacle, yes)
+ if(yes)
+ if(..()) //mech was thrown
+ return
+ if(istype(obstacle, /obj))
+ var/obj/O = obstacle
+ if(!O.anchored)
+ step(obstacle, dir)
+ else if(istype(obstacle, /mob))
step(obstacle, dir)
- else //I have no idea why I disabled this
- obstacle.Bumped(src)
- else if(istype(obstacle, /mob))
- step(obstacle, dir)
- else
- obstacle.Bumped(src)
- return
+
///////////////////////////////////
//////// Internal damage ////////
diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm
index 2d89998c4d7..780f45e5ffd 100644
--- a/code/game/objects/effects/decals/crayon.dm
+++ b/code/game/objects/effects/decals/crayon.dm
@@ -43,7 +43,6 @@
color = G.color_hex
icon_state = G.name
G.territory_new |= list(territory.type = territory.name)
- G.territory_lost -= territory.type
..(location, color, icon_state, e_name, rotation)
@@ -51,6 +50,7 @@
var/area/territory = get_area(src)
if(gang)
+ gang.territory -= territory.type
gang.territory_new -= territory.type
gang.territory_lost |= list(territory.type = territory.name)
..()
\ No newline at end of file
diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm
index bb68ce45f04..aa1abe7ae6c 100644
--- a/code/game/objects/effects/effect_system/effects_foam.dm
+++ b/code/game/objects/effects/effect_system/effects_foam.dm
@@ -29,7 +29,7 @@
/obj/effect/effect/foam/New(loc)
..(loc)
create_reagents(1000) //limited by the size of the reagent holder anyway.
- SSobj.processing.Add(src)
+ SSobj.processing |= src
playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
/obj/effect/effect/foam/Destroy()
diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index b2fcf48b72c..b1e6b6dde79 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -31,7 +31,7 @@
/obj/effect/effect/smoke/New()
..()
create_reagents(500)
- SSobj.processing.Add(src)
+ SSobj.processing |= src
lifetime += rand(-1,1)
/obj/effect/effect/smoke/Destroy()
@@ -276,8 +276,9 @@
lifetime = 10
/obj/effect/effect/smoke/sleeping/process()
- for(var/mob/living/carbon/M in range(1,src))
- smoke_mob(M)
+ if(..())
+ for(var/mob/living/carbon/M in range(1,src))
+ smoke_mob(M)
/obj/effect/effect/smoke/sleeping/smoke_mob(mob/living/carbon/M)
if(..())
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index e01861deec9..3cd61feaf1f 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -77,6 +77,8 @@
icon_state = "eggs"
var/amount_grown = 0
var/player_spiders = 0
+ var/poison_type = "toxin"
+ var/poison_per_bite = 5
/obj/effect/spider/eggcluster/New()
pixel_x = rand(3,-3)
@@ -89,6 +91,8 @@
var/num = rand(3,12)
for(var/i=0, i[src] stares up at you with friendly eyes."
+ if(!owned)
+ user << "You pet [src]. You swear it looks up at you."
owner = user
- owned = 0
+ owned = 1
return ..()
/obj/item/toy/carpplushie/dehy_carp/afterattack(obj/O, mob/user,proximity)
if(!proximity) return
if(istype(O,/obj/structure/sink))
- user << "You place [src] under a stream of water..."
user.drop_item()
loc = get_turf(O)
return Swell()
@@ -45,4 +44,8 @@
if(F == "neutral")
factions -= F
C.faction = factions
+ if (!owner || owner.faction != C.faction)
+ visible_message("You have a bad feeling about this.") // welcome to the hostile carp enjoy your die
+ else
+ visible_message("The newly grown carp looks up at you with friendly eyes.")
qdel(src)
\ No newline at end of file
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 12e6db99f6e..16769bb4b99 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -192,7 +192,7 @@ MASS SPECTROMETER
user << "Blood level [blood_percent] %, [blood_volume] cl, type: [blood_type]"
var/implant_detect
- for(var/obj/item/cybernetic_implant/CI in H.internal_organs)
+ for(var/obj/item/organ/internal/cyberimp/CI in H.internal_organs)
implant_detect += "[H.name] is modified with a [CI.name]. "
if(implant_detect)
user.show_message("Detected cybernetic modifications:")
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 5ab56ea942b..790815844be 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -43,7 +43,6 @@ var/global/list/datum/stack_recipe/rod_recipes = list ( \
if(WT.remove_fuel(0,user))
var/obj/item/stack/sheet/metal/new_item = new(usr.loc)
- new_item.add_to_stacks(usr)
user.visible_message("[user.name] shaped [src] into metal with the welding tool.", \
"You shape [src] into metal with the welding tool.", \
"You hear welding.")
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 3881915f99d..c12fa7dc3a2 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -42,7 +42,6 @@
if (V.get_amount() >= 1 && src.get_amount() >= 1)
var/obj/item/stack/sheet/rglass/RG = new (user.loc)
RG.add_fingerprint(user)
- RG.add_to_stacks(user)
var/obj/item/stack/sheet/glass/G = src
src = null
var/replace = (user.get_inactive_hand()==G)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 3feb6b0dff3..a18fb047f3d 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -133,7 +133,6 @@
if (R.max_res_amount > 1)
var/obj/item/stack/new_item = O
new_item.amount = R.res_amount*multiplier
- new_item.add_to_stacks(usr) //try to merge with existing stacks on current tile
if(new_item.amount <= 0)//if the stack is empty, i.e it has been merged with an existing stack and has been garbage collected
return
@@ -196,21 +195,27 @@
src.amount += amount
update_icon()
-/obj/item/stack/proc/add_to_stacks(mob/usr)
- var/obj/item/stack/oldsrc = src
- src = null
- for (var/obj/item/stack/item in usr.loc)
- if (item==oldsrc)
- continue
- if (!istype(item, oldsrc.type))
- continue
- if (item.amount>=item.max_amount)
- continue
- oldsrc.attackby(item, usr)
- usr << "You add new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s."
- if(oldsrc.amount <= 0)
- break
- oldsrc.update_icon()
+/obj/item/stack/proc/merge(obj/item/stack/S) //Merge src into S, as much as possible
+ var/transfer = get_amount()
+ if(S.is_cyborg)
+ transfer = min(transfer, round((S.source.max_energy - S.source.energy) / S.cost))
+ else
+ transfer = min(transfer, S.max_amount - S.amount)
+ if(pulledby)
+ pulledby.start_pulling(S)
+ S.copy_evidences(src)
+ use(transfer)
+ S.add(transfer)
+
+/obj/item/stack/Crossed(obj/o)
+ if(istype(o, src.type) && !o.throwing)
+ merge(o)
+ return ..()
+
+/obj/item/stack/hitby(atom/movable/AM, skip, hitpush)
+ if(istype(AM, src.type))
+ merge(AM)
+ return ..()
/obj/item/stack/attack_hand(mob/user)
if (user.get_inactive_hand() == src)
@@ -228,34 +233,10 @@
return
/obj/item/stack/attackby(obj/item/W, mob/user, params)
-
- if (istype(W, src.type))
- if(zero_amount()) return
+ if(istype(W, src.type))
var/obj/item/stack/S = W
- if (S.is_cyborg)
- var/to_transfer = min(src.amount, round((S.source.max_energy - S.source.energy) / S.cost))
- S.add(to_transfer)
- if (S && usr.machine==S)
- spawn(0) S.interact(usr)
- src.use(to_transfer)
- if (src && usr.machine==src)
- spawn(0) src.interact(usr)
- else
- if (S.amount >= max_amount)
- return
- var/to_transfer as num
- if (user.get_inactive_hand()==src)
- to_transfer = 1
- else
- to_transfer = min(src.amount, S.max_amount-S.amount)
- S.amount+=to_transfer
- if (S && usr.machine==S)
- spawn(0) S.interact(usr)
- src.use(to_transfer)
- if (src && usr.machine==src)
- spawn(0) src.interact(usr)
- S.update_icon()
-
+ merge(S)
+ user << "Your [S.name] stack now contains [S.get_amount()] [S.singular_name]\s."
else
..()
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 63b826797ef..27424a95a17 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -40,7 +40,6 @@
if (mineralType == "metal")
var/obj/item/stack/sheet/metal/new_item = new(user.loc)
- new_item.add_to_stacks(user)
user.visible_message("[user.name] shaped [src] into metal with the weldingtool.", \
"You shaped [src] into metal with the weldingtool.", \
"You hear welding.")
@@ -54,7 +53,6 @@
else
var/sheet_type = text2path("/obj/item/stack/sheet/mineral/[mineralType]")
var/obj/item/stack/sheet/mineral/new_item = new sheet_type(user.loc)
- new_item.add_to_stacks(user)
user.visible_message("[user.name] shaped [src] into a sheet with the weldingtool.", \
"You shaped [src] into a sheet with the weldingtool.", \
"You hear welding.")
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index a340ca49274..780de85afed 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -1132,6 +1132,7 @@
// Attack self
/obj/item/toy/carpplushie/attack_self(mob/user)
playsound(src.loc, bitesound, 20, 1)
+ user << "You pet [src]. D'awww."
return ..()
/*
diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm
index fd1c0971718..5266cb9077e 100644
--- a/code/game/objects/items/weapons/defib.dm
+++ b/code/game/objects/items/weapons/defib.dm
@@ -323,12 +323,6 @@
else
return 1
-/obj/item/weapon/twohanded/shockpaddles/Topic(href, href_list)
- if(href_list["reenter"])
- var/mob/dead/observer/ghost = usr
- if(istype(ghost))
- ghost.reenter_corpse(ghost)
-
/obj/item/weapon/twohanded/shockpaddles/attack(mob/M, mob/user)
var/halfwaycritdeath = (config.health_threshold_crit + config.health_threshold_dead) / 2
@@ -404,10 +398,8 @@
busy = 0
update_icon()
return
- var/mob/dead/observer/ghost = H.get_ghost()
- if(ghost)
- ghost << "Your heart is being defibrillated. Re-enter your corpse if you want to be revived! (Click to re-enter)"
- ghost << 'sound/effects/genetics.ogg'
+ H.notify_ghost_cloning("Your heart is being defibrillated. Re-enter your corpse if you want to be revived!")
+
user.visible_message("[user] begins to place [src] on [M.name]'s chest.", "You begin to place [src] on [M.name]'s chest...")
busy = 1
update_icon()
@@ -432,11 +424,10 @@
M.visible_message("[M]'s body convulses a bit.")
playsound(get_turf(src), "bodyfall", 50, 1)
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1)
- for(var/obj/item/organ/limb/O in H.organs)
- total_brute += O.brute_dam
- total_burn += O.burn_dam
- ghost = H.get_ghost()
- if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !(NOCLONE in H.mutations))
+ total_brute = H.getBruteLoss()
+ total_burn = H.getFireLoss()
+
+ if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !H.get_ghost() && tplus < tlimit && !(NOCLONE in H.mutations))
//If the body has been fixed so that they would not be in crit when defibbed, give them oxyloss to put them back into crit
if (H.health > halfwaycritdeath)
H.adjustOxyLoss(H.health - halfwaycritdeath)
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index cab57a23a05..0e7fd19d6c9 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -3,17 +3,19 @@
icon = 'icons/obj/implants.dmi'
icon_state = "generic" //Shows up as the action button icon
action_button_is_hands_free = 1
+ origin_tech = "materials=2;biotech=3;programming=2"
+
var/activated = 1 //1 for implant types that can be activated, 0 for ones that are "always on" like loyalty implants
var/implanted = null
var/mob/living/imp_in = null
item_color = "b"
- var/allow_reagents = 0
+ var/allow_multiple = 0
+ var/uses = -1
/obj/item/weapon/implant/proc/trigger(emote, mob/source)
return
-
/obj/item/weapon/implant/proc/activate()
return
@@ -22,16 +24,53 @@
//What does the implant do upon injection?
-//return 0 if the implant fails (ex. Revhead and loyalty implant.)
-//return 1 if the implant succeeds (ex. Nonrevhead and loyalty implant.)
-/obj/item/weapon/implant/proc/implanted(mob/source)
+//return 1 if the implant injects
+//return -1 if the implant fails to inject
+//return 0 if there is no room for implant
+/obj/item/weapon/implant/proc/implant(var/mob/source, var/mob/user)
+ var/obj/item/weapon/implant/imp_e = locate(src.type) in source
+ if(!allow_multiple && imp_e && imp_e != src)
+ if(imp_e.uses < initial(imp_e.uses)*2)
+ if(uses == -1)
+ imp_e.uses = -1
+ else
+ imp_e.uses = min(imp_e.uses + uses, initial(imp_e.uses)*2)
+ qdel(src)
+ return 1
+ else
+ return 0
+
+
if(activated)
action_button_name = "Activate [src.name]"
+ src.loc = source
+ imp_in = source
+ implanted = 1
if(istype(source, /mob/living/carbon/human))
var/mob/living/carbon/human/H = source
H.sec_hud_set_implants()
+
+ if(user)
+ add_logs(user, source, "implanted", object="[name]")
+
return 1
+/obj/item/weapon/implant/proc/removed(var/mob/source)
+ src.loc = null
+ imp_in = null
+ implanted = 0
+
+ if(istype(source, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = source
+ H.sec_hud_set_implants()
+
+ return 1
+
+/obj/item/weapon/implant/Destroy()
+ if(imp_in)
+ removed(imp_in)
+ ..()
+
/obj/item/weapon/implant/proc/get_data()
return "No information available"
@@ -45,6 +84,7 @@
name = "tracking implant"
desc = "Track with this."
activated = 0
+ origin_tech = "materials=2;magnets=2;programming=2;biotech=2"
var/id = 1.0
/obj/item/weapon/implant/tracking/get_data()
@@ -68,6 +108,7 @@
name = "firearms authentication implant"
desc = "Lets you shoot your guns"
icon_state = "auth"
+ origin_tech = "materials=2;magnets=2;programming=2;biotech=5;syndicate=5"
activated = 0
/obj/item/weapon/implant/weapons_auth/get_data()
@@ -78,181 +119,13 @@
Function: Allows operation of implant-locked weaponry, preventing equipment from falling into enemy hands."}
return dat
-/obj/item/weapon/implant/explosive
- name = "microbomb implant"
- desc = "And boom goes the weasel."
- icon_state = "explosive"
- var/weak = 1.6
- var/medium = 0.8
- var/heavy = 0.4
- var/delay = 7
-
-/obj/item/weapon/implant/explosive/get_data()
- var/dat = {"Implant Specifications:
- Name: Robust Corp RX-78 Employee Management Implant
- Life: Activates upon death.
- Important Notes: Explodes
-
- Implant Details:
- Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
- Special Features: Explodes
- Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."}
- return dat
-
-/obj/item/weapon/implant/explosive/trigger(emote, mob/source)
- if(emote == "deathgasp")
- activate("death")
-
-/obj/item/weapon/implant/explosive/activate(cause)
- if(!cause || !imp_in) return 0
- if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your microbomb implant? This will cause you to explode!", "Microbomb Implant Confirmation", "Yes", "No") != "Yes")
- return 0
- for(var/obj/item/weapon/implant/explosive/E in imp_in)
- heavy += 0.4
- medium += 0.8
- weak += 1.6
- delay += 7
- if(E != src)
- qdel(E)
- heavy = round(heavy)
- medium = round(medium)
- weak = round(weak)
- imp_in << "You activate your microbomb implant."
-//If the delay is short, just blow up already jeez
- if(delay <= 7)
- imp_in.gib()
- explosion(src,heavy,medium,weak,weak, flame_range = weak)
- qdel(src)
- return
- timed_explosion()
-
-/obj/item/weapon/implant/explosive/proc/timed_explosion()
- imp_in.visible_message("[imp_in] starts beeping ominously!")
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay/4)
- if(imp_in.stat)
- imp_in.visible_message("[imp_in] doubles over in pain!")
- imp_in.Weaken(7)
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay/4)
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay/4)
- playsound(loc, 'sound/items/timer.ogg', 30, 0)
- sleep(delay/4)
- imp_in.gib()
- explosion(src,heavy,medium,weak,weak, flame_range = weak)
- qdel(src)
-
-/obj/item/weapon/implant/explosive/macro
- name = "macrobomb implant"
- desc = "And boom goes the weasel. And everything else nearby."
- icon_state = "explosive"
- weak = 16
- medium = 8
- heavy = 4
- delay = 70
-
-/obj/item/weapon/implant/explosive/macro/activate(cause)
- if(!cause || !imp_in) return 0
- if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your macrobomb implant? This will cause you to explode and gib!", "Macrobomb Implant Confirmation", "Yes", "No") != "Yes")
- return 0
- for(var/obj/item/weapon/implant/explosive/macro/E in imp_in)
- if(E != src)
- qdel(E)
- imp_in << "You activate your macrobomb implant."
- timed_explosion()
-
-/obj/item/weapon/implant/chem
- name = "chem implant"
- desc = "Injects things."
- icon_state = "reagents"
- allow_reagents = 1
-
-/obj/item/weapon/implant/chem/get_data()
- var/dat = {"Implant Specifications:
- Name: Robust Corp MJ-420 Prisoner Management Implant
- Life: Deactivates upon death but remains within the body.
- Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject
- will suffer from an increased appetite.
-
- Implant Details:
- Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal
- the implant releases the chemicals directly into the blood stream.
- Special Features:
- Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units.
- Can only be loaded while still in its original case.
- Integrity: Implant will last so long as the subject is alive. However, if the subject suffers from malnutrition,
- the implant may become unstable and either pre-maturely inject the subject or simply break."}
- return dat
-
-/obj/item/weapon/implant/chem/New()
- ..()
- create_reagents(50)
-
-/obj/item/weapon/implant/chem/trigger(emote, mob/source)
- if(emote == "deathgasp")
- activate(reagents.total_volume)
-
-/obj/item/weapon/implant/chem/activate(cause)
- if(!cause || !imp_in) return 0
- var/mob/living/carbon/R = imp_in
- var/injectamount = null
- if (cause == "action_button")
- injectamount = reagents.total_volume
- else
- injectamount = cause
- reagents.trans_to(R, injectamount)
- R << "You hear a faint beep."
- if(!reagents.total_volume)
- R << "You hear a faint click from your chest."
- qdel(src)
-
-
-/obj/item/weapon/implant/loyalty
- name = "loyalty implant"
- desc = "Makes you loyal or such."
- activated = 0
-
-/obj/item/weapon/implant/loyalty/get_data()
- var/dat = {"Implant Specifications:
- Name: Nanotrasen Employee Management Implant
- Life: Ten years.
- Important Notes: Personnel injected with this device tend to be much more loyal to the company.
-
- Implant Details:
- Function: Contains a small pod of nanobots that manipulate the host's mental functions.
- Special Features: Will prevent and cure most forms of brainwashing.
- Integrity: Implant will last so long as the nanobots are inside the bloodstream."}
- return dat
-
-
-/obj/item/weapon/implant/loyalty/implanted(mob/target)
- ..()
- if((target.mind in (ticker.mode.head_revolutionaries | ticker.mode.get_gang_bosses())) || is_shadow_or_thrall(target))
- target.visible_message("[target] seems to resist the implant!", "You feel the corporate tendrils of Nanotrasen try to invade your mind!")
- return 0
- if(target.mind in ticker.mode.get_gangsters())
- ticker.mode.remove_gangster(target.mind)
- target.visible_message("[src] was destroyed in the process!", "You feel a surge of loyalty towards Nanotrasen.")
- return 0
- if(target.mind in ticker.mode.revolutionaries)
- ticker.mode.remove_revolutionary(target.mind)
- if(target.mind in ticker.mode.cult)
- target << "You feel the corporate tendrils of Nanotrasen try to invade your mind!"
- else
- target << "You feel a surge of loyalty towards Nanotrasen."
- return 1
-
-/obj/item/weapon/implant/loyalty/Destroy()
- if(imp_in.stat != DEAD)
- imp_in << "You feel a sense of liberation as Nanotrasen's grip on your mind fades away."
- ..()
/obj/item/weapon/implant/adrenalin
name = "adrenal implant"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
- var/uses = 3
+ origin_tech = "materials=2;biotech=4;combat=3;syndicate=4"
+ uses = 3
/obj/item/weapon/implant/adrenalin/get_data()
var/dat = {"Implant Specifications:
@@ -285,8 +158,8 @@
name = "emp implant"
desc = "Triggers an EMP."
icon_state = "emp"
-
- var/uses = 2
+ origin_tech = "materials=2;biotech=3;magnets=4;syndicate=4"
+ uses = 2
/obj/item/weapon/implant/emp/activate()
if (src.uses < 1) return 0
diff --git a/code/game/objects/items/weapons/implants/implant_chem.dm b/code/game/objects/items/weapons/implants/implant_chem.dm
new file mode 100644
index 00000000000..6f85742039b
--- /dev/null
+++ b/code/game/objects/items/weapons/implants/implant_chem.dm
@@ -0,0 +1,53 @@
+/obj/item/weapon/implant/chem
+ name = "chem implant"
+ desc = "Injects things."
+ icon_state = "reagents"
+ origin_tech = "materials=3;biotech=4"
+ flags = OPENCONTAINER
+
+/obj/item/weapon/implant/chem/get_data()
+ var/dat = {"Implant Specifications:
+ Name: Robust Corp MJ-420 Prisoner Management Implant
+ Life: Deactivates upon death but remains within the body.
+ Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject
+ will suffer from an increased appetite.
+
+ Implant Details:
+ Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal
+ the implant releases the chemicals directly into the blood stream.
+ Special Features:
+ Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units.
+ Can only be loaded while still in its original case.
+ Integrity: Implant will last so long as the subject is alive."}
+ return dat
+
+/obj/item/weapon/implant/chem/New()
+ ..()
+ create_reagents(50)
+
+/obj/item/weapon/implant/chem/trigger(emote, mob/source)
+ if(emote == "deathgasp")
+ activate(reagents.total_volume)
+
+/obj/item/weapon/implant/chem/activate(cause)
+ if(!cause || !imp_in) return 0
+ var/mob/living/carbon/R = imp_in
+ var/injectamount = null
+ if (cause == "action_button")
+ injectamount = reagents.total_volume
+ else
+ injectamount = cause
+ reagents.trans_to(R, injectamount)
+ R << "You hear a faint beep."
+ if(!reagents.total_volume)
+ R << "You hear a faint click from your chest."
+ qdel(src)
+
+
+/obj/item/weapon/implantcase/chem
+ name = "implant case - 'Remote Chemical'"
+ desc = "A glass case containing a remote chemical implant."
+
+/obj/item/weapon/implantcase/chem/New()
+ imp = new /obj/item/weapon/implant/chem(src)
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/implants/implant_explosive.dm b/code/game/objects/items/weapons/implants/implant_explosive.dm
new file mode 100644
index 00000000000..719666b47b2
--- /dev/null
+++ b/code/game/objects/items/weapons/implants/implant_explosive.dm
@@ -0,0 +1,119 @@
+/obj/item/weapon/implant/explosive
+ name = "microbomb implant"
+ desc = "And boom goes the weasel."
+ icon_state = "explosive"
+ origin_tech = "materials=2;combat=3;biotech=4;syndicate=4"
+ var/weak = 1.6
+ var/medium = 0.8
+ var/heavy = 0.4
+ var/delay = 7
+
+/obj/item/weapon/implant/explosive/get_data()
+ var/dat = {"Implant Specifications:
+ Name: Robust Corp RX-78 Employee Management Implant
+ Life: Activates upon death.
+ Important Notes: Explodes
+
+ Implant Details:
+ Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
+ Special Features: Explodes
+ "}
+ return dat
+
+/obj/item/weapon/implant/explosive/trigger(emote, mob/source)
+ if(emote == "deathgasp")
+ activate("death")
+
+/obj/item/weapon/implant/explosive/activate(cause)
+ if(!cause || !imp_in) return 0
+ if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your microbomb implant? This will cause you to explode!", "Microbomb Implant Confirmation", "Yes", "No") != "Yes")
+ return 0
+ heavy = round(heavy)
+ medium = round(medium)
+ weak = round(weak)
+ imp_in << "You activate your microbomb implant."
+//If the delay is short, just blow up already jeez
+ if(delay <= 7)
+ explosion(src,heavy,medium,weak,weak, flame_range = weak)
+ imp_in.gib()
+ qdel(src)
+ return
+ timed_explosion()
+
+/obj/item/weapon/implant/explosive/implant(mob/source)
+ var/obj/item/weapon/implant/explosive/imp_e = locate(src.type) in source
+ if(imp_e)
+ imp_e.heavy += heavy
+ imp_e.medium += medium
+ imp_e.weak += weak
+ imp_e.delay += delay
+ qdel(src)
+ return 1
+
+ return ..()
+
+/obj/item/weapon/implant/explosive/proc/timed_explosion()
+ imp_in.visible_message("[imp_in] starts beeping ominously!")
+ playsound(loc, 'sound/items/timer.ogg', 30, 0)
+ sleep(delay/4)
+ if(imp_in && imp_in.stat)
+ imp_in.visible_message("[imp_in] doubles over in pain!")
+ imp_in.Weaken(7)
+ playsound(loc, 'sound/items/timer.ogg', 30, 0)
+ sleep(delay/4)
+ playsound(loc, 'sound/items/timer.ogg', 30, 0)
+ sleep(delay/4)
+ playsound(loc, 'sound/items/timer.ogg', 30, 0)
+ sleep(delay/4)
+ explosion(src,heavy,medium,weak,weak, flame_range = weak)
+ if(imp_in)
+ imp_in.gib()
+ qdel(src)
+
+/obj/item/weapon/implant/explosive/macro
+ name = "macrobomb implant"
+ desc = "And boom goes the weasel. And everything else nearby."
+ icon_state = "explosive"
+ origin_tech = "materials=3;combat=5;biotech=4;syndicate=5"
+ weak = 16
+ medium = 8
+ heavy = 4
+ delay = 70
+
+/obj/item/weapon/implant/explosive/macro/activate(cause)
+ if(!cause || !imp_in) return 0
+ if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your macrobomb implant? This will cause you to explode and gib!", "Macrobomb Implant Confirmation", "Yes", "No") != "Yes")
+ return 0
+ imp_in << "You activate your macrobomb implant."
+ timed_explosion()
+
+/obj/item/weapon/implant/explosive/macro/implant(mob/source)
+ var/obj/item/weapon/implant/explosive/imp_e = locate(src.type) in source
+ if(imp_e)
+ return 0
+ imp_e = locate(/obj/item/weapon/implant/explosive) in source
+ if(imp_e)
+ heavy += imp_e.heavy
+ medium += imp_e.medium
+ weak += imp_e.weak
+ delay += imp_e.delay
+ qdel(imp_e)
+
+ return ..()
+
+
+/obj/item/weapon/implanter/explosive
+ name = "implanter (explosive)"
+
+/obj/item/weapon/implanter/explosive/New()
+ imp = new /obj/item/weapon/implant/explosive(src)
+ ..()
+
+
+/obj/item/weapon/implantcase/explosive
+ name = "implant case - 'Explosive'"
+ desc = "A glass case containing an explosive implant."
+
+/obj/item/weapon/implantcase/explosive/New()
+ imp = new /obj/item/weapon/implant/explosive(src)
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/implants/implantfreedom.dm b/code/game/objects/items/weapons/implants/implant_freedom.dm
similarity index 61%
rename from code/game/objects/items/weapons/implants/implantfreedom.dm
rename to code/game/objects/items/weapons/implants/implant_freedom.dm
index 821cec4c572..e3e70e982a2 100644
--- a/code/game/objects/items/weapons/implants/implantfreedom.dm
+++ b/code/game/objects/items/weapons/implants/implant_freedom.dm
@@ -1,37 +1,50 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
-
-/obj/item/weapon/implant/freedom
- name = "freedom implant"
- desc = "Use this to escape from those evil Red Shirts."
- icon_state = "freedom"
- item_color = "r"
- var/uses = 4.0
-
-
-/obj/item/weapon/implant/freedom/activate()
- if (src.uses < 1) return 0
- src.uses--
- imp_in << "You feel a faint click."
- if(iscarbon(imp_in))
- var/mob/living/carbon/C_imp_in = imp_in
- C_imp_in.uncuff()
-
-
-/obj/item/weapon/implant/freedom/get_data()
- var/dat = {"
-Implant Specifications:
-Name: Freedom Beacon
-Life: optimum 5 uses
-Important Notes: Illegal
-
-Implant Details:
-Function: Transmits a specialized cluster of signals to override handcuff locking
-mechanisms
-Special Features:
-Neuro-Scan- Analyzes certain shadow signals in the nervous system
-Integrity: The battery is extremely weak and commonly after injection its
-life can drive down to only 1 use.
-No Implant Specifics"}
- return dat
-
-
+/obj/item/weapon/implant/freedom
+ name = "freedom implant"
+ desc = "Use this to escape from those evil Red Shirts."
+ icon_state = "freedom"
+ item_color = "r"
+ origin_tech = "materials=2;magnets=3;biotech=3;syndicate=4"
+ uses = 4
+
+
+/obj/item/weapon/implant/freedom/activate()
+ if(uses == 0) return 0
+ if(uses != -1) uses--
+ imp_in << "You feel a faint click."
+ if(iscarbon(imp_in))
+ var/mob/living/carbon/C_imp_in = imp_in
+ C_imp_in.uncuff()
+
+
+/obj/item/weapon/implant/freedom/get_data()
+ var/dat = {"
+Implant Specifications:
+Name: Freedom Beacon
+Life: optimum 5 uses
+Important Notes: Illegal
+
+Implant Details:
+Function: Transmits a specialized cluster of signals to override handcuff locking
+mechanisms
+Special Features:
+Neuro-Scan- Analyzes certain shadow signals in the nervous system
+
+No Implant Specifics"}
+ return dat
+
+
+/obj/item/weapon/implanter/freedom
+ name = "implanter (freedom)"
+
+/obj/item/weapon/implanter/freedom/New()
+ imp = new /obj/item/weapon/implant/freedom(src)
+ ..()
+
+
+/obj/item/weapon/implantcase/freedom
+ name = "implant case - 'Freedom'"
+ desc = "A glass case containing a freedom implant."
+
+/obj/item/weapon/implantcase/freedom/New()
+ imp = new /obj/item/weapon/implant/freedom(src)
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/implants/implant_loyality.dm b/code/game/objects/items/weapons/implants/implant_loyality.dm
new file mode 100644
index 00000000000..3751cd63343
--- /dev/null
+++ b/code/game/objects/items/weapons/implants/implant_loyality.dm
@@ -0,0 +1,65 @@
+/obj/item/weapon/implant/loyalty
+ name = "loyalty implant"
+ desc = "Makes you loyal or such."
+ origin_tech = "materials=2;biotech=4;programming=4"
+ activated = 0
+
+/obj/item/weapon/implant/loyalty/get_data()
+ var/dat = {"Implant Specifications:
+ Name: Nanotrasen Employee Management Implant
+ Life: Ten years.
+ Important Notes: Personnel injected with this device tend to be much more loyal to the company.
+
+ Implant Details:
+ Function: Contains a small pod of nanobots that manipulate the host's mental functions.
+ Special Features: Will prevent and cure most forms of brainwashing.
+ Integrity: Implant will last so long as the nanobots are inside the bloodstream."}
+ return dat
+
+
+/obj/item/weapon/implant/loyalty/implant(mob/target)
+ if(..())
+ if((target.mind in (ticker.mode.head_revolutionaries | ticker.mode.get_gang_bosses())) || is_shadow_or_thrall(target))
+ target.visible_message("[target] seems to resist the implant!", "You feel the corporate tendrils of Nanotrasen try to invade your mind!")
+ imp_in = null
+ qdel(src)
+ return -1
+ if(target.mind in ticker.mode.get_gangsters())
+ ticker.mode.remove_gangster(target.mind)
+ target.visible_message("[src] was destroyed in the process!", "You feel a surge of loyalty towards Nanotrasen.")
+ imp_in = null
+ qdel(src)
+ return -1
+ if(target.mind in ticker.mode.revolutionaries)
+ ticker.mode.remove_revolutionary(target.mind)
+ if(target.mind in ticker.mode.cult)
+ target << "You feel the corporate tendrils of Nanotrasen try to invade your mind!"
+ else
+ target << "You feel a surge of loyalty towards Nanotrasen."
+ return 1
+ return 0
+
+/obj/item/weapon/implant/loyalty/removed(mob/target)
+ if(..())
+ if(target.stat != DEAD)
+ target << "You feel a sense of liberation as Nanotrasen's grip on your mind fades away."
+ return 1
+ return 0
+
+
+/obj/item/weapon/implanter/loyalty
+ name = "implanter (loyalty)"
+
+/obj/item/weapon/implanter/loyalty/New()
+ imp = new /obj/item/weapon/implant/loyalty(src)
+ ..()
+ update_icon()
+
+
+/obj/item/weapon/implantcase/loyalty
+ name = "implant case - 'Loyalty'"
+ desc = "A glass case containing a loyalty implant."
+
+/obj/item/weapon/implantcase/loyalty/New()
+ imp = new /obj/item/weapon/implant/loyalty(src)
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm
index 5da2cd828bc..b38dbaea378 100644
--- a/code/game/objects/items/weapons/implants/implantcase.dm
+++ b/code/game/objects/items/weapons/implants/implantcase.dm
@@ -1,19 +1,28 @@
/obj/item/weapon/implantcase
- name = "glass case"
- desc = "A case containing an implant."
+ name = "implant case"
+ desc = "A glass case containing an implant."
+ icon = 'icons/obj/items.dmi'
icon_state = "implantcase-0"
item_state = "implantcase"
throw_speed = 2
throw_range = 5
w_class = 1.0
+ origin_tech = "materials=1;biotech=2"
+ materials = list(MAT_GLASS=500)
var/obj/item/weapon/implant/imp = null
/obj/item/weapon/implantcase/update_icon()
if(imp)
icon_state = "implantcase-[imp.item_color]"
+ origin_tech = imp.origin_tech
+ flags = imp.flags
+ reagents = imp.reagents
else
icon_state = "implantcase-0"
+ origin_tech = initial(origin_tech)
+ flags = initial(flags)
+ reagents = null
/obj/item/weapon/implantcase/attackby(obj/item/weapon/W, mob/user, params)
@@ -25,21 +34,13 @@
if(!in_range(src, user) && loc != user)
return
if(t)
- name = "glass case- '[t]'"
+ name = "implant case - '[t]'"
else
- name = "glass case"
- else if(istype(W, /obj/item/weapon/reagent_containers/syringe))
- if(!imp) return
- if(!imp.allow_reagents) return
- if(imp.reagents.total_volume >= imp.reagents.maximum_volume)
- user << "[src] is full."
- else
- W.reagents.trans_to(imp, 5)
- user << "You inject 5 units of the solution. The syringe now contains [W.reagents.total_volume] units."
+ name = "implant case"
else if(istype(W, /obj/item/weapon/implanter))
var/obj/item/weapon/implanter/I = W
if(I.imp)
- if((imp || I.imp.implanted))
+ if(imp || I.imp.implanted)
return
I.imp.loc = src
imp = I.imp
@@ -56,55 +57,28 @@
update_icon()
I.update_icon()
+ /*else if(istype(W, /obj/item/ammo_casing/shotgun/implanter))
+ var/obj/item/ammo_casing/shotgun/implanter/I = W
+ if(I.implanter)
+ src.attackby(I.implanter, user, params) */ // COMING SOON -- c0
+
+/obj/item/weapon/implantcase/New()
+ ..()
+ update_icon()
+
/obj/item/weapon/implantcase/tracking
- name = "glass case- 'Tracking'"
- desc = "A case containing a tracking implant."
- icon = 'icons/obj/items.dmi'
- icon_state = "implantcase-b"
+ name = "implant case - 'Tracking'"
+ desc = "A glass case containing a tracking implant."
/obj/item/weapon/implantcase/tracking/New()
imp = new /obj/item/weapon/implant/tracking(src)
..()
-/obj/item/weapon/implantcase/explosive
- name = "glass case- 'Explosive'"
- desc = "A case containing an explosive implant."
- icon = 'icons/obj/items.dmi'
- icon_state = "implantcase-r"
-
-/obj/item/weapon/implantcase/explosive/New()
- imp = new /obj/item/weapon/implant/explosive(src)
- ..()
-
-
-/obj/item/weapon/implantcase/chem
- name = "glass case- 'Chem'"
- desc = "A case containing a chemical implant."
- icon = 'icons/obj/items.dmi'
- icon_state = "implantcase-b"
-
-/obj/item/weapon/implantcase/chem/New()
- imp = new /obj/item/weapon/implant/chem(src)
- ..()
-
-
-/obj/item/weapon/implantcase/loyalty
- name = "glass case- 'Loyalty'"
- desc = "A case containing a loyalty implant."
- icon = 'icons/obj/items.dmi'
- icon_state = "implantcase-r"
-
-/obj/item/weapon/implantcase/loyalty/New()
- imp = new /obj/item/weapon/implant/loyalty(src)
- ..()
-
/obj/item/weapon/implantcase/weapons_auth
- name = "glass case- 'Firearms Authentication'"
- desc = "A case containing a firearms authentication implant."
- icon = 'icons/obj/items.dmi'
- icon_state = "implantcase-r"
+ name = "implant case - 'Firearms Authentication'"
+ desc = "A glass case containing a firearms authentication implant."
/obj/item/weapon/implantcase/weapons_auth/New()
imp = new /obj/item/weapon/implant/weapons_auth(src)
diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm
index 72aca3d4a66..5b36e5337ae 100644
--- a/code/game/objects/items/weapons/implants/implantchair.dm
+++ b/code/game/objects/items/weapons/implants/implantchair.dm
@@ -132,11 +132,8 @@
if(istype(imp, /obj/item/weapon/implant/loyalty))
M.visible_message("[M] has been implanted by the [src.name].")
- if(imp.implanted(M))
- imp.loc = M
- imp.imp_in = M
- imp.implanted = 1
- implant_list -= imp
+ if(imp.implant(M))
+ implant_list -= imp
break
return
diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm
index cb54e6386b1..034e31ac510 100644
--- a/code/game/objects/items/weapons/implants/implanter.dm
+++ b/code/game/objects/items/weapons/implants/implanter.dm
@@ -1,82 +1,74 @@
/obj/item/weapon/implanter
name = "implanter"
+ desc = "A sterile automatic implant injector."
icon = 'icons/obj/items.dmi'
icon_state = "implanter0"
item_state = "syringe_0"
throw_speed = 3
throw_range = 5
w_class = 2.0
+ origin_tech = "materials=1;biotech=3;programming=2"
+ materials = list(MAT_METAL=600, MAT_GLASS=200)
var/obj/item/weapon/implant/imp = null
/obj/item/weapon/implanter/update_icon()
if(imp)
icon_state = "implanter1"
+ origin_tech = imp.origin_tech
else
icon_state = "implanter0"
+ origin_tech = initial(origin_tech)
/obj/item/weapon/implanter/attack(mob/living/carbon/M, mob/user)
if(!iscarbon(M))
return
if(user && imp)
- if(M.head && (M.head.flags & THICKMATERIAL))
- user << "[M]'s [M.head.name] is in the way! Take it off first!"
- return
- M.visible_message("[user] is attemping to implant [M].")
+ if(M != user)
+ M.visible_message("[user] is attemping to implant [M].")
var/turf/T = get_turf(M)
- if(T && (M == user || do_after(user, 50, target = M)))
+ if(T && (M == user || do_after(user, 50)))
if(user && M && (get_turf(M) == T) && src && imp)
- if(M.head && (M.head.flags & THICKMATERIAL))
- return
- M.visible_message("[user] has implanted [M].", "[user] implants you with the implant.")
- add_logs(user, M, "implanted", src)
- user << "You implant the implant into [M]."
- if(imp.implanted(M))
- imp.loc = M
- imp.imp_in = M
- imp.implanted = 1
+ if(imp.implant(M, user))
+ user << "You implant the implant into [M]."
+ M.visible_message("[user] has implanted [M].", "[user] implants you with the implant.")
+ imp = null
+ update_icon()
- imp = null
- update_icon()
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = M
- H.sec_hud_set_implants()
-
-
-
-/obj/item/weapon/implanter/loyalty
- name = "implanter-loyalty"
-
-/obj/item/weapon/implanter/loyalty/New()
- imp = new /obj/item/weapon/implant/loyalty(src)
+/obj/item/weapon/implanter/attackby(obj/item/weapon/W, mob/user, params)
..()
- update_icon()
+ if(istype(W, /obj/item/weapon/pen))
+ var/t = stripped_input(user, "What would you like the label to be?", name, null)
+ if(user.get_active_hand() != W)
+ return
+ if(!in_range(src, user) && loc != user)
+ return
+ if(t)
+ name = "implanter ([t])"
+ else
+ name = "implanter"
-
-/obj/item/weapon/implanter/explosive
- name = "implanter-explosive"
-
-/obj/item/weapon/implanter/explosive/New()
- imp = new /obj/item/weapon/implant/explosive(src)
+/obj/item/weapon/implanter/New()
..()
- update_icon()
+ spawn(1)
+ update_icon()
+
+
/obj/item/weapon/implanter/adrenalin
- name = "implanter-adrenalin"
+ name = "implanter (adrenalin)"
/obj/item/weapon/implanter/adrenalin/New()
imp = new /obj/item/weapon/implant/adrenalin(src)
..()
- update_icon()
/obj/item/weapon/implanter/emp
- name = "implanter-EMP"
+ name = "implanter (EMP)"
/obj/item/weapon/implanter/emp/New()
imp = new /obj/item/weapon/implant/emp(src)
..()
- update_icon()
diff --git a/code/game/objects/items/weapons/implants/implantuplink.dm b/code/game/objects/items/weapons/implants/implantuplink.dm
index 74a2b365aa9..b19bb66d995 100644
--- a/code/game/objects/items/weapons/implants/implantuplink.dm
+++ b/code/game/objects/items/weapons/implants/implantuplink.dm
@@ -3,18 +3,33 @@
desc = "Summon things."
icon = 'icons/obj/radio.dmi'
icon_state = "radio"
+ origin_tech = "materials=2;magnets=4;programming=4;biotech=4;syndicate=8;bluespace=5"
/obj/item/weapon/implant/uplink/New()
hidden_uplink = new(src)
hidden_uplink.uses = 10
..()
-/obj/item/weapon/implant/uplink/implanted(mob/source)
- ..()
- hidden_uplink.uplink_owner="[source.key]"
- return 1
+/obj/item/weapon/implant/uplink/implant(mob/source)
+ var/obj/item/weapon/implant/imp_e = locate(src.type) in source
+ if(imp_e)
+ imp_e.hidden_uplink.uses += hidden_uplink.uses
+ qdel(src)
+ return 1
+ if(..())
+ hidden_uplink.uplink_owner="[source.key]"
+ return 1
+ return 0
/obj/item/weapon/implant/uplink/activate()
if(hidden_uplink)
- hidden_uplink.check_trigger(imp_in)
\ No newline at end of file
+ hidden_uplink.check_trigger(imp_in)
+
+
+/obj/item/weapon/implanter/uplink
+ name = "implanter (uplink)"
+
+/obj/item/weapon/implanter/uplink/New()
+ imp = new /obj/item/weapon/implant/uplink(src)
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm
index 1e95e040502..25bbb762e03 100644
--- a/code/game/objects/items/weapons/storage/belt.dm
+++ b/code/game/objects/items/weapons/storage/belt.dm
@@ -205,6 +205,7 @@
/obj/item/weapon/gun/projectile/revolver,
/obj/item/ammo_box,
)
+ alternate_worn_layer = UNDER_SUIT_LAYER
/obj/item/weapon/storage/belt/fannypack
name = "fannypack"
diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm
index 463528288b0..72664925ca2 100644
--- a/code/game/objects/items/weapons/storage/fancy.dm
+++ b/code/game/objects/items/weapons/storage/fancy.dm
@@ -115,7 +115,8 @@
/obj/item/weapon/storage/fancy/cigarettes/remove_from_storage(obj/item/W, atom/new_location)
if(istype(W,/obj/item/clothing/mask/cigarette))
- reagents.trans_to(W,(reagents.total_volume/contents.len))
+ if(reagents)
+ reagents.trans_to(W,(reagents.total_volume/contents.len))
..()
/obj/item/weapon/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index 82758639261..e28daa43953 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -1,8 +1,8 @@
-// To clarify:
-// For use_to_pickup and allow_quick_gather functionality,
-// see item/attackby() (/game/objects/items.dm)
-// Do not remove this functionality without good reason, cough reagent_containers cough.
-// -Sayu
+// External storage-related logic:
+// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
+// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
+// /item/attackby() in /game/objects/items.dm - use_to_pickup and allow_quick_gather functionality
+// -- c0
/obj/item/weapon/storage
@@ -42,11 +42,11 @@
show_to(M)
return
- if(!( M.restrained() ) && !( M.stat ))
- if(!( istype(over_object, /obj/screen) ))
+ if(!M.restrained() && !M.stat)
+ if(!istype(over_object, /obj/screen))
return content_can_dump(over_object, M)
- if(!(loc == usr) || (loc && loc.loc == usr))
+ if(loc != usr || (loc && loc.loc == usr))
return
playsound(loc, "rustle", 50, 1, -5)
@@ -107,7 +107,7 @@
is_seeing |= user
-/obj/item/weapon/storage/throw_at(atom/target, range, speed)
+/obj/item/weapon/storage/throw_at(atom/target, range, speed, mob/thrower, spin)
close_all()
return ..()
@@ -168,6 +168,7 @@
if(display_contents_with_number)
for(var/datum/numbered_display/ND in display_contents)
+ ND.sample_object.mouse_opacity = 2
ND.sample_object.screen_loc = "[cx]:16,[cy]:16"
ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]"
ND.sample_object.layer = 20
@@ -177,6 +178,7 @@
cy--
else
for(var/obj/O in contents)
+ O.mouse_opacity = 2 //This is here so storage items that spawn with contents correctly have the "click around item to equip"
O.screen_loc = "[cx]:16,[cy]:16"
O.maptext = ""
O.layer = 20
@@ -310,6 +312,7 @@
orient2hud(usr)
for(var/mob/M in can_see_contents())
show_to(M)
+ W.mouse_opacity = 2 //So you can click on the area around the item to equip it, instead of having to pixel hunt
update_icon()
return 1
@@ -339,6 +342,7 @@
W.maptext = ""
W.on_exit_storage(src)
update_icon()
+ W.mouse_opacity = initial(W.mouse_opacity)
return 1
diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm
index 41b143a4e93..703a17807d5 100644
--- a/code/game/objects/items/weapons/storage/toolbox.dm
+++ b/code/game/objects/items/weapons/storage/toolbox.dm
@@ -80,9 +80,9 @@
new /obj/item/weapon/wrench(src)
new /obj/item/weapon/weldingtool/largetank(src)
new /obj/item/weapon/crowbar/red(src)
- new /obj/item/stack/cable_coil(src, 30, "red")
new /obj/item/weapon/wirecutters(src, "red")
new /obj/item/device/multitool(src)
+ new /obj/item/clothing/gloves/color/red/insulated(src)
/obj/item/weapon/storage/toolbox/drone
name = "mechanical toolbox"
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index 1ceaaa88648..becd01a5308 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -53,17 +53,11 @@
return
if("implant")
- var/obj/item/weapon/implanter/F = new /obj/item/weapon/implanter(src)
- F.imp = new /obj/item/weapon/implant/freedom(F)
- var/obj/item/weapon/implanter/U = new /obj/item/weapon/implanter(src)
- U.imp = new /obj/item/weapon/implant/uplink(U)
- var/obj/item/weapon/implanter/C = new /obj/item/weapon/implanter(src)
- C.imp = new /obj/item/weapon/implant/emp(C)
- var/obj/item/weapon/implanter/K = new /obj/item/weapon/implanter(src)
- K.imp = new /obj/item/weapon/implant/adrenalin(K)
- var/obj/item/weapon/implanter/S = new /obj/item/weapon/implanter(src)
- S.imp = new /obj/item/weapon/implant/explosive(S)
- S.name += " (explosive)"
+ new /obj/item/weapon/implanter/freedom(src)
+ new /obj/item/weapon/implanter/uplink(src)
+ new /obj/item/weapon/implanter/emp(src)
+ new /obj/item/weapon/implanter/adrenalin(src)
+ new /obj/item/weapon/implanter/explosive(src)
return
if("hacker")
@@ -173,8 +167,8 @@
..()
new /obj/item/weapon/grenade/empgrenade(src)
new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/implanter/emp/(src)
- new /obj/item/device/flashlight/emp/(src)
+ new /obj/item/weapon/implanter/emp(src)
+ new /obj/item/device/flashlight/emp(src)
return
/obj/item/weapon/storage/box/syndie_kit/chemical
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index 27c6aaebef1..32ad17dc3c7 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -7,8 +7,8 @@ LINEN BINS
/obj/item/weapon/bedsheet
name = "bedsheet"
desc = "A surprisingly soft linen bedsheet."
- icon = 'icons/obj/items.dmi'
- icon_state = "sheet"
+ icon = 'icons/obj/bedsheets.dmi'
+ icon_state = "white"
item_state = "bedsheet"
slot_flags = SLOT_BACK
layer = 4.0
@@ -41,129 +41,133 @@ LINEN BINS
..()
/obj/item/weapon/bedsheet/blue
- icon_state = "sheetblue"
+ icon_state = "blue"
item_color = "blue"
/obj/item/weapon/bedsheet/green
- icon_state = "sheetgreen"
+ icon_state = "green"
item_color = "green"
/obj/item/weapon/bedsheet/orange
- icon_state = "sheetorange"
+ icon_state = "orange"
item_color = "orange"
/obj/item/weapon/bedsheet/purple
- icon_state = "sheetpurple"
+ icon_state = "purple"
item_color = "purple"
/obj/item/weapon/bedsheet/patriot
name = "patriotic bedsheet"
desc = "You've never felt more free than when sleeping on this."
- icon_state = "sheetUSA"
+ icon_state = "USA"
item_color = "sheetUSA"
/obj/item/weapon/bedsheet/rainbow
name = "rainbow bedsheet"
- desc = "A multicolored blanket. It's actually several different sheets cut up and sewn together."
- icon_state = "sheetrainbow"
+ desc = "A multicolored blanket. It's actually several different sheets cut up and sewn together."
+ icon_state = "rainbow"
item_color = "rainbow"
/obj/item/weapon/bedsheet/red
- icon_state = "sheetred"
+ icon_state = "red"
item_color = "red"
/obj/item/weapon/bedsheet/yellow
- icon_state = "sheetyellow"
+ icon_state = "yellow"
item_color = "yellow"
/obj/item/weapon/bedsheet/mime
name = "mime's blanket"
desc = "A very soothing striped blanket. All the noise just seems to fade out when you're under the covers in this."
- icon_state = "sheetmime"
+ icon_state = "mime"
item_color = "mime"
/obj/item/weapon/bedsheet/clown
name = "clown's blanket"
- desc = "A rainbow blanket with a clown mask woven in. It smells faintly of bananas."
- icon_state = "sheetclown"
+ desc = "A rainbow blanket with a clown mask woven in. It smells faintly of bananas."
+ icon_state = "clown"
item_color = "clown"
/obj/item/weapon/bedsheet/captain
name = "captain's bedsheet"
desc = "It has a Nanotrasen symbol on it, and was woven with a revolutionary new kind of thread guaranteed to have 0.01% permeability for most non-chemical substances, popular among most modern captains."
- icon_state = "sheetcaptain"
+ icon_state = "captain"
item_color = "captain"
/obj/item/weapon/bedsheet/rd
name = "research director's bedsheet"
desc = "It appears to have a beaker emblem, and is made out of fire-resistant material, although it probably won't protect you in the event of fires you're familiar with every day."
- icon_state = "sheetrd"
+ icon_state = "rd"
item_color = "director"
/obj/item/weapon/bedsheet/medical
name = "medical blanket"
desc = "It's a sterilized* blanket commonly used in the Medbay. *Sterilization is voided if a virologist is present onboard the station."
- icon_state = "sheetmedical"
+ icon_state = "medical"
item_color = "medical"
/obj/item/weapon/bedsheet/cmo
name = "chief medical officer's bedsheet"
- desc = "It's a sterilized blanket that has a cross emblem. There's some cat fur on it, likely from Runtime."
- icon_state = "sheetcmo"
+ desc = "It's a sterilized blanket that has a cross emblem. There's some cat fur on it, likely from Runtime."
+ icon_state = "cmo"
item_color = "cmo"
/obj/item/weapon/bedsheet/hos
name = "head of security's bedsheet"
- desc = "It is decorated with a shield emblem. While crime doesn't sleep, you do, but you are still THE LAW!"
- icon_state = "sheethos"
+ desc = "It is decorated with a shield emblem. While crime doesn't sleep, you do, but you are still THE LAW!"
+ icon_state = "hos"
item_color = "hosred"
/obj/item/weapon/bedsheet/hop
name = "head of personnel's bedsheet"
- desc = "It is decorated with a key emblem. For those rare moments when you can rest and cuddle with Ian without someone screaming for you over the radio."
- icon_state = "sheethop"
+ desc = "It is decorated with a key emblem. For those rare moments when you can rest and cuddle with Ian without someone screaming for you over the radio."
+ icon_state = "hop"
item_color = "hop"
/obj/item/weapon/bedsheet/ce
name = "chief engineer's bedsheet"
- desc = "It is decorated with a wrench emblem. It's highly reflective and stain resistant, so you don't need to worry about ruining it with oil."
- icon_state = "sheetce"
+ desc = "It is decorated with a wrench emblem. It's highly reflective and stain resistant, so you don't need to worry about ruining it with oil."
+ icon_state = "ce"
item_color = "chief"
/obj/item/weapon/bedsheet/qm
name = "quartermaster's bedsheet"
desc = "It is decorated with a crate emblem in silver lining. It's rather tough, and just the thing to lie on after a hard day of pushing paper."
- icon_state = "sheetqm"
+ icon_state = "qm"
item_color = "qm"
/obj/item/weapon/bedsheet/brown
- icon_state = "sheetbrown"
+ icon_state = "brown"
item_color = "cargo"
/obj/item/weapon/bedsheet/centcom
name = "\improper Centcom bedsheet"
desc = "Woven with advanced nanothread for warmth as well as being very decorated, essential for all officials."
- icon_state = "sheetcentcom"
+ icon_state = "centcom"
item_color = "centcom"
/obj/item/weapon/bedsheet/syndie
name = "syndicate bedsheet"
desc = "It has a syndicate emblem and it has an aura of evil."
- icon_state = "sheetsyndie"
+ icon_state = "syndie"
item_color = "syndie"
/obj/item/weapon/bedsheet/cult
name = "cultist's bedsheet"
- desc = "You might dream of Nar'Sie if you sleep with this. It seems rather tattered and glows of an eldritch presence."
- icon_state = "sheetcult"
+ desc = "You might dream of Nar'Sie if you sleep with this. It seems rather tattered and glows of an eldritch presence."
+ icon_state = "cult"
item_color = "cult"
/obj/item/weapon/bedsheet/wiz
name = "wizard's bedsheet"
- desc = "A special fabric enchanted with magic so you can have an enchanted night. It even glows!"
- icon_state = "sheetwiz"
+ desc = "A special fabric enchanted with magic so you can have an enchanted night. It even glows!"
+ icon_state = "wiz"
item_color = "wiz"
+/obj/item/weapon/bedsheet/ian
+ icon_state = "ian"
+ item_color = "ian"
+
/obj/structure/bedsheetbin
name = "linen bin"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
index 0203442b693..4552fb78ff5 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
@@ -72,7 +72,7 @@
new /obj/item/weapon/storage/belt/medical(src)
new /obj/item/device/flash/handheld(src)
new /obj/item/weapon/reagent_containers/hypospray/CMO(src)
- new /obj/item/cybernetic_implant/eyes/hud/medical(src)
+ new /obj/item/organ/internal/cyberimp/eyes/hud/medical(src)
/obj/structure/closet/secure_closet/animal
name = "animal control"
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 6f5809891e2..e130ef5811a 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -25,7 +25,6 @@
icon_state = "door_as_1"
airlock_type = /obj/machinery/door/airlock
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_com
@@ -37,7 +36,6 @@
glass_type = /obj/machinery/door/airlock/glass_command
airlock_type = /obj/machinery/door/airlock/command
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_com/glass
@@ -53,7 +51,6 @@
glass_type = /obj/machinery/door/airlock/glass_security
airlock_type = /obj/machinery/door/airlock/security
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_sec/glass
@@ -69,7 +66,6 @@
glass_type = /obj/machinery/door/airlock/glass_engineering
airlock_type = /obj/machinery/door/airlock/engineering
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_eng/glass
@@ -85,7 +81,6 @@
glass_type = /obj/machinery/door/airlock/glass_mining
airlock_type = /obj/machinery/door/airlock/mining
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_min/glass
@@ -101,7 +96,6 @@
glass_type = /obj/machinery/door/airlock/glass_atmos
airlock_type = /obj/machinery/door/airlock/atmos
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_atmo/glass
@@ -117,7 +111,6 @@
glass_type = /obj/machinery/door/airlock/glass_research
airlock_type = /obj/machinery/door/airlock/research
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_research/glass
@@ -133,7 +126,6 @@
glass_type = /obj/machinery/door/airlock/glass_science
airlock_type = /obj/machinery/door/airlock/science
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_science/glass
@@ -149,7 +141,6 @@
glass_type = /obj/machinery/door/airlock/glass_medical
airlock_type = /obj/machinery/door/airlock/medical
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_med/glass
@@ -163,7 +154,6 @@
icontext = "mai"
airlock_type = /obj/machinery/door/airlock/maintenance
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_ext
@@ -173,7 +163,6 @@
icontext = "ext"
airlock_type = /obj/machinery/door/airlock/external
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_fre
@@ -183,7 +172,6 @@
icontext = "fre"
airlock_type = /obj/machinery/door/airlock/freezer
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_hatch
@@ -193,7 +181,6 @@
icontext = "hatch"
airlock_type = /obj/machinery/door/airlock/hatch
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_mhatch
@@ -203,7 +190,6 @@
icontext = "mhatch"
airlock_type = /obj/machinery/door/airlock/maintenance_hatch
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_glass
@@ -211,7 +197,6 @@
icon_state = "door_as_g1"
airlock_type = /obj/machinery/door/airlock/glass
anchored = 1
- density = 1
state = 1
mineral = "glass"
@@ -220,7 +205,6 @@
icon_state = "door_as_gold1"
airlock_type = /obj/machinery/door/airlock/gold
anchored = 1
- density = 1
state = 1
mineral = "gold"
@@ -229,7 +213,6 @@
icon_state = "door_as_silver1"
airlock_type = /obj/machinery/door/airlock/silver
anchored = 1
- density = 1
state = 1
mineral = "silver"
@@ -238,7 +221,6 @@
icon_state = "door_as_diamond1"
airlock_type = /obj/machinery/door/airlock/diamond
anchored = 1
- density = 1
state = 1
mineral = "diamond"
@@ -247,7 +229,6 @@
icon_state = "door_as_uranium1"
airlock_type = /obj/machinery/door/airlock/uranium
anchored = 1
- density = 1
state = 1
mineral = "uranium"
@@ -256,7 +237,6 @@
icon_state = "door_as_plasma1"
airlock_type = /obj/machinery/door/airlock/plasma
anchored = 1
- density = 1
state = 1
mineral = "plasma"
@@ -266,7 +246,6 @@
icon_state = "door_as_clown1"
airlock_type = /obj/machinery/door/airlock/clown
anchored = 1
- density = 1
state = 1
mineral = "bananium"
@@ -275,7 +254,6 @@
icon_state = "door_as_sandstone1"
airlock_type = /obj/machinery/door/airlock/sandstone
anchored = 1
- density = 1
state = 1
mineral = "sandstone"
@@ -286,7 +264,6 @@
icontext = "highsec"
airlock_type = /obj/machinery/door/airlock/highsecurity
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_vault
@@ -296,7 +273,6 @@
icontext = "vault"
airlock_type = /obj/machinery/door/airlock/vault
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_shuttle
@@ -306,7 +282,6 @@
icontext = "shuttle"
airlock_type = /obj/machinery/door/airlock/shuttle
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_wood
@@ -314,7 +289,6 @@
icon_state = "door_as_wood1"
airlock_type = /obj/machinery/door/airlock/wood
anchored = 1
- density = 1
state = 1
mineral = "wood"
@@ -327,13 +301,20 @@
glass_type = /obj/machinery/door/airlock/glass_virology
airlock_type = /obj/machinery/door/airlock/virology
anchored = 1
- density = 1
state = 1
/obj/structure/door_assembly/door_assembly_viro/glass
mineral = "glass"
icon_state = "door_as_gviro1"
+/obj/structure/door_assembly/door_assembly_centcom
+ icon_state = "door_as_ele1"
+ typetext = "centcom"
+ icontext = "ele"
+ airlock_type = /obj/machinery/door/airlock/centcom
+ anchored = 1
+ state = 1
+
/obj/structure/door_assembly/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weapon/pen))
var/t = stripped_input(user, "Enter the name for the door.", src.name, src.created_name,MAX_NAME_LEN)
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 8638ab62db3..1e72ad484a0 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -102,7 +102,7 @@
return
user << "You start building a false wall..."
if(do_after(user, 20, target = src))
- if(!src.loc || !S || S.amount < 2)
+ if(!src.loc || !S || S.get_amount() < 2)
return
S.use(2)
user << "You create a false wall. Push on it to open or close the passage."
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index 58ff54da606..22f4ae79d1b 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -233,7 +233,7 @@
if(user.stat || user.stunned || user.weakened || user.paralysis)
unbuckle_mob()
if(istype(user.l_hand, keytype) || istype(user.r_hand, keytype))
- if(!Process_Spacemove(direction) || !has_gravity(src.loc) || move_delay)
+ if(!Process_Spacemove(direction) || !has_gravity(src.loc) || move_delay || !isturf(loc))
return
step(src, direction)
update_mob()
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index d9035cb568a..2bcfe8d976f 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -268,7 +268,7 @@
return(2)
/turf/proc/can_have_cabling()
- return !density
+ return 1
/turf/proc/can_lay_cable()
return can_have_cabling() & !intact
diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm
index bd5cd555a65..2a1efc9735e 100644
--- a/code/game/verbs/who.dm
+++ b/code/game/verbs/who.dm
@@ -1,4 +1,3 @@
-
/client/verb/who()
set name = "Who"
set category = "OOC"
@@ -8,11 +7,40 @@
var/list/Lines = list()
if(holder)
- for(var/client/C in clients)
- var/entry = "\t[C.key]"
- if(C.holder && C.holder.fakekey)
- entry += " (as [C.holder.fakekey])"
- Lines += entry
+ if (check_rights(R_ADMIN,0) && isobserver(src.mob))//If they have +ADMIN and are a ghost they can see players IC names and statuses.
+ var/mob/dead/observer/G = src.mob
+ if(!G.started_as_observer)//If you aghost to do this, KorPhaeron will deadmin you in your sleep.
+ log_admin("[key_name(usr)] checked advanced who in-round")
+ for(var/client/C in clients)
+ var/entry = "\t[C.key]"
+ if(C.holder && C.holder.fakekey)
+ entry += " (as [C.holder.fakekey])"
+ if (isnewplayer(C.mob))
+ entry += " - In Lobby"
+ else
+ entry += " - Playing as [C.mob.real_name]"
+ switch(C.mob.stat)
+ if(UNCONSCIOUS)
+ entry += " - Unconscious"
+ if(DEAD)
+ if(isobserver(C.mob))
+ var/mob/dead/observer/O = C.mob
+ if(O.started_as_observer)
+ entry += " - Observing"
+ else
+ entry += " - DEAD"
+ else
+ entry += " - DEAD"
+ if(is_special_character(C.mob))
+ entry += " - Antagonist"
+ entry += " (?)"
+ Lines += entry
+ else//If they don't have +ADMIN, only show hidden admins
+ for(var/client/C in clients)
+ var/entry = "\t[C.key]"
+ if(C.holder && C.holder.fakekey)
+ entry += " (as [C.holder.fakekey])"
+ Lines += entry
else
for(var/client/C in clients)
if(C.holder && C.holder.fakekey)
diff --git a/code/modules/admin/admin_memo.dm b/code/modules/admin/admin_memo.dm
index 774f55ce6ae..7c40c3aa53a 100644
--- a/code/modules/admin/admin_memo.dm
+++ b/code/modules/admin/admin_memo.dm
@@ -1,13 +1,32 @@
-/client/proc/admin_memo(task in list("Show","Write","Edit","Remove"))
+/client/proc/admin_memo()
set name = "Memo"
set category = "Server"
if(!check_rights(0)) return
if(!dbcon.IsConnected())
- usr << "Failed to establish database connection."
+ src << "Failed to establish database connection."
+ return
+ var/memotask = input(usr,"Choose task.","Memo") in list("Show","Write","Edit","Remove")
+ if(!memotask)
+ return
+ admin_memo_output(memotask)
+
+/client/proc/admin_memo_output(task)
+ if(!task)
+ return
+ if(!dbcon.IsConnected())
+ src << "Failed to establish database connection."
return
var/sql_ckey = sanitizeSQL(src.ckey)
switch(task)
if("Write")
+ var/DBQuery/query_memocheck = dbcon.NewQuery("SELECT ckey FROM [format_table_name("memo")] WHERE (ckey = '[sql_ckey]')")
+ if(!query_memocheck.Execute())
+ var/err = query_memocheck.ErrorMsg()
+ log_game("SQL ERROR obtaining ckey from memo table. Error : \[[err]\]\n")
+ return
+ if(query_memocheck.NextRow())
+ src << "You already have set a memo."
+ return
var/memotext = input(src,"Write your Memo","Memo") as text|null
if(!memotext)
return
@@ -26,13 +45,13 @@
var/err = query_memolist.ErrorMsg()
log_game("SQL ERROR obtaining ckey from memo table. Error : \[[err]\]\n")
return
- if(!query_memolist.NextRow())
- src << "No memos found in database."
- return
var/list/memolist = list()
while(query_memolist.NextRow())
- var/ckey = query_memolist.item[2]
- memolist += "[ckey]"
+ var/lkey = query_memolist.item[1]
+ memolist += "[lkey]"
+ if(!memolist.len)
+ src << "No memos found in database."
+ return
var/target_ckey = input(src, "Select whose memo to edit", "Select memo") as null|anything in memolist
if(!target_ckey)
return
@@ -43,14 +62,14 @@
log_game("SQL ERROR obtaining ckey, memotext from memo table. Error : \[[err]\]\n")
return
if(query_memofind.NextRow())
- var/old_memo = query_memofind.item[3]
+ var/old_memo = query_memofind.item[2]
var/new_memo = input("Input new memo", "New Memo", "[old_memo]", null) as null|text
if(!new_memo)
return
new_memo = sanitizeSQL(new_memo)
var/edit_text = "Edited by [sql_ckey] on [SQLtime()] from [old_memo] to [new_memo]"
edit_text = sanitizeSQL(edit_text)
- var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("memo")] SET memotext = '[new_memo]', last_editor = '[sql_ckey]', edits = CONCAT(edits,'[edit_text]') WHERE (ckey = '[target_sql_ckey]')")
+ var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("memo")] SET memotext = '[new_memo]', last_editor = '[sql_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE (ckey = '[target_sql_ckey]')")
if(!update_query.Execute())
var/err = update_query.ErrorMsg()
log_game("SQL ERROR editing memo. Error : \[[err]\]\n")
@@ -62,18 +81,24 @@
log_admin("[key_name(src)] has edited [target_sql_ckey]'s memo from [old_memo] to [new_memo]")
message_admins("[key_name_admin(src)] has edited [target_sql_ckey]'s memo from [old_memo] to [new_memo]")
if("Show")
- var/DBQuery/query_memoshow = dbcon.NewQuery("SELECT id, ckey, memotext, timestamp, last_editor FROM [format_table_name("memo")])")
- var/output
+ var/DBQuery/query_memoshow = dbcon.NewQuery("SELECT ckey, memotext, timestamp, last_editor FROM [format_table_name("memo")]")
+ if(!query_memoshow.Execute())
+ var/err = query_memoshow.ErrorMsg()
+ log_game("SQL ERROR obtaining ckey, memotext, timestamp, last_editor from memo table. Error : \[[err]\]\n")
+ return
+ var/output = null
while(query_memoshow.NextRow())
- var/id = query_memoshow.item[1]
- var/ckey = query_memoshow.item[2]
- var/memotext = query_memoshow.item[3]
- var/timestamp = query_memoshow.item[4]
- var/last_editor = query_memoshow.item[5]
- output += "Memo by [ckey] on [timestamp]:"
+ var/ckey = query_memoshow.item[1]
+ var/memotext = query_memoshow.item[2]
+ var/timestamp = query_memoshow.item[3]
+ var/last_editor = query_memoshow.item[4]
+ output += "Memo by [ckey] on [timestamp]"
if(last_editor)
- output += " Last edit by [last_editor] (Click here to see edit log)"
+ output += " Last edit by [last_editor] (Click here to see edit log)"
output += " [memotext] "
+ if(!output)
+ src << "No memos found in database."
+ return
src << output
if("Remove")
var/DBQuery/query_memodellist = dbcon.NewQuery("SELECT ckey FROM [format_table_name("memo")]")
@@ -81,13 +106,13 @@
var/err = query_memodellist.ErrorMsg()
log_game("SQL ERROR obtaining ckey from memo table. Error : \[[err]\]\n")
return
- if(!query_memodellist.NextRow())
- src << "No memos found in database."
- return
var/list/memolist = list()
while(query_memodellist.NextRow())
- var/ckey = query_memodellist.item[2]
+ var/ckey = query_memodellist.item[1]
memolist += "[ckey]"
+ if(!memolist.len)
+ src << "No memos found in database."
+ return
var/target_ckey = input(src, "Select whose memo to delete", "Select memo") as null|anything in memolist
if(!target_ckey)
return
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index 1320ae695c2..7fdf3adb2d7 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -264,7 +264,11 @@
M_job = "New player"
else if(isobserver(M))
- M_job = "Ghost"
+ var/mob/dead/observer/O = M
+ if(O.started_as_observer)//Did they get BTFO or are they just not trying?
+ M_job = "Observer"
+ else
+ M_job = "Ghost"
var/M_name = html_encode(M.name)
var/M_rname = html_encode(M.real_name)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 6f0493a0f86..b1ce38e14d7 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -2058,10 +2058,14 @@
src.access_news_network()
else if(href_list["memoeditlist"])
- var/DBQuery/query_memoedits = dbcon.NewQuery("SELECT edits FROM [format_table_name("memo")] WHERE (id = '[href_list["id"]]")
- query_memoedits.Execute()
+ var/sql_key = sanitizeSQL("[href_list["memoeditlist"]]")
+ var/DBQuery/query_memoedits = dbcon.NewQuery("SELECT edits FROM [format_table_name("memo")] WHERE (ckey = '[sql_key]')")
+ if(!query_memoedits.Execute())
+ var/err = query_memoedits.ErrorMsg()
+ log_game("SQL ERROR obtaining edits from memo table. Error : \[[err]\]\n")
+ return
if(query_memoedits.NextRow())
- var/edit_log = query_memoedits.item[6]
+ var/edit_log = query_memoedits.item[1]
usr << browse(edit_log,"window=memoeditlist")
else if(href_list["check_antagonist"])
diff --git a/code/modules/admin/verbs/cinematic.dm b/code/modules/admin/verbs/cinematic.dm
index dce6bbf8659..107c5310770 100644
--- a/code/modules/admin/verbs/cinematic.dm
+++ b/code/modules/admin/verbs/cinematic.dm
@@ -10,7 +10,7 @@
var/override
switch(parameter)
if(1)
- override = input(src,"mode = ?","Enter Parameter",null) as anything in list("nuclear emergency","no override")
+ override = input(src,"mode = ?","Enter Parameter",null) as anything in list("nuclear emergency","gang war","fake","no override")
if(0)
override = input(src,"mode = ?","Enter Parameter",null) as anything in list("blob","nuclear emergency","AI malfunction","no override")
ticker.station_explosion_cinematic(parameter,override)
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index d7497060491..976ce7085e3 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -40,7 +40,12 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
switch(alert("Proc owned by something?",,"Yes","No"))
if("Yes")
targetselected = 1
- class = input("Proc owned by...","Owner",null) as null|anything in list("Obj","Mob","Area or Turf","Client")
+ if(src.holder && src.holder.marked_datum)
+ class = input("Proc owned by...","Owner",null) as null|anything in list("Obj","Mob","Area or Turf","Client","Marked datum ([holder.marked_datum.type])")
+ if(class == "Marked datum ([holder.marked_datum.type])")
+ class = "Marked datum"
+ else
+ class = input("Proc owned by...","Owner",null) as null|anything in list("Obj","Mob","Area or Turf","Client")
switch(class)
if("Obj")
target = input("Enter target:","Target",usr) as obj in world
@@ -53,6 +58,8 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
for(var/client/C)
keys += C
target = input("Please, select a player!", "Selection", null, null) as null|anything in keys
+ if("Marked datum")
+ target = holder.marked_datum
else
return
if("No")
@@ -61,7 +68,9 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
if(!procname) return
-
+ if(targetselected && !hascall(target,procname))
+ usr << "Error: callproc(): target has no such call [procname]."
+ return
var/list/lst = get_callproc_args()
if(!lst)
return
@@ -70,9 +79,6 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(!target)
usr << "Error: callproc(): owner of proc no longer exists."
return
- if(!hascall(target,procname))
- usr << "Error: callproc(): target has no such call [procname]."
- return
log_admin("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
returnval = call(target,procname)(arglist(lst)) // Pass the lst as an argument list to the proc
else
@@ -93,7 +99,9 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
if(!procname)
return
-
+ if(!hascall(A,procname))
+ usr << "Error: callproc_datum(): target has no such call [procname]."
+ return
var/list/lst = get_callproc_args()
if(!lst)
return
@@ -101,9 +109,6 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(!A || !IsValidSrc(A))
usr << "Error: callproc_datum(): owner of proc no longer exists."
return
- if(!hascall(A,procname))
- usr << "Error: callproc_datum(): target has no such call [procname]."
- return
log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
spawn()
@@ -115,15 +120,21 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
/client/proc/get_callproc_args()
var/argnum = input("Number of arguments","Number:",0) as num|null
if(!argnum && (argnum!=0)) return
-
+
var/list/lst = list()
//TODO: make a list to store whether each argument was initialised as null.
//Reason: So we can abort the proccall if say, one of our arguments was a mob which no longer exists
//this will protect us from a fair few errors ~Carn
while(argnum--)
+ var/class = null
// Make a list with each index containing one variable, to be given to the proc
- var/class = input("What kind of variable?","Variable Type") in list("text","num","type","reference","mob reference","icon","file","client","mob's area","CANCEL")
+ if(src.holder && src.holder.marked_datum)
+ class = input("What kind of variable?","Variable Type") in list("text","num","type","reference","mob reference","icon","file","client","mob's area","Marked datum ([holder.marked_datum.type])","CANCEL")
+ if(holder.marked_datum && class == "Marked datum ([holder.marked_datum.type])")
+ class = "Marked datum"
+ else
+ class = input("What kind of variable?","Variable Type") in list("text","num","type","reference","mob reference","icon","file","client","mob's area","CANCEL")
switch(class)
if("CANCEL")
return null
@@ -158,6 +169,8 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if("mob's area")
var/mob/temp = input("Select mob", "Selection", usr) as mob in world
lst += temp.loc
+ if("Marked datum")
+ lst += holder.marked_datum
return lst
@@ -400,6 +413,7 @@ var/list/TYPES_SHORTCUTS = list(
/obj/machinery/portable_atmospherics = "PORT_ATMOS",
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack = "MECHA_MISSILE_RACK",
/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
+ /obj/item/organ/internal = "ORGAN_INT",
)
var/global/list/g_fancy_list_of_types = null
diff --git a/code/modules/admin/verbs/manipulate_organs.dm b/code/modules/admin/verbs/manipulate_organs.dm
new file mode 100644
index 00000000000..ae500213e59
--- /dev/null
+++ b/code/modules/admin/verbs/manipulate_organs.dm
@@ -0,0 +1,56 @@
+/client/proc/manipulate_organs(mob/living/carbon/C in world)
+ set name = "Manipulate Organs"
+ set category = "Debug"
+ var/operation = input("Select organ operation.", "Organ Manipulation", "cancel") in list("add organ", "add implant", "drop organ/implant", "remove organ/implant", "cancel")
+
+ var/list/organs = list()
+ switch(operation)
+ if("add organ")
+ for(var/path in typesof(/obj/item/organ/internal) - /obj/item/organ/internal)
+ var/dat = replacetext("[path]", "/obj/item/organ/internal/", ":")
+ organs[dat] = path
+
+ var/obj/item/organ/internal/organ = input("Select organ type:", "Organ Manipulation", null) in organs
+ organ = organs[organ]
+ organ = new organ
+ organ.Insert(C)
+
+ if("add implant")
+ for(var/path in typesof(/obj/item/weapon/implant) - /obj/item/weapon/implant)
+ var/dat = replacetext("[path]", "/obj/item/weapon/implant/", ":")
+ organs[dat] = path
+
+ var/obj/item/weapon/implant/organ = input("Select implant type:", "Organ Manipulation", null) in organs
+ organ = organs[organ]
+ organ = new organ
+ organ.implant(C)
+
+ if("drop organ/implant", "remove organ/implant")
+ for(var/obj/item/organ/internal/I in C.internal_organs)
+ organs["[I.name] ([I.type])"] = I
+
+ for(var/obj/item/weapon/implant/I in C)
+ organs["[I.name] ([I.type])"] = I
+
+ var/obj/item/organ = input("Select organ/implant:", "Organ Manipulation", null) in organs
+ organ = organs[organ]
+ if(!organ) return
+ var/obj/item/organ/internal/O
+ var/obj/item/weapon/implant/I
+
+ if(isorgan(organ))
+ O = organ
+ O.Remove(C)
+ else
+ I = organ
+ I.removed(C)
+
+ organ.loc = get_turf(C)
+
+ if(operation == "remove organ/implant")
+ qdel(organ)
+ else if(I) // Put the implant in case.
+ var/obj/item/weapon/implantcase/case = new(get_turf(C))
+ case.imp = I
+ I.loc = case
+ case.update_icon()
\ No newline at end of file
diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm
index d947599c6d5..5152ab29436 100644
--- a/code/modules/admin/verbs/mapping.dm
+++ b/code/modules/admin/verbs/mapping.dm
@@ -159,6 +159,8 @@ var/intercom_range_display_status = 0
src.verbs += /client/proc/print_pointers
src.verbs += /client/proc/count_movable_instances
src.verbs += /client/proc/cmd_show_at_list
+ src.verbs += /client/proc/cmd_show_at_list
+ src.verbs += /client/proc/manipulate_organs
//src.verbs += /client/proc/cmd_admin_rejuvenate
feedback_add_details("admin_verb","mDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index 5cdf335ed49..25b84838539 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -450,17 +450,17 @@
// CENTCOM RESPONSE TEAM
/datum/admins/proc/makeEmergencyresponseteam()
- var/alert = input("Which team should we send?", "Select Response Level") as null|anything in list("Green: Centcom Official", "Blue: Light ERT", "Amber: Full ERT", "Red: Elite ERT", "Delta: Deathsquad")
+ var/alert = input("Which team should we send?", "Select Response Level") as null|anything in list("Green: Centcom Official", "Blue: Light ERT (No Armoury Access)", "Amber: Full ERT (Armoury Access)", "Red: Elite ERT (Armoury Access + Pulse Weapons)", "Delta: Deathsquad")
if(!alert)
return
switch(alert)
if("Delta: Deathsquad")
return makeDeathsquad()
- if("Red: Elite ERT")
+ if("Red: Elite ERT (Armoury Access + Pulse Weapons)")
alert = "Red"
- if("Amber: Full ERT")
+ if("Amber: Full ERT (Armoury Access)")
alert = "Amber"
- if("Blue: Light ERT")
+ if("Blue: Light ERT (No Armoury Access)")
alert = "Blue"
if("Green: Centcom Official")
return makeOfficial()
diff --git a/code/modules/awaymissions/exile.dm b/code/modules/awaymissions/exile.dm
index 7e36cf7e04a..4e6a69d591b 100644
--- a/code/modules/awaymissions/exile.dm
+++ b/code/modules/awaymissions/exile.dm
@@ -1,18 +1,10 @@
//Exile implants will allow you to use the station gate, but not return home.
//This will allow security to exile badguys/for badguys to exile their kill targets
-/obj/item/weapon/implanter/exile
- name = "implanter-exile"
-
-/obj/item/weapon/implanter/exile/New()
- imp = new /obj/item/weapon/implant/exile( src )
- ..()
- update_icon()
-
-
/obj/item/weapon/implant/exile
name = "exile implant"
desc = "Prevents you from returning from away missions"
+ origin_tech = "materials=2;biotech=3;magnets=2;bluespace=3"
activated = 0
/obj/item/weapon/implant/exile/get_data()
@@ -22,11 +14,16 @@
return dat
+/obj/item/weapon/implanter/exile
+ name = "implanter (exile)"
+
+/obj/item/weapon/implanter/exile/New()
+ imp = new /obj/item/weapon/implant/exile( src )
+ ..()
+
/obj/item/weapon/implantcase/exile
- name = "glass case- 'Exile'"
- desc = "A case containing an exile implant."
- icon = 'icons/obj/items.dmi'
- icon_state = "implantcase-r"
+ name = "implant case - 'Exile'"
+ desc = "A glass case containing an exile implant."
/obj/item/weapon/implantcase/exile/New()
imp = new /obj/item/weapon/implant/exile(src)
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 4e07e0d8a3c..15de84c0369 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -128,7 +128,7 @@ var/next_external_rsc = 0
if(holder)
add_admin_verbs()
- admin_memo("Show")
+ admin_memo_output("Show")
if((global.comms_key == "default_pwd" || length(global.comms_key) <= 6) && global.comms_allowed) //It's the default value or less than 6 characters long, but it somehow didn't disable comms.
src << "The server's API key is either too short or is the default value! Consider changing it immediately!"
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index d351a3e0890..d0119b29ec5 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1045,14 +1045,6 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
character.real_name = real_name
character.name = character.real_name
- if(character.dna)
- character.dna.real_name = character.real_name
- if(pref_species != /datum/species/human && config.mutant_races)
- hardset_dna(character, null, null, null, null, pref_species.type, features)
- else
- hardset_dna(character, null, null, null, null, /datum/species/human, features)
- character.update_mutcolor()
-
character.gender = gender
character.age = age
character.blood_type = blood_type
@@ -1072,5 +1064,15 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
character.backbag = backbag
- character.update_body()
- character.update_hair()
+ if(character.dna)
+ var/datum/species/chosen_species
+
+ character.dna.real_name = character.real_name
+ if(pref_species != /datum/species/human && config.mutant_races)
+ chosen_species = pref_species.type
+ else
+ chosen_species = /datum/species/human
+ hardset_dna(character, null, null, null, null, chosen_species, features)
+ else
+ character.update_body()
+ character.update_hair()
\ No newline at end of file
diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm
index 18f5c7937f4..ced08b92025 100644
--- a/code/modules/clothing/gloves/color.dm
+++ b/code/modules/clothing/gloves/color.dm
@@ -66,6 +66,13 @@
item_state = "redgloves"
item_color = "red"
+/obj/item/clothing/gloves/color/red/insulated
+ name = "insulated gloves"
+ desc = "These gloves will protect the wearer from electric shock."
+ siemens_coefficient = 0
+ permeability_coefficient = 0.05
+ burn_state = -1 //Won't burn in fires
+
/obj/item/clothing/gloves/color/rainbow
name = "rainbow gloves"
desc = "A pair of gloves, they don't look special in any way."
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 6f9bc4c6228..ccb288dd6cc 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -228,3 +228,8 @@
name = "jester hat"
desc = "A hat with bells, to add some merryness to the suit."
icon_state = "jester_hat"
+
+/obj/item/clothing/head/rice_hat
+ name = "rice hat"
+ desc = "Welcome to the rice fields, motherfucker."
+ icon_state = "rice_hat"
\ No newline at end of file
diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm
index 9237f31d8f2..cc3435554d5 100644
--- a/code/modules/clothing/under/jobs/civilian.dm
+++ b/code/modules/clothing/under/jobs/civilian.dm
@@ -3,9 +3,9 @@
/obj/item/clothing/under/rank/bartender
desc = "It looks like it could use some more flair."
name = "bartender's uniform"
- icon_state = "bar_suit"
+ icon_state = "barman"
item_state = "bar_suit"
- item_color = "bar_suit"
+ item_color = "barman"
/obj/item/clothing/under/rank/captain //Alright, technically not a 'civilian' but its better then giving a .dm file for a single define.
diff --git a/code/modules/events/spontaneous_appendicitis.dm b/code/modules/events/spontaneous_appendicitis.dm
index 6219d1fda69..11e8d74923e 100644
--- a/code/modules/events/spontaneous_appendicitis.dm
+++ b/code/modules/events/spontaneous_appendicitis.dm
@@ -14,5 +14,5 @@
continue
var/datum/disease/D = new /datum/disease/appendicitis
- H.AddDisease(D)
+ H.ForceContractDisease(D)
break
\ No newline at end of file
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 8ad8c75980a..756d7608141 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -15,7 +15,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
var/image/halimage
var/image/halbody
var/obj/halitem
- var/hal_screwyhud = 0 //1 - critical, 2 - dead, 3 - oxygen indicator, 4 - toxin indicator
+ var/hal_screwyhud = 0 //1 - critical, 2 - dead, 3 - oxygen indicator, 4 - toxin indicator, 5 - perfect health
var/handling_hal = 0
var/hal_crit = 0
diff --git a/code/modules/food&drinks/drinks/drinks/bottle.dm b/code/modules/food&drinks/drinks/drinks/bottle.dm
index 9fa1cbe5555..8f003e6fb75 100644
--- a/code/modules/food&drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food&drinks/drinks/drinks/bottle.dm
@@ -300,6 +300,11 @@
/obj/item/weapon/reagent_containers/food/drinks/bottle/molotov/attackby(obj/item/I, mob/user, params)
if(is_hot(I) && !active)
active = 1
+ var/turf/bombturf = get_turf(src)
+ var/area/bombarea = get_area(bombturf)
+ message_admins("[key_name(user)]? has primed a [name] for detonation at [bombarea] (JMP).")
+ log_game("[key_name(user)] has primed a [name] for detonation at [bombarea] ([bombturf.x],[bombturf.y],[bombturf.z]).")
+
user << "You light \the [src] on fire."
overlays += fire_overlay
if(!isGlass)
@@ -324,4 +329,4 @@
return
user << "You snuff out the flame on \the [src]."
overlays -= fire_overlay
- active = 0
\ No newline at end of file
+ active = 0
diff --git a/code/modules/food&drinks/recipes/tablecraft/recipes_burger.dm b/code/modules/food&drinks/recipes/tablecraft/recipes_burger.dm
index 54c0ed1c52e..ef5f43f7495 100644
--- a/code/modules/food&drinks/recipes/tablecraft/recipes_burger.dm
+++ b/code/modules/food&drinks/recipes/tablecraft/recipes_burger.dm
@@ -36,7 +36,7 @@
/datum/table_recipe/appendixburger
name = "Appendix burger"
reqs = list(
- /obj/item/organ/appendix = 1,
+ /obj/item/organ/internal/appendix = 1,
/obj/item/weapon/reagent_containers/food/snacks/bun = 1
)
result = /obj/item/weapon/reagent_containers/food/snacks/burger/appendix
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 82734bf827c..334cc5f671c 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -171,6 +171,7 @@
dat += "Leather Satchel: Make ([400/efficiency]) "
dat += "Leather Jacket: Make ([500/efficiency]) "
dat += "Leather Overcoat: Make ([1000/efficiency]) "
+ dat += "Rice Hat: Make ([300/efficiency]) "
dat += "
"
else
dat += "
No container inside, please insert container.
"
@@ -309,9 +310,9 @@
if("overcoat")
if (check_cost(1000/efficiency)) return 0
else new/obj/item/clothing/suit/jacket/leather/overcoat(src.loc)
- //if("monkey")
- // if (check_cost(500)) return 0
- // else new/mob/living/carbon/monkey(src.loc)
+ if("rice_hat")
+ if (check_cost(300/efficiency)) return 0
+ else new/obj/item/clothing/head/rice_hat(src.loc)
processing = 0
menustat = "complete"
update_icon()
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
index b7552f60814..81a3f2a4cf5 100644
--- a/code/modules/mining/abandoned_crates.dm
+++ b/code/modules/mining/abandoned_crates.dm
@@ -114,7 +114,7 @@
if(89)
new /obj/item/organ/brain/alien(src)
if(90)
- new /obj/item/organ/heart(src)
+ new /obj/item/organ/internal/heart(src)
if(91)
new /obj/item/device/soulstone/anybody(src)
if(92)
diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm
index 85d0eaa50f0..f0e699253be 100644
--- a/code/modules/mining/equipment_locker.dm
+++ b/code/modules/mining/equipment_locker.dm
@@ -623,7 +623,7 @@
if(istype(I, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/W = I
if(W.welding && !stat)
- if(stance != HOSTILE_STANCE_IDLE)
+ if(AIStatus == AI_ON)
user << "[src] is moving around too much to repair!"
return
if(maxHealth == health)
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index ea0886af653..9c4ca620e26 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -129,6 +129,7 @@
flags = CONDUCT
slot_flags = SLOT_BELT
force = 8.0
+ var/digspeed = 20
throwforce = 4.0
item_state = "shovel"
w_class = 3.0
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 01e6c9b3094..894d29cbc5c 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -432,9 +432,8 @@ var/global/list/rockTurfEdgeCache
P.playDigSound()
if(do_after(user,P.digspeed, target = src))
- if(istype(src, /turf/simulated/mineral)) //sanity check against turf being deleted during digspeed delay
+ if(istype(src, /turf/simulated/mineral))
user << "You finish cutting into the rock."
- P.update_icon()
gets_drilled(user)
feedback_add_details("pick_used_mining","[P.name]")
else
@@ -457,6 +456,13 @@ var/global/list/rockTurfEdgeCache
gets_drilled()
..()
+/turf/simulated/mineral/attack_alien(mob/living/carbon/alien/M)
+ M << "You start digging into the rock..."
+ playsound(src, 'sound/effects/break_stone.ogg', 50, 1)
+ if(do_after(M,40, target = src))
+ M << "You tunnel into the rock."
+ gets_drilled(M)
+
/*
/turf/simulated/mineral/proc/setRandomMinerals()
var/s = pickweight(list("uranium" = 5, "iron" = 50, "gold" = 5, "silver" = 5, "plasma" = 50, "diamond" = 1))
@@ -541,27 +547,14 @@ var/global/list/rockTurfEdgeCache
//note that this proc does not call ..()
if(!W || !user)
return 0
-
- if ((istype(W, /obj/item/weapon/shovel)))
- var/turf/T = user.loc
- if (!( istype(T, /turf) ))
- return
-
- if (dug)
- user << "This area has already been dug!"
- return
-
- user << "You start digging..."
- playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1) //FUCK YO RUSTLE I GOT'S THE DIGS SOUND HERE
-
- sleep(20)
- if ((user.loc == T && user.get_active_hand() == W))
- user << "You dig a hole."
- gets_dug()
- return
-
- if ((istype(W, /obj/item/weapon/pickaxe)))
+ var/digging_speed = 0
+ if (istype(W, /obj/item/weapon/shovel))
+ var/obj/item/weapon/shovel/S = W
+ digging_speed = S.digspeed
+ else if (istype(W, /obj/item/weapon/pickaxe))
var/obj/item/weapon/pickaxe/P = W
+ digging_speed = P.digspeed
+ if (digging_speed)
var/turf/T = user.loc
if (!( istype(T, /turf) ))
return
@@ -572,13 +565,13 @@ var/global/list/rockTurfEdgeCache
user << "You start digging..."
playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1) //FUCK YO RUSTLE I GOT'S THE DIGS SOUND HERE
-
- sleep(P.digspeed)
- if ((user.loc == T && user.get_active_hand() == W))
- user << "You dig a hole."
- gets_dug()
- return
-
+
+ if(do_after(user, digging_speed, target = src))
+ if(istype(src, /turf/simulated/floor/plating/asteroid))
+ user << "You dig a hole."
+ gets_dug()
+ feedback_add_details("pick_used_mining","[W.name]")
+
if(istype(W,/obj/item/weapon/storage/bag/ore))
var/obj/item/weapon/storage/bag/ore/S = W
if(S.collection_mode == 1)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 51f948910c1..13ca44627a0 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -167,6 +167,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
mind.current.key = key
return 1
+/mob/dead/observer/proc/notify_cloning(var/message, var/sound)
+ if(message)
+ src << "[message]"
+ src << "(Click to re-enter)"
+ if(sound)
+ src << sound(sound)
+
/mob/dead/observer/proc/dead_tele()
set category = "Ghost"
set name = "Teleport"
@@ -363,8 +370,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return ..()
/mob/dead/observer/Topic(href, href_list)
- if(href_list["follow"])
- var/atom/movable/target = locate(href_list["follow"])
- if((usr == src) && istype(target) && (target != src)) //for safety against href exploits
- ManualFollow(target)
-
+ ..()
+ if(usr == src)
+ if(href_list["follow"])
+ var/atom/movable/target = locate(href_list["follow"])
+ if(istype(target) && (target != src))
+ ManualFollow(target)
+ if(href_list["reenter"])
+ reenter_corpse()
\ No newline at end of file
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
new file mode 100644
index 00000000000..3283c0ebb4f
--- /dev/null
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -0,0 +1,115 @@
+//Travel through pools of blood. Slaughter Demon powers for everyone!
+
+#define BLOODCRAWL 1
+#define BLOODCRAWL_EAT 2
+
+/mob/living/proc/phaseout(obj/effect/decal/cleanable/B)
+ var/mob/living/kidnapped = null
+ var/turf/mobloc = get_turf(src.loc)
+ var/turf/bloodloc = get_turf(B.loc)
+ if(Adjacent(bloodloc))
+ src.notransform = TRUE
+ spawn(0)
+ src.visible_message("[src] sinks into the pool of blood.")
+ playsound(get_turf(src), 'sound/magic/enter_blood.ogg', 100, 1, -1)
+ var/obj/effect/dummy/slaughter/holder = PoolOrNew(/obj/effect/dummy/slaughter,mobloc)
+ src.ExtinguishMob()
+ if(src.buckled)
+ src.buckled.unbuckle_mob()
+ if(src.pulling && src.bloodcrawl == BLOODCRAWL_EAT)
+ if(istype(src.pulling, /mob/living))
+ var/mob/living/victim = src.pulling
+ if(victim.stat == CONSCIOUS)
+ src.visible_message("[victim] kicks free of the [src] at the last second!")
+ else
+ victim.loc = holder
+ src.visible_message("The [src] drags [victim] into the pool of blood!")
+ kidnapped = victim
+ src.loc = holder
+ src.holder = holder
+ if(kidnapped)
+ src << "You begin to feast on [kidnapped]. You can not move while you are doing this."
+ playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
+ sleep(30)
+ playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
+ sleep(30)
+ playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
+ sleep(30)
+ src << "You devour [kidnapped]. Your health is fully restored."
+ src.adjustBruteLoss(-1000)
+ src.adjustFireLoss(-1000)
+ src.adjustOxyLoss(-1000)
+ src.adjustToxLoss(-1000)
+ kidnapped.ghostize()
+ qdel(kidnapped)
+ src.notransform = 0
+
+/mob/living/proc/phasein(obj/effect/decal/cleanable/B)
+ if(src.notransform)
+ src << "Finish eating first!"
+ else
+ src.loc = B.loc
+ src.client.eye = src
+ src.visible_message("The [src] rises out of the pool of blood!")
+ playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
+ qdel(src.holder)
+ src.holder = null
+
+/obj/effect/decal/cleanable/blood/CtrlClick(mob/living/user)
+ ..()
+ if(user.bloodcrawl)
+ if(user.holder)
+ user.phasein(src)
+ else
+ user.phaseout(src)
+
+
+/obj/effect/decal/cleanable/trail_holder/CtrlClick(mob/living/user)
+ ..()
+ if(user.bloodcrawl)
+ if(user.holder)
+ user.phasein(src)
+ else
+ user.phaseout(src)
+
+
+
+/turf/CtrlClick(var/mob/living/user)
+ ..()
+ if(user.bloodcrawl)
+ for(var/obj/effect/decal/cleanable/B in src.contents)
+ if(istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/trail_holder))
+ if(user.holder)
+ user.phasein(B)
+ break
+ else
+ user.phaseout(B)
+ break
+
+/obj/effect/dummy/slaughter //Can't use the wizard one, blocked by jaunt/slow
+ name = "water"
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "nothing"
+ var/canmove = 1
+ density = 0
+ anchored = 1
+ invisibility = 60
+
+obj/effect/dummy/slaughter/relaymove(mob/user, direction)
+ if (!src.canmove || !direction) return
+ var/turf/newLoc = get_step(src,direction)
+ loc = newLoc
+ src.canmove = 0
+ spawn(1)
+ src.canmove = 1
+
+/obj/effect/dummy/slaughter/ex_act(blah)
+ return
+/obj/effect/dummy/slaughter/bullet_act(blah)
+ return
+
+/obj/effect/dummy/slaughter/singularity_act(blah)
+ return
+
+/obj/effect/dummy/slaughter/Destroy()
+ return QDEL_HINT_PUTINPOOL
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index f4e3a3a3573..f96c94af11a 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -34,7 +34,12 @@
/mob/living/carbon/alien/New()
verbs += /mob/living/proc/mob_sleep
verbs += /mob/living/proc/lay_down
+
internal_organs += new /obj/item/organ/brain/alien
+ for(var/obj/item/organ/internal/I in internal_organs)
+ I.Insert(src)
+
+
AddAbility(new/obj/effect/proc_holder/alien/nightvisiontoggle(null))
..()
@@ -54,7 +59,7 @@
return storedPlasma
/mob/living/carbon/alien/check_eye_prot()
- return 2
+ return ..() + 2
/mob/living/carbon/alien/getToxLoss()
return 0
@@ -185,7 +190,7 @@ Des: Gives the client of the alien an image on each infected mob.
if (client)
for (var/mob/living/C in mob_list)
if(C.status_flags & XENO_HOST)
- var/obj/item/body_egg/alien_embryo/A = locate() in C
+ var/obj/item/organ/internal/body_egg/alien_embryo/A = locate() in C
var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]")
client.images += I
return
diff --git a/code/modules/mob/living/carbon/alien/humanoid/emote.dm b/code/modules/mob/living/carbon/alien/humanoid/emote.dm
index fd46ca92087..5270fdabb6d 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/emote.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/emote.dm
@@ -6,56 +6,54 @@
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
var/muzzled = is_muzzled()
var/m_type = 1
var/message
switch(act) //Alphabetical please
- if ("deathgasp")
+ if ("deathgasp","deathgasps")
message = "[src] lets out a waning guttural screech, green blood bubbling from its maw..."
m_type = 2
- if ("gnarl")
+ if ("gnarl","gnarls")
if (!muzzled)
message = "[src] gnarls and shows its teeth.."
m_type = 2
- if ("hiss")
+ if ("hiss","hisses")
if(!muzzled)
message = "[src] hisses."
m_type = 2
- if ("moan")
+ if ("moan","moans")
message = "[src] moans!"
m_type = 2
- if ("roar")
+ if ("roar","roars")
if (!muzzled)
message = "[src] roars."
m_type = 2
- if ("roll")
+ if ("roll","rolls")
if (!src.restrained())
message = "[src] rolls."
m_type = 1
- if ("scratch")
+ if ("scratch","scratches")
if (!src.restrained())
message = "[src] scratches."
m_type = 1
- if ("scretch")
+ if ("screech","screeches")
if (!muzzled)
- message = "[src] scretches."
+ message = "[src] screeches."
m_type = 2
- if ("shiver")
+ if ("shiver","shivers")
message = "[src] shivers."
m_type = 2
- if ("sign")
+ if ("sign","signs")
if (!src.restrained())
message = text("[src] signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null))
m_type = 1
@@ -65,7 +63,7 @@
m_type = 1
if ("help") //This is an exception
- src << "Help for xenomorph emotes. You can use these emotes with say \"*emote\":\n\naflap, airguitar, blink, blink_r, blush, bow, burp, choke, chucke, clap, collapse, cough, dance, deathgasp, drool, flap, frown, gasp, giggle, glare-(none)/mob, gnarl, hiss, jump, laugh, look-atom, me, moan, nod, point-atom, roar, roll, scream, scratch, scretch, shake, shiver, sign-#, sit, smile, sneeze, sniff, snore, stare-(none)/mob, sulk, sway, tail, tremble, twitch, twitch_s, wave, whimper, wink, yawn"
+ src << "Help for xenomorph emotes. You can use these emotes with say \"*emote\":\n\naflap, airguitar, blink, blink_r, blush, bow, burp, choke, chucke, clap, collapse, cough, dance, deathgasp, drool, flap, frown, gasp, giggle, glare-(none)/mob, gnarl, hiss, jump, laugh, look-atom, me, moan, nod, point-atom, roar, roll, scream, scratch, screech, shake, shiver, sign-#, sit, smile, sneeze, sniff, snore, stare-(none)/mob, sulk, sway, tail, tremble, twitch, twitch_s, wave, whimper, wink, yawn"
else
..(act)
diff --git a/code/modules/mob/living/carbon/alien/larva/emote.dm b/code/modules/mob/living/carbon/alien/larva/emote.dm
index cf4f18c5d07..286ee10a07d 100644
--- a/code/modules/mob/living/carbon/alien/larva/emote.dm
+++ b/code/modules/mob/living/carbon/alien/larva/emote.dm
@@ -6,83 +6,81 @@
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
var/muzzled = is_muzzled()
var/m_type = 1
var/message
switch(act) //Alphabetically sorted please.
- if ("burp")
+ if ("burp","burps")
if (!muzzled)
message = "[src] burps."
m_type = 2
- if ("choke")
+ if ("choke","chokes")
message = "[src] chokes."
m_type = 2
- if ("collapse")
+ if ("collapse","collapses")
Paralyse(2)
message = "[src] collapses!"
m_type = 2
- if ("dance")
+ if ("dance","dances")
if (!src.restrained())
message = "[src] dances around happily."
m_type = 1
- if ("drool")
+ if ("drool","drools")
message = "[src] drools."
m_type = 1
- if ("gasp")
+ if ("gasp","gasps")
message = "[src] gasps."
m_type = 2
- if ("gnarl")
+ if ("gnarl","gnarls")
if (!muzzled)
message = "[src] gnarls and shows its teeth.."
m_type = 2
- if ("hiss")
+ if ("hiss","hisses")
message = "[src] hisses softly."
m_type = 1
- if ("jump")
+ if ("jump","jumps")
message = "[src] jumps!"
m_type = 1
- if ("moan")
+ if ("moan","moans")
message = "[src] moans!"
m_type = 2
- if ("nod")
+ if ("nod","nods")
message = "[src] nods its head."
m_type = 1
-// if ("roar")
-// if (!muzzled)
-// message = "[src] roars." Commenting out since larva shouldn't roar /N
-// m_type = 2
- if ("roll")
+ if ("roar","roars")
+ if (!muzzled)
+ message = "[src] softly roars."
+ m_type = 2
+ if ("roll","rolls")
if (!src.restrained())
message = "[src] rolls."
m_type = 1
- if ("scratch")
+ if ("scratch","scratches")
if (!src.restrained())
message = "[src] scratches."
m_type = 1
- if ("scretch")
+ if ("screech","screeches") //This orignally was called scretch, changing it. -Sum99
if (!muzzled)
- message = "[src] scretches."
+ message = "[src] screeches."
m_type = 2
- if ("shake")
+ if ("shake","shakes")
message = "[src] shakes its head."
m_type = 1
- if ("shiver")
+ if ("shiver","shivers")
message = "[src] shivers."
m_type = 2
- if ("sign")
+ if ("sign","signs")
if (!src.restrained())
message = text("[src] signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null))
m_type = 1
- if ("snore")
+ if ("snore","snores")
message = "[src] snores."
m_type = 2
- if ("sulk")
+ if ("sulk","sulks")
message = "[src] sulks down sadly."
m_type = 1
- if ("sway")
+ if ("sway","sways")
message = "[src] sways around dizzily."
m_type = 1
if ("tail")
@@ -91,13 +89,13 @@
if ("twitch")
message = "[src] twitches violently."
m_type = 1
- if ("whimper")
+ if ("whimper","whimpers")
if (!muzzled)
message = "[src] whimpers."
m_type = 2
if ("help") //"The exception"
- src << "Help for larva emotes. You can use these emotes with say \"*emote\":\n\nburp, choke, collapse, dance, drool, gasp, gnarl, hiss, jump, moan, nod, roll, scratch,\nscretch, shake, shiver, sign-#, sulk, sway, tail, twitch, whimper"
+ src << "Help for larva emotes. You can use these emotes with say \"*emote\":\n\nburp, choke, collapse, dance, drool, gasp, gnarl, hiss, jump, moan, nod, roll, roar, scratch, screech, shake, shiver, sign-#, sulk, sway, tail, twitch, whimper"
else
src << "Unusable emote '[act]'. Say *help for a list."
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 0f742d02a10..b62a11e5153 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -2,55 +2,53 @@
// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
var/const/ALIEN_AFK_BRACKET = 450 // 45 seconds
-/obj/item/body_egg/alien_embryo
+/obj/item/organ/internal/body_egg/alien_embryo
name = "alien embryo"
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "larva0_dead"
var/stage = 0
-/obj/item/body_egg/alien_embryo/egg_process()
+/obj/item/organ/internal/body_egg/alien_embryo/on_life()
+ switch(stage)
+ if(2, 3)
+ if(prob(1))
+ owner.emote("sneeze")
+ if(prob(1))
+ owner.emote("cough")
+ if(prob(1))
+ owner << "Your throat feels sore."
+ if(prob(1))
+ owner << "Mucous runs down the back of your throat."
+ if(4)
+ if(prob(1))
+ owner.emote("sneeze")
+ if(prob(1))
+ owner.emote("cough")
+ if(prob(2))
+ owner << "Your muscles ache."
+ if(prob(20))
+ owner.take_organ_damage(1)
+ if(prob(2))
+ owner << "Your stomach hurts."
+ if(prob(20))
+ owner.adjustToxLoss(1)
+ if(5)
+ owner << "You feel something tearing its way out of your stomach..."
+ owner.adjustToxLoss(10)
+
+/obj/item/organ/internal/body_egg/alien_embryo/egg_process()
if(stage < 5 && prob(3))
stage++
spawn(0)
RefreshInfectionImage()
- switch(stage)
- if(2, 3)
- if(affected_mob == DEAD)
- return
- if(prob(1))
- affected_mob.emote("sneeze")
- if(prob(1))
- affected_mob.emote("cough")
- if(prob(1))
- affected_mob << "Your throat feels sore."
- if(prob(1))
- affected_mob << "Mucous runs down the back of your throat."
- if(4)
- if(affected_mob == DEAD)
- return
- if(prob(1))
- affected_mob.emote("sneeze")
- if(prob(1))
- affected_mob.emote("cough")
- if(prob(2))
- affected_mob << "Your muscles ache."
- if(prob(20))
- affected_mob.take_organ_damage(1)
- if(prob(2))
- affected_mob << "Your stomach hurts."
- if(prob(20))
- affected_mob.adjustToxLoss(1)
- affected_mob.updatehealth()
- if(5)
- if(affected_mob != DEAD)
- affected_mob << "You feel something tearing its way out of your stomach..."
- affected_mob.adjustToxLoss(10)
- affected_mob.updatehealth()
- if(prob(50))
- AttemptGrow()
+ if(stage == 5 && prob(50))
+ AttemptGrow()
-/obj/item/body_egg/alien_embryo/proc/AttemptGrow(gib_on_success = 1)
+/obj/item/organ/internal/body_egg/alien_embryo/proc/AttemptGrow(gib_on_success = 1)
+ if(!owner) return
var/list/candidates = get_candidates(BE_ALIEN, ALIEN_AFK_BRACKET)
var/client/C = null
@@ -61,55 +59,47 @@ var/const/ALIEN_AFK_BRACKET = 450 // 45 seconds
if(candidates.len)
C = pick(candidates)
- else if(affected_mob.client)
- C = affected_mob.client
+ else if(owner.client)
+ C = owner.client
else
stage = 4 // Let's try again later.
return
- if(affected_mob.lying)
- affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_lie")
+ if(owner.lying)
+ owner.overlays += image('icons/mob/alien.dmi', loc = owner, icon_state = "burst_lie")
else
- affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_stand")
+ owner.overlays += image('icons/mob/alien.dmi', loc = owner, icon_state = "burst_stand")
spawn(6)
- var/location = get_turf(affected_mob)
- if(!location)
- location = affected_mob.loc
- var/mob/living/carbon/alien/larva/new_xeno = new(location)
+ var/atom/xeno_loc = owner
+ if(!gib_on_success)
+ xeno_loc = get_turf(xeno_loc)
+
+ var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
new_xeno.key = C.key
new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100) //To get the player's attention
if(gib_on_success)
- affected_mob.gib()
- if(istype(new_xeno.loc,/mob/living/carbon))
- var/mob/living/carbon/digester = new_xeno.loc
- digester.stomach_contents += new_xeno
+ owner.stomach_contents += new_xeno
+ owner.gib()
qdel(src)
-/*----------------------------------------
-Proc: RefreshInfectionImage()
-Des: Removes the current icons located in the infected mob adds the current stage
-----------------------------------------*/
-/obj/item/body_egg/alien_embryo/RefreshInfectionImage()
- RemoveInfectionImages()
- AddInfectionImages()
/*----------------------------------------
Proc: AddInfectionImages(C)
Des: Adds the infection image to all aliens for this embryo
----------------------------------------*/
-/obj/item/body_egg/alien_embryo/AddInfectionImages()
+/obj/item/organ/internal/body_egg/alien_embryo/AddInfectionImages()
for(var/mob/living/carbon/alien/alien in player_list)
if(alien.client)
- var/I = image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "infected[stage]")
+ var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
alien.client.images += I
/*----------------------------------------
Proc: RemoveInfectionImage(C)
Des: Removes all images from the mob infected by this embryo
----------------------------------------*/
-/obj/item/body_egg/alien_embryo/RemoveInfectionImages()
+/obj/item/organ/internal/body_egg/alien_embryo/RemoveInfectionImages()
for(var/mob/living/carbon/alien/alien in player_list)
if(alien.client)
for(var/image/I in alien.client.images)
- if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == affected_mob)
+ if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
qdel(I)
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index 7763954c786..ff8b9538eb8 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -87,7 +87,7 @@ var/const/MAX_ACTIVE_TIME = 400
return Attach(AM)
return 0
-/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed)
+/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed, mob/thrower, spin)
if(!..())
return
if(stat == CONSCIOUS)
@@ -116,7 +116,7 @@ var/const/MAX_ACTIVE_TIME = 400
if(loc == L) return 0
if(stat != CONSCIOUS) return 0
- if(locate(/obj/item/body_egg/alien_embryo) in L) return 0
+ if(locate(/obj/item/organ/internal/body_egg/alien_embryo) in L) return 0
if(!sterile) L.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage
L.visible_message("[src] leaps at [L]'s face!", \
@@ -176,8 +176,7 @@ var/const/MAX_ACTIVE_TIME = 400
icon_state = "[initial(icon_state)]_impregnated"
if(!target.getlimb(/obj/item/organ/limb/robot/chest) && !(target.status_flags & XENO_HOST))
- new /obj/item/body_egg/alien_embryo(target)
-
+ new /obj/item/organ/internal/body_egg/alien_embryo(target)
if(iscorgi(target))
var/mob/living/simple_animal/pet/dog/corgi/C = target
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index 216b5c0765b..1303a8ee03b 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -9,11 +9,6 @@
origin_tech = "biotech=3"
var/braintype = "Cyborg"
- req_access = list(access_robotics)
-
- //Revised. Brainmob is now contained directly within object of transfer. MMI in this case.
-
- var/locked = 0
var/syndiemmi = 0 //Whether or not this is a Syndicate MMI
var/mob/living/carbon/brain/brainmob = null //The current occupant.
var/mob/living/silicon/robot = null //Appears unused.
@@ -31,12 +26,6 @@
else
icon_state = "mmi_empty"
-/obj/item/device/mmi/Topic(href, href_list)
- if(href_list["reenter"])
- var/mob/dead/observer/ghost = usr
- if(istype(ghost))
- ghost.reenter_corpse(ghost)
-
/obj/item/device/mmi/attackby(obj/item/O, mob/user, params)
user.changeNext_move(CLICK_CD_MELEE)
if(istype(O,/obj/item/organ/brain)) //Time to stick a brain in it --NEO
@@ -52,11 +41,7 @@
return
var/mob/living/carbon/brain/B = newbrain.brainmob
if(!B.key)
- var/mob/dead/observer/ghost = B.get_ghost()
- if(ghost)
- if(ghost.client)
- ghost << "Someone has put your brain in a MMI!(Click to enter)"
- ghost << sound('sound/effects/genetics.ogg')
+ B.notify_ghost_cloning("Someone has put your brain in a MMI!")
visible_message("[user] sticks \a [newbrain] into \the [src].")
brainmob = newbrain.brainmob
@@ -73,19 +58,10 @@
name = "Man-Machine Interface: [brainmob.real_name]"
update_icon()
- locked = 1
-
feedback_inc("cyborg_mmis_filled",1)
return
- if((istype(O,/obj/item/weapon/card/id)||istype(O,/obj/item/device/pda)) && brainmob)
- if(allowed(user))
- locked = !locked
- user << "You [locked ? "lock" : "unlock"] the brain holder."
- else
- user << "Access denied."
- return
if(brainmob)
O.attack(brainmob, user) //Oh noooeeeee
return
@@ -94,10 +70,8 @@
/obj/item/device/mmi/attack_self(mob/user)
if(!brain)
user << "You upend the MMI, but there's nothing in it!"
- else if(locked)
- user << "You upend the MMI, but the brain is clamped into place!"
else
- user << "You upend the MMI, spilling the brain onto the floor."
+ user << "You unlock and upend the MMI, spilling the brain onto the floor."
brainmob.container = null //Reset brainmob mmi var.
brainmob.loc = brain //Throw mob into brain.
@@ -126,7 +100,6 @@
name = "Man-Machine Interface: [brainmob.real_name]"
update_icon()
- locked = 1
return
/obj/item/device/mmi/radio_enabled
diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm
index c301a6a8d04..5df89ec19ae 100644
--- a/code/modules/mob/living/carbon/brain/brain_item.dm
+++ b/code/modules/mob/living/carbon/brain/brain_item.dm
@@ -9,7 +9,7 @@
throw_speed = 3
throw_range = 5
layer = 4.1
- origin_tech = "biotech=3"
+ origin_tech = "biotech=4"
attack_verb = list("attacked", "slapped", "whacked")
var/mob/living/carbon/brain/brainmob = null
diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm
index c9feda102b4..072f5c3f7d5 100644
--- a/code/modules/mob/living/carbon/brain/emote.dm
+++ b/code/modules/mob/living/carbon/brain/emote.dm
@@ -6,8 +6,6 @@
var/t1 = findtext(act, "-", 1, null)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
if(src.stat == DEAD)
return
@@ -22,16 +20,16 @@
message = "[src] lets out a distressed noise."
m_type = 2
- if ("beep")
+ if ("beep","beeps")
src << "You beep."
message = "[src] beeps."
m_type = 2
- if ("blink")
+ if ("blink","blinks")
message = "[src] blinks."
m_type = 1
- if ("boop")
+ if ("boop","boops")
src << "You boop."
message = "[src] boops."
m_type = 2
@@ -45,7 +43,7 @@
message = "[src] plays a loud tone."
m_type = 2
- if ("whistle")
+ if ("whistle","whistles")
src << "You whistle."
message = "[src] whistles."
m_type = 2
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm
index 79817af275c..7f8445b95fc 100644
--- a/code/modules/mob/living/carbon/brain/posibrain.dm
+++ b/code/modules/mob/living/carbon/brain/posibrain.dm
@@ -11,7 +11,6 @@ var/global/posibrain_notif_cooldown = 0
var/askDelay = 10 * 60 * 1
brainmob = null
req_access = list(access_robotics)
- locked = 0
mecha = null//This does not appear to be used outside of reference in mecha.dm.
braintype = "Android"
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 6c4d86d89ae..c54c9e9f592 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -530,4 +530,16 @@ var/const/GALOSHES_DONT_HELP = 8
I.throw_at(target,I.throw_range,I.throw_speed,src)
if(61 to 90) //throw it down to the floor
var/turf/target = get_turf(loc)
- I.throw_at(target,I.throw_range,I.throw_speed,src)
\ No newline at end of file
+ I.throw_at(target,I.throw_range,I.throw_speed,src)
+
+/mob/living/carbon/emp_act(severity)
+ for(var/obj/item/organ/internal/O in internal_organs)
+ O.emp_act(severity)
+ ..()
+
+
+/mob/living/carbon/check_eye_prot()
+ var/number = ..()
+ for(var/obj/item/organ/internal/cyberimp/eyes/EFP in internal_organs)
+ number += EFP.flash_protect
+ return number
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 9b705841a82..3c92e6403a1 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -11,6 +11,11 @@
return 1
return ..()
+/mob/living/carbon/throw_impact(atom/hit_atom)
+ . = ..()
+ if(hit_atom.density && isturf(hit_atom))
+ Weaken(1)
+ take_organ_damage(10)
/mob/living/carbon/attackby(obj/item/I, mob/user, params)
if(lying)
diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm
index 320ae709bc3..2009c2bc5fe 100644
--- a/code/modules/mob/living/carbon/emote.dm
+++ b/code/modules/mob/living/carbon/emote.dm
@@ -10,9 +10,6 @@
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
-
var/muzzled = is_muzzled()
//var/m_type = 1
@@ -27,7 +24,7 @@
message = "[src] is strumming the air and headbanging like a safari chimp."
m_type = 1
- if ("blink")
+ if ("blink","blinks")
message = "[src] blinks."
m_type = 1
@@ -35,11 +32,11 @@
message = "[src] blinks rapidly."
m_type = 1
- if ("blush")
+ if ("blush","blushes")
message = "[src] blushes."
m_type = 1
- if ("bow")
+ if ("bow","bows")
if (!src.buckled)
var/M = null
if (param)
@@ -55,117 +52,117 @@
message = "[src] bows."
m_type = 1
- if ("burp")
+ if ("burp","burps")
if (!muzzled)
..(act)
- if ("choke")
+ if ("choke","chokes")
if (!muzzled)
..(act)
else
message = "[src] makes a strong noise."
m_type = 2
- if ("chuckle")
+ if ("chuckle","chuckles")
if (!muzzled)
..(act)
else
message = "[src] makes a noise."
m_type = 2
- if ("clap")
+ if ("clap","claps")
if (!src.restrained())
message = "[src] claps."
m_type = 2
- if ("cough")
+ if ("cough","coughs")
if (!muzzled)
..(act)
else
message = "[src] makes a strong noise."
m_type = 2
- if ("deathgasp")
+ if ("deathgasp","deathgasps")
message = "[src] seizes up and falls limp, \his eyes dead and lifeless..."
m_type = 1
- if ("flap")
+ if ("flap","flaps")
if (!src.restrained())
message = "[src] flaps \his wings."
m_type = 2
- if ("gasp")
+ if ("gasp","gasps")
if (!muzzled)
..(act)
else
message = "[src] makes a weak noise."
m_type = 2
- if ("giggle")
+ if ("giggle","giggles")
if (!muzzled)
..(act)
else
message = "[src] makes a noise."
m_type = 2
- if ("laugh")
+ if ("laugh","laughs")
if (!muzzled)
..(act)
else
message = "[src] makes a noise."
- if ("nod")
+ if ("nod","nods")
message = "[src] nods."
m_type = 1
- if ("scream")
+ if ("scream","screams")
if (!muzzled)
..(act)
else
message = "[src] makes a very loud noise."
m_type = 2
- if ("shake")
+ if ("shake","shakes")
message = "[src] shakes \his head."
m_type = 1
- if ("sneeze")
+ if ("sneeze","sneezes")
if (!muzzled)
..(act)
else
message = "[src] makes a strange noise."
m_type = 2
- if ("sigh")
+ if ("sigh","sighs")
if (!muzzled)
..(act)
else
message = "[src] sighs."
m_type = 2
- if ("sniff")
+ if ("sniff","sniffs")
message = "[src] sniffs."
m_type = 2
- if ("snore")
+ if ("snore","snores")
if (!muzzled)
..(act)
else
message = "[src] makes a noise."
m_type = 2
- if ("whimper")
+ if ("whimper","whimpers")
if (!muzzled)
..(act)
else
message = "[src] makes a weak noise."
m_type = 2
- if ("wink")
+ if ("wink","winks")
message = "[src] winks."
m_type = 1
- if ("yawn")
+ if ("yawn","yawns")
if (!muzzled)
..(act)
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 2b5a09b4c72..6523c085039 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -6,8 +6,6 @@
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
var/muzzled = is_muzzled()
//var/m_type = 1
@@ -28,29 +26,29 @@
message = "[src] flaps \his wings ANGRILY!"
m_type = 2
- if ("choke")
+ if ("choke","chokes")
if (miming)
message = "[src] clutches \his throat desperately!"
else
..(act)
- if ("chuckle")
+ if ("chuckle","chuckles")
if(miming)
message = "[src] appears to chuckle."
else
..(act)
- if ("clap")
+ if ("clap","claps")
if (!src.restrained())
message = "[src] claps."
m_type = 2
- if ("collapse")
+ if ("collapse","collapses")
Paralyse(2)
message = "[src] collapses!"
m_type = 2
- if ("cough")
+ if ("cough","coughs")
if (miming)
message = "[src] appears to cough!"
else
@@ -61,7 +59,7 @@
message = "[src] makes a strong noise."
m_type = 2
- if ("cry")
+ if ("cry","crys","cries") //I feel bad if people put s at the end of cry. -Sum99
if (miming)
message = "[src] cries."
else
@@ -101,7 +99,7 @@
return
message = "[src] [input]"
- if ("dap")
+ if ("dap","daps")
m_type = 1
if (!src.restrained())
var/M = null
@@ -119,24 +117,24 @@
message = "[src] raises an eyebrow."
m_type = 1
- if ("flap")
+ if ("flap","flaps")
if (!src.restrained())
message = "[src] flaps \his wings."
m_type = 2
- if ("gasp")
+ if ("gasp","gasps")
if (miming)
message = "[src] appears to be gasping!"
else
..(act)
- if ("giggle")
+ if ("giggle","giggles")
if (miming)
message = "[src] giggles silently!"
else
..(act)
- if ("groan")
+ if ("groan","groans")
if (miming)
message = "[src] appears to groan!"
else
@@ -147,7 +145,7 @@
message = "[src] makes a loud noise."
m_type = 2
- if ("grumble")
+ if ("grumble","grumbles")
if (!muzzled)
message = "[src] grumbles!"
else
@@ -171,7 +169,7 @@
else
message = "[src] holds out \his hand to [M]."
- if ("hug")
+ if ("hug","hugs")
m_type = 1
if (!src.restrained())
var/M = null
@@ -215,14 +213,14 @@
else
message = "[src] [message]"
- if ("moan")
+ if ("moan","moans")
if(miming)
message = "[src] appears to moan!"
else
message = "[src] moans!"
m_type = 2
- if ("mumble")
+ if ("mumble","mumbles")
message = "[src] mumbles!"
m_type = 2
@@ -235,7 +233,7 @@
message = "[src] raises a hand."
m_type = 1
- if ("salute")
+ if ("salute","salutes")
if (!src.buckled)
var/M = null
if (param)
@@ -251,27 +249,27 @@
message = "[src] salutes."
m_type = 1
- if ("scream")
+ if ("scream","screams")
if (miming)
message = "[src] acts out a scream!"
else
..(act)
- if ("shiver")
+ if ("shiver","shivers")
message = "[src] shivers."
m_type = 1
- if ("shrug")
+ if ("shrug","shrugs")
message = "[src] shrugs."
m_type = 1
- if ("sigh")
+ if ("sigh","sighs")
if(miming)
message = "[src] sighs."
else
..(act)
- if ("signal")
+ if ("signal","signals")
if (!src.restrained())
var/t1 = round(text2num(param))
if (isnum(t1))
@@ -281,34 +279,34 @@
message = "[src] raises [t1] finger\s."
m_type = 1
- if ("sneeze")
+ if ("sneeze","sneezes")
if (miming)
message = "[src] sneezes."
else
..(act)
- if ("sniff")
+ if ("sniff","sniffs")
message = "[src] sniffs."
m_type = 2
- if ("snore")
+ if ("snore","snores")
if (miming)
message = "[src] sleeps soundly."
else
..(act)
- if ("whimper")
+ if ("whimper","whimpers")
if (miming)
message = "[src] appears hurt."
else
..(act)
- if ("yawn")
+ if ("yawn","yawns")
if (!muzzled)
message = "[src] yawns."
m_type = 2
- if("wag")
+ if("wag","wags")
if(dna && dna.species && (("tail_lizard" in dna.species.mutant_bodyparts) || (features["tail_human"] != "None")))
message = "[src] wags \his tail."
startTailWag()
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 696c9a3b5a4..c9ff89d92bd 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -263,10 +263,12 @@
if(digitalcamo)
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
+ if(!wear_mask && is_thrall(src) && in_range(user,src))
+ msg += "Their features seem unnaturally tight and drawn.\n"
if(istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/H = user
- var/obj/item/cybernetic_implant/eyes/hud/CIH = locate(/obj/item/cybernetic_implant/eyes/hud) in H.internal_organs
+ var/obj/item/organ/internal/cyberimp/eyes/hud/CIH = H.getorgan(/obj/item/organ/internal/cyberimp/eyes/hud)
if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH)
var/perpname = get_face_name(get_id_name(""))
if(perpname)
@@ -275,9 +277,9 @@
msg += "Rank: [R.fields["rank"]] "
msg += "\[Front photo\] "
msg += "\[Side photo\] "
- if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH,/obj/item/cybernetic_implant/eyes/hud/medical))
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/medical))
var/implant_detect
- for(var/obj/item/cybernetic_implant/CI in internal_organs)
+ for(var/obj/item/organ/internal/cyberimp/CI in internal_organs)
implant_detect += "[name] is modified with a [CI.name]. "
if(implant_detect)
msg += "Detected cybernetic modifications: "
@@ -292,8 +294,9 @@
msg += "\[Medical evaluation\] "
- if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH,/obj/item/cybernetic_implant/eyes/hud/security))
- if(!user.stat && user != src) //|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/security))
+ if(!user.stat && user != src)
+ //|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
var/criminal = "None"
R = find_record("name", perpname, data_core.security)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 679fb191dc1..658bd354c0c 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -22,10 +22,13 @@
/obj/item/organ/limb/r_arm, /obj/item/organ/limb/r_leg, /obj/item/organ/limb/l_leg)
for(var/obj/item/organ/limb/O in organs)
O.owner = src
- internal_organs += new /obj/item/organ/appendix
- internal_organs += new /obj/item/organ/heart
+ internal_organs += new /obj/item/organ/internal/appendix
+ internal_organs += new /obj/item/organ/internal/heart
internal_organs += new /obj/item/organ/brain
+ for(var/obj/item/organ/internal/I in internal_organs)
+ I.Insert(src)
+
// for spawned humans; overwritten by other code
ready_dna(src)
randomize_human(src)
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index af0c7205b31..70d3d476103 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -172,7 +172,7 @@
if(blocked <= 0) return 0
var/obj/item/organ/limb/organ = null
- if(isorgan(def_zone))
+ if(islimb(def_zone))
organ = def_zone
else
if(!def_zone) def_zone = ran_zone(def_zone)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 06944984cf5..5522563f1cd 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -11,7 +11,7 @@ emp_act
var/organnum = 0
if(def_zone)
- if(isorgan(def_zone))
+ if(islimb(def_zone))
return checkarmor(def_zone, type)
var/obj/item/organ/limb/affecting = get_organ(ran_zone(def_zone))
return checkarmor(affecting, type)
@@ -190,7 +190,6 @@ emp_act
apply_effect(20, PARALYZE, armor)
if(prob(I.force + min(100,100 - src.health)) && src != user && I.damtype == BRUTE)
ticker.mode.remove_revolutionary(mind)
- ticker.mode.remove_gangster(mind)
if(bloody) //Apply blood
if(wear_mask)
wear_mask.add_blood(src)
@@ -469,4 +468,4 @@ emp_act
L.take_damage(I.w_class*I.embedded_impact_pain_multiplier)
visible_message("\the [I.name] embeds itself in [src]'s [L.getDisplayName()]!","\the [I.name] embeds itself in your [L.getDisplayName()]!")
return
- return ..()
+ return ..()
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 3e512e7b825..6950ff303f8 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -80,7 +80,7 @@
///checkeyeprot()
///Returns a number between -1 to 2
/mob/living/carbon/human/check_eye_prot()
- var/number = 0
+ var/number = ..()
if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
number += HFP.flash_protect
@@ -90,9 +90,6 @@
if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
var/obj/item/clothing/mask/MFP = src.wear_mask
number += MFP.flash_protect
- var/obj/item/cybernetic_implant/eyes/EFP = locate() in src
- if(EFP)
- number += EFP.flash_protect
return number
/mob/living/carbon/human/check_ear_prot()
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 4d4876bb4db..12266289786 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -707,6 +707,7 @@
switch(H.hal_screwyhud)
if(1) H.healths.icon_state = "health6"
if(2) H.healths.icon_state = "health7"
+ if(5) H.healths.icon_state = "health0"
else
switch(H.health - H.staminaloss)
if(100 to INFINITY) H.healths.icon_state = "health0"
@@ -737,6 +738,8 @@
icon_num = 4
if(damage > (comparison*4))
icon_num = 5
+ if(H.hal_screwyhud == 5)
+ icon_num = 0
if(icon_num)
H.healthdoll.overlays += image('icons/mob/screen_gen.dmi',"[L.name][icon_num]")
@@ -1037,7 +1040,6 @@
H.apply_effect(20, PARALYZE, armor)
if(prob(I.force + ((100 - H.health)/2)) && H != user && I.damtype == BRUTE)
ticker.mode.remove_revolutionary(H.mind)
- ticker.mode.remove_gangster(H.mind)
if(bloody) //Apply blood
if(H.wear_mask)
@@ -1098,7 +1100,7 @@
if(blocked <= 0) return 0
var/obj/item/organ/limb/organ = null
- if(isorgan(def_zone))
+ if(islimb(def_zone))
organ = def_zone
else
if(!def_zone) def_zone = ran_zone(def_zone)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 362a423eb50..8f8f5829970 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -212,13 +212,18 @@ Please contact me on #coderbus IRC. ~Carnie x
var/image/standing
var/iconfile2use //Which icon file to use to generate the overlay and any female alterations.
+ var/layer2use
if(U.alternate_worn_icon)
iconfile2use = U.alternate_worn_icon
if(!iconfile2use)
iconfile2use = 'icons/mob/uniform.dmi'
+ if(U.alternate_worn_layer)
+ layer2use = U.alternate_worn_layer
+ if(!layer2use)
+ layer2use = UNIFORM_LAYER
- standing = image("icon"=iconfile2use, "icon_state"="[t_color]_s", "layer"=-UNIFORM_LAYER)
+ standing = image("icon"=iconfile2use, "icon_state"="[t_color]_s", "layer"=-layer2use)
overlays_standing[UNIFORM_LAYER] = standing
@@ -266,11 +271,17 @@ Please contact me on #coderbus IRC. ~Carnie x
var/t_state = gloves.item_state
if(!t_state) t_state = gloves.icon_state
+ var/layer2use
+ if(gloves.alternate_worn_layer)
+ layer2use = gloves.alternate_worn_layer
+ if(!layer2use)
+ layer2use = GLOVES_LAYER
+
var/image/standing
if(gloves.alternate_worn_icon)
- standing = image("icon"=gloves.alternate_worn_icon, "icon_state"="[t_state]", "layer"=-GLOVES_LAYER)
+ standing = image("icon"=gloves.alternate_worn_icon, "icon_state"="[t_state]", "layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/hands.dmi', "icon_state"="[t_state]", "layer"=-GLOVES_LAYER)
+ standing = image("icon"='icons/mob/hands.dmi', "icon_state"="[t_state]", "layer"=-layer2use)
overlays_standing[GLOVES_LAYER] = standing
@@ -294,11 +305,17 @@ Please contact me on #coderbus IRC. ~Carnie x
glasses.screen_loc = ui_glasses //...draw the item in the inventory screen
client.screen += glasses //Either way, add the item to the HUD
+ var/layer2use
+ if(glasses.alternate_worn_layer)
+ layer2use = glasses.alternate_worn_layer
+ if(!layer2use)
+ layer2use = GLASSES_LAYER
+
var/image/standing
if(glasses.alternate_worn_icon)
- standing = image("icon"=glasses.alternate_worn_icon, "icon_state"="[glasses.icon_state]","layer"=-GLASSES_LAYER)
+ standing = image("icon"=glasses.alternate_worn_icon, "icon_state"="[glasses.icon_state]","layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/eyes.dmi', "icon_state"="[glasses.icon_state]", "layer"=-GLASSES_LAYER)
+ standing = image("icon"='icons/mob/eyes.dmi', "icon_state"="[glasses.icon_state]", "layer"=-layer2use)
overlays_standing[GLASSES_LAYER] = standing
@@ -314,11 +331,17 @@ Please contact me on #coderbus IRC. ~Carnie x
ears.screen_loc = ui_ears //...draw the item in the inventory screen
client.screen += ears //Either way, add the item to the HUD
+ var/layer2use
+ if(ears.alternate_worn_layer)
+ layer2use = ears.alternate_worn_layer
+ if(!layer2use)
+ layer2use = EARS_LAYER
+
var/image/standing
if(ears.alternate_worn_icon)
- standing = image("icon"=ears.alternate_worn_icon, "icon_state"="[ears.icon_state]", "layer"=-EARS_LAYER)
+ standing = image("icon"=ears.alternate_worn_icon, "icon_state"="[ears.icon_state]", "layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/ears.dmi', "icon_state"="[ears.icon_state]", "layer"=-EARS_LAYER)
+ standing = image("icon"='icons/mob/ears.dmi', "icon_state"="[ears.icon_state]", "layer"=-layer2use)
overlays_standing[EARS_LAYER] = standing
@@ -334,11 +357,17 @@ Please contact me on #coderbus IRC. ~Carnie x
shoes.screen_loc = ui_shoes //...draw the item in the inventory screen
client.screen += shoes //Either way, add the item to the HUD
+ var/layer2use
+ if(shoes.alternate_worn_layer)
+ layer2use = shoes.alternate_worn_layer
+ if(!layer2use)
+ layer2use = SHOES_LAYER
+
var/image/standing
if(shoes.alternate_worn_icon)
- standing = image("icon"=shoes.alternate_worn_icon, "icon_state"="[shoes.icon_state]","layer"=-SHOES_LAYER)
+ standing = image("icon"=shoes.alternate_worn_icon, "icon_state"="[shoes.icon_state]","layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/feet.dmi', "icon_state"="[shoes.icon_state]", "layer"=-SHOES_LAYER)
+ standing = image("icon"='icons/mob/feet.dmi', "icon_state"="[shoes.icon_state]", "layer"=-layer2use)
overlays_standing[SHOES_LAYER] = standing
if(shoes.blood_DNA)
@@ -384,11 +413,17 @@ Please contact me on #coderbus IRC. ~Carnie x
var/t_state = belt.item_state
if(!t_state) t_state = belt.icon_state
+ var/layer2use
+ if(belt.alternate_worn_layer)
+ layer2use = belt.alternate_worn_layer
+ if(!layer2use)
+ layer2use = BELT_LAYER
+
var/image/standing
if(belt.alternate_worn_icon)
- standing = image("icon"=belt.alternate_worn_icon, "icon_state"="[t_state]", "layer"=-BELT_LAYER)
+ standing = image("icon"=belt.alternate_worn_icon, "icon_state"="[t_state]", "layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/belt.dmi', "icon_state"="[t_state]", "layer"=-BELT_LAYER)
+ standing = image("icon"='icons/mob/belt.dmi', "icon_state"="[t_state]", "layer"=-layer2use)
overlays_standing[BELT_LAYER] = standing
@@ -405,11 +440,18 @@ Please contact me on #coderbus IRC. ~Carnie x
wear_suit.screen_loc = ui_oclothing //TODO //...draw the item in the inventory screen
client.screen += wear_suit //Either way, add the item to the HUD
+
+ var/layer2use
+ if(wear_suit.alternate_worn_layer)
+ layer2use = wear_suit.alternate_worn_layer
+ if(!layer2use)
+ layer2use = SUIT_LAYER
+
var/image/standing
if(wear_suit.alternate_worn_icon)
- standing = image("icon"=wear_suit.alternate_worn_icon, "icon_state"="[wear_suit.icon_state]", "layer"=-SUIT_LAYER)
+ standing = image("icon"=wear_suit.alternate_worn_icon, "icon_state"="[wear_suit.icon_state]", "layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/suit.dmi', "icon_state"="[wear_suit.icon_state]", "layer"=-SUIT_LAYER)
+ standing = image("icon"='icons/mob/suit.dmi', "icon_state"="[wear_suit.icon_state]", "layer"=-layer2use)
overlays_standing[SUIT_LAYER] = standing
if(istype(wear_suit, /obj/item/clothing/suit/straight_jacket))
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 16d75fc08a4..8f6db5b5086 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -9,6 +9,8 @@
if(..())
. = 1
+ for(var/obj/item/organ/internal/O in internal_organs)
+ O.on_life()
//Updates the number of stored chemicals for powers
handle_changeling()
@@ -456,7 +458,6 @@
return 1
/mob/living/carbon/update_sight()
-
if(stat == DEAD)
sight |= SEE_TURFS
sight |= SEE_MOBS
@@ -521,3 +522,8 @@
//We totally need a sweat system cause it totally makes sense...~
bodytemperature += min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers
+
+/mob/living/carbon/handle_actions()
+ ..()
+ for(var/obj/item/I in internal_organs)
+ give_action_button(I, 1)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/monkey/emote.dm b/code/modules/mob/living/carbon/monkey/emote.dm
index e21d3a48bb7..42adb99ec59 100644
--- a/code/modules/mob/living/carbon/monkey/emote.dm
+++ b/code/modules/mob/living/carbon/monkey/emote.dm
@@ -6,19 +6,17 @@
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
var/muzzled = is_muzzled()
var/m_type = 1
var/message
switch(act) //Ooh ooh ah ah keep this alphabetical ooh ooh ah ah!
- if ("deathgasp")
+ if ("deathgasp","deathgasps")
message = "[src] lets out a faint chimper as it collapses and stops moving..."
m_type = 1
- if ("gnarl")
+ if ("gnarl","gnarls")
if (!muzzled)
message = "[src] gnarls and shows its teeth.."
m_type = 2
@@ -28,35 +26,35 @@
message = "[src] flails its paw."
m_type = 1
- if ("moan")
+ if ("moan","moans")
message = "[src] moans!"
m_type = 2
- if ("roar")
+ if ("roar","roars")
if (!muzzled)
message = "[src] roars."
m_type = 2
- if ("roll")
+ if ("roll","rolls")
if (!src.restrained())
message = "[src] rolls."
m_type = 1
- if ("scratch")
+ if ("scratch","scratches")
if (!src.restrained())
message = "[src] scratches."
m_type = 1
- if ("scretch")
+ if ("screech","screeches")
if (!muzzled)
- message = "[src] scretches."
+ message = "[src] screeches."
m_type = 2
- if ("shiver")
+ if ("shiver","shivers")
message = "[src] shivers."
m_type = 2
- if ("sign")
+ if ("sign","signs")
if (!src.restrained())
message = text("[src] signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null))
m_type = 1
@@ -66,7 +64,7 @@
m_type = 1
if ("help") //Ooh ah ooh ooh this is an exception to alphabetical ooh ooh.
- src << "Help for monkey emotes. You can use these emotes with say \"*emote\":\n\naflap, airguitar, blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, dance, deathgasp, drool, flap, frown, gasp, gnarl, giggle, glare-(none)/mob, grin, jump, laugh, look, me, moan, nod, paw, point-(atom), roar, roll, scream, scratch, scretch, shake, shiver, sigh, sign-#, sit, smile, sneeze, sniff, snore, stare-(none)/mob, sulk, sway, tail, tremble, twitch, twitch_s, wave whimper, wink, yawn"
+ src << "Help for monkey emotes. You can use these emotes with say \"*emote\":\n\naflap, airguitar, blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, dance, deathgasp, drool, flap, frown, gasp, gnarl, giggle, glare-(none)/mob, grin, jump, laugh, look, me, moan, nod, paw, point-(atom), roar, roll, scream, scratch, screech, shake, shiver, sigh, sign-#, sit, smile, sneeze, sniff, snore, stare-(none)/mob, sulk, sway, tail, tremble, twitch, twitch_s, wave whimper, wink, yawn"
else
..(act)
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index 112fe73cc82..06f663a56f2 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -143,7 +143,7 @@
/mob/living/carbon/monkey/handle_changeling()
if(mind && hud_used)
if(mind.changeling)
- mind.changeling.regenerate()
+ mind.changeling.regenerate(src)
hud_used.lingchemdisplay.invisibility = 0
hud_used.lingchemdisplay.maptext = "
[round(mind.changeling.chem_charges)]
"
else
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 1d1bbcc64d5..7a2a5379910 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -16,10 +16,13 @@
verbs += /mob/living/proc/mob_sleep
verbs += /mob/living/proc/lay_down
- internal_organs += new /obj/item/organ/appendix
- internal_organs += new /obj/item/organ/heart
+ internal_organs += new /obj/item/organ/internal/appendix
+ internal_organs += new /obj/item/organ/internal/heart
internal_organs += new /obj/item/organ/brain
+ for(var/obj/item/organ/internal/I in internal_organs)
+ I.Insert(src)
+
if(name == "monkey")
name = text("monkey ([rand(1, 1000)])")
real_name = name
@@ -272,4 +275,11 @@
if(wear_mask)
protection = max(1 - wear_mask.permeability_coefficient, protection)
protection = protection/7 //the rest of the body isn't covered.
- return protection
\ No newline at end of file
+ return protection
+
+/mob/living/carbon/monkey/check_eye_prot()
+ var/number = ..()
+ if(istype(src.wear_mask, /obj/item/clothing/mask))
+ var/obj/item/clothing/mask/MFP = src.wear_mask
+ number += MFP.flash_protect
+ return number
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm
index 163ccdae8b1..b8129dd15c9 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -96,11 +96,18 @@
/mob/living/carbon/update_inv_wear_mask()
remove_overlay(FACEMASK_LAYER)
if(istype(wear_mask, /obj/item/clothing/mask))
+
+ var/layer2use
+ if(wear_mask.alternate_worn_layer)
+ layer2use = wear_mask.alternate_worn_layer
+ if(!layer2use)
+ layer2use = FACEMASK_LAYER
+
var/image/standing
if(wear_mask.alternate_worn_icon)
- standing = image("icon"=wear_mask.alternate_worn_icon, "icon_state"="[wear_mask.icon_state]", "layer"=-FACEMASK_LAYER)
+ standing = image("icon"=wear_mask.alternate_worn_icon, "icon_state"="[wear_mask.icon_state]", "layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/mask.dmi', "icon_state"="[wear_mask.icon_state]", "layer"=-FACEMASK_LAYER)
+ standing = image("icon"='icons/mob/mask.dmi', "icon_state"="[wear_mask.icon_state]", "layer"=-layer2use)
overlays_standing[FACEMASK_LAYER] = standing
@@ -111,11 +118,18 @@
/mob/living/carbon/update_inv_back()
remove_overlay(BACK_LAYER)
if(back)
+
+ var/layer2use
+ if(back.alternate_worn_layer)
+ layer2use = back.alternate_worn_layer
+ if(!layer2use)
+ layer2use = BACK_LAYER
+
var/image/standing
if(back.alternate_worn_icon)
- standing = image("icon"=back.alternate_worn_icon, "icon_state"="[back.icon_state]", "layer"=-BACK_LAYER)
+ standing = image("icon"=back.alternate_worn_icon, "icon_state"="[back.icon_state]", "layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/back.dmi', "icon_state"="[back.icon_state]", "layer"=-BACK_LAYER)
+ standing = image("icon"='icons/mob/back.dmi', "icon_state"="[back.icon_state]", "layer"=-layer2use)
overlays_standing[BACK_LAYER] = standing
return back
@@ -124,11 +138,18 @@
/mob/living/carbon/update_inv_head()
remove_overlay(HEAD_LAYER)
if(head)
+
+ var/layer2use
+ if(head.alternate_worn_layer)
+ layer2use = head.alternate_worn_layer
+ if(!layer2use)
+ layer2use = HEAD_LAYER
+
var/image/standing
if(head.alternate_worn_icon)
- standing = image("icon"=head.alternate_worn_icon, "icon_state"="[head.icon_state]", "layer"=-HEAD_LAYER)
+ standing = image("icon"=head.alternate_worn_icon, "icon_state"="[head.icon_state]", "layer"=-layer2use)
if(!standing)
- standing = image("icon"='icons/mob/head.dmi', "icon_state"="[head.icon_state]", "layer"=-HEAD_LAYER)
+ standing = image("icon"='icons/mob/head.dmi', "icon_state"="[head.icon_state]", "layer"=-layer2use)
standing.color = head.color // For now, this is here solely for kitty ears, but everything should do this eventually
standing.alpha = head.alpha
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index ef8a6b82680..a3092fb9228 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -8,25 +8,22 @@
var/param = null
- if (findtext(act, "-", 1, null))
+ if (findtext(act, "-", 1, null)) //Removes dashes for npcs "EMOTE-PLAYERNAME" or something like that, I ain't no AI coder. It's not for players. -Sum99
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
-
switch(act)//Hello, how would you like to order? Alphabetically!
if ("aflap")
if (!src.restrained())
message = "[src] flaps its wings ANGRILY!"
m_type = 2
- if ("blush")
+ if ("blush","blushes")
message = "[src] blushes."
m_type = 1
- if ("bow")
+ if ("bow","bows")
if (!src.buckled)
var/M = null
if (param)
@@ -42,70 +39,70 @@
message = "[src] bows."
m_type = 1
- if ("burp")
+ if ("burp","burps")
message = "[src] burps."
m_type = 2
- if ("choke")
+ if ("choke","chokes")
message = "[src] chokes!"
m_type = 2
- if ("chuckle")
+ if ("chuckle","chuckles")
message = "[src] chuckles."
m_type = 2
- if ("collapse")
+ if ("collapse","collapses")
Paralyse(2)
message = "[src] collapses!"
m_type = 2
- if ("cough")
+ if ("cough","coughs")
message = "[src] coughs!"
m_type = 2
- if ("dance")
+ if ("dance","dances")
if (!src.restrained())
message = "[src] dances around happily."
m_type = 1
- if ("deathgasp")
+ if ("deathgasp","deathgasps")
message = "[src] seizes up and falls limp, its eyes dead and lifeless..."
m_type = 1
- if ("drool")
+ if ("drool","drools")
message = "[src] drools."
m_type = 1
- if ("faint")
+ if ("faint","faints")
message = "[src] faints."
if(src.sleeping)
return //Can't faint while asleep
src.sleeping += 10 //Short-short nap
m_type = 1
- if ("flap")
+ if ("flap","flaps")
if (!src.restrained())
message = "[src] flaps its wings."
m_type = 2
- if ("flip")
+ if ("flip","flips")
if (!src.restrained() || !src.resting || !src.sleeping)
src.SpinAnimation(7,1)
m_type = 2
- if ("frown")
+ if ("frown","frowns")
message = "[src] frowns."
m_type = 1
- if ("gasp")
+ if ("gasp","gasps")
message = "[src] gasps!"
m_type = 2
- if ("giggle")
+ if ("giggle","giggles")
message = "[src] giggles."
m_type = 2
- if ("glare")
+ if ("glare","glares")
var/M = null
if (param)
for (var/mob/A in view(1, src))
@@ -119,19 +116,19 @@
else
message = "[src] glares."
- if ("grin")
+ if ("grin","grins")
message = "[src] grins."
m_type = 1
- if ("jump")
+ if ("jump","jumps")
message = "[src] jumps!"
m_type = 1
- if ("laugh")
+ if ("laugh","laughs")
message = "[src] laughs."
m_type = 2
- if ("look")
+ if ("look","looks")
var/M = null
if (param)
for (var/mob/A in view(1, src))
@@ -158,11 +155,11 @@
else
message = "[src] [message]"
- if ("nod")
+ if ("nod","nods")
message = "[src] nods."
m_type = 1
- if ("point")
+ if ("point","points")
if (!src.restrained())
var/atom/M = null
if (param)
@@ -176,39 +173,39 @@
pointed(M)
m_type = 1
- if ("scream")
+ if ("scream","screams")
message = "[src] screams!"
m_type = 2
- if ("shake")
+ if ("shake","shakes")
message = "[src] shakes its head."
m_type = 1
- if ("sigh")
+ if ("sigh","sighs")
message = "[src] sighs."
m_type = 2
- if ("sit")
+ if ("sit","sits")
message = "[src] sits down."
m_type = 1
- if ("smile")
+ if ("smile","smiles")
message = "[src] smiles."
m_type = 1
- if ("sneeze")
+ if ("sneeze","sneezes")
message = "[src] sneezes."
m_type = 2
- if ("sniff")
+ if ("sniff","sniffs")
message = "[src] sniffs."
m_type = 2
- if ("snore")
+ if ("snore","snores")
message = "[src] snores."
m_type = 2
- if ("stare")
+ if ("stare","stares")
var/M = null
if (param)
for (var/mob/A in view(1, src))
@@ -222,19 +219,19 @@
else
message = "[src] stares."
- if ("sulk")
+ if ("sulk","sulks")
message = "[src] sulks down sadly."
m_type = 1
- if ("sway")
+ if ("sway","sways")
message = "[src] sways around dizzily."
m_type = 1
- if ("tremble")
+ if ("tremble","trembles")
message = "[src] trembles in fear!"
m_type = 1
- if ("twitch")
+ if ("twitch","twitches")
message = "[src] twitches violently."
m_type = 1
@@ -242,15 +239,15 @@
message = "[src] twitches."
m_type = 1
- if ("wave")
+ if ("wave","waves")
message = "[src] waves."
m_type = 1
- if ("whimper")
+ if ("whimper","whimpers")
message = "[src] whimpers."
m_type = 2
- if ("yawn")
+ if ("yawn","yawns")
message = "[src] yawns."
m_type = 2
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 4d32293c25b..5fbd65c7037 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -138,27 +138,27 @@
if(A.CheckRemoval(src))
A.Remove(src)
for(var/obj/item/I in src)
- if(I.action_button_name)
- if(!I.action)
- if(I.action_button_is_hands_free)
- I.action = new/datum/action/item_action/hands_free
- else
- I.action = new/datum/action/item_action
- I.action.name = I.action_button_name
- I.action.target = I
- I.action.Grant(src)
- for(var/obj/item/T in I)
- if(T.action_button_name && T.action_button_internal)
- if(!T.action)
- if(T.action_button_is_hands_free)
- T.action = new/datum/action/item_action/hands_free
- else
- T.action = new/datum/action/item_action
- T.action.name = T.action_button_name
- T.action.target = T
- T.action.Grant(src)
+ give_action_button(I, 1)
return
+/mob/living/proc/give_action_button(var/obj/item/I, recursive = 0)
+ if(I.action_button_name)
+ if(!I.action)
+ if(istype(I, /obj/item/organ/internal))
+ I.action = new/datum/action/organ_action
+ else if(I.action_button_is_hands_free)
+ I.action = new/datum/action/item_action/hands_free
+ else
+ I.action = new/datum/action/item_action
+ I.action.name = I.action_button_name
+ I.action.target = I
+ I.action.Grant(src)
+
+ if(recursive)
+ for(var/obj/item/T in I)
+ give_action_button(I, recursive - 1)
+
+
//this handles hud updates. Calls update_vision() and handle_hud_icons()
/mob/living/proc/handle_regular_hud_updates()
if(!client) return 0
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index bbcdc72c6aa..5dc99707a72 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -99,22 +99,23 @@ Sorry Giacom. Please don't be mad :(
if(loc && !loc.Adjacent(M.loc))
return 1
now_pushing = 1
- //TODO: Make this use Move(). we're pretty much recreating it here.
- //it could be done by setting one of the locs to null to make Move() work, then setting it back and Move() the other mob
var/oldloc = loc
- loc = M.loc
- M.loc = oldloc
- M.LAssailant = src
+ var/oldMloc = M.loc
- for(var/mob/living/simple_animal/slime/slime in view(1,M))
- if(slime.Victim == M)
- slime.UpdateFeed()
- //cross any movable atoms on either turf
- for(var/atom/movable/AM in loc)
- AM.Crossed(src)
- for(var/atom/movable/AM in oldloc)
- AM.Crossed(M)
+ var/M_passmob = (M.pass_flags & PASSMOB) // we give PASSMOB to both mobs to avoid bumping other mobs during swap.
+ var/src_passmob = (pass_flags & PASSMOB)
+ M.pass_flags |= PASSMOB
+ pass_flags |= PASSMOB
+
+ M.Move(oldloc)
+ Move(oldMloc)
+
+ if(!src_passmob)
+ pass_flags &= ~PASSMOB
+ if(!M_passmob)
+ M.pass_flags &= ~PASSMOB
+
now_pushing = 0
return 1
@@ -569,7 +570,8 @@ Sorry Giacom. Please don't be mad :(
else
stop_pulling()
. = ..()
- if ((s_active && !( s_active in contents ) ))
+ if (s_active && !(s_active in contents) && !(s_active.loc in contents))
+ // It's ugly. But everything related to inventory/storage is. -- c0
s_active.close(src)
for(var/mob/living/simple_animal/slime/M in oview(1,src))
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 43e2c2735bf..9d8017d0c2b 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -44,12 +44,6 @@
else
return 0
-/mob/living/throw_impact(atom/hit_atom)
- . = ..()
- if(hit_atom.density)
- Weaken(1)
- take_organ_damage(10)
-
/mob/living/hitby(atom/movable/AM)
if(istype(AM, /obj/item))
var/obj/item/I = AM
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 56c0426c5bc..06f14523bcf 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -25,7 +25,7 @@
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
- var/now_pushing = null
+ var/now_pushing = null //used by living/Bump() and living/PushAM() to prevent potential infinite loop.
var/cameraFollow = null
@@ -34,6 +34,8 @@
var/on_fire = 0 //The "Are we on fire?" var
var/fire_stacks = 0 //Tracks how many stacks of fire we have on, max is usually 20
+ var/bloodcrawl = 0 //0 No blood crawling, BLOODCRAWL for bloodcrawling, BLOODCRAWL_EAT for crawling+mob devour
+ var/holder = null //The holder for blood crawling
var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
var/floating = 0
var/mob_size = MOB_SIZE_HUMAN
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index f7910fd9d77..d9a69f3c25a 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -90,7 +90,8 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
src << "You find yourself unable to speak!"
return
- message = treat_message(message)
+ if(message_mode != MODE_WHISPER) //whisper() calls treat_message(); double process results in "hisspering"
+ message = treat_message(message)
var/spans = list()
spans += get_spans()
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index d424af7bf41..4280be744bc 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -5,8 +5,6 @@
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
switch(act)//01000001011011000111000001101000011000010110001001100101011101000110100101111010011001010110010000100001 (Seriously please keep it that way.)
if ("aflap")
@@ -15,7 +13,7 @@
m_type = 2
m_type = 1
- if("beep")
+ if("beep","beeps")
var/M = null
if(param)
for (var/mob/A in view(1, src))
@@ -32,7 +30,7 @@
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 2
- if ("bow")
+ if ("bow","bows")
if (!src.buckled)
var/M = null
if (param)
@@ -70,12 +68,12 @@
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
m_type = 2
- if ("chime") //You have mail!
+ if ("chime","chimes") //You have mail!
message = "[src] chimes."
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
m_type = 2
- if ("clap")
+ if ("clap","claps")
if (!src.restrained())
message = "[src] claps."
m_type = 2
@@ -94,16 +92,16 @@
return
message = "[src] [input]"
- if ("deathgasp")
+ if ("deathgasp","deathgasps")
message = "[src] shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
m_type = 1
- if ("flap")
+ if ("flap","flaps")
if (!src.restrained())
message = "[src] flaps \his wings."
m_type = 2
- if ("glare")
+ if ("glare","glares")
var/M = null
if (param)
for (var/mob/A in view(1, src))
@@ -117,12 +115,12 @@
else
message = "[src] glares."
- if ("honk") //Honk!
+ if ("honk","honks") //Honk!
message = "[src] honks!"
playsound(loc, 'sound/items/bikehorn.ogg', 50, 1)
m_type = 2
- if ("look")
+ if ("look","looks")
var/M = null
if (param)
for (var/mob/A in view(1, src))
@@ -150,11 +148,11 @@
else
message = "[src] [message]"
- if ("nod")
+ if ("nod","nods")
message = "[src] nods."
m_type = 1
- if ("ping")
+ if ("ping","pings")
var/M = null
if(param)
for (var/mob/A in view(1, src))
@@ -175,7 +173,7 @@
playsound(loc, 'sound/misc/sadtrombone.ogg', 50, 0)
m_type = 2
- if ("salute")
+ if ("salute","salutes")
if (!src.buckled)
var/M = null
if (param)
@@ -191,7 +189,7 @@
else
message = "[src] salutes."
- if ("stare")
+ if ("stare","stares")
var/M = null
if (param)
for (var/mob/A in view(1, src))
@@ -206,7 +204,7 @@
message = "[src] stares."
m_type = 1
- if ("twitch")
+ if ("twitch","twitches")
message = "[src] twitches violently."
m_type = 1
diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm
index 66be85855e8..a646d4e159d 100644
--- a/code/modules/mob/living/silicon/robot/inventory.dm
+++ b/code/modules/mob/living/silicon/robot/inventory.dm
@@ -11,7 +11,7 @@
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
if(!O)
return 0
-
+ O.mouse_opacity = 2
if(istype(O,/obj/item/borg/sight))
var/obj/item/borg/sight/S = O
sight_mode &= ~S.sight_mode
@@ -45,6 +45,7 @@
src << "Already activated"
return
if(!module_state_1)
+ O.mouse_opacity = initial(O.mouse_opacity)
module_state_1 = O
O.layer = 20
O.screen_loc = inv1.screen_loc
@@ -52,6 +53,7 @@
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode |= module_state_1:sight_mode
else if(!module_state_2)
+ O.mouse_opacity = initial(O.mouse_opacity)
module_state_2 = O
O.layer = 20
O.screen_loc = inv2.screen_loc
@@ -59,6 +61,7 @@
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode |= module_state_2:sight_mode
else if(!module_state_3)
+ O.mouse_opacity = initial(O.mouse_opacity)
module_state_3 = O
O.layer = 20
O.screen_loc = inv3.screen_loc
diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm
index 5d86cc4d2e5..af742597953 100644
--- a/code/modules/mob/living/silicon/robot/login.dm
+++ b/code/modules/mob/living/silicon/robot/login.dm
@@ -5,6 +5,7 @@
show_laws(0)
if(mind) ticker.mode.remove_revolutionary(mind)
if(mind) ticker.mode.remove_gangster(mind,1,remove_bosses=1)
+ if(mind) ticker.mode.remove_thrall(mind,0)
/mob/living/silicon/robot/update_hotkey_mode()
winset(src, null, "mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#F0F0F0")
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 68300be05f1..e978c6c37a6 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -63,6 +63,7 @@
var/braintype = "Cyborg"
var/lamp_max = 10 //Maximum brightness of a borg lamp. Set as a var for easy adjusting.
var/lamp_intensity = 0 //Luminosity of the headlamp. 0 is off. Higher settings than the minimum require power.
+ var/lamp_recharging = 0 //Flag for if the lamp is on cooldown after being forcibly disabled.
/mob/living/silicon/robot/New(loc)
spark_system = new /datum/effect/effect/system/spark_spread()
@@ -107,7 +108,6 @@
mmi = new(src)
mmi.brain = new /obj/item/organ/brain(mmi)
mmi.brain.name = "[real_name]'s brain"
- mmi.locked = 1
mmi.icon_state = "mmi_full"
mmi.name = "Man-Machine Interface: [real_name]"
mmi.brainmob = new(src)
@@ -990,7 +990,7 @@
set_autosay()
/mob/living/silicon/robot/proc/control_headlamp()
- if(stat)
+ if(stat || lamp_recharging)
src << "This function is currently offline."
return
@@ -999,12 +999,15 @@
src << "[lamp_intensity ? "Headlamp power set to Level [lamp_intensity/2]" : "Headlamp disabled."]"
update_headlamp()
-/mob/living/silicon/robot/proc/update_headlamp(var/turn_off = 0)
+/mob/living/silicon/robot/proc/update_headlamp(var/turn_off = 0, var/cooldown = 100)
SetLuminosity(0)
if(lamp_intensity && (turn_off || stat))
src << "Your headlamp has been deactivated."
lamp_intensity = 0
+ lamp_recharging = 1
+ spawn(cooldown) //10 seconds by default, if the source of the deactivation does not keep stat that long.
+ lamp_recharging = 0
else
AddLuminosity(lamp_intensity)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 3cd0e9781c6..c594fbfdfbb 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -54,8 +54,10 @@
/obj/item/weapon/robot_module/proc/fix_modules()
for(var/obj/item/I in modules)
I.flags |= NODROP
+ I.mouse_opacity = 2
if(emag)
emag.flags |= NODROP
+ emag.mouse_opacity = 2
/obj/item/weapon/robot_module/proc/on_emag()
return
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 92749a073a2..83b20b450cb 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -153,7 +153,7 @@
/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
adjustBruteLoss(Proj.damage)
- Proj.on_hit(src,2)
+ Proj.on_hit(src)
return 2
/mob/living/silicon/apply_effect(effect = 0,effecttype = STUN, blocked = 0)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 261dad9eaa9..ed126f984ed 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -61,7 +61,7 @@
return
if(Proj.damage_type == BURN || Proj.damage_type == BRUTE)
adjustBruteLoss(Proj.damage)
- Proj.on_hit(src, 0)
+ Proj.on_hit(src)
return 0
/mob/living/simple_animal/construct/narsie_act()
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 36fa3134f1c..bc0ebe9883b 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -108,6 +108,8 @@
icon_state = icon_dead
return
..()
+ update_corgi_fluff()
+
/mob/living/simple_animal/pet/dog/corgi/Topic(href, href_list)
@@ -209,6 +211,7 @@
//Corgis are supposed to be simpler, so only a select few objects can actually be put
//to be compatible with them. The objects are below.
//Many hats added, Some will probably be removed, just want to see which ones are popular.
+
/mob/living/simple_animal/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/user)
if(istype(item_to_add,/obj/item/weapon/c4)) // last thing he ever wears, I guess
@@ -222,7 +225,6 @@
user.visible_message("[user] pets [src].","You rest your hand on [src]'s head for a moment.")
return
-
var/valid = 0
//Various hats and items (worn on his head) change Ian's behaviour. His attributes are reset when a hat is removed.
@@ -232,128 +234,16 @@
switch(item_to_add.type)
if( /obj/item/clothing/glasses/sunglasses, /obj/item/clothing/head/that, /obj/item/clothing/head/collectable/paper,
/obj/item/clothing/head/hardhat, /obj/item/clothing/head/collectable/hardhat, /obj/item/clothing/head/hardhat/white,
- /obj/item/weapon/paper)
- valid = 1
-
- if(/obj/item/clothing/head/helmet)
- name = "Sergeant [real_name]"
- desc = "The ever-loyal, the ever-vigilant."
- valid = 1
-
- if(/obj/item/clothing/head/chefhat, /obj/item/clothing/head/collectable/chef)
- name = "Sous chef [real_name]"
- desc = "Your food will be taste-tested. All of it."
- valid = 1
-
- if(/obj/item/clothing/head/caphat, /obj/item/clothing/head/collectable/captain)
- name = "Captain [real_name]"
- desc = "Probably better than the last captain."
- valid = 1
-
- if(/obj/item/clothing/head/kitty, /obj/item/clothing/head/collectable/kitty)
- name = "Runtime"
- emote_see = list("coughs up a furball", "stretches")
- emote_hear = list("purrs")
- speak = list("Purrr", "Meow!", "MAOOOOOW!", "HISSSSS", "MEEEEEEW")
- desc = "It's a cute little kitty-cat! ... wait ... what the hell?"
- valid = 1
-
- if(/obj/item/clothing/head/rabbitears, /obj/item/clothing/head/collectable/rabbitears)
- name = "Hoppy"
- emote_see = list("twitches its nose", "hops around a bit")
- desc = "This is Hoppy. It's a corgi-...urmm... bunny rabbit"
- valid = 1
-
- if(/obj/item/clothing/head/beret, /obj/item/clothing/head/collectable/beret)
- name = "Yann"
- desc = "Mon dieu! C'est un chien!"
- speak = list("le woof!", "le bark!", "JAPPE!!")
- emote_see = list("cowers in fear.", "surrenders.", "plays dead.","looks as though there is a wall in front of him.")
- valid = 1
-
- if(/obj/item/clothing/head/det_hat)
- name = "Detective [real_name]"
- desc = "[name] sees through your lies..."
- emote_see = list("investigates the area.","sniffs around for clues.","searches for scooby snacks.")
- valid = 1
-
- if(/obj/item/clothing/head/nursehat)
- name = "Nurse [real_name]"
- desc = "[name] needs 100cc of beef jerky... STAT!"
- valid = 1
-
- if(/obj/item/clothing/head/pirate, /obj/item/clothing/head/collectable/pirate)
- name = "[pick("Ol'","Scurvy","Black","Rum","Gammy","Bloody","Gangrene","Death","Long-John")] [pick("kibble","leg","beard","tooth","poop-deck","Threepwood","Le Chuck","corsair","Silver","Crusoe")]"
- desc = "Yaarghh!! Thar' be a scurvy dog!"
- emote_see = list("hunts for treasure.","stares coldly...","gnashes his tiny corgi teeth!")
- emote_hear = list("growls ferociously!", "snarls.")
- speak = list("Arrrrgh!!","Grrrrrr!")
- valid = 1
-
- if(/obj/item/clothing/head/ushanka)
- name = "[pick("Comrade","Commissar","Glorious Leader")] [real_name]"
- desc = "A follower of Karl Barx."
- emote_see = list("contemplates the failings of the capitalist economic model.", "ponders the pros and cons of vanguardism.")
- valid = 1
-
- if(/obj/item/clothing/head/warden, /obj/item/clothing/head/collectable/police)
- name = "Officer [real_name]"
- emote_see = list("drools.","looks for donuts.")
- desc = "Stop right there criminal scum!"
- valid = 1
-
- if(/obj/item/clothing/head/wizard/fake, /obj/item/clothing/head/wizard, /obj/item/clothing/head/collectable/wizard)
- name = "Grandwizard [real_name]"
- speak = list("YAP", "Woof!", "Bark!", "AUUUUUU", "EI NATH!")
- valid = 1
-
- if(/obj/item/clothing/head/cardborg)
- name = "Borgi"
- speak = list("Ping!","Beep!","Woof!")
- emote_see = list("goes rogue.", "sniffs out non-humans.")
- desc = "Result of robotics budget cuts."
- valid = 1
-
- if(/obj/item/weapon/bedsheet)
- name = "\improper Ghost"
- speak = list("WoooOOOooo~","AUUUUUUUUUUUUUUUUUU")
- emote_see = list("stumbles around.", "shivers.")
- emote_hear = list("howls!","groans.")
- desc = "Spooky!"
- valid = 1
-
- if(/obj/item/clothing/head/helmet/space/santahat)
- name = "Santa's Corgi Helper"
- emote_hear = list("barks Christmas songs.", "yaps merrily!")
- emote_see = list("looks for presents.", "checks his list.")
- desc = "He's very fond of milk and cookies."
- valid = 1
-
- if(/obj/item/clothing/head/soft)
- name = "Corgi Tech [real_name]"
- desc = "The reason your yellow gloves have chew-marks."
- valid = 1
-
- if(/obj/item/clothing/head/hardhat/reindeer)
- name = "[real_name] the red-nosed Corgi"
- emote_hear = list("lights the way!", "illuminates.", "yaps!")
- desc = "He has a very shiny nose."
- SetLuminosity(1)
- valid = 1
-
- if(/obj/item/clothing/head/sombrero)
- name = "Segnor [real_name]"
- desc = "You must respect elder [real_name]"
- valid = 1
-
- if(/obj/item/clothing/head/hopcap)
- name = "Lieutenant [real_name]"
- desc = "Can actually be trusted to not run off on his own."
- valid = 1
-
- if(/obj/item/clothing/head/helmet/space/hardsuit/deathsquad)
- name = "Trooper [real_name]"
- desc = "That's not red paint. That's real corgi blood."
+ /obj/item/weapon/paper, /obj/item/clothing/head/helmet, /obj/item/clothing/head/chefhat, /obj/item/clothing/head/collectable/chef,
+ /obj/item/clothing/head/caphat, /obj/item/clothing/head/collectable/captain, /obj/item/clothing/head/kitty,
+ /obj/item/clothing/head/collectable/kitty, /obj/item/clothing/head/rabbitears, /obj/item/clothing/head/collectable/rabbitears,
+ /obj/item/clothing/head/beret, /obj/item/clothing/head/collectable/beret, /obj/item/clothing/head/det_hat,
+ /obj/item/clothing/head/nursehat, /obj/item/clothing/head/pirate, /obj/item/clothing/head/collectable/pirate,
+ /obj/item/clothing/head/ushanka, /obj/item/clothing/head/warden, /obj/item/clothing/head/collectable/police,
+ /obj/item/clothing/head/wizard/fake, /obj/item/clothing/head/wizard, /obj/item/clothing/head/collectable/wizard,
+ /obj/item/clothing/head/cardborg, /obj/item/weapon/bedsheet, /obj/item/clothing/head/helmet/space/santahat,
+ /obj/item/clothing/head/soft, /obj/item/clothing/head/hardhat/reindeer, /obj/item/clothing/head/sombrero,
+ /obj/item/clothing/head/hopcap, /obj/item/clothing/head/helmet/space/hardsuit/deathsquad)
valid = 1
if(valid)
@@ -368,8 +258,8 @@
"You hear a friendly-sounding bark.")
item_to_add.loc = src
src.inventory_head = item_to_add
+ update_corgi_fluff()
regenerate_icons()
-
else
if(user && !user.drop_item())
user << "\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!"
@@ -384,6 +274,108 @@
return valid
+/mob/living/simple_animal/pet/dog/corgi/proc/update_corgi_fluff()
+ switch(src.inventory_head.type)
+ if(/obj/item/clothing/head/helmet)
+ name = "Sergeant [real_name]"
+ desc = "The ever-loyal, the ever-vigilant."
+
+ if(/obj/item/clothing/head/chefhat, /obj/item/clothing/head/collectable/chef)
+ name = "Sous chef [real_name]"
+ desc = "Your food will be taste-tested. All of it."
+
+
+ if(/obj/item/clothing/head/caphat, /obj/item/clothing/head/collectable/captain)
+ name = "Captain [real_name]"
+ desc = "Probably better than the last captain."
+
+ if(/obj/item/clothing/head/kitty, /obj/item/clothing/head/collectable/kitty)
+ name = "Runtime"
+ emote_see = list("coughs up a furball", "stretches")
+ emote_hear = list("purrs")
+ speak = list("Purrr", "Meow!", "MAOOOOOW!", "HISSSSS", "MEEEEEEW")
+ desc = "It's a cute little kitty-cat! ... wait ... what the hell?"
+
+ if(/obj/item/clothing/head/rabbitears, /obj/item/clothing/head/collectable/rabbitears)
+ name = "Hoppy"
+ emote_see = list("twitches its nose", "hops around a bit")
+ desc = "This is Hoppy. It's a corgi-...urmm... bunny rabbit"
+
+ if(/obj/item/clothing/head/beret, /obj/item/clothing/head/collectable/beret)
+ name = "Yann"
+ desc = "Mon dieu! C'est un chien!"
+ speak = list("le woof!", "le bark!", "JAPPE!!")
+ emote_see = list("cowers in fear.", "surrenders.", "plays dead.","looks as though there is a wall in front of him.")
+
+ if(/obj/item/clothing/head/det_hat)
+ name = "Detective [real_name]"
+ desc = "[name] sees through your lies..."
+ emote_see = list("investigates the area.","sniffs around for clues.","searches for scooby snacks.")
+
+ if(/obj/item/clothing/head/nursehat)
+ name = "Nurse [real_name]"
+ desc = "[name] needs 100cc of beef jerky... STAT!"
+
+ if(/obj/item/clothing/head/pirate, /obj/item/clothing/head/collectable/pirate)
+ name = "[pick("Ol'","Scurvy","Black","Rum","Gammy","Bloody","Gangrene","Death","Long-John")] [pick("kibble","leg","beard","tooth","poop-deck","Threepwood","Le Chuck","corsair","Silver","Crusoe")]"
+ desc = "Yaarghh!! Thar' be a scurvy dog!"
+ emote_see = list("hunts for treasure.","stares coldly...","gnashes his tiny corgi teeth!")
+ emote_hear = list("growls ferociously!", "snarls.")
+ speak = list("Arrrrgh!!","Grrrrrr!")
+
+ if(/obj/item/clothing/head/ushanka)
+ name = "[pick("Comrade","Commissar","Glorious Leader")] [real_name]"
+ desc = "A follower of Karl Barx."
+ emote_see = list("contemplates the failings of the capitalist economic model.", "ponders the pros and cons of vanguardism.")
+
+ if(/obj/item/clothing/head/warden, /obj/item/clothing/head/collectable/police)
+ name = "Officer [real_name]"
+ emote_see = list("drools.","looks for donuts.")
+ desc = "Stop right there criminal scum!"
+
+ if(/obj/item/clothing/head/wizard/fake, /obj/item/clothing/head/wizard, /obj/item/clothing/head/collectable/wizard)
+ name = "Grandwizard [real_name]"
+ speak = list("YAP", "Woof!", "Bark!", "AUUUUUU", "EI NATH!")
+
+ if(/obj/item/clothing/head/cardborg)
+ name = "Borgi"
+ speak = list("Ping!","Beep!","Woof!")
+ emote_see = list("goes rogue.", "sniffs out non-humans.")
+ desc = "Result of robotics budget cuts."
+
+ if(/obj/item/weapon/bedsheet)
+ name = "\improper Ghost"
+ speak = list("WoooOOOooo~","AUUUUUUUUUUUUUUUUUU")
+ emote_see = list("stumbles around.", "shivers.")
+ emote_hear = list("howls!","groans.")
+ desc = "Spooky!"
+
+ if(/obj/item/clothing/head/helmet/space/santahat)
+ name = "Santa's Corgi Helper"
+ emote_hear = list("barks Christmas songs.", "yaps merrily!")
+ emote_see = list("looks for presents.", "checks his list.")
+ desc = "He's very fond of milk and cookies."
+
+ if(/obj/item/clothing/head/soft)
+ name = "Corgi Tech [real_name]"
+ desc = "The reason your yellow gloves have chew-marks."
+
+ if(/obj/item/clothing/head/hardhat/reindeer)
+ name = "[real_name] the red-nosed Corgi"
+ emote_hear = list("lights the way!", "illuminates.", "yaps!")
+ desc = "He has a very shiny nose."
+
+ if(/obj/item/clothing/head/sombrero)
+ name = "Segnor [real_name]"
+ desc = "You must respect elder [real_name]"
+
+ if(/obj/item/clothing/head/hopcap)
+ name = "Lieutenant [real_name]"
+ desc = "Can actually be trusted to not run off on his own."
+
+ if(/obj/item/clothing/head/helmet/space/hardsuit/deathsquad)
+ name = "Trooper [real_name]"
+ desc = "That's not red paint. That's real corgi blood."
//IAN! SQUEEEEEEEEE~
/mob/living/simple_animal/pet/dog/corgi/Ian
diff --git a/code/modules/mob/living/simple_animal/friendly/pet.dm b/code/modules/mob/living/simple_animal/friendly/pet.dm
index a5ea4d03672..cf69255362c 100644
--- a/code/modules/mob/living/simple_animal/friendly/pet.dm
+++ b/code/modules/mob/living/simple_animal/friendly/pet.dm
@@ -14,7 +14,8 @@
regenerate_icons()
user << "You put the [P] around [src]'s neck."
if(P.tagname)
- name = "\proper [P.tagname]"
+ real_name = "\proper [P.tagname]"
+ name = real_name
qdel(P)
return
if(istype(O, /obj/item/weapon/newspaper))
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
new file mode 100644
index 00000000000..b102ef80167
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -0,0 +1,530 @@
+/mob/living/simple_animal/hostile/guardian
+ name = "Guardian Spirit"
+ real_name = "Guardian Spirit"
+ desc = "A mysterious being that stands by it's charge, ever vigilant."
+ speak_emote = list("intones")
+ response_help = "passes through"
+ response_disarm = "flails at"
+ response_harm = "punches"
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "stand"
+ icon_living = "stand"
+ speed = 0
+ a_intent = "harm"
+ stop_automated_movement = 1
+ floating = 1
+ attack_sound = 'sound/weapons/punch1.ogg'
+ 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)
+ minbodytemp = 0
+ attacktext = "punches"
+ maxHealth = 100000 //The spirit itself is invincible
+ health = 100000
+ environment_smash = 0
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ butcher_results = list(/obj/item/weapon/ectoplasm = 1)
+ var/cooldown = 0
+ var/damage_transfer = 1 //how much damage from each attack we transfer to the owner
+ var/mob/living/summoner
+ var/range = 10 //how far from the user the spirit can be
+ var/playstyle_string = "You are a standard Guardian. You shouldn't exist!"
+ var/magic_fluff_string = " You draw the Coder, symbolizing bugs and errors. This shouldn't happen! Submit a bug report!"
+ var/tech_fluff_string = "BOOT SEQUENCE COMPLETE. ERROR MODULE LOADED. THIS SHOULDN'T HAPPEN. Submit a bug report!"
+ var/bio_fluff_string = "Your scarabs fail to mutate. This shouldn't happen! Submit a bug report!"
+
+/mob/living/simple_animal/hostile/guardian/Life() //Dies if the summoner dies
+ ..()
+ if(summoner)
+ if(summoner.stat == DEAD)
+ src << "Your summoner has died!"
+ visible_message("The [src] dies along with its user!")
+ ghostize()
+ qdel(src)
+ else
+ src << "Your summoner has died!"
+ visible_message("The [src] dies along with its user!")
+ ghostize()
+ qdel(src)
+ if(summoner)
+ if (get_dist(get_turf(summoner),get_turf(src)) <= range)
+ return
+ else
+ src << "You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]"
+ visible_message("The [src] jumps back to its user.")
+ loc = get_turf(summoner)
+
+/mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range
+ ..()
+ if(summoner)
+ if (get_dist(get_turf(summoner),get_turf(src)) <= range)
+ return
+ else
+ src << "You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]"
+ visible_message("The [src] jumps back to its user.")
+ loc = get_turf(summoner)
+
+
+/mob/living/simple_animal/hostile/guardian/adjustBruteLoss(amount) //The spirit is invincible, but passes on damage to the summoner
+ var/damage = amount * src.damage_transfer
+ if (src.summoner)
+ src.summoner.adjustBruteLoss(damage)
+ if(damage)
+ src.summoner << "Your [src.name] is under attack! You take damage!"
+
+
+/mob/living/simple_animal/hostile/guardian/ex_act(severity, target)
+ switch (severity)
+ if (1)
+ if(src.summoner)
+ src.summoner << "Your [src.name] was blown up!"
+ src.summoner.gib()
+ gib()
+ return
+ if (2)
+ adjustBruteLoss(60)
+
+ if(3)
+ adjustBruteLoss(30)
+
+
+//Manifest, Recall, Communicate
+
+/mob/living/simple_animal/hostile/guardian/verb/Manifest()
+ set name = "Manifest"
+ set category = "Guardian"
+ set desc = "Spring forth into battle!"
+ if(cooldown > world.time)
+ return
+ if(src.loc == summoner)
+ src.loc = get_turf(summoner)
+ cooldown = world.time + 30
+
+/mob/living/simple_animal/hostile/guardian/verb/Recall()
+ set name = "Recall"
+ set category = "Guardian"
+ set desc = "Return to your summoner."
+ if(cooldown > world.time)
+ return
+ src.loc = summoner
+ cooldown = world.time + 30
+
+/mob/living/simple_animal/hostile/guardian/verb/Communicate()
+ set name = "Communicate"
+ set category = "Guardian"
+ set desc = "Communicate telepathically with your summoner."
+ var/input = stripped_input(src, "Please enter a message to tell your summoner.", "Guardian", "")
+
+ for(var/mob/M in mob_list)
+ if(M == src.summoner)
+ M << "[src]: [input]"
+ src << "[src]: [input]"
+
+/mob/living/proc/guardian_comm()
+ set name = "Communicate"
+ set category = "Guardian"
+ set desc = "Communicate telepathically with your guardian."
+ var/input = stripped_input(src, "Please enter a message to tell your guardian.", "Message", "")
+
+ for(var/mob/living/simple_animal/hostile/guardian/M in mob_list)
+ if(M.summoner == src)
+ M << "[src]: [input]"
+ src << "[src]: [input]"
+
+
+//////////////////////////TYPES OF GUARDIANS
+
+
+//Fire. Low damage, low resistance, sets mobs on fire when bumping
+
+/mob/living/simple_animal/hostile/guardian/fire
+ a_intent = "help"
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ attack_sound = 'sound/items/Welder.ogg'
+ attacktext = "sears"
+ damage_transfer = 0.7
+ range = 10
+ playstyle_string = "As a fire type, you have only light damage resistance, but will ignite any enemy you bump into."
+ environment_smash = 1
+ magic_fluff_string = "..And draw Atmosia, bringer of cleansing fires!"
+ tech_fluff_string = "Boot sequence complete. Incendiary combat modules loaded. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of igniting enemies on touch."
+
+
+/mob/living/simple_animal/hostile/guardian/fire/Crossed(AM as mob|obj)
+ if(istype(AM, /mob/living/))
+ var/mob/living/M = AM
+ if(AM != src.summoner)
+ M.adjust_fire_stacks(10)
+ M.IgniteMob()
+
+//Standard
+
+/mob/living/simple_animal/hostile/guardian/punch
+ melee_damage_lower = 25
+ melee_damage_upper = 25
+ damage_transfer = 0.5
+ playstyle_string = "As a standard type you have no special abilities, but have a high damage resistance and a powerful attack capable of smashing through walls."
+ environment_smash = 2
+ magic_fluff_string = "..And draw the Assistant, faceless and generic, but never to be underestimated."
+ tech_fluff_string = "Boot sequence complete. Standard combat modules loaded. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm stirs to life, ready to tear apart your enemies."
+ var/battlecry = "AT"
+
+/mob/living/simple_animal/hostile/guardian/punch/verb/Battlecry()
+ set name = "Set Battlecry"
+ set category = "Guardian"
+ set desc = "Choose what you shout as you punch"
+ var/input = stripped_input(src,"What do you want your battlecry to be? Max length of 6 characters.", ,"", 6)
+ if(input)
+ src.battlecry = input
+
+
+
+/mob/living/simple_animal/hostile/guardian/punch/AttackingTarget()
+ ..()
+ if(istype(target, /mob/living))
+ src.say("[src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry]\
+ [src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry][src.battlecry]")
+ playsound(loc, src.attack_sound, 50, 1, 1)
+ playsound(loc, src.attack_sound, 50, 1, 1)
+ playsound(loc, src.attack_sound, 50, 1, 1)
+ playsound(loc, src.attack_sound, 50, 1, 1)
+
+
+
+
+//Fast Standard. Does less damage, has less resistance, but moves faster, has higher range
+
+/mob/living/simple_animal/hostile/guardian/fast
+ melee_damage_lower = 20
+ melee_damage_upper = 20
+ damage_transfer = 0.7
+ speed = -1
+ range = 15
+ attacktext = "slices"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ playstyle_string = "As a fast standard type, you have no special abilities and only light damage resistance, but deal high damage at high speed."
+ environment_smash = 1
+ magic_fluff_string = "..And draw the Shoes, bringer of great speed. The card is badly damaged, and barely legible."
+ tech_fluff_string = "Boot sequence complete. High speed combat modules active. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of moving at blinding speed."
+
+//Defender. Does no damage, takes no damage, moves slowly.
+/mob/living/simple_animal/hostile/guardian/shield
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ speed = 1
+ range = 10
+ damage_transfer = 0
+ friendly = "stares down"
+ status_flags = CANPUSH
+ playstyle_string = "As a defensive type, you are incapable of attacking and move slowly, but completely nullify any attack that hits you."
+ magic_fluff_string = "..And draw the Juggernaut, an invincible, unstoppable force."
+ tech_fluff_string = "Boot sequence complete. Defensive modules active. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, helpless, but invulnerable."
+
+//Scout. No damage, high range, high mobility, low resistance
+
+/mob/living/simple_animal/hostile/guardian/scout
+ range = 255
+ incorporeal_move = 1
+ damage_transfer = 1.2
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ alpha = 60
+ friendly = "quietly assesses"
+ playstyle_string = "As a scout type, you are incapable of attacking, but have infinite range, can pass through walls, and crawl through vents."
+ magic_fluff_string = "..And draw the AI, all seeing and all knowing."
+ tech_fluff_string = "Boot sequence complete. Surveillance modules loaded. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, helpless, but near invsible, and capable of near unlimited travel."
+
+//Healer
+
+/mob/living/simple_animal/hostile/guardian/healer
+ a_intent = "help"
+ friendly = "heals"
+ speed = 1
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ playstyle_string = "As a healer type, you are incapable of attacking, but can mend any wound simply by touching a target."
+ magic_fluff_string = "..And draw the CMO, a potent force of life and health."
+ tech_fluff_string = "Boot sequence complete. Medical modules active. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of mending wounds."
+
+/mob/living/simple_animal/hostile/guardian/healer/AttackingTarget()
+ ..()
+ if(src.loc == summoner)
+ src << "You must be manifested to heal!"
+ return
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ C.adjustBruteLoss(-5)
+ C.adjustFireLoss(-5)
+ C.adjustOxyLoss(-5)
+ C.adjustToxLoss(-5)
+
+/obj/item/projectile/guardian
+ name = "crystal spray"
+ icon_state = "guardian"
+ damage = 4
+ damage_type = BRUTE
+
+/mob/living/simple_animal/hostile/guardian/ranged
+ a_intent = "help"
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ damage_transfer = 1.2
+ projectiletype = /obj/item/projectile/guardian
+ ranged_cooldown_cap = 0
+ projectilesound = 'sound/effects/hit_on_shattered_glass.ogg'
+ ranged = 1
+ range = 13
+ playstyle_string = "As a ranged type, you have only light damage resistance, but are capable of spraying shards of crystal at incredibly high speed."
+ magic_fluff_string = "..And draw the Sentinel, an alien master of ranged combat."
+ tech_fluff_string = "Boot sequence complete. Ranged combat modules active. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of spraying shards of crystal."
+
+
+/mob/living/simple_animal/hostile/guardian/bluespace
+ ranged = 1
+ range = 15
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ speed = -1
+ attack_sound = 'sound/weapons/emitter.ogg'
+ projectiletype = /obj/item/projectile/magic/teleport
+ projectilesound = 'sound/weapons/emitter.ogg'
+ playstyle_string = "As a bluespace type, you have only light damage resistance, but are capable of shooting teleporation bolts as well as flinging enemies away with your standard attack."
+ magic_fluff_string = "..And draw the Wizard, master of teleportation."
+ tech_fluff_string = "Boot sequence complete. Experimental bluespace combat modules active. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, crackling with bluespace energy."
+
+/mob/living/simple_animal/hostile/guardian/bluespace/AttackingTarget()
+ ..()
+ if(istype(target, /atom/movable))
+ var/atom/movable/M = target
+ if(!M.anchored && M != src.summoner)
+ do_teleport(M, M, 10)
+
+/mob/living/simple_animal/hostile/guardian/bomb
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ damage_transfer = 0.6
+ range = 13
+ playstyle_string = "As an explosive type, you have only moderate close combat abilities, but are capable of converting any adjacent item into a disguised bomb via shift click."
+ magic_fluff_string = "..And draw the Scientist, master of explosive death."
+ tech_fluff_string = "Boot sequence complete. Explosive modules active. Nanoswarm online."
+ bio_fluff_string = "Your scarab swarm finishes mutating and stirs to life, capable of stealthily booby trapping items."
+ var/bomb_cooldown = 0
+
+/mob/living/simple_animal/hostile/guardian/bomb/ShiftClickOn(atom/movable/A)
+ if(src.loc == summoner)
+ src << "You must be manifested to create bombs!"
+ return
+ if(istype(A, /obj/))
+ if(bomb_cooldown <= world.time && !stat)
+ var/obj/item/weapon/guardian_bomb/B = new /obj/item/weapon/guardian_bomb(get_turf(A))
+ src << "Success! Bomb armed!"
+ bomb_cooldown = world.time + 400
+ B.spawner = src
+ B.disguise (A)
+ else
+ src << "Your powers are on cooldown! You must wait 40 seconds between bombs."
+
+/obj/item/weapon/guardian_bomb
+ name = "bomb"
+ desc = "You shouldn't be seeing this!"
+ var/obj/stored_obj
+ var/mob/living/spawner
+
+
+
+/obj/item/weapon/guardian_bomb/proc/disguise(var/obj/A)
+ A.loc = src
+ stored_obj = A
+ anchored = A.anchored
+ density = A.density
+ appearance = A.appearance
+ spawn(600)
+ stored_obj.loc = get_turf(src.loc)
+ spawner << "Failure! Your trap didn't catch anyone this time."
+ qdel(src)
+
+/obj/item/weapon/guardian_bomb/proc/detonate(var/mob/living/user)
+ user << "The [src] was boobytrapped!"
+ spawner << "Success! Your trap caught [user]"
+ stored_obj.loc = get_turf(src.loc)
+ playsound(get_turf(src),'sound/effects/Explosion2.ogg', 200, 1)
+ user.ex_act(2)
+ qdel(src)
+
+/obj/item/weapon/guardian_bomb/attackby(mob/living/user)
+ detonate(user)
+ return
+
+/obj/item/weapon/guardian_bomb/pickup(mob/living/user)
+ detonate(user)
+ return
+
+/obj/item/weapon/guardian_bomb/examine(mob/user)
+ stored_obj.examine(user)
+ if(get_dist(user,src)<=2)
+ user << "Looks odd!"
+
+
+
+
+
+
+
+
+
+
+
+////////Creation
+
+/obj/item/weapon/guardiancreator
+ name = "deck of tarot cards"
+ desc = "An enchanted deck of tarot cards, rumored to be a source of unimaginable power. "
+ icon = 'icons/obj/toy.dmi'
+ icon_state = "deck_syndicate_full"
+ var/used = FALSE
+ var/theme = "magic"
+ var/mob_name = "Guardian Spirit"
+ var/use_message = "You shuffle the deck..."
+ var/used_message = "All the cards seem to be blank now."
+ var/failure_message = "..And draw a card! It's...blank? Maybe you should try again later."
+ var/list/possible_guardians = list("Fire", "Standard", "Scout", "Shield", "Ranged", "Healer", "Fast", "Explosive")
+ var/random = TRUE
+
+/obj/item/weapon/guardiancreator/attack_self(mob/living/user)
+ if(used == TRUE)
+ user << "[used_message]"
+ return
+ used = TRUE
+ user << "[use_message]"
+ var/list/candidates = get_candidates(BE_ALIEN, ALIEN_AFK_BRACKET)
+
+ shuffle(candidates)
+
+ var/time_passed = world.time
+ var/list/consenting_candidates = list()
+
+ for(var/candidate in candidates)
+
+ spawn(0)
+ switch(alert(candidate, "Would you like to play as the [mob_name] of [user.real_name]? Please choose quickly!","Confirmation","Yes","No"))
+ if("Yes")
+ if((world.time-time_passed)>=50 || !src)
+ return
+ consenting_candidates += candidate
+
+ sleep(50)
+
+ if(!src)
+ return
+
+ if(consenting_candidates.len)
+ var/client/C = null
+ C = pick(consenting_candidates)
+ spawn_guardian(user, C.key)
+ else
+ user << "[failure_message]"
+ used = FALSE
+
+
+/obj/item/weapon/guardiancreator/proc/spawn_guardian(var/mob/living/user, var/key)
+ var/gaurdiantype = "Standard"
+ if(random)
+ gaurdiantype = pick(possible_guardians)
+ else
+ gaurdiantype = input(user, "Pick the type pf [mob_name]", "[mob_name] Creation") as null|anything in possible_guardians
+ var/pickedtype = /mob/living/simple_animal/hostile/guardian/punch
+ var/picked_color = randomColor(0)
+ switch(gaurdiantype)
+
+ if("Fire")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/fire
+
+ if("Standard")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/punch
+
+ if("Scout")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/scout
+
+ if("Shield")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/shield
+
+ if("Ranged")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/ranged
+
+ if("Healer")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/healer
+
+ if("Fast")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/fast
+
+ if("Bluespace")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/bluespace
+
+ if("Explosive")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/bomb
+
+ var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user)
+ G.summoner = user
+ G.key = key
+ G.name = "[mob_name] [capitalize(picked_color)]"
+ G.real_name = "[mob_name] [capitalize(picked_color)]"
+ G.color = color2hex(picked_color)
+ G << "You are a [mob_name] bound to serve [user.real_name]."
+ G << "You are capable of manifesting or recalling to your master with verbs in the Guardian tab. You will also find a verb to communicate with them privately there."
+ G << "While personally invincible, you will die if [user.real_name] does, and any damage dealt to you will have a portion passed on to them as you feed upon them to sustain yourself."
+ G << "[G.playstyle_string]"
+ user.verbs += /mob/living/proc/guardian_comm
+ switch (theme)
+ if("magic")
+ user << "[G.magic_fluff_string]."
+ if("tech")
+ user << "[G.tech_fluff_string]."
+ G.attacktext = "swarms"
+ G.speak_emote = list("states")
+ if("bio")
+ user << "[G.bio_fluff_string]."
+ G.attacktext = "swarms"
+ G.speak_emote = list("chitters")
+
+
+
+/obj/item/weapon/guardiancreator/choose
+ random = FALSE
+
+/obj/item/weapon/guardiancreator/tech
+ name = "parasitic nanomachine injector"
+ desc = "Though powerful in combat, these nanomachines require a living host as a source of fuel and home base."
+ icon = 'icons/obj/syringe.dmi'
+ icon_state = "combat_hypo"
+ theme = "tech"
+ mob_name = "Nanomachine Swarm"
+ use_message = "You start to power on the injector..."
+ used_message = "The injector has already been used."
+ failure_message = "...ERROR. BOOT SEQUENCE ABORTED. AI FAILED TO INTIALIZE. PLEASE CONTACT SUPPORT OR TRY AGAIN LATER."
+
+/obj/item/weapon/guardiancreator/tech/choose
+ random = FALSE
+
+
+
+/obj/item/weapon/guardiancreator/biological
+ name = "scarab egg cluster"
+ desc = "A parasitic species that will nest in the closest living creature upon birth. While not great for your health, they'll defend their new 'hive' to the death."
+ icon = 'icons/obj/syringe.dmi'
+ icon_state = "combat_hypo"
+ theme = "bio"
+ mob_name = "Scarab Swarm"
+ use_message = "The eggs begin to twitch..."
+ used_message = "The cluster already hatched."
+ failure_message = "...but soon settles again. Guess they weren't ready to hatch after all."
+
+/obj/item/weapon/guardiancreator/biological/choose
+ random = FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm
index cfafe5093b8..3d04bb5dc61 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -40,14 +40,14 @@
var/plant_cooldown = 30
var/plants_off = 0
-/mob/living/simple_animal/hostile/alien/drone/Life()
- ..()
- if(!stat)
- plant_cooldown--
- if(stance==HOSTILE_STANCE_IDLE)
- if(!plants_off && prob(10) && plant_cooldown<=0)
- plant_cooldown = initial(plant_cooldown)
- SpreadPlants()
+/mob/living/simple_animal/hostile/alien/drone/handle_automated_action()
+ if(!..()) //AIStatus is off
+ return
+ plant_cooldown--
+ if(AIStatus == AI_IDLE)
+ if(!plants_off && prob(10) && plant_cooldown<=0)
+ plant_cooldown = initial(plant_cooldown)
+ SpreadPlants()
/mob/living/simple_animal/hostile/alien/sentinel
name = "alien sentinel"
@@ -87,18 +87,18 @@
var/egg_cooldown = 30
var/plant_cooldown = 30
-/mob/living/simple_animal/hostile/alien/queen/Life()
- ..()
- if(!stat)
- egg_cooldown--
- plant_cooldown--
- if(stance==HOSTILE_STANCE_IDLE)
- if(!plants_off && prob(10) && plant_cooldown<=0)
- plant_cooldown = initial(plant_cooldown)
- SpreadPlants()
- if(!sterile && prob(10) && egg_cooldown<=0)
- egg_cooldown = initial(egg_cooldown)
- LayEggs()
+/mob/living/simple_animal/hostile/alien/queen/handle_automated_action()
+ if(!..()) //AIStatus is off
+ return
+ egg_cooldown--
+ plant_cooldown--
+ if(AIStatus == AI_IDLE)
+ if(!plants_off && prob(10) && plant_cooldown<=0)
+ plant_cooldown = initial(plant_cooldown)
+ SpreadPlants()
+ if(!sterile && prob(10) && egg_cooldown<=0)
+ egg_cooldown = initial(egg_cooldown)
+ LayEggs()
/mob/living/simple_animal/hostile/alien/proc/SpreadPlants()
if(!isturf(loc) || istype(loc, /turf/space))
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index e28524867f2..ae03ebe143e 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -13,10 +13,7 @@
if(isliving(target))
var/mob/living/L = target
if(L.reagents)
- L.reagents.add_reagent("toxin", poison_per_bite)
- if(prob(poison_per_bite))
- L << "You feel a tiny prick."
- L.reagents.add_reagent(poison_type, poison_per_bite)
+ L.reagents.add_reagent(poison_type, poison_per_bite)
@@ -77,20 +74,18 @@
poison_per_bite = 5
move_to_delay = 5
-/mob/living/simple_animal/hostile/poison/giant_spider/Life()
- ..()
- if(!stat && !ckey)
- if(stance == HOSTILE_STANCE_IDLE)
- //1% chance to skitter madly away
- if(!busy && prob(1))
- /*var/list/move_targets = list()
- for(var/turf/T in orange(20, src))
- move_targets.Add(T)*/
- stop_automated_movement = 1
- Goto(pick(orange(20, src)), move_to_delay)
- spawn(50)
- stop_automated_movement = 0
- walk(src,0)
+/mob/living/simple_animal/hostile/poison/giant_spider/handle_automated_action()
+ if(!..()) //AIStatus is off
+ return 0
+ if(AIStatus == AI_IDLE)
+ //1% chance to skitter madly away
+ if(!busy && prob(1))
+ stop_automated_movement = 1
+ Goto(pick(orange(20, src)), move_to_delay)
+ spawn(50)
+ stop_automated_movement = 0
+ walk(src,0)
+ return 1
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/GiveUp(C)
spawn(100)
@@ -100,53 +95,50 @@
busy = 0
stop_automated_movement = 0
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Life()
- ..()
- if(!stat && !ckey)
- if(stance == HOSTILE_STANCE_IDLE)
- var/list/can_see = view(src, 10)
- //30% chance to stop wandering and do something
- if(!busy && prob(30))
- //first, check for potential food nearby to cocoon
- for(var/mob/living/C in can_see)
- if(C.stat && !istype(C,/mob/living/simple_animal/hostile/poison/giant_spider))
- cocoon_target = C
- busy = MOVING_TO_TARGET
- Goto(C, move_to_delay)
- //give up if we can't reach them after 10 seconds
- GiveUp(C)
- return
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/handle_automated_action()
+ if(..())
+ var/list/can_see = view(src, 10)
+ if(!busy && prob(30)) //30% chance to stop wandering and do something
+ //first, check for potential food nearby to cocoon
+ for(var/mob/living/C in can_see)
+ if(C.stat && !istype(C,/mob/living/simple_animal/hostile/poison/giant_spider))
+ cocoon_target = C
+ busy = MOVING_TO_TARGET
+ Goto(C, move_to_delay)
+ //give up if we can't reach them after 10 seconds
+ GiveUp(C)
+ return
- //second, spin a sticky spiderweb on this tile
- var/obj/effect/spider/stickyweb/W = locate() in get_turf(src)
- if(!W)
- Web()
+ //second, spin a sticky spiderweb on this tile
+ var/obj/effect/spider/stickyweb/W = locate() in get_turf(src)
+ if(!W)
+ Web()
+ else
+ //third, lay an egg cluster there
+ if(fed)
+ LayEggs()
else
- //third, lay an egg cluster there
- if(fed)
- LayEggs()
- else
- //fourthly, cocoon any nearby items so those pesky pinkskins can't use them
- for(var/obj/O in can_see)
+ //fourthly, cocoon any nearby items so those pesky pinkskins can't use them
+ for(var/obj/O in can_see)
- if(O.anchored)
- continue
+ if(O.anchored)
+ continue
- if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
- cocoon_target = O
- busy = MOVING_TO_TARGET
- stop_automated_movement = 1
- Goto(O, move_to_delay)
- //give up if we can't reach them after 10 seconds
- GiveUp(O)
+ if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
+ cocoon_target = O
+ busy = MOVING_TO_TARGET
+ stop_automated_movement = 1
+ Goto(O, move_to_delay)
+ //give up if we can't reach them after 10 seconds
+ GiveUp(O)
- else if(busy == MOVING_TO_TARGET && cocoon_target)
- if(get_dist(src, cocoon_target) <= 1)
- Wrap()
+ else if(busy == MOVING_TO_TARGET && cocoon_target)
+ if(get_dist(src, cocoon_target) <= 1)
+ Wrap()
- else
- busy = 0
- stop_automated_movement = 0
+ else
+ busy = 0
+ stop_automated_movement = 0
/mob/living/simple_animal/hostile/poison/giant_spider/verb/Web()
set name = "Lay Web"
@@ -249,6 +241,8 @@
var/obj/effect/spider/eggcluster/C = new /obj/effect/spider/eggcluster(src.loc)
if(ckey)
C.player_spiders = 1
+ C.poison_type = poison_type
+ C.poison_per_bite = poison_per_bite
fed--
busy = 0
stop_automated_movement = 0
@@ -262,4 +256,4 @@
#undef SPINNING_WEB
#undef LAYING_EGGS
#undef MOVING_TO_TARGET
-#undef SPINNING_COCOON
\ No newline at end of file
+#undef SPINNING_COCOON
diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
index 1d46890166d..587e686d67d 100644
--- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
@@ -1,4 +1,4 @@
-#define EGG_INCUBATION_TIME 180
+#define EGG_INCUBATION_TIME 120
/mob/living/simple_animal/hostile/headcrab
name = "Headslug"
@@ -21,13 +21,15 @@
var/datum/mind/origin
var/egg_lain = 0
-/mob/living/simple_animal/hostile/headcrab/proc/Infect(mob/living/carbon/human/victim)
- var/obj/item/body_egg/changeling_egg/egg = new(victim)
+/mob/living/simple_animal/hostile/headcrab/proc/Infect(mob/living/carbon/victim)
+ var/obj/item/organ/internal/body_egg/changeling_egg/egg = new(victim)
+ egg.Insert(victim)
if(origin)
- egg.owner = origin
+ egg.origin = origin
else if(mind) // Let's make this a feature
- egg.owner = mind
- victim.internal_organs += egg
+ egg.origin = mind
+ for(var/obj/item/organ/internal/I in src)
+ I.loc = egg
visible_message("[src] lays an egg in a [victim].")
egg_lain = 1
@@ -35,9 +37,10 @@
if(egg_lain)
target.attack_animal(src)
return
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- if(H.stat == DEAD)
+ if(iscarbon(target) && !ismonkey(target))
+ // Changeling egg can survive in aliens!
+ var/mob/living/carbon/C = target
+ if(C.stat == DEAD)
Infect(target)
src << "With your egg laid you feel your death rapidly approaching, time to die..."
spawn(100)
@@ -48,32 +51,36 @@
-/obj/item/body_egg/changeling_egg
+/obj/item/organ/internal/body_egg/changeling_egg
name = "changeling egg"
- desc = "Twitching and disgusting"
- var/datum/mind/owner
+ desc = "Twitching and disgusting."
+ origin_tech = "biotech=7" // You need to be really lucky to obtain it.
+ var/datum/mind/origin
var/time
- var/used
-/obj/item/body_egg/changeling_egg/egg_process()
- //Changeling eggs grow in dead people
+/obj/item/organ/internal/body_egg/changeling_egg/egg_process()
+ // Changeling eggs grow in dead people
time++
if(time >= EGG_INCUBATION_TIME)
Pop()
+ Remove(owner)
+ qdel(src)
-/obj/item/body_egg/changeling_egg/proc/Pop()
- if(!used)
- var/mob/living/carbon/monkey/M = new(affected_mob.loc)
- if(owner)
- owner.transfer_to(M)
- if(owner.changeling)
- owner.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
- M.key = owner.key
- if(ishuman(affected_mob))
- var/mob/living/carbon/human/H = affected_mob
- H.internal_organs.Remove(src)
- affected_mob.gib()
- used = 1
- qdel(src)
+/obj/item/organ/internal/body_egg/changeling_egg/proc/Pop()
+ var/mob/living/carbon/monkey/M = new(owner)
+ owner.stomach_contents += M
+
+ for(var/obj/item/organ/internal/I in src)
+ I.Insert(M, 1)
+
+ if(!origin && owner.mind)
+ origin = owner.mind
+
+ if(origin)
+ origin.transfer_to(M)
+ if(origin.changeling)
+ origin.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
+ M.key = origin.key
+ owner.gib()
#undef EGG_INCUBATION_TIME
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index b70b4418d89..1f24ed85e1c 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -2,7 +2,6 @@
faction = list("hostile")
stop_automated_movement_when_pulled = 0
environment_smash = 1 //Set to 1 to break closets,tables,racks, etc; 2 for walls; 3 for rwalls
- var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior
var/atom/target
var/ranged = 0
var/rapid = 0
@@ -32,37 +31,32 @@
var/stat_exclusive = 0 //Mobs with this set to 1 will exclusively attack things defined by stat_attack, stat_attack 2 means they will only attack corpses
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
- var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_SLEEP (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
+ var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
/mob/living/simple_animal/hostile/Life()
-
. = ..()
+ if(ranged)
+ ranged_cooldown--
if(!.) //dead
walk(src, 0) //stops walking
return 0
- if(ranged)
- ranged_cooldown--
- if(client)
+
+/mob/living/simple_animal/hostile/handle_automated_action()
+ if(AIStatus == AI_OFF)
return 0
- if(!AICanContinue())
- return 0
- if(!stat)
- switch(stance)
- if(HOSTILE_STANCE_IDLE)
- if(environment_smash)
- EscapeConfinement()
- FindTarget()
+ var/list/possible_targets = ListTargets() //we look around for potential targets and make it a list for later use.
- if(HOSTILE_STANCE_ATTACK)
- MoveToTarget()
- DestroySurroundings()
+ if(environment_smash)
+ EscapeConfinement()
+
+ if(AICanContinue(possible_targets))
+ DestroySurroundings()
+ if(!MoveToTarget(possible_targets)) //if we lose our target
+ if(AIShouldSleep(possible_targets)) // we try to acquire a new one
+ AIStatus = AI_IDLE // otherwise we go idle
+ return 1
- if(HOSTILE_STANCE_ATTACKING)
- AttackTarget()
- DestroySurroundings()
- if(AIShouldSleep())
- AIStatus = AI_SLEEP
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
@@ -81,19 +75,18 @@
L += Objects
return L
-/mob/living/simple_animal/hostile/proc/FindTarget()//Step 2, filter down possible targets to things we actually care about
+/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()
- var/Target
- for(var/atom/A in ListTargets())
+ if(!HasTargetsList)
+ possible_targets = ListTargets()
+ for(var/atom/A in possible_targets)
if(Found(A))//Just in case people want to override targetting
- var/list/FoundTarget = list()
- FoundTarget += A
- Targets = FoundTarget
+ Targets = list(A)
break
if(CanAttack(A))//Can we attack it?
Targets += A
continue
- Target = PickTarget(Targets)
+ var/Target = PickTarget(Targets)
GiveTarget(Target)
return Target //We now have a target
@@ -101,14 +94,14 @@
return
/mob/living/simple_animal/hostile/proc/PickTarget(list/Targets)//Step 3, pick amongst the possible, attackable targets
+ if(!Targets.len)//We didnt find nothin!
+ return
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)
var/target_dist = get_dist(src, target)
var/possible_target_distance = get_dist(src, A)
if(target_dist < possible_target_distance)
Targets -= A
- if(!Targets.len)//We didnt find nothin!
- return
var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random
return chosen_target
@@ -150,15 +143,14 @@
target = new_target
if(target != null)
Aggro()
- stance = HOSTILE_STANCE_ATTACK
- return
+ return 1
-/mob/living/simple_animal/hostile/proc/MoveToTarget()//Step 5, handle movement between us and our target
+/mob/living/simple_animal/hostile/proc/MoveToTarget(var/list/possible_targets)//Step 5, handle movement between us and our target
stop_automated_movement = 1
if(!target || !CanAttack(target))
LoseTarget()
- return
- if(target in ListTargets())
+ return 0
+ if(target in possible_targets)
var/target_distance = get_dist(src,target)
if(ranged)//We ranged? Shoot at em
if(target_distance >= 2 && ranged_cooldown <= 0)//But make sure they're a tile away at least, and our range attack is off cooldown
@@ -172,46 +164,33 @@
Goto(target,move_to_delay,minimum_distance)
if(isturf(loc) && target.Adjacent(src)) //If they're next to us, attack
AttackingTarget()
- return
+ return 1
if(environment_smash)
if(target.loc != null && get_dist(src, target.loc) <= vision_range)//We can't see our target, but he's in our vision range still
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
+ return 1
else
if(FindHidden())
- return
+ return 1
LoseTarget()
+ return 0
/mob/living/simple_animal/hostile/proc/Goto(target, delay, minimum_distance)
walk_to(src, target, minimum_distance, delay)
/mob/living/simple_animal/hostile/adjustBruteLoss(damage)
..(damage)
- if(!client && !stat && search_objects < 3)//Not unconscious, and we don't ignore mobs
+ if(!ckey && !stat && search_objects < 3)//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
- if(stance == HOSTILE_STANCE_IDLE)//If we took damage while idle, immediately attempt to find the source of it so we find a living target
- Aggro()
+ if(AIStatus == AI_IDLE)
+ AIStatus = AI_ON
+ FindTarget()
+ else if(target != null && prob(40))//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one
FindTarget()
- if(stance == HOSTILE_STANCE_ATTACK)//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one
- if(target != null && prob(40))
- FindTarget()
-
-/mob/living/simple_animal/hostile/proc/AttackTarget()
-
- stop_automated_movement = 1
- if(!target || !CanAttack(target))
- LoseTarget()
- return 0
- if(!(target in ListTargets()))
- LoseTarget()
- return 0
- if(isturf(loc) && target.Adjacent(src))
- AttackingTarget()
- return 1
/mob/living/simple_animal/hostile/proc/AttackingTarget()
target.attack_animal(src)
@@ -229,7 +208,6 @@
taunt_chance = initial(taunt_chance)
/mob/living/simple_animal/hostile/proc/LoseTarget()
- stance = HOSTILE_STANCE_IDLE
target = null
walk(src, 0)
LoseAggro()
@@ -325,30 +303,16 @@
////// AI Status ///////
-/mob/living/simple_animal/hostile/proc/AICanContinue()
+/mob/living/simple_animal/hostile/proc/AICanContinue(var/list/possible_targets)
switch(AIStatus)
if(AI_ON)
. = 1
- if(AI_SLEEP)
- if(AIShouldWake())
+ if(AI_IDLE)
+ if(FindTarget(possible_targets, 1))
. = 1
AIStatus = AI_ON //Wake up for more than one Life() cycle.
else
. = 0
- if(AI_OFF)
- . = 0
-
-//Returns 1 if the AI should wake up
-//Returns 0 if the AI should remain asleep
-/mob/living/simple_animal/hostile/proc/AIShouldWake()
- . = 0
- if(FindTarget())
- . = 1
-
-
-//Convenience
-/mob/living/simple_animal/hostile/proc/AIShouldSleep()
- . = !(AIShouldWake())
- if(. && stance != HOSTILE_STANCE_IDLE) //This proc was called before LoseTarget().
- LoseTarget()
+/mob/living/simple_animal/hostile/proc/AIShouldSleep(var/list/possible_targets)
+ return !FindTarget(possible_targets, 1)
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 45c8d140c89..7e01e2942ef 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
@@ -87,16 +87,12 @@
temperature = 50
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(new_target)
- target = new_target
- if(target != null)
- Aggro()
- stance = HOSTILE_STANCE_ATTACK
+ if(..()) //we have a target
if(isliving(target))
var/mob/living/L = target
if(L.bodytemperature > 200)
L.bodytemperature = 200
visible_message("The [src.name]'s stare chills [L.name] to the bone!")
- return
/mob/living/simple_animal/hostile/asteroid/basilisk/ex_act(severity, target)
switch(severity)
@@ -154,17 +150,14 @@
if(target != null)
if(istype(target, /obj/item/weapon/ore))
visible_message("The [src.name] looks at [target.name] with hungry eyes.")
- stance = HOSTILE_STANCE_ATTACK
- return
- if(isliving(target))
+
+ else if(isliving(target))
Aggro()
- stance = HOSTILE_STANCE_ATTACK
visible_message("The [src.name] tries to flee from [target.name]!")
retreat_distance = 10
minimum_distance = 10
Burrow()
- return
- return
+
/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget()
if(istype(target, /obj/item/weapon/ore))
@@ -366,7 +359,7 @@
/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack()
if(ranged_cooldown <= 2 && !pre_attack)
pre_attack++
- if(!pre_attack || stat || stance == HOSTILE_STANCE_IDLE)
+ if(!pre_attack || stat || AIStatus == AI_IDLE)
return
icon_state = "Goliath_preattack"
diff --git a/code/modules/mob/living/simple_animal/morph/morph.dm b/code/modules/mob/living/simple_animal/morph/morph.dm
index 15d69564839..e543a67193c 100644
--- a/code/modules/mob/living/simple_animal/morph/morph.dm
+++ b/code/modules/mob/living/simple_animal/morph/morph.dm
@@ -35,7 +35,7 @@
/mob/living/simple_animal/hostile/morph/examine(mob/user)
if(morphed)
form.examine(user) // Refactor examine to return desc so it's static? Not sure if worth it
- if(get_dist(user,src)<=3)
+ if(get_dist(user,src)<=3)
user << "Looks odd!"
else
..()
@@ -61,7 +61,7 @@
/mob/living/simple_animal/hostile/morph/proc/assume(atom/movable/target)
morphed = 1
form = target
-
+
//anim(loc,src,'icons/mob/mob.dmi',,"morph",,src.dir) No effect better than shit effect
//Todo : update to .appearance once 508 hits
@@ -89,9 +89,9 @@
return
morphed = 0
form = null
-
- //anim(loc,src,'icons/mob/mob.dmi',,"morph",,src.dir)
-
+
+ //anim(loc,src,'icons/mob/mob.dmi',,"morph",,src.dir)
+
name = initial(name)
icon = initial(icon)
icon_state = initial(icon_state)
@@ -127,7 +127,7 @@
/mob/living/simple_animal/hostile/morph/LoseAggro()
vision_range = idle_vision_range
-/mob/living/simple_animal/hostile/morph/AIShouldSleep()
+/mob/living/simple_animal/hostile/morph/AIShouldSleep(var/list/possible_targets)
. = ..()
if(.)
var/list/things = list()
@@ -160,6 +160,9 @@
return
target.attack_animal(src)
+/mob/living/simple_animal/hostile/morph/update_action_buttons() //So all eaten objects are not counted every life
+ return
+
//Spawn Event
/datum/round_event_control/morph
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 938ee7cf586..64a70739e32 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -74,10 +74,10 @@
health = Clamp(health, 0, maxHealth)
/mob/living/simple_animal/Life()
- if(..())
- if(!client && !stat)
+ if(..()) //alive
+ if(!ckey)
handle_automated_movement()
-
+ handle_automated_action()
handle_automated_speech()
return 1
@@ -114,6 +114,9 @@
if(druggy)
druggy = 0
+/mob/living/simple_animal/proc/handle_automated_action()
+ return
+
/mob/living/simple_animal/proc/handle_automated_movement()
if(!stop_automated_movement && wander)
if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
@@ -254,7 +257,7 @@
if(!Proj)
return
apply_damage(Proj.damage, Proj.damage_type)
- Proj.on_hit(src, 0)
+ Proj.on_hit(src)
return 0
/mob/living/simple_animal/adjustFireLoss(amount)
diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
index 58fe29515b3..ff0c9866215 100644
--- a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
+++ b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
@@ -12,7 +12,7 @@
icon = 'icons/mob/mob.dmi'
icon_state = "daemon"
icon_living = "daemon"
- speed = 0
+ speed = 1
a_intent = "harm"
stop_automated_movement = 1
status_flags = CANPUSH
@@ -21,22 +21,26 @@
minbodytemp = 0
faction = list("slaughter")
attacktext = "wildly tears into"
- maxHealth = 250
- health = 250
+ maxHealth = 200
+ health = 200
environment_smash = 1
melee_damage_lower = 30
melee_damage_upper = 30
see_in_dark = 8
+ var/boost = 0
+ bloodcrawl = BLOODCRAWL_EAT
see_invisible = SEE_INVISIBLE_MINIMUM
- var/devoured = 0
- var/phased = FALSE
- var/holder = null
- var/eating = FALSE
- var/mob/living/kidnapped = null
var/playstyle_string = "You are the Slaughter Demon, a terible creature from another existence. You have a single desire: To kill. \
You may Ctrl+Click on blood pools to travel through them, appearing and dissaapearing from the station at will. \
- Pulling a dead or critical mob while you enter a pool will pull them in with you, allowing you to feast. "
+ Pulling a dead or critical mob while you enter a pool will pull them in with you, allowing you to feast. \
+ You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. "
+/mob/living/simple_animal/slaughter/Life()
+ ..()
+ if(boostThe [src] drags [victim] into the pool of blood!")
- src.kidnapped = victim
- src.loc = holder
- src.phased = TRUE
- src.holder = holder
- if(src.kidnapped)
- src << "You begin to feast on [kidnapped]. You can not move while you are doing this."
- src.eating = TRUE
- playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
- sleep(30)
- playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
- sleep(30)
- playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
- sleep(30)
- src << "You devour [kidnapped]. Your health is fully restored."
- src.adjustBruteLoss(-1000)
- kidnapped.ghostize()
- qdel(kidnapped)
- src.devoured++
- src.kidnapped = null
- src.eating = FALSE
- src.notransform = 0
-
-/mob/living/simple_animal/slaughter/proc/phasein(obj/effect/decal/cleanable/B)
- if(src.eating)
- src << "Finish eating first!"
- else
- src.loc = B.loc
- src.phased = FALSE
- src.client.eye = src
- src.visible_message("The [src] rises out of the pool of blood!")
- playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
- qdel(src.holder)
-
-/obj/effect/decal/cleanable/blood/CtrlClick(mob/user)
+/mob/living/simple_animal/slaughter/phasein()
..()
- if(istype(user, /mob/living/simple_animal/slaughter))
- var/mob/living/simple_animal/slaughter/S = user
- if(S.phased)
- S.phasein(src)
- else
- S.phaseout(src)
-
-
-/obj/effect/decal/cleanable/trail_holder/CtrlClick(mob/user)
- ..()
- if(istype(user, /mob/living/simple_animal/slaughter))
- var/mob/living/simple_animal/slaughter/S = user
- if(S.phased)
- S.phasein(src)
- else
- S.phaseout(src)
-
-
-
-/turf/CtrlClick(var/mob/user)
- ..()
- if(istype(user, /mob/living/simple_animal/slaughter))
- var/mob/living/simple_animal/slaughter/S = user
- for(var/obj/effect/decal/cleanable/B in src.contents)
- if(istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/trail_holder))
- if(S.phased)
- S.phasein(B)
- break
- else
- S.phaseout(B)
- break
-
-/obj/effect/dummy/slaughter //Can't use the wizard one, blocked by jaunt/slow
- name = "water"
- icon = 'icons/effects/effects.dmi'
- icon_state = "nothing"
- var/canmove = 1
- density = 0
- anchored = 1
- invisibility = 60
-
-obj/effect/dummy/slaughter/relaymove(mob/user, direction)
- if (!src.canmove || !direction) return
- var/turf/newLoc = get_step(src,direction)
- loc = newLoc
- src.canmove = 0
- spawn(1)
- src.canmove = 1
-
-/obj/effect/dummy/slaughter/ex_act(blah)
- return
-/obj/effect/dummy/slaughter/bullet_act(blah)
- return
-
-/obj/effect/dummy/slaughter/singularity_act(blah)
- return
+ speed = 0
+ boost = world.time + 30
//////////The Loot
@@ -172,4 +66,11 @@ obj/effect/dummy/slaughter/relaymove(mob/user, direction)
desc = "It's still faintly beating with rage"
icon = 'icons/obj/surgery.dmi'
icon_state = "heart-on"
- origin_tech = "combat=5;biotech=8"
\ No newline at end of file
+ origin_tech = "combat=5;biotech=8"
+
+/obj/item/weapon/demonheart/attack_self(mob/living/user)
+ visible_message("[user] feasts upon the [src].")
+ user << "You absorb some of the demon's power!"
+ user.bloodcrawl = BLOODCRAWL
+ qdel(src)
+
diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm b/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm
index 8e836a74250..de3e477ab6d 100644
--- a/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm
+++ b/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm
@@ -36,9 +36,9 @@
spawn_locs += L.loc
if(!spawn_locs)
return find_slaughter()
- var /obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(pick(spawn_locs))
+ var /obj/effect/dummy/slaughter/holder = PoolOrNew(/obj/effect/dummy/slaughter,(pick(spawn_locs)))
var/mob/living/simple_animal/slaughter/S = new /mob/living/simple_animal/slaughter/(holder)
- S.phased = TRUE
+ S.holder = holder
player_mind.transfer_to(S)
player_mind.assigned_role = "Slaughter Demon"
player_mind.special_role = "Slaughter Demon"
@@ -64,4 +64,4 @@
log_game("[key_of_slaughter] was spawned as a Slaughter Demon by an event.")
return 0
message_admins("Unfortunately, no candidates were available for becoming a Slaugter Demon. Shutting down.")
- return kill()
\ No newline at end of file
+ return kill()
diff --git a/code/modules/mob/living/simple_animal/slime/emote.dm b/code/modules/mob/living/simple_animal/slime/emote.dm
index 85a298336a0..183ace95d10 100644
--- a/code/modules/mob/living/simple_animal/slime/emote.dm
+++ b/code/modules/mob/living/simple_animal/slime/emote.dm
@@ -6,43 +6,41 @@
//param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
- if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
- act = copytext(act,1,length(act))
var/m_type = 1
var/regenerate_icons
var/message
switch(act) //Alphabetical please
- if("bounce")
+ if("bounce","bounces")
message = "The [src.name] bounces in place."
m_type = 1
- if("jiggle")
+ if("jiggle","jiggles")
message = "The [src.name] jiggles!"
m_type = 1
- if("light")
+ if("light","lights")
message = "The [src.name] lights up for a bit, then stops."
m_type = 1
- if("moan")
+ if("moan","moans")
message = "The [src.name] moans."
m_type = 2
- if("shiver")
+ if("shiver","shivers")
message = "The [src.name] shivers."
m_type = 2
- if("sway")
+ if("sway","sways")
message = "The [src.name] sways around dizzily."
m_type = 1
- if("twitch")
+ if("twitch","twitches")
message = "The [src.name] twitches."
m_type = 1
- if("vibrate")
+ if("vibrate","vibrates")
message = "The [src.name] vibrates!"
m_type = 1
@@ -50,7 +48,7 @@
mood = null
regenerate_icons = 1
- if("smile")
+ if("smile","smiles")
mood = "mischevous"
regenerate_icons = 1
@@ -58,15 +56,15 @@
mood = ":33"
regenerate_icons = 1
- if("pout")
+ if("pout","pouts")
mood = "pout"
regenerate_icons = 1
- if("frown")
+ if("frown","frowns")
mood = "sad"
regenerate_icons = 1
- if("scowl")
+ if("scowl","scowls")
mood = "angry"
regenerate_icons = 1
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 75da09b542c..6c2582fe005 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -167,7 +167,7 @@
attacked += 10
if((Proj.damage_type == BURN))
adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes.
- Proj.on_hit(src, 0)
+ Proj.on_hit(src)
else
..(Proj)
return 0
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index b2415704445..3c0e579eb5f 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -946,6 +946,14 @@ var/list/slot_equipment_priority = list( \
return G
break
+/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg')
+ var/mob/dead/observer/ghost = get_ghost()
+ if(ghost)
+ ghost.notify_cloning(message, sound)
+ return ghost
+
+
+
/mob/proc/adjustEarDamage()
return
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 62fb5c75178..857b7f35181 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -46,7 +46,7 @@
return 0
/proc/iscorgi(A)
- if(istype(A, /mob/living/simple_animal/pet/corgi))
+ if(istype(A, /mob/living/simple_animal/pet/dog/corgi))
return 1
return 0
@@ -125,7 +125,7 @@
return 1
return 0
-/proc/isorgan(A)
+/proc/islimb(A)
if(istype(A, /obj/item/organ/limb))
return 1
return 0
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 0b5158f6085..2b4776c12b7 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -300,14 +300,11 @@
/mob/new_player/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank)
if (ticker.current_state == GAME_STATE_PLAYING)
- var/ailist[] = list()
- for (var/mob/living/silicon/ai/A in living_mob_list)
- ailist += A
- if (ailist.len)
- var/mob/living/silicon/ai/announcer = pick(ailist)
+ if(announcement_systems.len)
if(character.mind)
if((character.mind.assigned_role != "Cyborg") && (character.mind.assigned_role != character.mind.special_role))
- announcer.say("[announcer.radiomod] [character.real_name] has signed up as [rank].")
+ var/obj/machinery/announcement_system/announcer = pick(announcement_systems)
+ announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common
/mob/new_player/proc/LateChoices()
var/mills = world.time // 1/10 of a second, not real milliseconds but whatever
diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm
index d065b489ff6..8cebce6b253 100644
--- a/code/modules/mob/new_player/preferences_setup.dm
+++ b/code/modules/mob/new_player/preferences_setup.dm
@@ -163,7 +163,7 @@
else if(backbag == 2)
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
if(BARTENDER)
- clothes_s = new /icon('icons/mob/uniform.dmi', "bar_suit_s")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "barman_s")
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_OVERLAY)
clothes_s.Blend(new /icon('icons/mob/suit.dmi', "armor"), ICON_OVERLAY)
if(backbag == 1)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 45fe320ce0c..674b88eacb6 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -3,15 +3,18 @@
return
//Handle items on mob
- //first implants
+ //first implants & organs
var/list/implants = list()
+ var/list/int_organs = list()
+
if (tr_flags & TR_KEEPIMPLANTS)
for(var/obj/item/weapon/implant/W in src)
implants += W
- if(tr_flags & TR_KEEPITEMS)
- for(var/obj/item/W in (src.contents-implants))
- unEquip(W)
+ if (tr_flags & TR_KEEPORGANS)
+ for(var/obj/item/organ/internal/I in internal_organs)
+ int_organs += I
+ I.Remove(src, 1)
//Make mob invisible and spawn animation
regenerate_icons()
@@ -70,6 +73,14 @@
I.loc = O
I.implanted = O
+ //re-add organs to new mob
+ if(tr_flags & TR_KEEPORGANS)
+ for(var/obj/item/organ/internal/I in O.internal_organs)
+ qdel(I)
+
+ for(var/obj/item/organ/internal/I in int_organs)
+ I.Insert(O, 1)
+
//transfer mind and delete old mob
if(mind)
mind.transfer_to(O)
@@ -98,12 +109,19 @@
return
//Handle items on mob
- //first implants
+ //first implants & organs
var/list/implants = list()
+ var/list/int_organs = list()
+
if (tr_flags & TR_KEEPIMPLANTS)
for(var/obj/item/weapon/implant/W in src)
implants += W
+ if (tr_flags & TR_KEEPORGANS)
+ for(var/obj/item/organ/internal/I in internal_organs)
+ int_organs += I
+ I.Remove(src, 1)
+
//now the rest
if (tr_flags & TR_KEEPITEMS)
for(var/obj/item/W in (src.contents-implants))
@@ -187,6 +205,13 @@
I.implanted = O
O.sec_hud_set_implants()
+ if(tr_flags & TR_KEEPORGANS)
+ for(var/obj/item/organ/internal/I in O.internal_organs)
+ qdel(I)
+
+ for(var/obj/item/organ/internal/I in int_organs)
+ I.Insert(O, 1)
+
if(mind)
mind.transfer_to(O)
O.a_intent = "help"
@@ -430,7 +455,7 @@
for(var/t in organs) //this really should not be necessary
qdel(t)
- var/mob/living/simple_animal/pet/corgi/new_corgi = new /mob/living/simple_animal/pet/corgi (loc)
+ var/mob/living/simple_animal/pet/dog/corgi/new_corgi = new /mob/living/simple_animal/pet/dog/corgi (loc)
new_corgi.a_intent = "harm"
new_corgi.key = key
@@ -509,7 +534,7 @@
//Good mobs!
if(ispath(MP, /mob/living/simple_animal/pet/cat))
return 1
- if(ispath(MP, /mob/living/simple_animal/pet/corgi))
+ if(ispath(MP, /mob/living/simple_animal/pet/dog/corgi))
return 1
if(ispath(MP, /mob/living/simple_animal/crab))
return 1
diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm
index c9e36f27b46..37e5ff55bd2 100644
--- a/code/modules/ninja/ninja_event.dm
+++ b/code/modules/ninja/ninja_event.dm
@@ -213,7 +213,5 @@ Contents:
equip_to_slot_or_del(new /obj/item/weapon/tank/jetpack/carbondioxide(src), slot_back)
var/obj/item/weapon/implant/explosive/E = new/obj/item/weapon/implant/explosive(src)
- E.imp_in = src
- E.implanted = 1
- E.implanted(src)
+ E.implant(src)
return 1
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
index e87ac8e1ff8..107502ce151 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
@@ -3,20 +3,22 @@
Contents:
- Stealth Verbs
-- Stealth Icon Stuff
*/
/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth()
var/mob/living/carbon/human/U = affecting
+ if(!U)
+ return
if(s_active)
cancel_stealth()
else
- spawn(0)
- anim(U.loc,U,'icons/mob/mob.dmi',,"cloak",,U.dir)
+ if(cell.charge <= 0)
+ U << "You don't have enough power to enable Stealth!"
+ return
s_active=!s_active
- U.alpha = 0
+ animate(U, U.alpha = 0,time = 15)
U.visible_message("[U.name] vanishes into thin air!", \
"You are now invisible to normal detection.")
return
@@ -24,11 +26,11 @@ Contents:
/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth()
var/mob/living/carbon/human/U = affecting
+ if(!U)
+ return 0
if(s_active)
- spawn(0)
- anim(U.loc,U,'icons/mob/mob.dmi',,"uncloak",,U.dir)
s_active=!s_active
- U.alpha = 255
+ animate(U, U.alpha = 255, time = 15)
U.visible_message("[U.name] appears from thin air!", \
"You are now visible.")
return 1
@@ -45,34 +47,3 @@ Contents:
else
affecting << "Stealth does not appear to work!"
-
-//Allows the mob to grab a stealth icon.
-/mob/proc/NinjaStealthActive(atom/A)//A is the atom which we are using as the overlay.
- invisibility = INVISIBILITY_LEVEL_TWO//Set ninja invis to 2.
- var/icon/opacity_icon = new(A.icon, A.icon_state)
- var/icon/alpha_mask = getIconMask(src)
- var/icon/alpha_mask_2 = new('icons/effects/effects.dmi', "at_shield1")
- alpha_mask.AddAlphaMask(alpha_mask_2)
- opacity_icon.AddAlphaMask(alpha_mask)
- for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it.
- var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like.
- switch(i)//Now to determine offset so the result is somewhat blurred.
- if(1)
- I.pixel_x -= 1
- if(2)
- I.pixel_x += 1
- if(3)
- I.pixel_y -= 1
- if(4)
- I.pixel_y += 1
-
- overlays += I//And finally add the overlay.
- overlays += image("icon"='icons/effects/effects.dmi',"icon_state" ="electricity","layer" = layer+0.9)
-
-//When ninja steal malfunctions.
-/mob/proc/NinjaStealthMalf()
- invisibility = 0//Set ninja invis to 0.
- overlays += image("icon"='icons/effects/effects.dmi',"icon_state" ="electricity","layer" = layer+0.9)
- playsound(loc, 'sound/effects/stealthoff.ogg', 75, 1)
-
-
diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm
index 810e9058165..5fcca544ae9 100644
--- a/code/modules/ninja/suit/suit.dm
+++ b/code/modules/ninja/suit/suit.dm
@@ -83,7 +83,6 @@ Contents:
cell.charge = 9000
-
/obj/item/clothing/suit/space/space_ninja/Destroy()
if(affecting)
affecting << browse(null, "window=hack spideros")
diff --git a/code/modules/ninja/suit/suit_process.dm b/code/modules/ninja/suit/suit_process.dm
index 6440ffc71c9..73fcd2d788c 100644
--- a/code/modules/ninja/suit/suit_process.dm
+++ b/code/modules/ninja/suit/suit_process.dm
@@ -4,25 +4,27 @@
set background = BACKGROUND_ENABLED
//Runs in the background while the suit is initialized.
- spawn while(cell.charge)
+ //Requires charge or stealth to process.
+ spawn while(cell.charge || s_active)
- //Let's check for some safeties.
if(s_initialized && !affecting)
terminate()//Kills the suit and attached objects.
if(!s_initialized)
- return//When turned off the proc stops.
+ return
- //Now let's do the normal processing.
- if(s_coold)
- s_coold--//Checks for ability s_cooldown first.
+ if(cell.charge)
+ if(s_coold)
+ s_coold--//Checks for ability s_cooldown first.
- var/A = s_cost//s_cost is the default energy cost each ntick, usually 5.
- if(s_active)//If stealth is active.
- A += s_acost
- cell.charge-=A
+ var/A = s_cost//s_cost is the default energy cost each ntick, usually 5.
+ if(s_active)//If stealth is active.
+ A += s_acost
+ cell.charge-=A
- if(!cell.charge)
+ if(cell.charge <= 0)
cell.charge=0
cancel_stealth()
sleep(10)//Checks every second.
+
+
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index 0a89745dfcf..ef0d35fb175 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -122,12 +122,12 @@
projectile_type = /obj/item/projectile/plasma
select_name = "plasma burst"
fire_sound = 'sound/weapons/Laser.ogg'
- delay = 10
+ delay = 15
e_cost = 25
/obj/item/ammo_casing/energy/plasma/adv
projectile_type = /obj/item/projectile/plasma/adv
- delay = 8
+ delay = 10
e_cost = 10
/obj/item/ammo_casing/energy/wormhole
diff --git a/code/modules/projectiles/firing.dm b/code/modules/projectiles/firing.dm
index a90eda4508f..2833f2de7f5 100644
--- a/code/modules/projectiles/firing.dm
+++ b/code/modules/projectiles/firing.dm
@@ -31,8 +31,9 @@
var/turf/curloc = user.loc
if (!istype(targloc) || !istype(curloc) || !BB)
return 0
- if(targloc == curloc) //Fire the projectile
- user.bullet_act(BB)
+ if(targloc == curloc)
+ if(BB.original == user) //if we target ourselves we go straight to bullet_act()
+ user.bullet_act(BB)
del(BB)
return 1
BB.loc = get_turf(user)
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index e1a143f2f5d..fcd6363ddbb 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -11,6 +11,7 @@
var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next.
var/can_charge = 1 //Can it be charged in a recharger?
ammo_x_offset = 2
+ var/shaded_charge = 0 //if this gun uses a stateful charge bar for more detail
/obj/item/weapon/gun/energy/emp_act(severity)
power_supply.use(round(power_supply.charge / severity))
@@ -87,9 +88,12 @@
itemState += "[shot.select_name]"
if(power_supply.charge < shot.e_cost)
overlays += "[icon_state]_empty"
- ratio = 0
- for(var/i = ratio, i >= 1, i--)
- overlays += image(icon = icon, icon_state = iconState, pixel_x = ammo_x_offset * (i -1))
+ else
+ if(!shaded_charge)
+ for(var/i = ratio, i >= 1, i--)
+ overlays += image(icon = icon, icon_state = iconState, pixel_x = ammo_x_offset * (i -1))
+ else
+ overlays += image(icon = icon, icon_state = "[icon_state]_charge[ratio]")
if(F)
var/iconF = "flight"
if(F.on)
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index a3312bbe75e..f6b625d1169 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -8,7 +8,7 @@
origin_tech = "combat=3;magnets=2"
ammo_type = list(/obj/item/ammo_casing/energy/lasergun)
ammo_x_offset = 1
-
+ shaded_charge = 1
/obj/item/weapon/gun/energy/laser/practice
name = "practice laser gun"
diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm
index e11357de9a7..89c73331581 100644
--- a/code/modules/projectiles/guns/energy/nuclear.dm
+++ b/code/modules/projectiles/guns/energy/nuclear.dm
@@ -20,6 +20,7 @@
icon_state = "hoslaser"
force = 10
ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/disabler)
+ ammo_x_offset = 4
/obj/item/weapon/gun/energy/gun/dragnet
name = "DRAGnet"
diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm
index 18706908c93..0e143cefe8e 100644
--- a/code/modules/projectiles/guns/energy/pulse.dm
+++ b/code/modules/projectiles/guns/energy/pulse.dm
@@ -59,6 +59,6 @@
/obj/item/weapon/gun/energy/pulse/pistol/m1911
name = "\improper M1911-P"
desc = "A compact pulse core in a classic handgun frame for Nanotrasen officers. It's not the size of the gun, it's the size of the hole it puts through people."
- icon_state = "m1911-p"
+ icon_state = "m1911"
item_state = "gun"
cell_type = "/obj/item/weapon/stock_parts/cell/infinite"
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 45e936f8867..1401c31937a 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -52,6 +52,7 @@
origin_tech = "materials=2;biotech=3;powerstorage=3"
modifystate = 1
var/charge_tick = 0
+ ammo_x_offset = 1
/obj/item/weapon/gun/energy/floragun/New()
..()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 0a1eddc7eb5..dc411940f0d 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -60,19 +60,20 @@
if(!isliving(target))
return 0
var/mob/living/L = target
-
- var/organ_hit_text = ""
- if(L.has_limbs)
- organ_hit_text = " in \the [parse_zone(def_zone)]"
- if(suppressed)
- playsound(loc, hitsound, 5, 1, -1)
- L << "You're shot by \a [src][organ_hit_text]!"
- else
- if(hitsound)
- var/volume = vol_by_damage()
- playsound(loc, hitsound, volume, 1, -1)
- L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \
- "[L] is hit by \a [src][organ_hit_text]!") //X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
+ if(blocked != 100) // not completely blocked
+ var/organ_hit_text = ""
+ if(L.has_limbs)
+ organ_hit_text = " in \the [parse_zone(def_zone)]"
+ if(suppressed)
+ playsound(loc, hitsound, 5, 1, -1)
+ L << "You're shot by \a [src][organ_hit_text]!"
+ else
+ if(hitsound)
+ var/volume = vol_by_damage()
+ playsound(loc, hitsound, volume, 1, -1)
+ L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \
+ "[L] is hit by \a [src][organ_hit_text]!") //X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
+ L.on_hit(type)
var/reagent_note
if(reagents && reagents.reagent_list)
@@ -81,7 +82,6 @@
reagent_note += R.id + " ("
reagent_note += num2text(R.volume) + ") "
- L.on_hit(type)
add_logs(firer, L, "shot", src, reagent_note)
return L.apply_effects(stun, weaken, paralyze, irradiate, stutter, slur, eyeblur, drowsy, blocked, stamina, jitter)
@@ -94,9 +94,10 @@
/obj/item/projectile/Bump(atom/A, yes)
if(!yes) //prevents double bumps.
return
- if(A == firer || A == src)
- loc = A.loc
- return 0 //cannot shoot yourself
+ if(firer)
+ if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
+ loc = A.loc
+ return 0
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
@@ -134,7 +135,7 @@
if((!( current ) || loc == current))
current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
step_towards(src, current)
- if((original && original.layer>=2.75) || ismob(original))
+ if(original && (original.layer>=2.75) || ismob(original))
if(loc == get_turf(original))
if(!(original in permutated))
Bump(original, 1)
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 84bbe11872b..83d693f3479 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -125,19 +125,19 @@
create_reagents(50)
/obj/item/projectile/bullet/dart/on_hit(atom/target, blocked = 0, hit_zone)
- var/deflect = 0
if(iscarbon(target))
var/mob/living/carbon/M = target
- if(M.can_inject(null,0,hit_zone)) // Pass the hit zone to see if it can inject by whether it hit the head or the body.
- ..()
- reagents.trans_to(M, reagents.total_volume)
- return 1
- else
- deflect = 1
- target.visible_message("The [name] was deflected!", \
- "You were protected against the [name]!")
- if(!deflect)
- ..()
+ if(blocked != 100) // not completely blocked
+ if(M.can_inject(null,0,hit_zone)) // Pass the hit zone to see if it can inject by whether it hit the head or the body.
+ ..()
+ reagents.trans_to(M, reagents.total_volume)
+ return 1
+ else
+ blocked = 100
+ target.visible_message("The [name] was deflected!", \
+ "You were protected against the [name]!")
+
+ ..(target, blocked, hit_zone)
flags &= ~NOREACT
reagents.handle_reactions()
return 1
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 7ad01293b93..bbe10e02af3 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -22,7 +22,6 @@
damage = 10
damage_type = BRUTE
nodamage = 0
- flag = "magic"
/obj/item/projectile/magic/fireball/Range()
var/mob/living/L = locate(/mob/living) in (range(src, 1) - firer)
@@ -45,7 +44,6 @@
damage = 0
damage_type = OXY
nodamage = 1
- flag = "magic"
/obj/item/projectile/magic/resurrection/on_hit(mob/living/carbon/target)
. = ..()
@@ -69,7 +67,6 @@
damage = 0
damage_type = OXY
nodamage = 1
- flag = "magic"
var/inner_tele_radius = 0
var/outer_tele_radius = 6
@@ -93,7 +90,6 @@
damage = 0
damage_type = OXY
nodamage = 1
- flag = "magic"
/obj/item/projectile/magic/door/on_hit(atom/target)
. = ..()
@@ -114,7 +110,6 @@
damage = 0
damage_type = BURN
nodamage = 1
- flag = "magic"
/obj/item/projectile/magic/change/on_hit(atom/change)
. = ..()
@@ -205,7 +200,7 @@
var/animal = pick("parrot","corgi","crab","pug","cat","mouse","chicken","cow","lizard","chick","fox","butterfly")
switch(animal)
if("parrot") new_mob = new /mob/living/simple_animal/parrot(M.loc)
- if("corgi") new_mob = new /mob/living/simple_animal/pet/corgi(M.loc)
+ if("corgi") new_mob = new /mob/living/simple_animal/pet/dog/corgi(M.loc)
if("crab") new_mob = new /mob/living/simple_animal/crab(M.loc)
if("pug") new_mob = new /mob/living/simple_animal/pet/pug(M.loc)
if("cat") new_mob = new /mob/living/simple_animal/pet/cat(M.loc)
@@ -257,7 +252,6 @@
damage = 0
damage_type = BURN
nodamage = 1
- flag = "magic"
/obj/item/projectile/magic/animate/Bump(atom/change)
..()
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index ed67992617a..87f2acf69c3 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -25,7 +25,6 @@
name ="explosive bolt"
icon_state= "bolter"
damage = 50
- flag = "bullet"
/obj/item/projectile/bullet/gyro/on_hit(atom/target, blocked = 0)
..()
@@ -37,7 +36,6 @@
desc = "USE A WEEL GUN"
icon_state= "bolter"
damage = 60
- flag = "bullet"
/obj/item/projectile/bullet/a40mm/on_hit(atom/target, blocked = 0)
..()
@@ -206,29 +204,31 @@ obj/item/projectile/kinetic/New()
icon_state = "plasmacutter"
damage_type = BRUTE
damage = 5
- range = 1
+ range = 3
/obj/item/projectile/plasma/New()
var/turf/proj_turf = get_turf(src)
if(!istype(proj_turf, /turf))
return
var/datum/gas_mixture/environment = proj_turf.return_air()
- var/pressure = environment.return_pressure()
- if(pressure < 30)
- name = "full strength plasma blast"
- damage *= 3
- range += 3
+ if(environment)
+ var/pressure = environment.return_pressure()
+ if(pressure < 30)
+ name = "full strength plasma blast"
+ damage *= 3
..()
/obj/item/projectile/plasma/on_hit(atom/target)
+ . = ..()
if(istype(target, /turf/simulated/mineral))
var/turf/simulated/mineral/M = target
M.gets_drilled(firer)
- return ..()
+ range = max(range - 1, 1)
+ return -1
/obj/item/projectile/plasma/adv
- range = 2
+ range = 5
/obj/item/projectile/plasma/adv/mech
damage = 10
- range = 3
+ range = 6
\ No newline at end of file
diff --git a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
index 80aea6a6168..3f08110b756 100644
--- a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
@@ -224,6 +224,42 @@
..()
return
+/datum/reagent/medicine/mine_salve
+ name = "Miner's Salve"
+ id = "mine_salve"
+ description = "Slowly heals burn and brute damage, and causes subject to believe they are fully healed."
+ reagent_state = LIQUID
+ color = "#6D6374"
+ metabolization_rate = 0.4 * REAGENTS_METABOLISM
+
+/datum/reagent/medicine/mine_salve/on_mob_life(mob/living/M)
+ if(iscarbon(M))
+ var/mob/living/carbon/N = M
+ N.hal_screwyhud = 5
+ M.adjustBruteLoss(-0.25*REM)
+ M.adjustFireLoss(-0.25*REM)
+ ..()
+ return
+
+/datum/reagent/medicine/mine_salve/reaction_mob(mob/living/M, method=TOUCH, volume, show_message = 1)
+ if(iscarbon(M))
+ if(method == TOUCH)
+ if(show_message)
+ M << "You feel your wounds knitting back together!"
+ if(method == INGEST)
+ if(show_message)
+ M << "That tasted horrible."
+ M.AdjustStunned(2)
+ M.AdjustWeakened(2)
+ ..()
+ return
+
+/datum/reagent/medicine/mine_salve/on_mob_delete(mob/living/M)
+ if(iscarbon(M))
+ var/mob/living/carbon/N = M
+ N.hal_screwyhud = 0
+ ..()
+
/datum/reagent/medicine/synthflesh
name = "Synthflesh"
id = "synthflesh"
@@ -614,11 +650,6 @@
..()
return
-/datum/reagent/medicine/strange_reagent/Topic(href, href_list)
- if(href_list["reenter"])
- var/mob/dead/observer/ghost = usr
- if(istype(ghost))
- ghost.reenter_corpse(ghost)
/datum/reagent/medicine/strange_reagent
name = "Strange Reagent"
@@ -633,14 +664,11 @@
if(M.getBruteLoss() >= 100 || M.getFireLoss() >= 100)
M.visible_message("[M]'s body convulses a bit, and then falls still once more.")
return
- var/mob/dead/observer/ghost = M.get_ghost()
M.visible_message("[M]'s body convulses a bit.")
if(!M.suiciding && !(NOCLONE in M.mutations))
if(!M)
return
- if(ghost)
- ghost << "Someone is trying to revive you. Re-enter your corpse if you want to be revived! (Click to re-enter)"
- ghost << sound('sound/effects/genetics.ogg')
+ if(M.notify_ghost_cloning())
spawn (100) //so the ghost has time to re-enter
return
else
diff --git a/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
index 2ebceebbd64..edfd038e960 100644
--- a/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
@@ -253,6 +253,95 @@
if(volume >= 1)
T.MakeSlippery(2)
+/datum/reagent/spraytan
+ name = "Spray Tan"
+ id = "spraytan"
+ description = "A substance applied to the skin to darken the skin."
+ color = "#FFC080" // rgb: 255, 196, 128 Bright orange
+ metabolization_rate = 10 * REAGENTS_METABOLISM // very fast, so it can be applied rapidly. But this changes on an overdose
+ overdose_threshold = 11 //Slightly more than one un-nozzled spraybottle.
+
+/datum/reagent/spraytan/reaction_mob(mob/living/M, method=TOUCH, volume, show_message = 1)
+ if(istype(M, /mob/living/carbon/human))
+ if(method == TOUCH)
+ var/mob/living/carbon/human/N = M
+ if(N.dna.species.id == "human")
+ switch(N.skin_tone)
+ if("african1")
+ N.skin_tone = "african2"
+ if("indian")
+ N.skin_tone = "african1"
+ if("arab")
+ N.skin_tone = "indian"
+ if("asian2")
+ N.skin_tone = "arab"
+ if("asian1")
+ N.skin_tone = "asian2"
+ if("mediterranean")
+ N.skin_tone = "african1"
+ if("latino")
+ N.skin_tone = "mediterranean"
+ if("caucasian3")
+ N.skin_tone = "mediterranean"
+ if("caucasian2")
+ N.skin_tone = pick("caucasian3", "latino")
+ if("caucasian1")
+ N.skin_tone = "caucasian2"
+ if ("albino")
+ N.skin_tone = "caucasian1"
+
+ if(MUTCOLORS in N.dna.species.specflags) //take current alien color and darken it slightly
+ var/newcolor = ""
+ var/len = length(N.dna.features["mcolor"])
+ for(var/i=1, i<=len, i+=1)
+ var/ascii = text2ascii(N.dna.features["mcolor"],i)
+ switch(ascii)
+ if(48) newcolor += "0"
+ if(49 to 57) newcolor += ascii2text(ascii-1) //numbers 1 to 9
+ if(97) newcolor += "9"
+ if(98 to 102) newcolor += ascii2text(ascii-1) //letters b to f lowercase
+ if(65) newcolor +="9"
+ if(66 to 70) newcolor += ascii2text(ascii+31) //letters B to F - translates to lowercase
+ else
+ break
+ N.dna.features["mcolor"] = newcolor
+ N.regenerate_icons()
+ N.update_body()
+
+
+
+ if(method == INGEST)
+ if(show_message)
+ M << "That tasted horrible."
+ M.AdjustStunned(2)
+ M.AdjustWeakened(2)
+ ..()
+
+
+/datum/reagent/spraytan/overdose_process(mob/living/M)
+ metabolization_rate = 1 * REAGENTS_METABOLISM
+
+ if(istype(M, /mob/living/carbon/human))
+ var/mob/living/carbon/human/N = M
+ if(N.dna.species.id == "human") // If they're human, turn em to the "orange" race, and give em spiky black hair
+ N.skin_tone = "orange"
+ N.hair_style = "Spiky"
+ N.hair_color = "000"
+ N.update_hair()
+ if(MUTCOLORS in N.dna.species.specflags) //Aliens with custom colors simply get turned orange
+ N.dna.features["mcolor"] = "f80"
+ N.regenerate_icons()
+ N.update_body()
+ if(prob(7))
+ if(N.w_uniform)
+ M.visible_message(pick("[M]'s collar pops up without warning.", "[M] flexes their arms."))
+ else
+ M.visible_message("[M] flexes their arms.")
+ if(prob(10))
+ M.say(pick("Check these sweet biceps bro!", "Deal with it.", "CHUG! CHUG! CHUG! CHUG!", "Winning!", "NERDS!", "My name is John and I hate every single one of you."))
+ ..()
+ return
+
/datum/reagent/slimetoxin
name = "Mutation Toxin"
id = "mutationtoxin"
@@ -455,7 +544,7 @@
if(volume >= 3)
if(!istype(T, /turf/space))
var/obj/effect/decal/cleanable/reagentdecal = new/obj/effect/decal/cleanable/greenglow(T)
- reagentdecal.reagents.add_reagent("uranium", volume)
+ reagentdecal.reagents.add_reagent("radium", volume)
/datum/reagent/sterilizine
name = "Sterilizine"
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index 5dc555550e2..e7f7014e135 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -35,10 +35,9 @@
/mob/living/simple_animal/hostile/syndicate/ranged,
/mob/living/simple_animal/hostile/syndicate/ranged/space,
/mob/living/simple_animal/hostile/alien/queen/large,
- /mob/living/simple_animal/hostile/retaliate,
- /mob/living/simple_animal/hostile/retaliate/clown,
/mob/living/simple_animal/hostile/mushroom,
/mob/living/simple_animal/hostile/asteroid,
+ /mob/living/simple_animal/hostile/retaliate,
/mob/living/simple_animal/hostile/asteroid/basilisk,
/mob/living/simple_animal/hostile/asteroid/goldgrub,
/mob/living/simple_animal/hostile/asteroid/goliath,
@@ -50,7 +49,15 @@
/mob/living/simple_animal/hostile/blob,
/mob/living/simple_animal/ascendant_shadowling
)//exclusion list for things you don't want the reaction to create.
- var/list/critters = typesof(/mob/living/simple_animal/hostile) - blocked // list of possible hostile mobs
+ var/list/meancritters = typesof(/mob/living/simple_animal/hostile) - blocked // list of possible hostile mobs
+ var/list/nicecritters = list(/mob/living/simple_animal/crab,
+ /mob/living/simple_animal/mouse,
+ /mob/living/simple_animal/lizard,
+ /mob/living/simple_animal/parrot,
+ /mob/living/simple_animal/butterfly,
+ /mob/living/simple_animal/cow,
+ /mob/living/simple_animal/chicken) // and possible friendly mobs
+ nicecritters += typesof(/mob/living/simple_animal/pet) - /mob/living/simple_animal/pet
var/atom/A = holder.my_atom
var/turf/T = get_turf(A)
var/area/my_area = get_area(T)
@@ -70,13 +77,22 @@
for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null))
C.flash_eyes()
for(var/i = 1, i <= amount_to_spawn, i++)
- var/chosen = pick(critters)
- var/mob/living/simple_animal/hostile/C = new chosen
- C.faction |= mob_faction
- C.loc = get_turf(holder.my_atom)
- if(prob(50))
- for(var/j = 1, j <= rand(1, 3), j++)
- step(C, pick(NORTH,SOUTH,EAST,WEST))
+ if (reaction_name == "Friendly Gold Slime")
+ var/chosen = pick(nicecritters)
+ var/mob/living/simple_animal/C = new chosen
+ C.faction |= mob_faction
+ C.loc = get_turf(holder.my_atom)
+ if(prob(50))
+ for(var/j = 1, j <= rand(1, 3), j++)
+ step(C, pick(NORTH,SOUTH,EAST,WEST))
+ else
+ var/chosen = pick(meancritters)
+ var/mob/living/simple_animal/hostile/C = new chosen
+ C.faction |= mob_faction
+ C.loc = get_turf(holder.my_atom)
+ if(prob(50))
+ for(var/j = 1, j <= rand(1, 3), j++)
+ step(C, pick(NORTH,SOUTH,EAST,WEST))
/datum/chemical_reaction/proc/goonchem_vortex(turf/simulated/T, setting_type, range)
for(var/atom/movable/X in orange(range, T))
diff --git a/code/modules/reagents/Chemistry-Recipes/Medicine.dm b/code/modules/reagents/Chemistry-Recipes/Medicine.dm
index 357eac96a5e..60e80923400 100644
--- a/code/modules/reagents/Chemistry-Recipes/Medicine.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Medicine.dm
@@ -57,6 +57,20 @@
result = "salglu_solution"
required_reagents = list("sodiumchloride" = 1, "water" = 1, "sugar" = 1)
result_amount = 3
+
+/datum/chemical_reaction/mine_salve
+ name = "Miner's Salve"
+ id = "mine_salve"
+ result = "mine_salve"
+ required_reagents = list("oil" = 1, "water" = 1, "iron" = 1)
+ result_amount = 3
+
+/datum/chemical_reaction/mine_salve2
+ name = "Miner's Salve"
+ id = "mine_salve"
+ result = "mine_salve"
+ required_reagents = list("plasma" = 5, "iron" = 5, "sugar" = 1) // A sheet of plasma, a twinkie and a sheet of metal makes four of these
+ result_amount = 15
/datum/chemical_reaction/synthflesh
name = "Synthflesh"
diff --git a/code/modules/reagents/Chemistry-Recipes/Others.dm b/code/modules/reagents/Chemistry-Recipes/Others.dm
index b839ad05c4c..aa015604409 100644
--- a/code/modules/reagents/Chemistry-Recipes/Others.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Others.dm
@@ -12,6 +12,20 @@
result = "lube"
required_reagents = list("water" = 1, "silicon" = 1, "oxygen" = 1)
result_amount = 4
+
+/datum/chemical_reaction/spraytan
+ name = "Spray Tan"
+ id = "spraytan"
+ result = "spraytan"
+ required_reagents = list("orangejuice" = 1, "oil" = 1)
+ result_amount = 2
+
+/datum/chemical_reaction/spraytan2
+ name = "Spray Tan"
+ id = "spraytan"
+ result = "spraytan"
+ required_reagents = list("orangejuice" = 1, "cornoil" = 1)
+ result_amount = 2
/datum/chemical_reaction/impedrezene
name = "Impedrezene"
@@ -308,7 +322,7 @@
/datum/chemical_reaction/corgium/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
- new /mob/living/simple_animal/pet/corgi(location)
+ new /mob/living/simple_animal/pet/dog/corgi(location)
..()
/datum/chemical_reaction/hair_dye
diff --git a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
index 46f1d7a1e74..a0b76e0bad4 100644
--- a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
@@ -123,6 +123,23 @@
chemical_mob_spawn(holder, 1, "Lesser Gold Slime", "neutral")
+/datum/chemical_reaction/slimecritfriendly
+ name = "Slime Crit Friendly"
+ id = "m_tele5"
+ result = null
+ required_reagents = list("water" = 1)
+ result_amount = 1
+ required_container = /obj/item/slime_extract/gold
+ required_other = 1
+
+/datum/chemical_reaction/slimecritfriendly/on_reaction(datum/reagents/holder)
+ feedback_add_details("slime_cores_used","[replacetext(name," ","_")]")
+ for(var/mob/O in viewers(get_turf(holder.my_atom), null))
+ O.show_message(text("The slime extract begins to vibrate adorably !"), 1)
+ spawn(50)
+
+ chemical_mob_spawn(holder, 1, "Friendly Gold Slime", "neutral")
+
//Silver
/datum/chemical_reaction/slimebork
name = "Slime Bork"
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index b64d21f6c14..99f7e10089c 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -82,7 +82,7 @@
/obj/item/weapon/reagent_containers/throw_impact(atom/target)
. = ..()
- if(!reagents.total_volume || !spillable)
+ if(!reagents || !reagents.total_volume || !spillable)
return
if(ismob(target) && target.reagents)
@@ -91,10 +91,9 @@
var/R
target.visible_message("[M] has been splashed with something!", \
"[M] has been splashed with something!")
- if(reagents)
- for(var/datum/reagent/A in reagents.reagent_list)
- R += A.id + " ("
- R += num2text(A.volume) + "),"
+ for(var/datum/reagent/A in reagents.reagent_list)
+ R += A.id + " ("
+ R += num2text(A.volume) + "),"
if(thrownby)
add_logs(thrownby, M, "splashed", R)
diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm
index e85c1218e39..d636f818374 100644
--- a/code/modules/recycling/disposal-construction.dm
+++ b/code/modules/recycling/disposal-construction.dm
@@ -138,7 +138,7 @@
if(DISP_END_TRUNK)
return /obj/structure/disposalpipe/trunk
if(DISP_END_BIN)
- return /obj/machinery/disposal
+ return /obj/machinery/disposal/bin
if(DISP_END_OUTLET)
return /obj/structure/disposaloutlet
if(DISP_END_CHUTE)
@@ -240,9 +240,9 @@
SortP.updatedir()
else if(ptype == DISP_END_BIN)
- var/obj/machinery/disposal/P = new /obj/machinery/disposal(loc,src)
- P.mode = 0 // start with pump off
- transfer_fingerprints_to(P)
+ var/obj/machinery/disposal/bin/B = new /obj/machinery/disposal/bin(loc,src)
+ B.mode = 0 // start with pump off
+ transfer_fingerprints_to(B)
else if(ptype == DISP_END_OUTLET)
var/obj/structure/disposaloutlet/P = new /obj/structure/disposaloutlet(loc,src)
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal-structures.dm
similarity index 60%
rename from code/modules/recycling/disposal.dm
rename to code/modules/recycling/disposal-structures.dm
index 0ad17216e87..ca1364644be 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal-structures.dm
@@ -1,1335 +1,869 @@
-// Disposal bin
-// Holds items for disposal into pipe system
-// Draws air from turf, gradually charges internal reservoir
-// Once full (~1 atm), uses air resv to flush items into the pipes
-// Automatically recharges air (unless off), will flush when ready if pre-set
-// Can hold items and human size things, no other draggables
-// Toilets are a type of disposal bin for small objects only and work on magic. By magic, I mean torque rotation
-#define SEND_PRESSURE 0.05*ONE_ATMOSPHERE
-
-/obj/machinery/disposal
- name = "disposal unit"
- desc = "A pneumatic waste disposal unit."
- icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
- icon_state = "disposal"
- anchored = 1
- density = 1
- var/datum/gas_mixture/air_contents // internal reservoir
- var/mode = 1 // item mode 0=off 1=charging 2=charged
- var/flush = 0 // true if flush handle is pulled
- var/obj/structure/disposalpipe/trunk/trunk = null // the attached pipe trunk
- var/flushing = 0 // true if flushing in progress
- var/flush_every_ticks = 30 //Every 30 ticks it will look whether it is ready to flush
- var/flush_count = 0 //this var adds 1 once per tick. When it reaches flush_every_ticks it resets and tries to flush.
- var/last_sound = 0
- var/obj/structure/disposalconstruct/stored
- // create a new disposal
- // find the attached trunk (if present) and init gas resvr.
-/obj/machinery/disposal/New(loc, var/obj/structure/disposalconstruct/make_from)
- ..()
-
- if(make_from)
- dir = make_from.dir
- make_from.loc = 0
- stored = make_from
- else
- stored = new /obj/structure/disposalconstruct(0,DISP_END_BIN,dir)
-
- trunk_check()
-
- air_contents = new/datum/gas_mixture()
- //gas.volume = 1.05 * CELLSTANDARD
- update()
-
-/obj/machinery/disposal/proc/trunk_check()
- trunk = locate() in src.loc
- if(!trunk)
- mode = 0
- flush = 0
- else
- mode = initial(mode)
- flush = initial(flush)
- trunk.linked = src // link the pipe trunk to self
-
-/obj/machinery/disposal/Destroy()
- eject()
- if(trunk)
- trunk.linked = null
- ..()
-
-/obj/machinery/disposal/singularity_pull(S, current_size)
- if(current_size >= STAGE_FIVE)
- Deconstruct()
-
-/obj/machinery/disposal/initialize()
- // this will get a copy of the air turf and take a SEND PRESSURE amount of air from it
- var/atom/L = loc
- var/datum/gas_mixture/env = new
- env.copy_from(L.return_air())
- var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1)
- air_contents.merge(removed)
- trunk_check()
-
- // attack by item places it in to disposal
-/obj/machinery/disposal/attackby(obj/item/I, mob/user, params)
- if(stat & BROKEN || !I || !user)
- return
-
- src.add_fingerprint(user)
- if(mode<=0) // It's off
- if(istype(I, /obj/item/weapon/screwdriver))
- if(contents.len > 0)
- user << "Eject the items first!"
- return
- if(mode==0) // It's off but still not unscrewed
- mode=-1 // Set it to doubleoff l0l
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You remove the screws around the power connection."
- return
- else if(mode==-1)
- mode=0
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You attach the screws around the power connection."
- return
- else if(istype(I,/obj/item/weapon/weldingtool) && mode==-1)
- if(contents.len > 0)
- user << "Eject the items first!"
- return
- var/obj/item/weapon/weldingtool/W = I
- if(W.remove_fuel(0,user))
- playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
- user << "You start slicing the floorweld off \the [src]..."
-
- if(do_after(user,20, target = src))
- if(!src || !W.isOn()) return
- user << "You slice the floorweld off \the [src]."
- Deconstruct()
- return
- else
- return
-
- if(istype(I, /obj/item/weapon/storage/bag/trash))
- var/obj/item/weapon/storage/bag/trash/T = I
- user << "You empty the bag."
- for(var/obj/item/O in T.contents)
- T.remove_from_storage(O,src)
- T.update_icon()
- update()
- return
-
- var/obj/item/weapon/grab/G = I
- if(istype(G)) // handle grabbed mob
- if(ismob(G.affecting))
- stuff_mob_in(G.affecting, user)
- return
-
- if(!user.drop_item())
- return
-
- I.loc = src
- user.visible_message("[user.name] places \the [I] into \the [src].", \
- "You place \the [I] into \the [src].")
-
- update()
-
-// mouse drop another mob or self
-//
-/obj/machinery/disposal/MouseDrop_T(mob/living/target, mob/living/user)
- if(istype(target) && user == target)
- stuff_mob_in(target, user)
-
-/obj/machinery/disposal/proc/stuff_mob_in(mob/living/target, mob/living/user)
- if(!iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves.
- return
- if(target.mob_size > MOB_SIZE_HUMAN)
- user << "[target] doesn't fit inside [src]!"
- return
- src.add_fingerprint(user)
- if(user == target)
- user.visible_message("[user] starts climbing into [src].", \
- "You start climbing into [src]...")
- else
- target.visible_message("[user] starts putting [target] into [src].", \
- "[user] starts putting you into [src]!")
- if(do_mob(user, target, 20))
- if (!src.loc)
- return
- if (target.client)
- target.client.perspective = EYE_PERSPECTIVE
- target.client.eye = src
- target.loc = src
- if(user == target)
- user.visible_message("[user] climbs into [src].", \
- "You climb into [src].")
- else
- target.visible_message("[user] has placed [target] in [src].", \
- "[user] has placed [target] in [src].")
- add_logs(user, target, "stuffed", addition="into [src]")
- update()
-
-// can breath normally in the disposal
-/obj/machinery/disposal/alter_health()
- return get_turf(src)
-
-/obj/machinery/disposal/relaymove(mob/user)
- attempt_escape(user)
-
-// resist to escape the bin
-/obj/machinery/disposal/container_resist()
- attempt_escape(usr)
-
-/obj/machinery/disposal/proc/attempt_escape(mob/user)
- if(src.flushing)
- return
- go_out(user)
- return
-
-// leave the disposal
-/obj/machinery/disposal/proc/go_out(mob/user)
-
- if (user.client)
- user.client.eye = user.client.mob
- user.client.perspective = MOB_PERSPECTIVE
- user.loc = src.loc
- update()
- return
-
-
-// monkeys and xenos can only pull the flush lever
-/obj/machinery/disposal/attack_paw(mob/user)
- if(stat & BROKEN)
- return
- flush = !flush
- update()
-
-// ai as human but can't flush
-/obj/machinery/disposal/attack_ai(mob/user)
- interact(user, 1)
-
-// human interact with machine
-/obj/machinery/disposal/attack_hand(mob/user)
- if(user && user.loc == src)
- usr << "You cannot reach the controls from inside!"
- return
- /*
- if(mode==-1)
- usr << "\red The disposal units power is disabled."
- return
- */
- interact(user, 0)
-
-// hostile mob escape from disposals
-/obj/machinery/disposal/attack_animal(mob/living/simple_animal/M)
- if(M.environment_smash)
- M.do_attack_animation(src)
- visible_message("[M.name] smashes \the [src] apart!")
- qdel(src)
- return
-
-// user interaction
-/obj/machinery/disposal/interact(mob/user, ai=0)
-
- src.add_fingerprint(user)
- if(stat & BROKEN)
- user.unset_machine()
- return
-
- var/dat = "Waste Disposal UnitWaste Disposal Unit"
-
- if(!ai) // AI can't pull flush handle
- if(flush)
- dat += "Disposal handle: DisengageEngaged"
- else
- dat += "Disposal handle: DisengagedEngage"
-
- dat += " Eject contents"
-
- if(mode <= 0)
- dat += "Pump: OffOn "
- else if(mode == 1)
- dat += "Pump: OffOn (pressurizing) "
- else
- dat += "Pump: OffOn (idle) "
-
- var/per = Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
-
- dat += "Pressure: [round(per, 1)]% "
-
-
- user.set_machine(src)
- user << browse(dat, "window=disposal;size=360x170")
- onclose(user, "disposal")
-
-// handle machine interaction
-
-/obj/machinery/disposal/Topic(href, href_list)
- if(..())
- return
- if(usr.loc == src)
- usr << "You cannot reach the controls from inside!"
- return
-
- if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
- usr << "\The [src]'s power is disabled."
- return
- ..()
- usr.set_machine(src)
-
- if(href_list["close"])
- usr.unset_machine()
- usr << browse(null, "window=disposal")
- return
-
- if(href_list["pump"])
- if(text2num(href_list["pump"]))
- mode = 1
- else
- mode = 0
- update()
-
- if(href_list["handle"])
- flush = text2num(href_list["handle"])
- update()
-
- if(href_list["eject"])
- eject()
- return
-
-// eject the contents of the disposal unit
-/obj/machinery/disposal/proc/eject()
- for(var/atom/movable/AM in src)
- AM.loc = src.loc
- AM.pipe_eject(0)
- update()
-
-// update the icon & overlays to reflect mode & status
-/obj/machinery/disposal/proc/update()
- overlays.Cut()
- if(stat & BROKEN)
- icon_state = "disposal-broken"
- mode = 0
- flush = 0
- return
-
- // flush handle
- if(flush)
- overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-handle")
-
- // only handle is shown if no power
- if(stat & NOPOWER || mode == -1)
- return
-
- // check for items in disposal - occupied light
- if(contents.len > 0)
- overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-full")
-
- // charging and ready light
- if(mode == 1)
- overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-charge")
- else if(mode == 2)
- overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-ready")
-
-// timed process
-// charge the gas reservoir and perform flush if ready
-/obj/machinery/disposal/process()
- if(stat & BROKEN) // nothing can happen if broken
- return
-
- flush_count++
- if( flush_count >= flush_every_ticks )
- if( contents.len )
- if(mode == 2)
- spawn(0)
- feedback_inc("disposal_auto_flush",1)
- flush()
- flush_count = 0
-
- src.updateDialog()
-
- if(flush && air_contents.return_pressure() >= SEND_PRESSURE ) // flush can happen even without power
- spawn(0)
- flush()
-
- if(stat & NOPOWER) // won't charge if no power
- return
-
- use_power(100) // base power usage
-
- if(mode != 1) // if off or ready, no need to charge
- return
-
- // otherwise charge
- use_power(500) // charging power usage
-
- var/atom/L = loc // recharging from loc turf
-
- var/datum/gas_mixture/env = L.return_air()
- var/pressure_delta = (SEND_PRESSURE*1.01) - air_contents.return_pressure()
-
- if(env.temperature > 0)
- var/transfer_moles = 0.1 * pressure_delta*air_contents.volume/(env.temperature * R_IDEAL_GAS_EQUATION)
-
- //Actually transfer the gas
- var/datum/gas_mixture/removed = env.remove(transfer_moles)
- air_contents.merge(removed)
- air_update_turf()
-
-
- // if full enough, switch to ready mode
- if(air_contents.return_pressure() >= SEND_PRESSURE)
- mode = 2
- update()
- return
-
-/obj/machinery/disposal/proc/flush()
- flushing = 1
- flushAnimation()
- var/obj/structure/disposalholder/H = new()
- newHolderDestination(H)
- sleep(10)
- if(last_sound < world.time + 1)
- playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0)
- last_sound = world.time
- sleep(5)
- H.init(src)
- air_contents = new()
- H.start(src)
- flushing = 0
- flush = 0
- if(mode == 2)
- mode = 1
- update()
-
-/obj/machinery/disposal/proc/newHolderDestination(obj/structure/disposalholder/H)
- for(var/obj/item/smallDelivery/O in src)
- H.tomail = 1
- return
-
-/obj/machinery/disposal/proc/flushAnimation()
- flick("[icon_state]-flush", src)
-
-// called when area power changes
-/obj/machinery/disposal/power_change()
- ..() // do default setting/reset of stat NOPOWER bit
- update() // update icon
- return
-
-
-// called when holder is expelled from a disposal
-// should usually only occur if the pipe network is modified
-/obj/machinery/disposal/proc/expel(obj/structure/disposalholder/H)
-
- var/turf/target
- playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
- if(H) // Somehow, someone managed to flush a window which broke mid-transit and caused the disposal to go in an infinite loop trying to expel null, hopefully this fixes it
- for(var/atom/movable/AM in H)
- target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5))
-
- AM.loc = src.loc
- AM.pipe_eject(0)
- spawn(1)
- if(AM)
- AM.throw_at(target, 5, 1)
-
- H.vent_gas(loc)
- qdel(H)
-
-/obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height=0)
- if (istype(mover,/obj/item) && mover.throwing)
- var/obj/item/I = mover
- if(istype(I, /obj/item/projectile))
- return
- if(prob(75))
- I.loc = src
- visible_message("\the [I] lands in \the [src].")
- update()
- else
- visible_message("\the [I] bounces off of \the [src]'s rim!")
- return 0
- else
- return ..(mover, target, height)
-
-/obj/machinery/disposal/Deconstruct()
- if(stored)
- var/turf/T = loc
- stored.loc = T
- src.transfer_fingerprints_to(stored)
- stored.anchored = 0
- stored.density = 1
- stored.update()
- ..()
-
-//How disposal handles getting a storage dump from a storage object
-/obj/machinery/disposal/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
- for(var/obj/item/I in src_object)
- src_object.remove_from_storage(I, src)
- return 1
-
-// virtual disposal object
-// travels through pipes in lieu of actual items
-// contents will be items flushed by the disposal
-// this allows the gas flushed to be tracked
-
-/obj/structure/disposalholder
- invisibility = 101
- var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point
- var/active = 0 // true if the holder is moving, otherwise inactive
- dir = 0
- var/count = 1000 //*** can travel 1000 steps before going inactive (in case of loops)
- var/destinationTag = 0 // changes if contains a delivery container
- var/tomail = 0 //changes if contains wrapped package
- var/hasmob = 0 //If it contains a mob
-
-/obj/structure/disposalholder/Destroy()
- qdel(gas)
- active = 0
- ..()
-
- // initialize a holder from the contents of a disposal unit
-/obj/structure/disposalholder/proc/init(obj/machinery/disposal/D)
- gas = D.air_contents// transfer gas resv. into holder object
-
- //Check for any living mobs trigger hasmob.
- //hasmob effects whether the package goes to cargo or its tagged destination.
- for(var/mob/living/M in D)
- if(M && M.stat != DEAD)
- if(M.client)
- M.client.eye = src
- hasmob = 1
-
- //Checks 1 contents level deep. This means that players can be sent through disposals...
- //...but it should require a second person to open the package. (i.e. person inside a wrapped locker)
- for(var/obj/O in D)
- if(O.contents)
- for(var/mob/living/M in O.contents)
- if(M && M.stat != DEAD)
- if(M.client)
- M.client.eye = src
- hasmob = 1
-
- // now everything inside the disposal gets put into the holder
- // note AM since can contain mobs or objs
- for(var/atom/movable/AM in D)
- AM.loc = src
- if(istype(AM, /obj/structure/bigDelivery) && !hasmob)
- var/obj/structure/bigDelivery/T = AM
- src.destinationTag = T.sortTag
- if(istype(AM, /obj/item/smallDelivery) && !hasmob)
- var/obj/item/smallDelivery/T = AM
- src.destinationTag = T.sortTag
-
-
-// start the movement process
-// argument is the disposal unit the holder started in
-/obj/structure/disposalholder/proc/start(obj/machinery/disposal/D)
- if(!D.trunk)
- D.expel(src) // no trunk connected, so expel immediately
- return
-
- loc = D.trunk
- active = 1
- dir = DOWN
- spawn(1)
- move() // spawn off the movement process
-
- return
-
-// movement process, persists while holder is moving through pipes
-/obj/structure/disposalholder/proc/move()
- var/obj/structure/disposalpipe/last
- while(active)
- var/obj/structure/disposalpipe/curr = loc
- last = curr
- curr = curr.transfer(src)
- if(!curr && active)
- last.expel(src, loc, dir)
-
- sleep(1)
- if(!(count--))
- active = 0
- return
-
-// find the turf which should contain the next pipe
-/obj/structure/disposalholder/proc/nextloc()
- return get_step(loc,dir)
-
-// find a matching pipe on a turf
-/obj/structure/disposalholder/proc/findpipe(turf/T)
-
- if(!T)
- return null
-
- var/fdir = turn(dir, 180) // flip the movement direction
- for(var/obj/structure/disposalpipe/P in T)
- if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir
- return P
- // if no matching pipe, return null
- return null
-
-// merge two holder objects
-// used when a a holder meets a stuck holder
-/obj/structure/disposalholder/proc/merge(obj/structure/disposalholder/other)
- for(var/atom/movable/AM in other)
- AM.loc = src // move everything in other holder to this one
- if(ismob(AM))
- var/mob/M = AM
- if(M.client) // if a client mob, update eye to follow this holder
- M.client.eye = src
- qdel(other)
-
-
-// called when player tries to move while in a pipe
-/obj/structure/disposalholder/relaymove(mob/user)
- if (user.stat)
- return
- if (src.loc)
- for (var/mob/M in get_hearers_in_view(src.loc.loc))
- M.show_message("CLONG, clong!", 2)
- playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0)
-
-// called to vent all gas in holder to a location
-/obj/structure/disposalholder/proc/vent_gas(atom/location)
- if(location)
- location.assume_air(gas) // vent all gas to turf
- air_update_turf()
- return
-
-/obj/structure/disposalholder/allow_drop()
- return 1
-
-// Disposal pipes
-
-/obj/structure/disposalpipe
- icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
- name = "disposal pipe"
- desc = "An underfloor disposal pipe."
- anchored = 1
- density = 0
-
- level = 1 // underfloor only
- var/dpdir = 0 // bitmask of pipe directions
- dir = 0 // dir will contain dominant direction for junction pipes
- var/health = 10 // health points 0-10
- layer = 2.3 // slightly lower than wires and other pipes
- var/base_icon_state // initial icon state on map
- var/obj/structure/disposalconstruct/stored
-
- // new pipe, set the icon_state as on map
-/obj/structure/disposalpipe/New(loc,var/obj/structure/disposalconstruct/make_from)
- ..()
-
- if(make_from && !make_from.gc_destroyed)
- base_icon_state = make_from.base_state
- dir = make_from.dir
- dpdir = make_from.dpdir
- make_from.loc = src
- stored = make_from
- else
- base_icon_state = icon_state
- stored = new /obj/structure/disposalconstruct(src,direction=dir)
- switch(base_icon_state)
- if("pipe-s")
- stored.ptype = DISP_PIPE_STRAIGHT
- if("pipe-c")
- stored.ptype = DISP_PIPE_BENT
- if("pipe-j1")
- stored.ptype = DISP_JUNCTION
- if("pipe-j2")
- stored.ptype = DISP_JUNCTION_FLIP
- if("pipe-y")
- stored.ptype = DISP_YJUNCTION
- if("pipe-t")
- stored.ptype = DISP_END_TRUNK
- if("pipe-j1s")
- stored.ptype = DISP_SORTJUNCTION
- if("pipe-j2s")
- stored.ptype = DISP_SORTJUNCTION_FLIP
- return
-
-
- // pipe is deleted
- // ensure if holder is present, it is expelled
-/obj/structure/disposalpipe/Destroy()
- var/obj/structure/disposalholder/H = locate() in src
- if(H)
- // holder was present
- H.active = 0
- var/turf/T = src.loc
- if(T.density)
- // deleting pipe is inside a dense turf (wall)
- // this is unlikely, but just dump out everything into the turf in case
-
- for(var/atom/movable/AM in H)
- AM.loc = T
- AM.pipe_eject(0)
- qdel(H)
- ..()
- return
-
- // otherwise, do normal expel from turf
- if(H)
- expel(H, T, 0)
- ..()
-
-// returns the direction of the next pipe object, given the entrance dir
-// by default, returns the bitmask of remaining directions
-/obj/structure/disposalpipe/proc/nextdir(fromdir)
- return dpdir & (~turn(fromdir, 180))
-
-// transfer the holder through this pipe segment
-// overriden for special behaviour
-//
-/obj/structure/disposalpipe/proc/transfer(obj/structure/disposalholder/H)
- var/nextdir = nextdir(H.dir)
- H.dir = nextdir
- var/turf/T = H.nextloc()
- var/obj/structure/disposalpipe/P = H.findpipe(T)
-
- if(P)
- // find other holder in next loc, if inactive merge it with current
- var/obj/structure/disposalholder/H2 = locate() in P
- if(H2 && !H2.active)
- H.merge(H2)
-
- H.loc = P
- else // if wasn't a pipe, then set loc to turf
- H.loc = T
- return null
-
- return P
-
-
-// update the icon_state to reflect hidden status
-/obj/structure/disposalpipe/proc/update()
- var/turf/T = src.loc
- hide(T.intact && !istype(T,/turf/space)) // space never hides pipes
-
-// hide called by levelupdate if turf intact status changes
-// change visibility status and force update of icon
-/obj/structure/disposalpipe/hide(var/intact)
- invisibility = intact ? 101: 0 // hide if floor is intact
- updateicon()
-
-// update actual icon_state depending on visibility
-// if invisible, append "f" to icon_state to show faded version
-// this will be revealed if a T-scanner is used
-// if visible, use regular icon_state
-/obj/structure/disposalpipe/proc/updateicon()
- if(invisibility)
- icon_state = "[base_icon_state]f"
- else
- icon_state = base_icon_state
- return
-
-
-// expel the held objects into a turf
-// called when there is a break in the pipe
-//
-
-/obj/structure/disposalpipe/proc/expel(obj/structure/disposalholder/H, turf/T, direction)
-
- var/turf/target
-
- if(istype(T, /turf/simulated/floor)) //intact floor, pop the tile
- var/turf/simulated/floor/myturf = T
- if(myturf.builtin_tile)
- myturf.builtin_tile.loc = T
- myturf.builtin_tile = null
- myturf.make_plating()
-
- if(direction) // direction is specified
- if(istype(T, /turf/space)) // if ended in space, then range is unlimited
- target = get_edge_target_turf(T, direction)
- else // otherwise limit to 10 tiles
- target = get_ranged_target_turf(T, direction, 10)
-
- playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
- if(H)
- for(var/atom/movable/AM in H)
- AM.loc = T
- AM.pipe_eject(direction)
- spawn(1)
- if(AM)
- AM.throw_at(target, 100, 1)
-
- else // no specified direction, so throw in random direction
-
- playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
- if(H)
- for(var/atom/movable/AM in H)
- target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5))
-
- AM.loc = T
- AM.pipe_eject(0)
- spawn(1)
- if(AM)
- AM.throw_at(target, 5, 1)
- H.vent_gas(T)
- qdel(H)
- return
-
-// call to break the pipe
-// will expel any holder inside at the time
-// then delete the pipe
-// remains : set to leave broken pipe pieces in place
-/obj/structure/disposalpipe/proc/broken(remains = 0)
- if(remains)
- for(var/D in cardinal)
- if(D & dpdir)
- var/obj/structure/disposalpipe/broken/P = new(src.loc)
- P.dir = D
-
- src.invisibility = 101 // make invisible (since we won't delete the pipe immediately)
- var/obj/structure/disposalholder/H = locate() in src
- if(H)
- // holder was present
- H.active = 0
- var/turf/T = src.loc
- if(T.density)
- // broken pipe is inside a dense turf (wall)
- // this is unlikely, but just dump out everything into the turf in case
-
- for(var/atom/movable/AM in H)
- AM.loc = T
- AM.pipe_eject(0)
- qdel(H)
- return
-
- // otherwise, do normal expel from turf
- if(H)
- expel(H, T, 0)
-
- spawn(2) // delete pipe after 2 ticks to ensure expel proc finished
- qdel(src)
-
-
-// pipe affected by explosion
-/obj/structure/disposalpipe/ex_act(severity, target)
-
- //pass on ex_act to our contents before calling it on ourself
- var/obj/structure/disposalholder/H = locate() in src
- if(H)
- H.contents_explosion(severity, target)
-
- switch(severity)
- if(1.0)
- broken(0)
- return
- if(2.0)
- health -= rand(5,15)
- healthcheck()
- return
- if(3.0)
- health -= rand(0,15)
- healthcheck()
- return
-
-
-// test health for brokenness
-/obj/structure/disposalpipe/proc/healthcheck()
- if(health < -2)
- broken(0)
- else if(health<1)
- broken(1)
- return
-
-//attack by item
-//weldingtool: unfasten and convert to obj/disposalconstruct
-
-/obj/structure/disposalpipe/attackby(obj/item/I, mob/user, params)
-
- var/turf/T = src.loc
- if(T.intact)
- return // prevent interaction with T-scanner revealed pipes
- src.add_fingerprint(user)
- if(istype(I, /obj/item/weapon/weldingtool))
- var/obj/item/weapon/weldingtool/W = I
-
- if(W.remove_fuel(0,user))
- playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
- user << "You start slicing the disposal pipe..."
- // check if anything changed over 2 seconds
- if(do_after(user,30, target = src))
- if(!src || !W.isOn()) return
- Deconstruct()
- user << "You slice the disposal pipe."
- else
- return
-
-// called when pipe is cut with welder
-/obj/structure/disposalpipe/Deconstruct()
- if(stored)
- var/turf/T = loc
- stored.loc = T
- transfer_fingerprints_to(stored)
- stored.dir = dir
- stored.density = 0
- stored.anchored = 1
- stored.update()
- ..()
-
-/obj/structure/disposalpipe/singularity_pull(S, current_size)
- if(current_size >= STAGE_FIVE)
- Deconstruct()
-
-// *** TEST verb
-//client/verb/dispstop()
-// for(var/obj/structure/disposalholder/H in world)
-// H.active = 0
-
-// a straight or bent segment
-/obj/structure/disposalpipe/segment
- icon_state = "pipe-s"
-
-/obj/structure/disposalpipe/segment/New()
- ..()
- if(stored.ptype == DISP_PIPE_STRAIGHT)
- dpdir = dir | turn(dir, 180)
- else
- dpdir = dir | turn(dir, -90)
-
- update()
- return
-
-
-
-
-//a three-way junction with dir being the dominant direction
-/obj/structure/disposalpipe/junction
- icon_state = "pipe-j1"
-
-/obj/structure/disposalpipe/junction/New()
- ..()
- switch(stored.ptype)
- if(DISP_JUNCTION)
- dpdir = dir | turn(dir, -90) | turn(dir,180)
- if(DISP_JUNCTION_FLIP)
- dpdir = dir | turn(dir, 90) | turn(dir,180)
- if(DISP_YJUNCTION)
- dpdir = dir | turn(dir,90) | turn(dir, -90)
- update()
- return
-
-
-// next direction to move
-// if coming in from secondary dirs, then next is primary dir
-// if coming in from primary dir, then next is equal chance of other dirs
-
-/obj/structure/disposalpipe/junction/nextdir(fromdir)
- var/flipdir = turn(fromdir, 180)
- if(flipdir != dir) // came from secondary dir
- return dir // so exit through primary
- else // came from primary
- // so need to choose either secondary exit
- var/mask = ..(fromdir)
-
- // find a bit which is set
- var/setbit = 0
- if(mask & NORTH)
- setbit = NORTH
- else if(mask & SOUTH)
- setbit = SOUTH
- else if(mask & EAST)
- setbit = EAST
- else
- setbit = WEST
-
- if(prob(50)) // 50% chance to choose the found bit or the other one
- return setbit
- else
- return mask & (~setbit)
-
-//a three-way junction that sorts objects
-/obj/structure/disposalpipe/sortjunction
-
- icon_state = "pipe-j1s"
- var/sortType = 0 //Look at the list called TAGGERLOCATIONS in setup.dm
- var/posdir = 0
- var/negdir = 0
- var/sortdir = 0
-
-/obj/structure/disposalpipe/sortjunction/proc/updatedesc()
- desc = "An underfloor disposal pipe with a package sorting mechanism."
- if(sortType>0)
- var/tag = uppertext(TAGGERLOCATIONS[sortType])
- desc += "\nIt's tagged with [tag]"
-
-/obj/structure/disposalpipe/sortjunction/proc/updatedir()
- posdir = dir
- negdir = turn(posdir, 180)
-
- if(stored.ptype == DISP_SORTJUNCTION)
- sortdir = turn(posdir, -90)
- else
- icon_state = "pipe-j2s"
- sortdir = turn(posdir, 90)
-
- dpdir = sortdir | posdir | negdir
-
-/obj/structure/disposalpipe/sortjunction/New()
- ..()
- updatedir()
- updatedesc()
- update()
- return
-
-/obj/structure/disposalpipe/sortjunction/attackby(obj/item/I, mob/user, params)
- if(..())
- return
-
- if(istype(I, /obj/item/device/destTagger))
- var/obj/item/device/destTagger/O = I
-
- if(O.currTag > 0)// Tag set
- sortType = O.currTag
- playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1)
- var/tag = uppertext(TAGGERLOCATIONS[O.currTag])
- user << "Changed filter to [tag]."
- updatedesc()
-
-
-// next direction to move
-// if coming in from negdir, then next is primary dir or sortdir
-// if coming in from posdir, then flip around and go back to posdir
-// if coming in from sortdir, go to posdir
-
-/obj/structure/disposalpipe/sortjunction/nextdir(fromdir, sortTag)
- //var/flipdir = turn(fromdir, 180)
- if(fromdir != sortdir) // probably came from the negdir
-
- if(src.sortType == sortTag) //if destination matches filtered type...
- return sortdir // exit through sortdirection
- else
- return posdir
- else // came from sortdir
- // so go with the flow to positive direction
- return posdir
-
-/obj/structure/disposalpipe/sortjunction/transfer(obj/structure/disposalholder/H)
- var/nextdir = nextdir(H.dir, H.destinationTag)
- H.dir = nextdir
- var/turf/T = H.nextloc()
- var/obj/structure/disposalpipe/P = H.findpipe(T)
-
- if(P)
- // find other holder in next loc, if inactive merge it with current
- var/obj/structure/disposalholder/H2 = locate() in P
- if(H2 && !H2.active)
- H.merge(H2)
-
- H.loc = P
- else // if wasn't a pipe, then set loc to turf
- H.loc = T
- return null
-
- return P
-
-
-//a three-way junction that sorts objects destined for the mail office mail table (tomail = 1)
-/obj/structure/disposalpipe/wrapsortjunction
-
- desc = "An underfloor disposal pipe which sorts wrapped and unwrapped objects."
- icon_state = "pipe-j1s"
- var/posdir = 0
- var/negdir = 0
- var/sortdir = 0
-
-/obj/structure/disposalpipe/wrapsortjunction/New()
- ..()
- posdir = dir
- if(stored.ptype == DISP_SORTJUNCTION)
- sortdir = turn(posdir, -90)
- negdir = turn(posdir, 180)
- else
- icon_state = "pipe-j2s"
- sortdir = turn(posdir, 90)
- negdir = turn(posdir, 180)
- dpdir = sortdir | posdir | negdir
-
- update()
- return
-
-// next direction to move
-// if coming in from negdir, then next is primary dir or sortdir
-// if coming in from posdir, then flip around and go back to posdir
-// if coming in from sortdir, go to posdir
-
-/obj/structure/disposalpipe/wrapsortjunction/nextdir(fromdir, istomail)
- //var/flipdir = turn(fromdir, 180)
- if(fromdir != sortdir) // probably came from the negdir
-
- if(istomail) //if destination matches filtered type...
- return sortdir // exit through sortdirection
- else
- return posdir
- else // came from sortdir
- // so go with the flow to positive direction
- return posdir
-
-/obj/structure/disposalpipe/wrapsortjunction/transfer(obj/structure/disposalholder/H)
- var/nextdir = nextdir(H.dir, H.tomail)
- H.dir = nextdir
- var/turf/T = H.nextloc()
- var/obj/structure/disposalpipe/P = H.findpipe(T)
-
- if(P)
- // find other holder in next loc, if inactive merge it with current
- var/obj/structure/disposalholder/H2 = locate() in P
- if(H2 && !H2.active)
- H.merge(H2)
-
- H.loc = P
- else // if wasn't a pipe, then set loc to turf
- H.loc = T
- return null
-
- return P
-
-
-
-
-
-//a trunk joining to a disposal bin or outlet on the same turf
-/obj/structure/disposalpipe/trunk
- icon_state = "pipe-t"
- var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet
-
-/obj/structure/disposalpipe/trunk/New()
- ..()
- dpdir = dir
- spawn(1)
- getlinked()
-
- update()
- return
-
-/obj/structure/disposalpipe/trunk/proc/getlinked()
- linked = null
- var/obj/machinery/disposal/D = locate() in src.loc
- if(D)
- linked = D
- if (!D.trunk)
- D.trunk = src
-
- var/obj/structure/disposaloutlet/O = locate() in src.loc
- if(O)
- linked = O
-
- update()
- return
-
- // Override attackby so we disallow trunkremoval when somethings ontop
-/obj/structure/disposalpipe/trunk/attackby(obj/item/I, mob/user, params)
-
- //Disposal bins or chutes
- /*
- These shouldn't be required
- var/obj/machinery/disposal/D = locate() in src.loc
- if(D && D.anchored)
- return
-
- //Disposal outlet
- var/obj/structure/disposaloutlet/O = locate() in src.loc
- if(O && O.anchored)
- return
- */
-
- //Disposal constructors
- var/obj/structure/disposalconstruct/C = locate() in src.loc
- if(C && C.anchored)
- return
-
- var/turf/T = src.loc
- if(T.intact)
- return // prevent interaction with T-scanner revealed pipes
- src.add_fingerprint(user)
- if(istype(I, /obj/item/weapon/weldingtool))
- var/obj/item/weapon/weldingtool/W = I
-
- if(linked)
- user << "You need to deconstruct disposal machinery above this pipe!"
- return
-
- if(W.remove_fuel(0,user))
- playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
- user << "You start slicing the disposal pipe..."
- if(do_after(user,30, target = src))
- if(!src || !W.isOn()) return
- Deconstruct()
- user << "You slice the disposal pipe."
- else
- return
-
- // would transfer to next pipe segment, but we are in a trunk
- // if not entering from disposal bin,
- // transfer to linked object (outlet or bin)
-
-/obj/structure/disposalpipe/trunk/transfer(obj/structure/disposalholder/H)
-
- if(H.dir == DOWN) // we just entered from a disposer
- return ..() // so do base transfer proc
- // otherwise, go to the linked object
- if(linked)
- var/obj/structure/disposaloutlet/O = linked
- if(istype(O) && (H))
- O.expel(H) // expel at outlet
- else
- var/obj/machinery/disposal/D = linked
- if(H)
- D.expel(H) // expel at disposal
- else
- if(H)
- src.expel(H, src.loc, 0) // expel at turf
- return null
-
- // nextdir
-
-/obj/structure/disposalpipe/trunk/nextdir(fromdir)
- if(fromdir == DOWN)
- return dir
- else
- return 0
-
-// a broken pipe
-/obj/structure/disposalpipe/broken
- icon_state = "pipe-b"
- dpdir = 0 // broken pipes have dpdir=0 so they're not found as 'real' pipes
- // i.e. will be treated as an empty turf
- desc = "A broken piece of disposal pipe."
-
-/obj/structure/disposalpipe/broken/New()
- ..()
- update()
- return
-
-// the disposal outlet machine
-
-/obj/structure/disposalpipe/broken/Deconstruct()
- qdel(src)
-
-/obj/structure/disposaloutlet
- name = "disposal outlet"
- desc = "An outlet for the pneumatic disposal system."
- icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
- icon_state = "outlet"
- density = 1
- anchored = 1
- var/active = 0
- var/turf/target // this will be where the output objects are 'thrown' to.
- var/obj/structure/disposalpipe/trunk/trunk = null // the attached pipe trunk
- var/obj/structure/disposalconstruct/stored
- var/mode = 0
- var/start_eject = 0
- var/eject_range = 2
-
-/obj/structure/disposaloutlet/New(loc, var/obj/structure/disposalconstruct/make_from)
- ..()
-
- if(make_from)
- dir = make_from.dir
- make_from.loc = src
- stored = make_from
- else
- stored = new (src, DISP_END_OUTLET,dir)
-
- spawn(1)
- target = get_ranged_target_turf(src, dir, 10)
-
- trunk = locate() in src.loc
- if(trunk)
- trunk.linked = src // link the pipe trunk to self
-
-/obj/structure/disposaloutlet/Destroy()
- if(trunk)
- trunk.linked = null
- ..()
-
-// expel the contents of the holder object, then delete it
-// called when the holder exits the outlet
-/obj/structure/disposaloutlet/proc/expel(obj/structure/disposalholder/H)
-
- flick("outlet-open", src)
- if((start_eject + 30) < world.time)
- start_eject = world.time
- playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 0, 0)
- sleep(20)
- playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
- else
- sleep(20)
- if(H)
- for(var/atom/movable/AM in H)
- AM.loc = src.loc
- AM.pipe_eject(dir)
- spawn(5)
- if(AM)
- AM.throw_at(target, eject_range, 1)
- H.vent_gas(src.loc)
- qdel(H)
- return
-
-/obj/structure/disposaloutlet/attackby(obj/item/I, mob/user, params)
- if(!I || !user)
- return
- src.add_fingerprint(user)
- if(istype(I, /obj/item/weapon/screwdriver))
- if(mode==0)
- mode=1
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You remove the screws around the power connection."
- return
- else if(mode==1)
- mode=0
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You attach the screws around the power connection."
- return
- else if(istype(I,/obj/item/weapon/weldingtool) && mode==1)
- var/obj/item/weapon/weldingtool/W = I
- if(W.remove_fuel(0,user))
- playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
- user << "You start slicing the floorweld off \the [src]..."
- if(do_after(user,20, target = src))
- if(!src || !W.isOn()) return
- user << "You slice the floorweld off \the [src]."
- stored.loc = loc
- src.transfer_fingerprints_to(stored)
- stored.update()
- stored.anchored = 0
- stored.density = 1
- qdel(src)
- return
- else
- return
-
-
-
-// called when movable is expelled from a disposal pipe or outlet
-// by default does nothing, override for special behaviour
-
-/atom/movable/proc/pipe_eject(direction)
- return
-
-// check if mob has client, if so restore client view on eject
-/mob/pipe_eject(var/direction)
- if (src.client)
- src.client.perspective = MOB_PERSPECTIVE
- src.client.eye = src
-
- return
-
-/obj/effect/decal/cleanable/blood/gibs/pipe_eject(direction)
- var/list/dirs
- if(direction)
- dirs = list( direction, turn(direction, -45), turn(direction, 45))
- else
- dirs = alldirs.Copy()
-
- src.streak(dirs)
-
-/obj/effect/decal/cleanable/robot_debris/gib/pipe_eject(direction)
- var/list/dirs
- if(direction)
- dirs = list( direction, turn(direction, -45), turn(direction, 45))
- else
- dirs = alldirs.Copy()
-
- src.streak(dirs)
+
+// virtual disposal object
+// travels through pipes in lieu of actual items
+// contents will be items flushed by the disposal
+// this allows the gas flushed to be tracked
+
+/obj/structure/disposalholder
+ invisibility = 101
+ var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point
+ var/active = 0 // true if the holder is moving, otherwise inactive
+ dir = 0
+ var/count = 1000 //*** can travel 1000 steps before going inactive (in case of loops)
+ var/destinationTag = 0 // changes if contains a delivery container
+ var/tomail = 0 //changes if contains wrapped package
+ var/hasmob = 0 //If it contains a mob
+
+/obj/structure/disposalholder/Destroy()
+ qdel(gas)
+ active = 0
+ ..()
+
+ // initialize a holder from the contents of a disposal unit
+/obj/structure/disposalholder/proc/init(obj/machinery/disposal/D)
+ gas = D.air_contents// transfer gas resv. into holder object
+
+ //Check for any living mobs trigger hasmob.
+ //hasmob effects whether the package goes to cargo or its tagged destination.
+ for(var/mob/living/M in D)
+ if(M && M.stat != DEAD)
+ if(M.client)
+ M.client.eye = src
+ hasmob = 1
+
+ //Checks 1 contents level deep. This means that players can be sent through disposals...
+ //...but it should require a second person to open the package. (i.e. person inside a wrapped locker)
+ for(var/obj/O in D)
+ if(O.contents)
+ for(var/mob/living/M in O.contents)
+ if(M && M.stat != DEAD)
+ if(M.client)
+ M.client.eye = src
+ hasmob = 1
+
+ // now everything inside the disposal gets put into the holder
+ // note AM since can contain mobs or objs
+ for(var/atom/movable/AM in D)
+ AM.loc = src
+ if(istype(AM, /obj/structure/bigDelivery) && !hasmob)
+ var/obj/structure/bigDelivery/T = AM
+ src.destinationTag = T.sortTag
+ if(istype(AM, /obj/item/smallDelivery) && !hasmob)
+ var/obj/item/smallDelivery/T = AM
+ src.destinationTag = T.sortTag
+
+
+// start the movement process
+// argument is the disposal unit the holder started in
+/obj/structure/disposalholder/proc/start(obj/machinery/disposal/D)
+ if(!D.trunk)
+ D.expel(src) // no trunk connected, so expel immediately
+ return
+
+ loc = D.trunk
+ active = 1
+ dir = DOWN
+ spawn(1)
+ move() // spawn off the movement process
+
+ return
+
+// movement process, persists while holder is moving through pipes
+/obj/structure/disposalholder/proc/move()
+ var/obj/structure/disposalpipe/last
+ while(active)
+ var/obj/structure/disposalpipe/curr = loc
+ last = curr
+ curr = curr.transfer(src)
+ if(!curr && active)
+ last.expel(src, loc, dir)
+
+ sleep(1)
+ if(!(count--))
+ active = 0
+ return
+
+// find the turf which should contain the next pipe
+/obj/structure/disposalholder/proc/nextloc()
+ return get_step(loc,dir)
+
+// find a matching pipe on a turf
+/obj/structure/disposalholder/proc/findpipe(turf/T)
+
+ if(!T)
+ return null
+
+ var/fdir = turn(dir, 180) // flip the movement direction
+ for(var/obj/structure/disposalpipe/P in T)
+ if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir
+ return P
+ // if no matching pipe, return null
+ return null
+
+// merge two holder objects
+// used when a a holder meets a stuck holder
+/obj/structure/disposalholder/proc/merge(obj/structure/disposalholder/other)
+ for(var/atom/movable/AM in other)
+ AM.loc = src // move everything in other holder to this one
+ if(ismob(AM))
+ var/mob/M = AM
+ if(M.client) // if a client mob, update eye to follow this holder
+ M.client.eye = src
+ qdel(other)
+
+
+// called when player tries to move while in a pipe
+/obj/structure/disposalholder/relaymove(mob/user)
+ if (user.stat)
+ return
+ if (src.loc)
+ for (var/mob/M in get_hearers_in_view(src.loc.loc))
+ M.show_message("CLONG, clong!", 2)
+ playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0)
+
+// called to vent all gas in holder to a location
+/obj/structure/disposalholder/proc/vent_gas(atom/location)
+ if(location)
+ location.assume_air(gas) // vent all gas to turf
+ air_update_turf()
+ return
+
+/obj/structure/disposalholder/allow_drop()
+ return 1
+
+// Disposal pipes
+
+/obj/structure/disposalpipe
+ icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
+ name = "disposal pipe"
+ desc = "An underfloor disposal pipe."
+ anchored = 1
+ density = 0
+
+ level = 1 // underfloor only
+ var/dpdir = 0 // bitmask of pipe directions
+ dir = 0 // dir will contain dominant direction for junction pipes
+ var/health = 10 // health points 0-10
+ layer = 2.3 // slightly lower than wires and other pipes
+ var/base_icon_state // initial icon state on map
+ var/obj/structure/disposalconstruct/stored
+
+ // new pipe, set the icon_state as on map
+/obj/structure/disposalpipe/New(loc,var/obj/structure/disposalconstruct/make_from)
+ ..()
+
+ if(make_from && !make_from.gc_destroyed)
+ base_icon_state = make_from.base_state
+ dir = make_from.dir
+ dpdir = make_from.dpdir
+ make_from.loc = src
+ stored = make_from
+ else
+ base_icon_state = icon_state
+ stored = new /obj/structure/disposalconstruct(src,direction=dir)
+ switch(base_icon_state)
+ if("pipe-s")
+ stored.ptype = DISP_PIPE_STRAIGHT
+ if("pipe-c")
+ stored.ptype = DISP_PIPE_BENT
+ if("pipe-j1")
+ stored.ptype = DISP_JUNCTION
+ if("pipe-j2")
+ stored.ptype = DISP_JUNCTION_FLIP
+ if("pipe-y")
+ stored.ptype = DISP_YJUNCTION
+ if("pipe-t")
+ stored.ptype = DISP_END_TRUNK
+ if("pipe-j1s")
+ stored.ptype = DISP_SORTJUNCTION
+ if("pipe-j2s")
+ stored.ptype = DISP_SORTJUNCTION_FLIP
+ return
+
+
+ // pipe is deleted
+ // ensure if holder is present, it is expelled
+/obj/structure/disposalpipe/Destroy()
+ var/obj/structure/disposalholder/H = locate() in src
+ if(H)
+ // holder was present
+ H.active = 0
+ var/turf/T = src.loc
+ if(T.density)
+ // deleting pipe is inside a dense turf (wall)
+ // this is unlikely, but just dump out everything into the turf in case
+
+ for(var/atom/movable/AM in H)
+ AM.loc = T
+ AM.pipe_eject(0)
+ qdel(H)
+ ..()
+ return
+
+ // otherwise, do normal expel from turf
+ if(H)
+ expel(H, T, 0)
+ ..()
+
+// returns the direction of the next pipe object, given the entrance dir
+// by default, returns the bitmask of remaining directions
+/obj/structure/disposalpipe/proc/nextdir(fromdir)
+ return dpdir & (~turn(fromdir, 180))
+
+// transfer the holder through this pipe segment
+// overriden for special behaviour
+//
+/obj/structure/disposalpipe/proc/transfer(obj/structure/disposalholder/H)
+ var/nextdir = nextdir(H.dir)
+ H.dir = nextdir
+ var/turf/T = H.nextloc()
+ var/obj/structure/disposalpipe/P = H.findpipe(T)
+
+ if(P)
+ // find other holder in next loc, if inactive merge it with current
+ var/obj/structure/disposalholder/H2 = locate() in P
+ if(H2 && !H2.active)
+ H.merge(H2)
+
+ H.loc = P
+ else // if wasn't a pipe, then set loc to turf
+ H.loc = T
+ return null
+
+ return P
+
+
+// update the icon_state to reflect hidden status
+/obj/structure/disposalpipe/proc/update()
+ var/turf/T = src.loc
+ hide(T.intact && !istype(T,/turf/space)) // space never hides pipes
+
+// hide called by levelupdate if turf intact status changes
+// change visibility status and force update of icon
+/obj/structure/disposalpipe/hide(var/intact)
+ invisibility = intact ? 101: 0 // hide if floor is intact
+ updateicon()
+
+// update actual icon_state depending on visibility
+// if invisible, append "f" to icon_state to show faded version
+// this will be revealed if a T-scanner is used
+// if visible, use regular icon_state
+/obj/structure/disposalpipe/proc/updateicon()
+ if(invisibility)
+ icon_state = "[base_icon_state]f"
+ else
+ icon_state = base_icon_state
+ return
+
+
+// expel the held objects into a turf
+// called when there is a break in the pipe
+//
+
+/obj/structure/disposalpipe/proc/expel(obj/structure/disposalholder/H, turf/T, direction)
+
+ var/turf/target
+
+ if(istype(T, /turf/simulated/floor)) //intact floor, pop the tile
+ var/turf/simulated/floor/myturf = T
+ if(myturf.builtin_tile)
+ myturf.builtin_tile.loc = T
+ myturf.builtin_tile = null
+ myturf.make_plating()
+
+ if(direction) // direction is specified
+ if(istype(T, /turf/space)) // if ended in space, then range is unlimited
+ target = get_edge_target_turf(T, direction)
+ else // otherwise limit to 10 tiles
+ target = get_ranged_target_turf(T, direction, 10)
+
+ playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
+ if(H)
+ for(var/atom/movable/AM in H)
+ AM.loc = T
+ AM.pipe_eject(direction)
+ spawn(1)
+ if(AM)
+ AM.throw_at(target, 10, 1)
+
+ else // no specified direction, so throw in random direction
+
+ playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
+ if(H)
+ for(var/atom/movable/AM in H)
+ target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5))
+
+ AM.loc = T
+ AM.pipe_eject(0)
+ spawn(1)
+ if(AM)
+ AM.throw_at(target, 5, 1)
+ H.vent_gas(T)
+ qdel(H)
+ return
+
+// call to break the pipe
+// will expel any holder inside at the time
+// then delete the pipe
+// remains : set to leave broken pipe pieces in place
+/obj/structure/disposalpipe/proc/broken(remains = 0)
+ if(remains)
+ for(var/D in cardinal)
+ if(D & dpdir)
+ var/obj/structure/disposalpipe/broken/P = new(src.loc)
+ P.dir = D
+
+ src.invisibility = 101 // make invisible (since we won't delete the pipe immediately)
+ var/obj/structure/disposalholder/H = locate() in src
+ if(H)
+ // holder was present
+ H.active = 0
+ var/turf/T = src.loc
+ if(T.density)
+ // broken pipe is inside a dense turf (wall)
+ // this is unlikely, but just dump out everything into the turf in case
+
+ for(var/atom/movable/AM in H)
+ AM.loc = T
+ AM.pipe_eject(0)
+ qdel(H)
+ return
+
+ // otherwise, do normal expel from turf
+ if(H)
+ expel(H, T, 0)
+
+ spawn(2) // delete pipe after 2 ticks to ensure expel proc finished
+ qdel(src)
+
+
+// pipe affected by explosion
+/obj/structure/disposalpipe/ex_act(severity, target)
+
+ //pass on ex_act to our contents before calling it on ourself
+ var/obj/structure/disposalholder/H = locate() in src
+ if(H)
+ H.contents_explosion(severity, target)
+
+ switch(severity)
+ if(1.0)
+ broken(0)
+ return
+ if(2.0)
+ health -= rand(5,15)
+ healthcheck()
+ return
+ if(3.0)
+ health -= rand(0,15)
+ healthcheck()
+ return
+
+
+// test health for brokenness
+/obj/structure/disposalpipe/proc/healthcheck()
+ if(health < -2)
+ broken(0)
+ else if(health<1)
+ broken(1)
+ return
+
+//attack by item
+//weldingtool: unfasten and convert to obj/disposalconstruct
+
+/obj/structure/disposalpipe/attackby(obj/item/I, mob/user, params)
+
+ var/turf/T = src.loc
+ if(T.intact)
+ return // prevent interaction with T-scanner revealed pipes
+ src.add_fingerprint(user)
+ if(istype(I, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/W = I
+
+ if(W.remove_fuel(0,user))
+ playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
+ user << "You start slicing the disposal pipe..."
+ // check if anything changed over 2 seconds
+ if(do_after(user,30, target = src))
+ if(!src || !W.isOn()) return
+ Deconstruct()
+ user << "You slice the disposal pipe."
+ else
+ return
+
+// called when pipe is cut with welder
+/obj/structure/disposalpipe/Deconstruct()
+ if(stored)
+ var/turf/T = loc
+ stored.loc = T
+ transfer_fingerprints_to(stored)
+ stored.dir = dir
+ stored.density = 0
+ stored.anchored = 1
+ stored.update()
+ ..()
+
+/obj/structure/disposalpipe/singularity_pull(S, current_size)
+ if(current_size >= STAGE_FIVE)
+ Deconstruct()
+
+// *** TEST verb
+//client/verb/dispstop()
+// for(var/obj/structure/disposalholder/H in world)
+// H.active = 0
+
+// a straight or bent segment
+/obj/structure/disposalpipe/segment
+ icon_state = "pipe-s"
+
+/obj/structure/disposalpipe/segment/New()
+ ..()
+ if(stored.ptype == DISP_PIPE_STRAIGHT)
+ dpdir = dir | turn(dir, 180)
+ else
+ dpdir = dir | turn(dir, -90)
+
+ update()
+ return
+
+
+
+
+//a three-way junction with dir being the dominant direction
+/obj/structure/disposalpipe/junction
+ icon_state = "pipe-j1"
+
+/obj/structure/disposalpipe/junction/New()
+ ..()
+ switch(stored.ptype)
+ if(DISP_JUNCTION)
+ dpdir = dir | turn(dir, -90) | turn(dir,180)
+ if(DISP_JUNCTION_FLIP)
+ dpdir = dir | turn(dir, 90) | turn(dir,180)
+ if(DISP_YJUNCTION)
+ dpdir = dir | turn(dir,90) | turn(dir, -90)
+ update()
+ return
+
+
+// next direction to move
+// if coming in from secondary dirs, then next is primary dir
+// if coming in from primary dir, then next is equal chance of other dirs
+
+/obj/structure/disposalpipe/junction/nextdir(fromdir)
+ var/flipdir = turn(fromdir, 180)
+ if(flipdir != dir) // came from secondary dir
+ return dir // so exit through primary
+ else // came from primary
+ // so need to choose either secondary exit
+ var/mask = ..(fromdir)
+
+ // find a bit which is set
+ var/setbit = 0
+ if(mask & NORTH)
+ setbit = NORTH
+ else if(mask & SOUTH)
+ setbit = SOUTH
+ else if(mask & EAST)
+ setbit = EAST
+ else
+ setbit = WEST
+
+ if(prob(50)) // 50% chance to choose the found bit or the other one
+ return setbit
+ else
+ return mask & (~setbit)
+
+//a three-way junction that sorts objects
+/obj/structure/disposalpipe/sortjunction
+
+ icon_state = "pipe-j1s"
+ var/sortType = 0 //Look at the list called TAGGERLOCATIONS in setup.dm
+ var/posdir = 0
+ var/negdir = 0
+ var/sortdir = 0
+
+/obj/structure/disposalpipe/sortjunction/proc/updatedesc()
+ desc = "An underfloor disposal pipe with a package sorting mechanism."
+ if(sortType>0)
+ var/tag = uppertext(TAGGERLOCATIONS[sortType])
+ desc += "\nIt's tagged with [tag]"
+
+/obj/structure/disposalpipe/sortjunction/proc/updatedir()
+ posdir = dir
+ negdir = turn(posdir, 180)
+
+ if(stored.ptype == DISP_SORTJUNCTION)
+ sortdir = turn(posdir, -90)
+ else
+ icon_state = "pipe-j2s"
+ sortdir = turn(posdir, 90)
+
+ dpdir = sortdir | posdir | negdir
+
+/obj/structure/disposalpipe/sortjunction/New()
+ ..()
+ updatedir()
+ updatedesc()
+ update()
+ return
+
+/obj/structure/disposalpipe/sortjunction/attackby(obj/item/I, mob/user, params)
+ if(..())
+ return
+
+ if(istype(I, /obj/item/device/destTagger))
+ var/obj/item/device/destTagger/O = I
+
+ if(O.currTag > 0)// Tag set
+ sortType = O.currTag
+ playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1)
+ var/tag = uppertext(TAGGERLOCATIONS[O.currTag])
+ user << "Changed filter to [tag]."
+ updatedesc()
+
+
+// next direction to move
+// if coming in from negdir, then next is primary dir or sortdir
+// if coming in from posdir, then flip around and go back to posdir
+// if coming in from sortdir, go to posdir
+
+/obj/structure/disposalpipe/sortjunction/nextdir(fromdir, sortTag)
+ //var/flipdir = turn(fromdir, 180)
+ if(fromdir != sortdir) // probably came from the negdir
+
+ if(src.sortType == sortTag) //if destination matches filtered type...
+ return sortdir // exit through sortdirection
+ else
+ return posdir
+ else // came from sortdir
+ // so go with the flow to positive direction
+ return posdir
+
+/obj/structure/disposalpipe/sortjunction/transfer(obj/structure/disposalholder/H)
+ var/nextdir = nextdir(H.dir, H.destinationTag)
+ H.dir = nextdir
+ var/turf/T = H.nextloc()
+ var/obj/structure/disposalpipe/P = H.findpipe(T)
+
+ if(P)
+ // find other holder in next loc, if inactive merge it with current
+ var/obj/structure/disposalholder/H2 = locate() in P
+ if(H2 && !H2.active)
+ H.merge(H2)
+
+ H.loc = P
+ else // if wasn't a pipe, then set loc to turf
+ H.loc = T
+ return null
+
+ return P
+
+
+//a three-way junction that sorts objects destined for the mail office mail table (tomail = 1)
+/obj/structure/disposalpipe/wrapsortjunction
+
+ desc = "An underfloor disposal pipe which sorts wrapped and unwrapped objects."
+ icon_state = "pipe-j1s"
+ var/posdir = 0
+ var/negdir = 0
+ var/sortdir = 0
+
+/obj/structure/disposalpipe/wrapsortjunction/New()
+ ..()
+ posdir = dir
+ if(stored.ptype == DISP_SORTJUNCTION)
+ sortdir = turn(posdir, -90)
+ negdir = turn(posdir, 180)
+ else
+ icon_state = "pipe-j2s"
+ sortdir = turn(posdir, 90)
+ negdir = turn(posdir, 180)
+ dpdir = sortdir | posdir | negdir
+
+ update()
+ return
+
+// next direction to move
+// if coming in from negdir, then next is primary dir or sortdir
+// if coming in from posdir, then flip around and go back to posdir
+// if coming in from sortdir, go to posdir
+
+/obj/structure/disposalpipe/wrapsortjunction/nextdir(fromdir, istomail)
+ //var/flipdir = turn(fromdir, 180)
+ if(fromdir != sortdir) // probably came from the negdir
+
+ if(istomail) //if destination matches filtered type...
+ return sortdir // exit through sortdirection
+ else
+ return posdir
+ else // came from sortdir
+ // so go with the flow to positive direction
+ return posdir
+
+/obj/structure/disposalpipe/wrapsortjunction/transfer(obj/structure/disposalholder/H)
+ var/nextdir = nextdir(H.dir, H.tomail)
+ H.dir = nextdir
+ var/turf/T = H.nextloc()
+ var/obj/structure/disposalpipe/P = H.findpipe(T)
+
+ if(P)
+ // find other holder in next loc, if inactive merge it with current
+ var/obj/structure/disposalholder/H2 = locate() in P
+ if(H2 && !H2.active)
+ H.merge(H2)
+
+ H.loc = P
+ else // if wasn't a pipe, then set loc to turf
+ H.loc = T
+ return null
+
+ return P
+
+
+
+
+
+//a trunk joining to a disposal bin or outlet on the same turf
+/obj/structure/disposalpipe/trunk
+ icon_state = "pipe-t"
+ var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet
+
+/obj/structure/disposalpipe/trunk/New()
+ ..()
+ dpdir = dir
+ spawn(1)
+ getlinked()
+
+ update()
+ return
+
+/obj/structure/disposalpipe/trunk/proc/getlinked()
+ linked = null
+ var/obj/machinery/disposal/D = locate() in src.loc
+ if(D)
+ linked = D
+ if (!D.trunk)
+ D.trunk = src
+
+ var/obj/structure/disposaloutlet/O = locate() in src.loc
+ if(O)
+ linked = O
+
+ update()
+ return
+
+ // Override attackby so we disallow trunkremoval when somethings ontop
+/obj/structure/disposalpipe/trunk/attackby(obj/item/I, mob/user, params)
+
+ //Disposal bins or chutes
+ /*
+ These shouldn't be required
+ var/obj/machinery/disposal/D = locate() in src.loc
+ if(D && D.anchored)
+ return
+
+ //Disposal outlet
+ var/obj/structure/disposaloutlet/O = locate() in src.loc
+ if(O && O.anchored)
+ return
+ */
+
+ //Disposal constructors
+ var/obj/structure/disposalconstruct/C = locate() in src.loc
+ if(C && C.anchored)
+ return
+
+ var/turf/T = src.loc
+ if(T.intact)
+ return // prevent interaction with T-scanner revealed pipes
+ src.add_fingerprint(user)
+ if(istype(I, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/W = I
+
+ if(linked)
+ user << "You need to deconstruct disposal machinery above this pipe!"
+ return
+
+ if(W.remove_fuel(0,user))
+ playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
+ user << "You start slicing the disposal pipe..."
+ if(do_after(user,30, target = src))
+ if(!src || !W.isOn()) return
+ Deconstruct()
+ user << "You slice the disposal pipe."
+ else
+ return
+
+ // would transfer to next pipe segment, but we are in a trunk
+ // if not entering from disposal bin,
+ // transfer to linked object (outlet or bin)
+
+/obj/structure/disposalpipe/trunk/transfer(obj/structure/disposalholder/H)
+
+ if(H.dir == DOWN) // we just entered from a disposer
+ return ..() // so do base transfer proc
+ // otherwise, go to the linked object
+ if(linked)
+ var/obj/structure/disposaloutlet/O = linked
+ if(istype(O) && (H))
+ O.expel(H) // expel at outlet
+ else
+ var/obj/machinery/disposal/D = linked
+ if(H)
+ D.expel(H) // expel at disposal
+ else
+ if(H)
+ src.expel(H, src.loc, 0) // expel at turf
+ return null
+
+ // nextdir
+
+/obj/structure/disposalpipe/trunk/nextdir(fromdir)
+ if(fromdir == DOWN)
+ return dir
+ else
+ return 0
+
+// a broken pipe
+/obj/structure/disposalpipe/broken
+ icon_state = "pipe-b"
+ dpdir = 0 // broken pipes have dpdir=0 so they're not found as 'real' pipes
+ // i.e. will be treated as an empty turf
+ desc = "A broken piece of disposal pipe."
+
+/obj/structure/disposalpipe/broken/New()
+ ..()
+ update()
+ return
+
+// the disposal outlet machine
+
+/obj/structure/disposalpipe/broken/Deconstruct()
+ qdel(src)
+
+/obj/structure/disposaloutlet
+ name = "disposal outlet"
+ desc = "An outlet for the pneumatic disposal system."
+ icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
+ icon_state = "outlet"
+ density = 1
+ anchored = 1
+ var/active = 0
+ var/turf/target // this will be where the output objects are 'thrown' to.
+ var/obj/structure/disposalpipe/trunk/trunk = null // the attached pipe trunk
+ var/obj/structure/disposalconstruct/stored
+ var/mode = 0
+ var/start_eject = 0
+ var/eject_range = 2
+
+/obj/structure/disposaloutlet/New(loc, var/obj/structure/disposalconstruct/make_from)
+ ..()
+
+ if(make_from)
+ dir = make_from.dir
+ make_from.loc = src
+ stored = make_from
+ else
+ stored = new (src, DISP_END_OUTLET,dir)
+
+ spawn(1)
+ target = get_ranged_target_turf(src, dir, 10)
+
+ trunk = locate() in src.loc
+ if(trunk)
+ trunk.linked = src // link the pipe trunk to self
+
+/obj/structure/disposaloutlet/Destroy()
+ if(trunk)
+ trunk.linked = null
+ ..()
+
+// expel the contents of the holder object, then delete it
+// called when the holder exits the outlet
+/obj/structure/disposaloutlet/proc/expel(obj/structure/disposalholder/H)
+
+ flick("outlet-open", src)
+ if((start_eject + 30) < world.time)
+ start_eject = world.time
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 0, 0)
+ sleep(20)
+ playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
+ else
+ sleep(20)
+ if(H)
+ for(var/atom/movable/AM in H)
+ AM.loc = src.loc
+ AM.pipe_eject(dir)
+ spawn(5)
+ if(AM)
+ AM.throw_at(target, eject_range, 1)
+ H.vent_gas(src.loc)
+ qdel(H)
+ return
+
+/obj/structure/disposaloutlet/attackby(obj/item/I, mob/user, params)
+ if(!I || !user)
+ return
+ src.add_fingerprint(user)
+ if(istype(I, /obj/item/weapon/screwdriver))
+ if(mode==0)
+ mode=1
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You remove the screws around the power connection."
+ return
+ else if(mode==1)
+ mode=0
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You attach the screws around the power connection."
+ return
+ else if(istype(I,/obj/item/weapon/weldingtool) && mode==1)
+ var/obj/item/weapon/weldingtool/W = I
+ if(W.remove_fuel(0,user))
+ playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
+ user << "You start slicing the floorweld off \the [src]..."
+ if(do_after(user,20, target = src))
+ if(!src || !W.isOn()) return
+ user << "You slice the floorweld off \the [src]."
+ stored.loc = loc
+ src.transfer_fingerprints_to(stored)
+ stored.update()
+ stored.anchored = 0
+ stored.density = 1
+ qdel(src)
+ return
+ else
+ return
+
+
+
+// called when movable is expelled from a disposal pipe or outlet
+// by default does nothing, override for special behaviour
+
+/atom/movable/proc/pipe_eject(direction)
+ return
+
+// check if mob has client, if so restore client view on eject
+/mob/pipe_eject(var/direction)
+ if (src.client)
+ src.client.perspective = MOB_PERSPECTIVE
+ src.client.eye = src
+
+ return
+
+/obj/effect/decal/cleanable/blood/gibs/pipe_eject(direction)
+ var/list/dirs
+ if(direction)
+ dirs = list( direction, turn(direction, -45), turn(direction, 45))
+ else
+ dirs = alldirs.Copy()
+
+ src.streak(dirs)
+
+/obj/effect/decal/cleanable/robot_debris/gib/pipe_eject(direction)
+ var/list/dirs
+ if(direction)
+ dirs = list( direction, turn(direction, -45), turn(direction, 45))
+ else
+ dirs = alldirs.Copy()
+
+ src.streak(dirs)
diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal-unit.dm
new file mode 100644
index 00000000000..a348aa86165
--- /dev/null
+++ b/code/modules/recycling/disposal-unit.dm
@@ -0,0 +1,540 @@
+
+//disposal bin and Delivery chute.
+
+#define SEND_PRESSURE 0.05*ONE_ATMOSPHERE
+
+/obj/machinery/disposal
+ icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
+ anchored = 1
+ density = 1
+ var/datum/gas_mixture/air_contents // internal reservoir
+ var/mode = 1 // mode -1=screws removed 0=off 1=charging 2=charged
+ var/flush = 0 // true if flush handle is pulled
+ var/obj/structure/disposalpipe/trunk/trunk = null // the attached pipe trunk
+ var/flushing = 0 // true if flushing in progress
+ var/flush_every_ticks = 30 //Every 30 ticks it will look whether it is ready to flush
+ var/flush_count = 0 //this var adds 1 once per tick. When it reaches flush_every_ticks it resets and tries to flush.
+ var/last_sound = 0
+ var/obj/structure/disposalconstruct/stored
+ // create a new disposal
+ // find the attached trunk (if present) and init gas resvr.
+
+/obj/machinery/disposal/New(loc, var/obj/structure/disposalconstruct/make_from)
+ ..()
+
+ if(make_from)
+ dir = make_from.dir
+ make_from.loc = 0
+ stored = make_from
+ else
+ stored = new /obj/structure/disposalconstruct(0,DISP_END_BIN,dir)
+
+ trunk_check()
+
+ air_contents = new/datum/gas_mixture()
+ //gas.volume = 1.05 * CELLSTANDARD
+ update()
+
+/obj/machinery/disposal/proc/trunk_check()
+ trunk = locate() in src.loc
+ if(!trunk)
+ mode = 0
+ flush = 0
+ else
+ mode = initial(mode)
+ flush = initial(flush)
+ trunk.linked = src // link the pipe trunk to self
+
+/obj/machinery/disposal/Destroy()
+ eject()
+ if(trunk)
+ trunk.linked = null
+ ..()
+
+/obj/machinery/disposal/singularity_pull(S, current_size)
+ if(current_size >= STAGE_FIVE)
+ Deconstruct()
+
+/obj/machinery/disposal/initialize()
+ // this will get a copy of the air turf and take a SEND PRESSURE amount of air from it
+ var/atom/L = loc
+ var/datum/gas_mixture/env = new
+ env.copy_from(L.return_air())
+ var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1)
+ air_contents.merge(removed)
+ trunk_check()
+
+/obj/machinery/disposal/attackby(obj/item/I, mob/user, params)
+ if(stat & BROKEN || !I || !user)
+ return
+
+ add_fingerprint(user)
+ if(mode<=0) // It's off
+ if(istype(I, /obj/item/weapon/screwdriver))
+ if(contents.len > 0)
+ user << "Eject the items first!"
+ return
+ if(mode==0)
+ mode=-1
+ else
+ mode=0
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You [mode==0?"attach":"remove"] the screws around the power connection."
+ return
+ else if(istype(I,/obj/item/weapon/weldingtool) && mode==-1)
+ var/obj/item/weapon/weldingtool/W = I
+ if(W.remove_fuel(0,user))
+ if(contents.len > 0)
+ user << "Eject the items first!"
+ return
+ playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
+ user << "You start slicing the floorweld off \the [src]..."
+ if(do_after(user,20, target = src))
+ if(!W.isOn())
+ return
+ user << "You slice the floorweld off \the [src]."
+ Deconstruct()
+ return
+ return 1
+
+// mouse drop another mob or self
+//
+/obj/machinery/disposal/MouseDrop_T(mob/living/target, mob/living/user)
+ if(istype(target) && user == target)
+ stuff_mob_in(target, user)
+
+/obj/machinery/disposal/proc/stuff_mob_in(mob/living/target, mob/living/user)
+ if(!iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves.
+ return
+ if(target.buckled)
+ return
+ if(target.mob_size > MOB_SIZE_HUMAN)
+ user << "[target] doesn't fit inside [src]!"
+ return
+ add_fingerprint(user)
+ if(user == target)
+ user.visible_message("[user] starts climbing into [src].", \
+ "You start climbing into [src]...")
+ else
+ target.visible_message("[user] starts putting [target] into [src].", \
+ "[user] starts putting you into [src]!")
+ if(do_mob(user, target, 20))
+ if (!loc)
+ return
+ if (target.client)
+ target.client.perspective = EYE_PERSPECTIVE
+ target.client.eye = src
+ target.loc = src
+ if(user == target)
+ user.visible_message("[user] climbs into [src].", \
+ "You climb into [src].")
+ else
+ target.visible_message("[user] has placed [target] in [src].", \
+ "[user] has placed [target] in [src].")
+ add_logs(user, target, "stuffed", addition="into [src]")
+ update()
+
+// can breath normally in the disposal
+/obj/machinery/disposal/alter_health()
+ return get_turf(src)
+
+/obj/machinery/disposal/relaymove(mob/user)
+ attempt_escape(user)
+
+// resist to escape the bin
+/obj/machinery/disposal/container_resist()
+ attempt_escape(usr)
+
+/obj/machinery/disposal/proc/attempt_escape(mob/user)
+ if(src.flushing)
+ return
+ go_out(user)
+ return
+
+// leave the disposal
+/obj/machinery/disposal/proc/go_out(mob/user)
+
+ if (user.client)
+ user.client.eye = user.client.mob
+ user.client.perspective = MOB_PERSPECTIVE
+ user.loc = src.loc
+ update()
+ return
+
+
+// monkeys and xenos can only pull the flush lever
+/obj/machinery/disposal/attack_paw(mob/user)
+ if(stat & BROKEN)
+ return
+ flush = !flush
+ update()
+
+// ai as human but can't flush
+/obj/machinery/disposal/attack_ai(mob/user)
+ interact(user, 1)
+
+// human interact with machine
+/obj/machinery/disposal/attack_hand(mob/user)
+ if(user && user.loc == src)
+ usr << "You cannot reach the controls from inside!"
+ return
+ /*
+ if(mode==-1)
+ usr << "\red The disposal units power is disabled."
+ return
+ */
+ interact(user, 0)
+
+// hostile mob escape from disposals
+/obj/machinery/disposal/attack_animal(mob/living/simple_animal/M)
+ if(M.environment_smash)
+ M.do_attack_animation(src)
+ visible_message("[M.name] smashes \the [src] apart!")
+ qdel(src)
+ return
+
+// eject the contents of the disposal unit
+/obj/machinery/disposal/proc/eject()
+ for(var/atom/movable/AM in src)
+ AM.loc = src.loc
+ AM.pipe_eject(0)
+ update()
+
+// update the icon & overlays to reflect mode & status
+/obj/machinery/disposal/proc/update()
+ return
+
+/obj/machinery/disposal/proc/flush()
+ flushing = 1
+ flushAnimation()
+ sleep(10)
+ if(last_sound < world.time + 1)
+ playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0)
+ last_sound = world.time
+ sleep(5)
+ if(gc_destroyed)
+ return
+ var/obj/structure/disposalholder/H = new()
+ newHolderDestination(H)
+ H.init(src)
+ air_contents = new()
+ H.start(src)
+ flushing = 0
+ flush = 0
+
+/obj/machinery/disposal/bin/flush()
+ ..()
+ if(mode == 2)
+ mode = 1
+ update()
+
+/obj/machinery/disposal/proc/newHolderDestination(obj/structure/disposalholder/H)
+ for(var/obj/item/smallDelivery/O in src)
+ H.tomail = 1
+ return
+
+/obj/machinery/disposal/proc/flushAnimation()
+ flick("[icon_state]-flush", src)
+
+// called when area power changes
+/obj/machinery/disposal/power_change()
+ ..() // do default setting/reset of stat NOPOWER bit
+ update() // update icon
+ return
+
+
+// called when holder is expelled from a disposal
+// should usually only occur if the pipe network is modified
+/obj/machinery/disposal/proc/expel(obj/structure/disposalholder/H)
+
+ var/turf/target
+ playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
+ if(H) // Somehow, someone managed to flush a window which broke mid-transit and caused the disposal to go in an infinite loop trying to expel null, hopefully this fixes it
+ for(var/atom/movable/AM in H)
+ target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5))
+
+ AM.loc = src.loc
+ AM.pipe_eject(0)
+ spawn(1)
+ if(AM)
+ AM.throw_at(target, 5, 1)
+
+ H.vent_gas(loc)
+ qdel(H)
+
+/obj/machinery/disposal/Deconstruct()
+ if(stored)
+ var/turf/T = loc
+ stored.loc = T
+ src.transfer_fingerprints_to(stored)
+ stored.anchored = 0
+ stored.density = 1
+ stored.update()
+ ..()
+
+//How disposal handles getting a storage dump from a storage object
+/obj/machinery/disposal/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
+ for(var/obj/item/I in src_object)
+ src_object.remove_from_storage(I, src)
+ return 1
+
+
+// Disposal bin
+// Holds items for disposal into pipe system
+// Draws air from turf, gradually charges internal reservoir
+// Once full (~1 atm), uses air resv to flush items into the pipes
+// Automatically recharges air (unless off), will flush when ready if pre-set
+// Can hold items and human size things, no other draggables
+
+/obj/machinery/disposal/bin
+ name = "disposal unit"
+ desc = "A pneumatic waste disposal unit."
+ icon_state = "disposal"
+
+ // attack by item places it in to disposal
+/obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params)
+ if(!..())
+ return
+
+ if(istype(I, /obj/item/weapon/storage/bag/trash))
+ var/obj/item/weapon/storage/bag/trash/T = I
+ user << "You empty the bag."
+ for(var/obj/item/O in T.contents)
+ T.remove_from_storage(O,src)
+ T.update_icon()
+ update()
+ return
+
+ var/obj/item/weapon/grab/G = I
+ if(istype(G)) // handle grabbed mob
+ if(ismob(G.affecting))
+ stuff_mob_in(G.affecting, user)
+ return
+
+ if(!user.drop_item())
+ return
+
+ I.loc = src
+ user.visible_message("[user.name] places \the [I] into \the [src].", \
+ "You place \the [I] into \the [src].")
+
+ update()
+
+// user interaction
+/obj/machinery/disposal/bin/interact(mob/user, ai=0)
+ src.add_fingerprint(user)
+ if(stat & BROKEN)
+ user.unset_machine()
+ return
+
+ var/dat = "Waste Disposal UnitWaste Disposal Unit"
+
+ if(!ai) // AI can't pull flush handle
+ if(flush)
+ dat += "Disposal handle: DisengageEngaged"
+ else
+ dat += "Disposal handle: DisengagedEngage"
+
+ dat += " Eject contents"
+
+ if(mode <= 0)
+ dat += "Pump: OffOn "
+ else if(mode == 1)
+ dat += "Pump: OffOn (pressurizing) "
+ else
+ dat += "Pump: OffOn (idle) "
+
+ var/per = Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
+
+ dat += "Pressure: [round(per, 1)]% "
+
+
+ user.set_machine(src)
+ user << browse(dat, "window=disposal;size=360x170")
+ onclose(user, "disposal")
+
+// handle machine interaction
+
+/obj/machinery/disposal/bin/Topic(href, href_list)
+ if(..())
+ return
+ if(usr.loc == src)
+ usr << "You cannot reach the controls from inside!"
+ return
+
+ if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
+ usr << "\The [src]'s power is disabled."
+ return
+ ..()
+ usr.set_machine(src)
+
+ if(href_list["close"])
+ usr.unset_machine()
+ usr << browse(null, "window=disposal")
+ return
+
+ if(href_list["pump"])
+ if(text2num(href_list["pump"]))
+ mode = 1
+ else
+ mode = 0
+ update()
+
+ if(href_list["handle"])
+ flush = text2num(href_list["handle"])
+ update()
+
+ if(href_list["eject"])
+ eject()
+ return
+
+/obj/machinery/disposal/bin/CanPass(atom/movable/mover, turf/target, height=0)
+ if (istype(mover,/obj/item) && mover.throwing)
+ var/obj/item/I = mover
+ if(istype(I, /obj/item/projectile))
+ return
+ if(prob(75))
+ I.loc = src
+ visible_message("\the [I] lands in \the [src].")
+ update()
+ else
+ visible_message("\the [I] bounces off of \the [src]'s rim!")
+ return 0
+ else
+ return ..(mover, target, height)
+
+/obj/machinery/disposal/bin/update()
+ overlays.Cut()
+ if(stat & BROKEN)
+ mode = 0
+ flush = 0
+ return
+
+ // flush handle
+ if(flush)
+ overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-handle")
+
+ // only handle is shown if no power
+ if(stat & NOPOWER || mode == -1)
+ return
+
+ // check for items in disposal - occupied light
+ if(contents.len > 0)
+ overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-full")
+
+ // charging and ready light
+ if(mode == 1)
+ overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-charge")
+ else if(mode == 2)
+ overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-ready")
+
+
+// timed process
+// charge the gas reservoir and perform flush if ready
+/obj/machinery/disposal/bin/process()
+ if(stat & BROKEN) // nothing can happen if broken
+ return
+
+ flush_count++
+ if( flush_count >= flush_every_ticks )
+ if( contents.len )
+ if(mode == 2)
+ spawn(0)
+ feedback_inc("disposal_auto_flush",1)
+ flush()
+ flush_count = 0
+
+ src.updateDialog()
+
+ if(flush && air_contents.return_pressure() >= SEND_PRESSURE ) // flush can happen even without power
+ spawn(0)
+ flush()
+
+ if(stat & NOPOWER) // won't charge if no power
+ return
+
+ use_power(100) // base power usage
+
+ if(mode != 1) // if off or ready, no need to charge
+ return
+
+ // otherwise charge
+ use_power(500) // charging power usage
+
+ var/atom/L = loc // recharging from loc turf
+
+ var/datum/gas_mixture/env = L.return_air()
+ var/pressure_delta = (SEND_PRESSURE*1.01) - air_contents.return_pressure()
+
+ if(env.temperature > 0)
+ var/transfer_moles = 0.1 * pressure_delta*air_contents.volume/(env.temperature * R_IDEAL_GAS_EQUATION)
+
+ //Actually transfer the gas
+ var/datum/gas_mixture/removed = env.remove(transfer_moles)
+ air_contents.merge(removed)
+ air_update_turf()
+
+
+ // if full enough, switch to ready mode
+ if(air_contents.return_pressure() >= SEND_PRESSURE)
+ mode = 2
+ update()
+ return
+
+
+//Delivery Chute
+
+/obj/machinery/disposal/deliveryChute
+ name = "delivery chute"
+ desc = "A chute for big and small packages alike!"
+ density = 1
+ icon_state = "intake"
+ mode = 0 // the chute doesn't need charging and always works
+
+/obj/machinery/disposal/deliveryChute/New(loc,var/obj/structure/disposalconstruct/make_from)
+ ..()
+ stored.ptype = DISP_END_CHUTE
+ spawn(5)
+ trunk = locate() in loc
+ if(trunk)
+ trunk.linked = src // link the pipe trunk to self
+
+/obj/machinery/disposal/deliveryChute/Bumped(atom/movable/AM) //Go straight into the chute
+ if(!AM.disposalEnterTry())
+ return
+ switch(dir)
+ if(NORTH)
+ if(AM.loc.y != loc.y+1) return
+ if(EAST)
+ if(AM.loc.x != loc.x+1) return
+ if(SOUTH)
+ if(AM.loc.y != loc.y-1) return
+ if(WEST)
+ if(AM.loc.x != loc.x-1) return
+
+ if(istype(AM, /obj))
+ var/obj/O = AM
+ O.loc = src
+ else if(istype(AM, /mob))
+ var/mob/M = AM
+ if(prob(2)) // to prevent mobs being stuck in infinite loops
+ M << "You hit the edge of the chute."
+ return
+ M.loc = src
+ flush()
+
+/atom/movable/proc/disposalEnterTry()
+ return 1
+
+/obj/item/projectile/disposalEnterTry()
+ return
+
+/obj/effect/disposalEnterTry()
+ return
+
+/obj/mecha/disposalEnterTry()
+ return
+
+/obj/machinery/disposal/deliveryChute/newHolderDestination(obj/structure/disposalholder/H)
+ H.destinationTag = 1
+
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index fc8b12cbe5b..df47b62e337 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -230,99 +230,6 @@
currTag = n
openwindow(usr)
-/obj/machinery/disposal/deliveryChute
- name = "delivery chute"
- desc = "A chute for big and small packages alike!"
- density = 1
- icon_state = "intake"
- var/c_mode = 0
-
-/obj/machinery/disposal/deliveryChute/New(loc,var/obj/structure/disposalconstruct/make_from)
- ..()
- stored.ptype = DISP_END_CHUTE
- spawn(5)
- trunk = locate() in loc
- if(trunk)
- trunk.linked = src // link the pipe trunk to self
-
-/obj/machinery/disposal/deliveryChute/Destroy()
- if(trunk)
- trunk.linked = null
- ..()
-
-/obj/machinery/disposal/deliveryChute/interact()
- return
-
-/obj/machinery/disposal/deliveryChute/update()
- return
-
-/obj/machinery/disposal/deliveryChute/Bumped(atom/movable/AM) //Go straight into the chute
- if(!AM.disposalEnterTry())
- return
- switch(dir)
- if(NORTH)
- if(AM.loc.y != loc.y+1) return
- if(EAST)
- if(AM.loc.x != loc.x+1) return
- if(SOUTH)
- if(AM.loc.y != loc.y-1) return
- if(WEST)
- if(AM.loc.x != loc.x-1) return
-
- if(istype(AM, /obj))
- var/obj/O = AM
- O.loc = src
- else if(istype(AM, /mob))
- var/mob/M = AM
- M.loc = src
- flush()
-
-/atom/movable/proc/disposalEnterTry()
- return 1
-
-/obj/item/projectile/disposalEnterTry()
- return
-
-/obj/mecha/disposalEnterTry()
- return
-
-/obj/machinery/disposal/deliveryChute/flushAnimation()
- flick("intake-closing", src)
-
-/obj/machinery/disposal/deliveryChute/newHolderDestination(obj/structure/disposalholder/H)
- H.destinationTag = 1
-
-/obj/machinery/disposal/deliveryChute/attackby(obj/item/I, mob/user, params)
- if(!I || !user)
- return
-
- if(istype(I, /obj/item/weapon/screwdriver))
- if(c_mode==0)
- c_mode=1
- playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You remove the screws around the power connection."
- return
- else if(c_mode==1)
- c_mode=0
- playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You attach the screws around the power connection."
- return
- else if(istype(I,/obj/item/weapon/weldingtool) && c_mode==1)
- var/obj/item/weapon/weldingtool/W = I
-
- if(W.remove_fuel(0,user))
- playsound(loc, 'sound/items/Welder2.ogg', 100, 1)
- user << "You start slicing the floorweld off the delivery chute..."
- if(do_after(user,20, target = src))
- if(!src || !W.isOn()) return
- Deconstruct()
- user << "You slice the floorweld off the delivery chute."
- return
- else
- return
-
-/obj/machinery/disposal/deliveryChute/process()
- return PROCESS_KILL
/obj/item/weapon/c_tube
name = "cardboard tube"
diff --git a/code/modules/research/designs/comp_board_designs.dm b/code/modules/research/designs/comp_board_designs.dm
index 8ca566a7661..0f657da38b0 100644
--- a/code/modules/research/designs/comp_board_designs.dm
+++ b/code/modules/research/designs/comp_board_designs.dm
@@ -210,7 +210,7 @@
build_path = /obj/item/weapon/circuitboard/arcade/orion_trail
category = list("Computer Boards")
-/datum/design/orion_trail
+/datum/design/slot_machine
name = "Computer Design (Slot Machine)"
desc = "Allows for the construction of circuit boards used to build a new slot machine."
id = "slotmachine"
@@ -378,4 +378,4 @@
build_type = IMPRINTER
materials = list(MAT_GLASS = 1000, "sacid" = 20)
build_path = /obj/item/weapon/circuitboard/libraryconsole
- category = list("Computer Boards")
\ No newline at end of file
+ category = list("Computer Boards")
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 8c0cfe30ea1..75202c87387 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -12,6 +12,16 @@
build_path = /obj/item/weapon/circuitboard/smes
category = list ("Engineering Machinery")
+/datum/design/announcement_system
+ name = "Machine Design (Automated Announcement System Board)"
+ desc = "The circuit board for an automated announcement system."
+ id = "automated_announcement"
+ req_tech = list("programming" = 3, "bluespace" = 2)
+ build_type = IMPRINTER
+ materials = list(MAT_GLASS = 1000, "sacid" = 20)
+ build_path = /obj/item/weapon/circuitboard/announcement_system
+ category = list("Subspace Telecomms")
+
/datum/design/turbine_computer
name = "Computer Design (Power Turbine Console Board)"
desc = "The circuit board for a power turbine console."
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index abf6b2663a7..1501167a730 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -118,7 +118,7 @@
req_tech = list("materials" = 6, "programming" = 4, "biotech" = 4)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 500, MAT_GOLD = 500)
- build_path = /obj/item/cybernetic_implant/eyes/hud/medical
+ build_path = /obj/item/organ/internal/cyberimp/eyes/hud/medical
category = list("Medical Designs")
/datum/design/cyberimp_security_hud
@@ -128,7 +128,7 @@
req_tech = list("materials" = 6, "programming" = 5, "biotech" = 4, "combat" = 2)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 750, MAT_GOLD = 750)
- build_path = /obj/item/cybernetic_implant/eyes/hud/security
+ build_path = /obj/item/organ/internal/cyberimp/eyes/hud/security
category = list("Medical Designs")
/datum/design/cyberimp_xray
@@ -138,7 +138,7 @@
req_tech = list("materials" = 7, "programming" = 5, "biotech" = 6, "magnets" = 5)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 600, MAT_GOLD = 600, MAT_PLASMA = 1000, MAT_URANIUM = 1000, MAT_DIAMOND = 2000)
- build_path = /obj/item/cybernetic_implant/eyes/xray
+ build_path = /obj/item/organ/internal/cyberimp/eyes/xray
category = list("Medical Designs")
/datum/design/cyberimp_thermals
@@ -148,7 +148,7 @@
req_tech = list("materials" = 7, "programming" = 5, "biotech" = 5, "magnets" = 5, "syndicate" = 5)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 600, MAT_GOLD = 600, MAT_PLASMA = 1000, MAT_DIAMOND = 2000)
- build_path = /obj/item/cybernetic_implant/eyes/thermals
+ build_path = /obj/item/organ/internal/cyberimp/eyes/thermals
category = list("Medical Designs")
/datum/design/cyberimp_antidrop
@@ -158,7 +158,7 @@
req_tech = list("materials" = 7, "programming" = 5, "biotech" = 5)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 400, MAT_GOLD = 400)
- build_path = /obj/item/cybernetic_implant/brain/anti_drop
+ build_path = /obj/item/organ/internal/cyberimp/brain/anti_drop
category = list("Medical Designs")
/datum/design/cyberimp_antistun
@@ -168,7 +168,7 @@
req_tech = list("materials" = 7, "programming" = 5, "biotech" = 6)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_SILVER = 500, MAT_GOLD = 1000)
- build_path = /obj/item/cybernetic_implant/brain/anti_stun
+ build_path = /obj/item/organ/internal/cyberimp/brain/anti_stun
category = list("Medical Designs")
/datum/design/cyberimp_nutriment
@@ -178,7 +178,7 @@
req_tech = list("materials" = 6, "programming" = 4, "biotech" = 5)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_GOLD = 500, MAT_URANIUM = 500)
- build_path = /obj/item/cybernetic_implant/chest/nutriment
+ build_path = /obj/item/organ/internal/cyberimp/chest/nutriment
category = list("Medical Designs")
/datum/design/cyberimp_nutriment_plus
@@ -188,7 +188,7 @@
req_tech = list("materials" = 6, "programming" = 4, "biotech" = 6)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_GOLD = 500, MAT_URANIUM = 750)
- build_path = /obj/item/cybernetic_implant/chest/nutriment/plus
+ build_path = /obj/item/organ/internal/cyberimp/chest/nutriment/plus
category = list("Medical Designs")
/datum/design/cyberimp_reviver
@@ -198,5 +198,5 @@
req_tech = list("materials" = 6, "programming" = 4, "biotech" = 7, "syndicate" = 4)
build_type = PROTOLATHE | MECHFAB
materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_GOLD = 500, MAT_URANIUM = 1000, MAT_DIAMOND = 2000)
- build_path = /obj/item/cybernetic_implant/chest/reviver
- category = list("Medical Designs")
+ build_path = /obj/item/organ/internal/cyberimp/chest/reviver
+ category = list("Medical Designs")
\ No newline at end of file
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index e5c5a93dfb2..e57a3762319 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -512,7 +512,7 @@
trackedIan.loc = src.loc
investigate_log("Experimentor has stolen Ian!", "experimentor") //...if anyone ever fixes it...
else
- new /mob/living/simple_animal/pet/corgi(src.loc)
+ new /mob/living/simple_animal/pet/dog/corgi(src.loc)
investigate_log("Experimentor has spawned a new corgi.", "experimentor")
ejectItem(TRUE)
if(globalMalf > 36 && globalMalf < 50)
@@ -658,7 +658,7 @@
/obj/item/weapon/relic/proc/corgicannon(mob/user)
playsound(src.loc, "sparks", rand(25,50), 1)
- var/mob/living/simple_animal/pet/dog/corgi/C = new/mob/living/simple_animal/pet/corgi(get_turf(user))
+ var/mob/living/simple_animal/pet/dog/corgi/C = new/mob/living/simple_animal/pet/dog/corgi(get_turf(user))
C.throw_at(pick(oview(10,user)),10,rand(3,8))
throwSmoke(get_turf(C))
warn_admins(user, "Corgi Cannon", 0)
@@ -681,7 +681,7 @@
user << message
var/animals = rand(1,25)
var/counter
- var/list/valid_animals = list(/mob/living/simple_animal/parrot,/mob/living/simple_animal/butterfly,/mob/living/simple_animal/pet/cat,/mob/living/simple_animal/pet/corgi,/mob/living/simple_animal/crab,/mob/living/simple_animal/pet/fox,/mob/living/simple_animal/lizard,/mob/living/simple_animal/mouse,/mob/living/simple_animal/pet/pug,/mob/living/simple_animal/hostile/bear,/mob/living/simple_animal/hostile/poison/bees,/mob/living/simple_animal/hostile/carp)
+ var/list/valid_animals = list(/mob/living/simple_animal/parrot,/mob/living/simple_animal/butterfly,/mob/living/simple_animal/pet/cat,/mob/living/simple_animal/pet/dog/corgi,/mob/living/simple_animal/crab,/mob/living/simple_animal/pet/fox,/mob/living/simple_animal/lizard,/mob/living/simple_animal/mouse,/mob/living/simple_animal/pet/pug,/mob/living/simple_animal/hostile/bear,/mob/living/simple_animal/hostile/poison/bees,/mob/living/simple_animal/hostile/carp)
for(counter = 1; counter < animals; counter++)
var/mobType = pick(valid_animals)
new mobType(get_turf(src))
diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm
index 07ab76f7b5d..0e998a0cb1b 100644
--- a/code/modules/research/protolathe.dm
+++ b/code/modules/research/protolathe.dm
@@ -165,18 +165,16 @@ Note: Must be placed west/left of and R&D console to function.
var/obj/item/stack/sheet/stack = O
var/amount = round(input("How many sheets do you want to add?") as num)//No decimals
- if(!stack || stack.amount <= 0 || amount <= 0)
+ if(!stack || stack.amount <= 0 || amount <= 0 || !in_range(src, stack) || !user.Adjacent(src))
return
if(amount > stack.amount)
amount = stack.amount
if(max_material_storage - TotalMaterials() < (amount*stack.perunit))//Can't overfill
amount = min(stack.amount, round((max_material_storage-TotalMaterials())/stack.perunit))
- icon_state = "protolathe"
busy = 1
use_power(max(1000, (MINERAL_MATERIAL_AMOUNT*amount/10)))
user << "You add [amount] sheets to the [src.name]."
- icon_state = "protolathe"
if(istype(stack, /obj/item/stack/sheet/metal))
m_amount += amount * MINERAL_MATERIAL_AMOUNT
else if(istype(stack, /obj/item/stack/sheet/glass))
@@ -196,11 +194,10 @@ Note: Must be placed west/left of and R&D console to function.
else if(istype(stack, /obj/item/stack/sheet/mineral/adamantine))
adamantine_amount += amount * MINERAL_MATERIAL_AMOUNT
stack.use(amount)
- busy = 0
- src.updateUsrDialog()
+ updateUsrDialog()
- src.overlays += "protolathe_[stack.name]"
+ overlays += "protolathe_[stack.name]"
sleep(10)
- src.overlays -= "protolathe_[stack.name]"
+ overlays -= "protolathe_[stack.name]"
+ busy = 0
- return
diff --git a/code/modules/surgery/appendectomy.dm b/code/modules/surgery/appendectomy.dm
index 0ba1db2da7c..9355890cb5f 100644
--- a/code/modules/surgery/appendectomy.dm
+++ b/code/modules/surgery/appendectomy.dm
@@ -2,15 +2,15 @@
name = "appendectomy"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/incise, /datum/surgery_step/extract_appendix, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
- location = "groin"
- requires_organic_chest = 1
+ possible_locs = list("groin")
//extract appendix
/datum/surgery_step/extract_appendix
+ name = "extract appendix"
accept_hand = 1
time = 64
- var/obj/item/organ/appendix/A = null
+ var/obj/item/organ/internal/appendix/A = null
/datum/surgery_step/extract_appendix/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
A = locate() in target.internal_organs
@@ -23,9 +23,10 @@
if(A)
user.visible_message("[user] successfully removes [target]'s appendix!", "You successfully removes [target]'s appendix.")
A.loc = get_turf(target)
- target.internal_organs -= A
+ A.Remove(target)
for(var/datum/disease/appendicitis in target.viruses)
appendicitis.cure()
+ target.resistances += /datum/disease/appendicitis
else
user << "You can't find an appendix in [target]!"
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/surgery/brain_removal.dm b/code/modules/surgery/brain_removal.dm
index 0d57fb6f9a2..0d2426775a6 100644
--- a/code/modules/surgery/brain_removal.dm
+++ b/code/modules/surgery/brain_removal.dm
@@ -2,11 +2,13 @@
name = "brain removal"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/extract_brain)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
- location = "head"
+ possible_locs = list("head")
+ requires_organic_bodypart = 0
//extract brain
/datum/surgery_step/extract_brain
+ name = "extract brain"
implements = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/crowbar = 55)
time = 64
var/obj/item/organ/brain/B = null
diff --git a/code/modules/surgery/cavity_implant.dm b/code/modules/surgery/cavity_implant.dm
index 6f556860bee..9ad5d579ae1 100644
--- a/code/modules/surgery/cavity_implant.dm
+++ b/code/modules/surgery/cavity_implant.dm
@@ -2,12 +2,12 @@
name = "cavity implant"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/incise, /datum/surgery_step/handle_cavity, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
- location = "chest"
- requires_organic_chest = 1
+ possible_locs = list("chest")
//handle cavity
/datum/surgery_step/handle_cavity
+ name = "implant item"
accept_hand = 1
accept_any_item = 1
time = 32
@@ -25,7 +25,7 @@
/datum/surgery_step/handle_cavity/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(tool)
- if(IC || tool.w_class > 3 || (tool.flags & NODROP) || tool.GetTypeInAllContents(/obj/item/weapon/disk/nuclear) || istype(tool, /obj/item/weapon/disk/nuclear) || istype(tool, /obj/item/organ))
+ if(IC || tool.w_class > 3 || NODROP in tool.flags || tool.GetTypeInAllContents(/obj/item/weapon/disk/nuclear) || istype(tool, /obj/item/weapon/disk/nuclear) || istype(tool, /obj/item/organ))
user << "You can't seem to fit [tool] in [target]'s [target_zone]!"
return 0
else
diff --git a/code/modules/surgery/core_removal.dm b/code/modules/surgery/core_removal.dm
index 6a38e160560..fe976b25824 100644
--- a/code/modules/surgery/core_removal.dm
+++ b/code/modules/surgery/core_removal.dm
@@ -7,6 +7,7 @@
//extract brain
/datum/surgery_step/extract_core
+ name = "extract core"
implements = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/crowbar = 100)
time = 16
diff --git a/code/modules/surgery/cybernetic_implants.dm b/code/modules/surgery/cybernetic_implants.dm
index ced4776f535..ed6813bf087 100644
--- a/code/modules/surgery/cybernetic_implants.dm
+++ b/code/modules/surgery/cybernetic_implants.dm
@@ -1,42 +1,45 @@
#define MAX_BRAIN_IMPLANT 2
#define MAX_CHEST_IMPLANT 3
-/datum/surgery_step/cybernetic_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/cybernetic_implant/implant, datum/surgery/surgery)
+/datum/surgery_step/cybernetic_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/organ/internal/cyberimp/implant, datum/surgery/surgery)
user.visible_message("[user] begins to implant [target] with [implant].", "You begin to implant [target] with [implant]...")
//[[[[EYES]]]]
-/datum/surgery/eye_cybernetic_implant/eyes
+/datum/surgery/cybernetic_implant/eyes
name = "eye cybernetic implant"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/cybernetic_implant/eyes, /datum/surgery_step/fix_eyes, /datum/surgery_step/close)
- location = "eyes"
+ possible_locs = list("eyes")
/datum/surgery_step/cybernetic_implant/eyes
- implements = list(/obj/item/cybernetic_implant/eyes = 100)
+ name = "insert eye cybernetic implant"
+ implements = list(/obj/item/organ/internal/cyberimp/eyes = 100)
time = 32
-/datum/surgery_step/cybernetic_implant/eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/cybernetic_implant/eyes/implant, datum/surgery/surgery)
+/datum/surgery_step/cybernetic_implant/eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/organ/internal/cyberimp/eyes/implant, datum/surgery/surgery)
if(implant)
var/full = 0
- if(locate(/obj/item/cybernetic_implant/eyes,target.internal_organs))
+ if(locate(/obj/item/organ/internal/cyberimp/eyes, target.internal_organs))
full = 1
insert(user,target,implant,target_zone,full)
return 1
//[[[[BRAIN]]]]
-/datum/surgery/eye_cybernetic_implant/brain
+/datum/surgery/cybernetic_implant/brain
name = "brain cybernetic implant"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/cybernetic_implant/brain, /datum/surgery_step/close)
- location = "head"
+ possible_locs = list("head")
+ requires_organic_bodypart = 0
/datum/surgery_step/cybernetic_implant/brain
- implements = list(/obj/item/cybernetic_implant/brain = 100)
+ name = "insert brain cybernetic implant"
+ implements = list(/obj/item/organ/internal/cyberimp/brain = 100)
time = 32
-/datum/surgery_step/cybernetic_implant/brain/success(mob/user, mob/living/carbon/target, target_zone, obj/item/cybernetic_implant/brain/implant, datum/surgery/surgery)
+/datum/surgery_step/cybernetic_implant/brain/success(mob/user, mob/living/carbon/target, target_zone, obj/item/organ/internal/cyberimp/brain/implant, datum/surgery/surgery)
if(implant)
var/full = 0
for(var/obj/item/I in target.internal_organs)
- if(istype(I,/obj/item/cybernetic_implant/brain))
+ if(istype(I,/obj/item/organ/internal/cyberimp/brain))
full++
if(full < MAX_BRAIN_IMPLANT)
@@ -45,20 +48,22 @@
return 1
//[[[[CHEST]]]]
-/datum/surgery/eye_cybernetic_implant/chest
+/datum/surgery/cybernetic_implant/chest
name = "torso cybernetic implant"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/cybernetic_implant/chest, /datum/surgery_step/close)
- location = "chest"
+ possible_locs = list("chest")
+ requires_organic_bodypart = 0
/datum/surgery_step/cybernetic_implant/chest
- implements = list(/obj/item/cybernetic_implant/chest = 100)
+ name = "insert torso cybernetic implant"
+ implements = list(/obj/item/organ/internal/cyberimp/chest = 100)
time = 32
-/datum/surgery_step/cybernetic_implant/chest/success(mob/user, mob/living/carbon/target, target_zone, obj/item/cybernetic_implant/chest/implant, datum/surgery/surgery)
+/datum/surgery_step/cybernetic_implant/chest/success(mob/user, mob/living/carbon/target, target_zone, obj/item/organ/internal/cyberimp/chest/implant, datum/surgery/surgery)
if(implant)
var/full = 0
for(var/obj/item/I in target.internal_organs)
- if(istype(I,/obj/item/cybernetic_implant/chest))
+ if(istype(I,/obj/item/organ/internal/cyberimp/chest))
full++
if(full < MAX_CHEST_IMPLANT)
full = 0
@@ -66,14 +71,10 @@
insert(user,target,implant,target_zone,full)
return 1
-/datum/surgery_step/cybernetic_implant/proc/insert(mob/user, mob/living/carbon/target, obj/item/cybernetic_implant/implant,target_zone,full)
+/datum/surgery_step/cybernetic_implant/proc/insert(mob/user, mob/living/carbon/target, obj/item/organ/internal/cyberimp/implant,target_zone,full)
if(full)
user << "You can't seem to implant anything else into the [target]'s [target_zone]!"
else
- if(!user.drop_item())
- return
user.visible_message("[user] inserts [implant] into the [target]'s [target_zone == "head" ? "brain" : target_zone]!", "You insert [implant] into the [target]'s [target_zone == "head" ? "brain" : target_zone].")
- implant.owner = target
- implant.function()
- target.internal_organs |= implant
- implant.loc = target
\ No newline at end of file
+ user.drop_item()
+ implant.Insert(target)
\ No newline at end of file
diff --git a/code/modules/surgery/dethrall.dm b/code/modules/surgery/dethrall.dm
new file mode 100644
index 00000000000..bd54a7f3f6f
--- /dev/null
+++ b/code/modules/surgery/dethrall.dm
@@ -0,0 +1,41 @@
+/datum/surgery/dethrall
+ name = "dethralling"
+ steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/dethrall)
+ possible_locs = list("head")
+
+/datum/surgery_step/dethrall
+ name = "search head"
+ accept_hand = 1
+ time = 70
+ var/obj/item/organ/brain/B = null
+
+/datum/surgery_step/dethrall/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ B = target.getorgan(/obj/item/organ/brain)
+ if(B)
+ user.visible_message("[user] begins looking around in [target]'s head.", "You begin looking for foreign influences on [target]'s brain...")
+
+/datum/surgery_step/dethrall/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(B)
+ if(!is_thrall(target))
+ user << "You are unable to locate anything on [target]'s brain."
+ return 1
+ user << "You locate a small, pulsing black tumor on the side of [target]'s brain and begin to remove it."
+ target << "A small part of your head pulses with agony as the light impacts it."
+ sleep(30)
+ user.visible_message("[user] begins removing something from [target]'s head.", \
+ "You begin carefully extracting the tumor...")
+ if(!do_mob(user, target, 50))
+ if(prob(50))
+ user.visible_message("[user] slips and rips the tumor out from [target]'s head!", \
+ "You fumble and tear out [target]'s tumor!")
+ ticker.mode.remove_thrall(target.mind,1)
+ return 1
+ else
+ user.visible_message("[user] screws up!")
+ return 0
+ user.visible_message("[user] carefully extracts the tumor from [target]'s brain!", \
+ "You extract the black tumor from [target]'s head. It quickly shrivels and burns away.")
+ ticker.mode.remove_thrall(target.mind,0)
+ else
+ user << "[target] has no brain!"
+ return 1
diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm
index 71e136efa72..06117fb80d7 100644
--- a/code/modules/surgery/eye_surgery.dm
+++ b/code/modules/surgery/eye_surgery.dm
@@ -2,11 +2,12 @@
name = "eye surgery"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/fix_eyes, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
- location = "eyes"
-
+ possible_locs = list("eyes")
+ requires_organic_bodypart = 0
//fix eyes
/datum/surgery_step/fix_eyes
+ name = "fix eyes"
implements = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/screwdriver = 45, /obj/item/weapon/pen = 25)
time = 64
diff --git a/code/modules/surgery/gender_reassignment.dm b/code/modules/surgery/gender_reassignment.dm
index 4cc6be2d953..797450ae2f6 100644
--- a/code/modules/surgery/gender_reassignment.dm
+++ b/code/modules/surgery/gender_reassignment.dm
@@ -2,12 +2,12 @@
name = "gender reassignment"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/reshape_genitals, /datum/surgery_step/close)
species = list(/mob/living/carbon/human)
- location = "groin"
- requires_organic_chest = 1
+ possible_locs = list("groin")
//reshape_genitals
/datum/surgery_step/reshape_genitals
+ name = "reshape genitals"
implements = list(/obj/item/weapon/scalpel = 100, /obj/item/weapon/hatchet = 50, /obj/item/weapon/wirecutters = 35)
time = 64
diff --git a/code/modules/surgery/generic_steps.dm b/code/modules/surgery/generic_steps.dm
index a4ea6e51ba2..1f01549e999 100644
--- a/code/modules/surgery/generic_steps.dm
+++ b/code/modules/surgery/generic_steps.dm
@@ -1,6 +1,7 @@
//make incision
/datum/surgery_step/incise
+ name = "make incision"
implements = list(/obj/item/weapon/scalpel = 100, /obj/item/weapon/kitchen/knife = 65, /obj/item/weapon/shard = 45)
time = 24
@@ -11,15 +12,22 @@
//clamp bleeders
/datum/surgery_step/clamp_bleeders
+ name = "clamp bleeders"
implements = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/wirecutters = 60, /obj/item/stack/cable_coil = 15)
time = 48
/datum/surgery_step/clamp_bleeders/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].", "You begin to clamp bleeders in [target]'s [parse_zone(target_zone)]...")
+/datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(locate(/datum/surgery_step/saw) in surgery.steps)
+ target.heal_organ_damage(20,0)
+ return ..()
+
//retract skin
/datum/surgery_step/retract_skin
+ name = "retract skin"
implements = list(/obj/item/weapon/retractor = 100, /obj/item/weapon/screwdriver = 45, /obj/item/weapon/wirecutters = 35)
time = 32
@@ -30,6 +38,7 @@
//close incision
/datum/surgery_step/close
+ name = "mend incision"
implements = list(/obj/item/weapon/cautery = 100, /obj/item/weapon/weldingtool = 70, /obj/item/weapon/lighter = 45, /obj/item/weapon/match = 20)
time = 32
@@ -55,14 +64,26 @@
return 0
+/datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(locate(/datum/surgery_step/saw) in surgery.steps)
+ target.heal_organ_damage(45,0)
+ return ..()
+
+
//saw bone
/datum/surgery_step/saw
+ name = "saw bone"
implements = list(/obj/item/weapon/circular_saw = 100, /obj/item/weapon/melee/arm_blade = 75, /obj/item/weapon/hatchet = 35, /obj/item/weapon/kitchen/knife/butcher = 25)
time = 64
/datum/surgery_step/saw/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].", "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...")
+/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ H.apply_damage(50,"brute","[target_zone]")
-
+ user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.")
+ return 1
\ No newline at end of file
diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm
index 4982c6bcc64..021eddeb277 100644
--- a/code/modules/surgery/helpers.dm
+++ b/code/modules/surgery/helpers.dm
@@ -1,65 +1,64 @@
/proc/attempt_initiate_surgery(obj/item/I, mob/living/M, mob/user)
if(istype(M))
+ var/mob/living/carbon/human/H
+ var/obj/item/organ/limb/affecting
+ var/selected_zone = user.zone_sel.selecting
+
+ if(istype(M, /mob/living/carbon/human))
+ H = M
+ affecting = H.get_organ(check_zone(selected_zone))
+
if(M.lying || isslime(M)) //if they're prone or a slime
- var/list/all_surgeries = surgeries_list.Copy()
- var/list/available_surgeries = list()
- for(var/i in all_surgeries)
- var/datum/surgery/S = all_surgeries[i]
+ var/datum/surgery/current_surgery
- if(locate(S.type) in M.surgeries)
- continue
- if(S.user_species_restricted)
- if(!istype(user, /mob/living/carbon/human))
+ for(var/datum/surgery/S in M.surgeries)
+ if(S.location == selected_zone)
+ current_surgery = S
+
+ if(!current_surgery)
+ var/list/all_surgeries = surgeries_list.Copy()
+ var/list/available_surgeries = list()
+ for(var/i in all_surgeries)
+ var/datum/surgery/S = all_surgeries[i]
+ if(!S.possible_locs.Find(selected_zone))
continue
- var/mob/living/carbon/human/doc = user
- if(!(doc.dna.species.id in S.user_species_ids))
+ if(affecting && S.requires_organic_bodypart && affecting.status == ORGAN_ROBOTIC)
continue
- if(S.target_must_be_dead && M.stat != DEAD)
- continue
- if(S.target_must_be_fat && !(M.disabilities & FAT))
- continue
-
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = M //So we can use get_organ and not some terriblly long Switch or something worse - RR
-
- if(S.requires_organic_chest && H.getlimb(/obj/item/organ/limb/robot/chest)) //This a seperate case to below, see "***" in surgery.dm - RR
+ if(!S.can_start(user, M))
continue
+ for(var/path in S.species)
+ if(istype(M, path))
+ available_surgeries[S.name] = S
+ break
- var/obj/item/organ/limb/affecting = H.get_organ(check_zone(user.zone_sel.selecting))
+ var/P = input("Begin which procedure?", "Surgery", null, null) as null|anything in available_surgeries
+ if(P && user.Adjacent(M) && (I in user))
+ var/datum/surgery/S = available_surgeries[P]
+ var/datum/surgery/procedure = new S.type
+ if(procedure)
+ procedure.location = selected_zone
+ if(procedure.ignore_clothes || get_location_accessible(M, selected_zone))
+ M.surgeries += procedure
+ procedure.organ = affecting
+ user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].", \
+ "You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].")
- if(affecting.status == ORGAN_ROBOTIC && affecting.body_part != HEAD) //Cannot operate on Robotic organs except for the head. - RR
- continue
+ add_logs(user, M, "operated", addition="Operation type: [procedure.name], location: [selected_zone]")
+ else
+ user << "You need to expose [M]'s [parse_zone(selected_zone)] first!"
- for(var/path in S.species)
- if(istype(M, path))
- available_surgeries[S.name] = S
- break
-
- var/P = input("Begin which procedure?", "Surgery", null, null) as null|anything in available_surgeries
- if(P)
- var/datum/surgery/S = available_surgeries[P]
- var/datum/surgery/procedure = new S.type
- if(procedure)
- if(get_location_accessible(M, procedure.location) || procedure.ignore_clothes)
- if(procedure.location == "anywhere") // if location == "anywhere" change location to the surgeon's target, otherwise leave location as is.
- procedure.location = user.zone_sel.selecting
- M.surgeries += procedure
- user.visible_message("[user] drapes [I] over [M]'s [parse_zone(procedure.location)] to prepare for \an [procedure.name].", "You drape [I] over [M]'s [parse_zone(procedure.location)] to prepare for \an [procedure.name].")
-
- add_logs(user, M, "operated", addition="Operation type: [procedure.name]")
- feedback_add_details("surgery_initiated","[procedure.name]")
- return 1
- else
- user << "You need to expose [M]'s [procedure.location] first!"
- return 1 //return 1 so we don't slap the guy in the dick with the drapes.
- else
- return 1 //once the input menu comes up, cancelling it shouldn't hit the guy with the drapes either.
+ else if(current_surgery.status == 1 && !current_surgery.step_in_progress)
+ M.surgeries -= current_surgery
+ user.visible_message("[user] removes the drapes from [M]'s [parse_zone(selected_zone)].", \
+ "You remove the drapes from [M]'s [parse_zone(selected_zone)].")
+ qdel(current_surgery)
+ return 1
return 0
-/proc/get_location_modifier(mob/M)
+proc/get_location_modifier(mob/M)
var/turf/T = get_turf(M)
if(locate(/obj/structure/optable, T))
return 1
diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm
index 86851838afc..b3ab5a6379c 100644
--- a/code/modules/surgery/implant_removal.dm
+++ b/code/modules/surgery/implant_removal.dm
@@ -2,22 +2,19 @@
name = "implant removal"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/extract_implant, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
- location = "chest"
- requires_organic_chest = 1
-
+ possible_locs = list("chest")
+ requires_organic_bodypart = 0
//extract implant
/datum/surgery_step/extract_implant
+ name = "extract implant"
implements = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/crowbar = 65)
time = 64
var/obj/item/weapon/implant/I = null
/datum/surgery_step/extract_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- for(var/obj/item/weapon/implant/W in target)
- if(W.imp_in == target) //Checking that it's actually implanted, not just in his pocket
- I = W
- break
+ I = locate(/obj/item/weapon/implant) in target
if(I)
user.visible_message("[user] begins to extract [I] from [target]'s [target_zone].", "You begin to extract [I] from [target]'s [target_zone]...")
else
@@ -26,10 +23,25 @@
/datum/surgery_step/extract_implant/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(I)
user.visible_message("[user] successfully removes [I] from [target]'s [target_zone]!", "You successfully remove [I] from [target]'s [target_zone].")
- qdel(I)
- if(istype(target, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = target
- H.sec_hud_set_implants()
+ I.removed(target)
+
+ var/obj/item/weapon/implantcase/case
+
+ if(istype(user.get_item_by_slot(slot_l_hand), /obj/item/weapon/implantcase))
+ case = user.get_item_by_slot(slot_l_hand)
+ else if(istype(user.get_item_by_slot(slot_r_hand), /obj/item/weapon/implantcase))
+ case = user.get_item_by_slot(slot_r_hand)
+ else
+ case = locate(/obj/item/weapon/implantcase) in get_turf(target)
+
+ if(case && !case.imp)
+ case.imp = I
+ I.loc = case
+ case.update_icon()
+ user.visible_message("[user] places [I] into [case]!", "You place [I] into [case].")
+ else
+ qdel(I)
+
else
user << "You can't find anything in [target]'s [target_zone]!"
- return 1
+ return 1
\ No newline at end of file
diff --git a/code/modules/surgery/limb augmentation.dm b/code/modules/surgery/limb augmentation.dm
index 22d168044c0..d7ff7340302 100644
--- a/code/modules/surgery/limb augmentation.dm
+++ b/code/modules/surgery/limb augmentation.dm
@@ -5,6 +5,7 @@
//SURGERY STEPS
/datum/surgery_step/replace
+ name = "sever muscules"
implements = list(/obj/item/weapon/scalpel = 100, /obj/item/weapon/wirecutters = 55)
time = 32
@@ -14,15 +15,15 @@
/datum/surgery_step/add_limb
+ name = "replace limb"
implements = list(/obj/item/robot_parts = 100)
time = 32
var/obj/item/organ/limb/L = null // L because "limb"
- allowed_organs = list("r_arm","l_arm","r_leg","l_leg","chest","head")
/datum/surgery_step/add_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- L = new_organ
+ L = surgery.organ
if(L)
user.visible_message("[user] begins to augment [target]'s [parse_zone(user.zone_sel.selecting)].", "You begin to augment [target]'s [parse_zone(user.zone_sel.selecting)]...")
else
@@ -36,8 +37,7 @@
name = "augmentation"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/replace, /datum/surgery_step/saw, /datum/surgery_step/add_limb)
species = list(/mob/living/carbon/human)
- location = "anywhere" //Check attempt_initate_surgery() (in code/modules/surgery/helpers) to see what this does if you can't tell
- has_multi_loc = 1 //Multi location stuff, See multiple_location_example.dm
+ possible_locs = list("r_arm","l_arm","r_leg","l_leg","chest","head")
//SURGERY STEP SUCCESSES
@@ -45,34 +45,6 @@
/datum/surgery_step/add_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(L)
if(ishuman(target))
- switch(L.body_part)
- if(CHEST)
- if(!istype(tool,/obj/item/robot_parts/chest))
- user << "That is the wrong robotic limb for this body part."
- return 0
- if(HEAD)
- if(!istype(tool,/obj/item/robot_parts/head))
- user << "That is the wrong robotic limb for this body part."
- return 0
- if(ARM_LEFT)
- if(!istype(tool,/obj/item/robot_parts/l_arm))
- user << "That is the wrong robotic limb for this body part."
- return 0
- if(ARM_RIGHT)
- if(!istype(tool,/obj/item/robot_parts/r_arm))
- user << "That is the wrong robotic limb for this body part."
- return 0
- if(LEG_LEFT)
- if(!istype(tool,/obj/item/robot_parts/l_leg))
- user << "That is the wrong robotic limb for this body part."
- return 0
- if(LEG_RIGHT)
- if(!istype(tool,/obj/item/robot_parts/r_leg))
- user << "That is the wrong robotic limb for this body part."
- return 0
-
- if(!user.drop_item())
- return 0
var/mob/living/carbon/human/H = target
user.visible_message("[user] successfully augments [target]'s [parse_zone(target_zone)]!", "You successfully augment [target]'s [parse_zone(target_zone)].")
L.loc = get_turf(target)
@@ -94,6 +66,7 @@
H.organs += new /obj/item/organ/limb/robot/chest(src)
for(var/datum/disease/appendicitis/A in H.viruses) //If they already have Appendicitis, Remove it
A.cure(1)
+ user.drop_item()
qdel(tool)
H.update_damage_overlays(0)
H.update_augments() //Gives them the Cyber limb overlay
diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm
index 532e90e1e9e..7fcf8616e62 100644
--- a/code/modules/surgery/lipoplasty.dm
+++ b/code/modules/surgery/lipoplasty.dm
@@ -1,14 +1,17 @@
/datum/surgery/lipoplasty
name = "lipoplasty"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/cut_fat, /datum/surgery_step/remove_fat, /datum/surgery_step/close)
- species = list(/mob/living/carbon/human)
- target_must_be_fat = 1
- location = "chest"
- requires_organic_chest = 1
+ possible_locs = list("chest")
+
+/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target)
+ if(target.disabilities & FAT)
+ return 1
+ return 0
//cut fat
/datum/surgery_step/cut_fat
+ name = "cut excess fat"
implements = list(/obj/item/weapon/circular_saw = 100, /obj/item/weapon/hatchet = 35, /obj/item/weapon/kitchen/knife/butcher = 25)
time = 64
@@ -21,6 +24,7 @@
//remove fat
/datum/surgery_step/remove_fat
+ name = "remove loose fat"
implements = list(/obj/item/weapon/retractor = 100, /obj/item/weapon/screwdriver = 45, /obj/item/weapon/wirecutters = 35)
time = 32
diff --git a/code/modules/surgery/multiple_location_example.dm b/code/modules/surgery/multiple_location_example.dm
deleted file mode 100644
index e5e331843e5..00000000000
--- a/code/modules/surgery/multiple_location_example.dm
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-//CONTENTS//
-Multiple location example surgery
-
-
-
-//THE SURGERY//
-it is very similar to a normal surgery.
-Location = "anywhere" is the unique difference.
-
-/datum/surgery/multiLocExample
- name = "Multiple Location Surgery Example"
- steps = list(/datum/surgery_step/multiLocExampleStep)
- species = list(/mob/living/carbon)
- location = "anywhere" //A Location "Anywhere" is handled in /code/modules/surgery/helpers attempt_initiate_surgery(), it is converted into a User.zone_sel.selecting.
- has_multi_loc = 1 //Needed to handle Multilocation
-
-//THE STEPS//
-The block of "If's" is necessary, add or remove so you have just the areas you want, and set them to convert L(or your subsitute) to what you want it to be
-EG: a zone on a mob (where user is targetting) to the limb thats actually there.
-
-
-/datum/surgery_step/multiLocExampleStep
- implements = list()
- time = 9001
- allowed_organs = list("r_arm","l_arm","r_leg","l_leg","chest","head", "etc")
- // allowed_organs is a list of organs this operation works with, it is defined in the earliest instance of the surgery_step (Eg, datum/surgery_step/multiLocExampleStep)
- // allowed_organs is handled in Handle_Multi_Loc() in surgery_step.dm
-
-
-/datum/surgery_step/multiLocExampleStep/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- L = new_organ //new_organ is a variable in /datum/surgery_step, it is null by default, and is given a value in Handle_Multi_Loc()
- //Although Handle_Multi_Loc() is /datum/surgery_step/SURGERYNAME/Handle_Multi_Loc() you do not need to rewrite it in the surgery
- if(L)
- user.visible_message("Generic Statement.")
- else
- user.visible_message("Generic Statement 2.")
-
-
-/datum/surgery_step/multiLocExampleStep/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
-You can use whatever you substituted "L" for here for useful things, swapping limbs for other limbs, etc.
-if the surgery is intended to be MultiLoc but should only be performable once per limb, add this
-"surgery.invalid_locations += user.zone_sel.selecting"
-Just after you have swapped limbs around, see limb augmentation for an example of this
-
-*/
-
-//This file is commented out as to avoid:
-// a snowflakey removal of it 100% of the time
-// it's an example, it doesn't work perfectly due to just being the multiple locations section.
-// It is also not set to compile, due to being Empty (according to the compiler)
-
-//Enjoy making Multi-location operations! (if you understood my Rambling)
-//If you didn't understand this, Ask for RobRichards in Coderbus
\ No newline at end of file
diff --git a/code/modules/surgery/organs/augments.dm b/code/modules/surgery/organs/augments_external.dm
similarity index 95%
rename from code/modules/surgery/organs/augments.dm
rename to code/modules/surgery/organs/augments_external.dm
index 263315aba1b..d3acb5135d9 100644
--- a/code/modules/surgery/organs/augments.dm
+++ b/code/modules/surgery/organs/augments_external.dm
@@ -1,51 +1,51 @@
-/////AUGMENTATION\\\\\
-//See code/modules/surgery/organs/organ.dm for the parent "limb"
-
-
-/obj/item/organ/limb/robot
- name = "cyberlimb"
- desc = "You should never be seeing this!"
- status = ORGAN_ROBOTIC
-
-/obj/item/organ/limb/robot/chest
- name = "chest"
- desc = "A Robotic chest"
- icon_state = "chest"
- max_damage = 200
- body_part = CHEST
-
-/obj/item/organ/limb/robot/head
- name = "head"
- desc = "A Robotic head"
- icon_state = "head"
- max_damage = 200
- body_part = HEAD
-
-/obj/item/organ/limb/robot/l_arm
- name = "l_arm"
- desc = "A Robotic arm"
- icon_state = "l_arm"
- max_damage = 75
- body_part = ARM_LEFT
-
-/obj/item/organ/limb/robot/l_leg
- name = "l_leg"
- desc = "A Robotic leg"
- icon_state = "l_leg"
- max_damage = 75
- body_part = LEG_LEFT
-
-/obj/item/organ/limb/robot/r_arm
- name = "r_arm"
- desc = "A Robotic arm"
- icon_state = "r_arm"
- max_damage = 75
- body_part = ARM_RIGHT
-
-/obj/item/organ/limb/robot/r_leg
- name = "r_leg"
- desc = "A Robotic leg"
- icon_state = "r_leg"
- max_damage = 75
- body_part = LEG_RIGHT
-
+/////AUGMENTATION\\\\\
+//See code/modules/surgery/organs/organ.dm for the parent "limb"
+
+
+/obj/item/organ/limb/robot
+ name = "cyberlimb"
+ desc = "You should never be seeing this!"
+ status = ORGAN_ROBOTIC
+
+/obj/item/organ/limb/robot/chest
+ name = "chest"
+ desc = "A Robotic chest"
+ icon_state = "chest"
+ max_damage = 200
+ body_part = CHEST
+
+/obj/item/organ/limb/robot/head
+ name = "head"
+ desc = "A Robotic head"
+ icon_state = "head"
+ max_damage = 200
+ body_part = HEAD
+
+/obj/item/organ/limb/robot/l_arm
+ name = "l_arm"
+ desc = "A Robotic arm"
+ icon_state = "l_arm"
+ max_damage = 75
+ body_part = ARM_LEFT
+
+/obj/item/organ/limb/robot/l_leg
+ name = "l_leg"
+ desc = "A Robotic leg"
+ icon_state = "l_leg"
+ max_damage = 75
+ body_part = LEG_LEFT
+
+/obj/item/organ/limb/robot/r_arm
+ name = "r_arm"
+ desc = "A Robotic arm"
+ icon_state = "r_arm"
+ max_damage = 75
+ body_part = ARM_RIGHT
+
+/obj/item/organ/limb/robot/r_leg
+ name = "r_leg"
+ desc = "A Robotic leg"
+ icon_state = "r_leg"
+ max_damage = 75
+ body_part = LEG_RIGHT
+
diff --git a/code/modules/surgery/organs/augments_eyes.dm b/code/modules/surgery/organs/augments_eyes.dm
new file mode 100644
index 00000000000..ab814cbf9df
--- /dev/null
+++ b/code/modules/surgery/organs/augments_eyes.dm
@@ -0,0 +1,127 @@
+/obj/item/organ/internal/cyberimp/eyes
+ name = "cybernetic eyes"
+ desc = "artificial photoreceptors with specialized functionality"
+ icon_state = "eye_implant"
+ implant_overlay = "eye_implant_overlay"
+ slot = "eye_sight"
+ zone = "eyes"
+ w_class = 1
+
+ var/sight_flags = 0
+ var/eye_color = "fff"
+ var/old_eye_color = "fff"
+ var/flash_protect = 0
+ var/aug_message = "Your vision is augmented!"
+
+
+/obj/item/organ/internal/cyberimp/eyes/Insert(var/mob/living/carbon/M, var/special = 0)
+ ..()
+ if(istype(owner, /mob/living/carbon/human) && eye_color)
+ var/mob/living/carbon/human/HMN = owner
+ old_eye_color = HMN.eye_color
+ HMN.eye_color = eye_color
+ HMN.regenerate_icons()
+ if(aug_message && !special)
+ owner << "[aug_message]"
+ M.sight |= sight_flags
+
+/obj/item/organ/internal/cyberimp/eyes/Remove(var/mob/living/carbon/M, var/special = 0)
+ M.sight ^= sight_flags
+ if(istype(M,/mob/living/carbon/human) && eye_color)
+ var/mob/living/carbon/human/HMN = owner
+ HMN.eye_color = old_eye_color
+ HMN.regenerate_icons()
+ ..()
+
+/obj/item/organ/internal/cyberimp/eyes/on_life()
+ ..()
+ owner.sight |= sight_flags
+
+/obj/item/organ/internal/cyberimp/eyes/emp_act(severity)
+ if(!owner)
+ return
+ if(severity > 1)
+ if(prob(10 * severity))
+ return
+ var/save_sight = owner.sight
+ owner.sight &= 0
+ owner.disabilities |= BLIND
+ owner << "Static obfuscates your vision!"
+ spawn(60 / severity)
+ if(owner)
+ owner.sight |= save_sight
+ owner.disabilities ^= BLIND
+
+
+
+/obj/item/organ/internal/cyberimp/eyes/xray
+ name = "X-ray implant"
+ desc = "These cybernetic eye implants will give you X-ray vision. Blinking is futile."
+ eye_color = "000"
+ implant_color = "#000000"
+ origin_tech = "materials=6;programming=4;biotech=6;magnets=5"
+ sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
+
+/obj/item/organ/internal/cyberimp/eyes/thermals
+ name = "Thermals implant"
+ desc = "These cybernetic eye implants will give you Thermal vision. Vertical slit pupil included."
+ eye_color = "FC0"
+ implant_color = "#FFCC00"
+ sight_flags = SEE_MOBS
+ flash_protect = -1
+ origin_tech = "materials=6;programming=4;biotech=5;magnets=5;syndicate=4"
+ aug_message = "You see prey everywhere you look..."
+
+
+// HUD implants
+/obj/item/organ/internal/cyberimp/eyes/hud
+ name = "HUD implant"
+ desc = "These cybernetic eyes will display a HUD over everything you see. Maybe."
+ slot = "eye_hud"
+ var/HUD_type = 0
+
+/obj/item/organ/internal/cyberimp/eyes/hud/Insert(var/mob/living/carbon/M, var/special = 0)
+ ..()
+ if(HUD_type)
+ var/datum/atom_hud/H = huds[HUD_type]
+ H.add_hud_to(M)
+ M.permanent_huds |= H
+
+/obj/item/organ/internal/cyberimp/eyes/hud/Remove(var/mob/living/carbon/M, var/special = 0)
+ if(HUD_type)
+ var/datum/atom_hud/H = huds[HUD_type]
+ M.permanent_huds ^= H
+ H.remove_hud_from(M)
+ ..()
+
+/obj/item/organ/internal/cyberimp/eyes/hud/medical
+ name = "Medical HUD implant"
+ desc = "These cybernetic eye implants will display a medical HUD over everything you see."
+ eye_color = "0ff"
+ implant_color = "#00FFFF"
+ origin_tech = "materials=4;programming=3;biotech=4"
+ aug_message = "You suddenly see health bars floating above people's heads..."
+ HUD_type = DATA_HUD_MEDICAL_ADVANCED
+
+/obj/item/organ/internal/cyberimp/eyes/hud/security
+ name = "Security HUD implant"
+ desc = "These cybernetic eye implants will display a security HUD over everything you see."
+ eye_color = "d00"
+ implant_color = "#CC0000"
+ origin_tech = "materials=4;programming=4;biotech=3;combat=1"
+ aug_message = "Job indicator icons pop up in your vision. That is not a certified surgeon..."
+ HUD_type = DATA_HUD_SECURITY_ADVANCED
+
+
+// Welding shield implant
+/obj/item/organ/internal/cyberimp/eyes/shield
+ name = "welding shield implant"
+ desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
+ slot = "eye_shield"
+ origin_tech = "materials=4;biotech=3"
+ implant_color = "#101010"
+ flash_protect = 2
+ // Welding with thermals will still hurt your eyes a bit.
+
+/obj/item/organ/internal/cyberimp/eyes/shield/emp_act(severity)
+ return
\ No newline at end of file
diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm
new file mode 100644
index 00000000000..b904d93f9e3
--- /dev/null
+++ b/code/modules/surgery/organs/augments_internal.dm
@@ -0,0 +1,273 @@
+#define STUN_SET_AMOUNT 2
+
+/obj/item/organ/internal/cyberimp
+ name = "cybernetic implant"
+ desc = "a state-of-the-art implant that improves a baseline's functionality"
+ status = ORGAN_ROBOTIC
+ var/implant_color = "#FFFFFF"
+ var/implant_overlay
+
+/obj/item/organ/internal/cyberimp/New(var/mob/M = null)
+ if(iscarbon(M))
+ src.Insert(M)
+ if(implant_overlay)
+ var/image/overlay = new /image(icon, implant_overlay)
+ overlay.color = implant_color
+ overlays |= overlay
+ return ..()
+
+
+
+//[[[[BRAIN]]]]
+
+/obj/item/organ/internal/cyberimp/brain
+ name = "cybernetic brain implant"
+ desc = "injectors of extra sub-routines for the brain"
+ icon_state = "brain_implant"
+ implant_overlay = "brain_implant_overlay"
+ zone = "head"
+
+/obj/item/organ/internal/cyberimp/brain/emp_act(severity)
+ if(!owner)
+ return
+ var/stun_amount = 5 + (severity-1 ? 0 : 5)
+ owner.Stun(stun_amount)
+ owner << "Your body seizes up!"
+ return stun_amount
+
+
+/obj/item/organ/internal/cyberimp/brain/anti_drop
+ name = "Anti-drop implant"
+ desc = "This cybernetic brain implant will allow you to force your hand muscles to contract, preventing item dropping. Twitch ear to toggle."
+ var/active = 0
+ var/l_hand_ignore = 0
+ var/r_hand_ignore = 0
+ var/obj/item/l_hand_obj = null
+ var/obj/item/r_hand_obj = null
+ implant_color = "#DE7E00"
+ slot = "brain_antidrop"
+ origin_tech = "materials=5;programming=4;biotech=4"
+ organ_action_name = "Toggle Anti-Drop"
+
+/obj/item/organ/internal/cyberimp/brain/anti_drop/ui_action_click()
+ active = !active
+ if(active)
+ l_hand_obj = owner.l_hand
+ r_hand_obj = owner.r_hand
+ if(l_hand_obj)
+ if(owner.l_hand.flags & NODROP)
+ l_hand_ignore = 1
+ else
+ owner.l_hand.flags |= NODROP
+ l_hand_ignore = 0
+
+ if(r_hand_obj)
+ if(owner.r_hand.flags & NODROP)
+ r_hand_ignore = 1
+ else
+ owner.r_hand.flags |= NODROP
+ r_hand_ignore = 0
+
+ if(!l_hand_obj && !r_hand_obj)
+ owner << "You are not holding any items, your hands relax..."
+ active = 0
+ else
+ var/msg = 0
+ msg += !l_hand_ignore && l_hand_obj ? 1 : 0
+ msg += !r_hand_ignore && r_hand_obj ? 2 : 0
+ switch(msg)
+ if(1)
+ owner << "Your left hand's grip tightens."
+ if(2)
+ owner << "Your right hand's grip tightens."
+ if(3)
+ owner << "Both of your hand's grips tighten."
+ else
+ release_items()
+ owner << "Your hands relax..."
+ l_hand_obj = null
+ r_hand_obj = null
+
+/obj/item/organ/internal/cyberimp/brain/anti_drop/emp_act(severity)
+ if(!owner)
+ return
+ var/range = severity ? 10 : 5
+ var/atom/A
+ var/obj/item/L_item = owner.l_hand
+ var/obj/item/R_item = owner.r_hand
+
+ release_items()
+ ..()
+ if(L_item)
+ A = pick(oview(range))
+ L_item.throw_at(A, range, 2)
+ owner << "Your left arm spasms and throws the [L_item.name]!"
+ if(R_item)
+ A = pick(oview(range))
+ R_item.throw_at(A, range, 2)
+ owner << "Your right arm spasms and throws the [R_item.name]!"
+
+/obj/item/organ/internal/cyberimp/brain/anti_drop/proc/release_items()
+ if(!l_hand_ignore && l_hand_obj in owner.contents)
+ l_hand_obj.flags ^= NODROP
+ if(!r_hand_ignore && r_hand_obj in owner.contents)
+ r_hand_obj.flags ^= NODROP
+
+/obj/item/organ/internal/cyberimp/brain/anti_drop/Remove(var/mob/living/carbon/M, special = 0)
+ if(active)
+ ui_action_click()
+ ..()
+
+
+/obj/item/organ/internal/cyberimp/brain/anti_stun
+ name = "CNS Rebooter implant"
+ desc = "This implant will automatically give you back control over your central nervous system, reducing downtime when stunned."
+ implant_color = "#FFFF00"
+ slot = "brain_antistun"
+ origin_tech = "materials=6;programming=4;biotech=5"
+
+/obj/item/organ/internal/cyberimp/brain/anti_stun/on_life()
+ ..()
+ if(crit_fail)
+ return
+
+ if(owner.stunned > STUN_SET_AMOUNT)
+ owner.stunned = STUN_SET_AMOUNT
+ if(owner.weakened > STUN_SET_AMOUNT)
+ owner.weakened = STUN_SET_AMOUNT
+
+/obj/item/organ/internal/cyberimp/brain/anti_stun/emp_act(severity)
+ if(crit_fail)
+ return
+ crit_fail = 1
+ spawn(90 / severity)
+ crit_fail = 0
+
+
+//[[[[CHEST]]]]
+
+/obj/item/organ/internal/cyberimp/chest
+ name = "cybernetic torso implant"
+ desc = "implants for the organs in your torso"
+ icon_state = "chest_implant"
+ implant_overlay = "chest_implant_overlay"
+ zone = "chest"
+
+/obj/item/organ/internal/cyberimp/chest/nutriment
+ name = "Nutriment pump implant"
+ desc = "This implant with synthesize and pump into your bloodstream a small amount of nutriment when you are starving."
+ icon_state = "chest_implant"
+ implant_color = "#00AA00"
+ var/hunger_threshold = NUTRITION_LEVEL_STARVING
+ var/synthesizing = 0
+ var/poison_amount = 5
+ slot = "stomach"
+ origin_tech = "materials=5;programming=3;biotech=4"
+
+/obj/item/organ/internal/cyberimp/chest/nutriment/on_life()
+ if(synthesizing)
+ return
+
+ if(owner.nutrition <= hunger_threshold)
+ synthesizing = 1
+ owner << "You feel less hungry..."
+ owner.nutrition += 50
+ spawn(50)
+ synthesizing = 0
+
+/obj/item/organ/internal/cyberimp/chest/nutriment/emp_act(severity)
+ if(!owner)
+ return
+ owner.reagents.add_reagent("????",poison_amount / severity) //food poisoning
+ owner << "You feel like your insides are burning."
+
+
+/obj/item/organ/internal/cyberimp/chest/nutriment/plus
+ name = "Nutriment pump implant PLUS"
+ desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are hungry."
+ icon_state = "chest_implant"
+ implant_color = "#006607"
+ hunger_threshold = NUTRITION_LEVEL_HUNGRY
+ poison_amount = 10
+ origin_tech = "materials=5;programming=3;biotech=5"
+
+
+
+/obj/item/organ/internal/cyberimp/chest/reviver
+ name = "Reviver implant"
+ desc = "This implant will attempt to revive you if you lose consciousness. For the faint of heart!"
+ icon_state = "chest_implant"
+ implant_color = "#AD0000"
+ origin_tech = "materials=6;programming=3;biotech=6;syndicate=4"
+ slot = "heartdrive"
+ var/revive_cost = 0
+ var/reviving = 0
+ var/cooldown = 0
+
+/obj/item/organ/internal/cyberimp/chest/reviver/on_life()
+ if(reviving)
+ if(owner.stat == UNCONSCIOUS)
+ spawn(30)
+ if(prob(90) && owner.getOxyLoss())
+ owner.adjustOxyLoss(-3)
+ revive_cost += 5
+ if(prob(75) && owner.getBruteLoss())
+ owner.adjustBruteLoss(-1)
+ revive_cost += 20
+ if(prob(75) && owner.getFireLoss())
+ owner.adjustFireLoss(-1)
+ revive_cost += 20
+ if(prob(40) && owner.getToxLoss())
+ owner.adjustToxLoss(-1)
+ revive_cost += 50
+ else
+ cooldown = revive_cost + world.time
+ reviving = 0
+ return
+
+ if(cooldown > world.time)
+ return
+ if(owner.stat != UNCONSCIOUS)
+ return
+ if(owner.suiciding)
+ return
+
+ revive_cost = 0
+ reviving = 1
+
+/obj/item/organ/internal/cyberimp/chest/reviver/emp_act(severity)
+ if(!owner)
+ return
+
+ if(reviving)
+ revive_cost += 200
+ else
+ cooldown += 200
+
+ if(istype(owner, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = owner
+ if(H.stat != DEAD && prob(50 / severity))
+ H.heart_attack = 1
+ spawn(600 / severity)
+ H.heart_attack = 0
+ if(H.stat == CONSCIOUS)
+ H << "You feel your heart beating again!"
+
+
+//BOX O' IMPLANTS
+
+/obj/item/weapon/storage/box/cyber_implants
+ name = "boxed cybernetic implants"
+ desc = "A sleek, sturdy box."
+ icon_state = "cyber_implants"
+ var/list/boxed = list(/obj/item/organ/internal/cyberimp/eyes/xray,/obj/item/organ/internal/cyberimp/eyes/thermals,
+ /obj/item/organ/internal/cyberimp/brain/anti_stun, /obj/item/organ/internal/cyberimp/chest/reviver)
+ var/amount = 5
+
+/obj/item/weapon/storage/box/cyber_implants/New()
+ ..()
+ var/i
+ var/implant
+ for(i = 0, i < amount, i++)
+ implant = pick(boxed)
+ new implant(src)
\ No newline at end of file
diff --git a/code/modules/surgery/organs/cybernetic_implants.dm b/code/modules/surgery/organs/cybernetic_implants.dm
deleted file mode 100644
index 61a58711ac8..00000000000
--- a/code/modules/surgery/organs/cybernetic_implants.dm
+++ /dev/null
@@ -1,396 +0,0 @@
-#define STUN_SET_AMOUNT 2
-
-/obj/item/cybernetic_implant
- name = "cybernetic implant"
- desc = "a state-of-the-art implant that improves a baseline's functionality"
- icon = 'icons/obj/surgery.dmi'
- var/mob/living/carbon/owner = null
- var/implant_color = "#FFFFFF"
-
-/obj/item/cybernetic_implant/New(var/mob/M = null)
- owner = M
- return ..()
-
-/obj/item/cybernetic_implant/proc/function()
- return
-
-
-//[[[[EYES]]]]
-
-/obj/item/cybernetic_implant/eyes
- name = "cybernetic eyes"
- desc = "artificial photoreceptors with specialized functionality"
- icon_state = "eye_implant"
- var/eye_color = "fff"
- var/flash_protect = 0
-
-/obj/item/cybernetic_implant/eyes/New()
- var/icon/overlay = new /icon('icons/obj/surgery.dmi',"eye_implant_overlay")
- overlay.ColorTone(implant_color)
- overlays |= overlay
- ..()
-
-/obj/item/cybernetic_implant/eyes/proc/update_eye_color(fluff_message)
- if(istype(owner,/mob/living/carbon/human))
- var/mob/living/carbon/human/HMN = owner
- HMN.eye_color = eye_color
- HMN.regenerate_icons()
- if(fluff_message)
- owner << "[fluff_message]"
-
-/obj/item/cybernetic_implant/eyes/hud/medical
- name = "Medical HUD implant"
- desc = "These cybernetic eyes will display a medical HUD over everything you see. Wiggle eyes to control."
- eye_color = "0ff"
- implant_color = "#00FFFF"
- origin_tech = "materials=4;programming=3;biotech=4"
-
-/obj/item/cybernetic_implant/eyes/hud/medical/function()
- if(!owner)
- return
-
- var/datum/atom_hud/H = huds[DATA_HUD_MEDICAL_ADVANCED]
- H.add_hud_to(owner)
- owner.permanent_huds |= H
- update_eye_color("You suddenly see health bars floating above people's heads...")
-
-/obj/item/cybernetic_implant/eyes/hud/security
- name = "Security HUD implant"
- desc = "These cybernetic eyes will display a security HUD over everything you see. Wiggle eyes to control."
- eye_color = "d00"
- implant_color = "#CC0000"
- origin_tech = "materials=4;programming=4;biotech=3;combat=1"
-
-/obj/item/cybernetic_implant/eyes/hud/security/function()
- if(!owner)
- return
-
- var/datum/atom_hud/H = huds[DATA_HUD_SECURITY_ADVANCED]
- H.add_hud_to(owner)
- owner.permanent_huds |= H
- update_eye_color("Job indicator icons pop up in your vision. That is not a certified surgeon...")
-
-/obj/item/cybernetic_implant/eyes/xray
- name = "X-ray implant"
- desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
- eye_color = "000"
- implant_color = "#000000"
- origin_tech = "materials=6;programming=4;biotech=6;magnets=5"
-
-/obj/item/cybernetic_implant/eyes/xray/function()
- if(!owner)
- return
-
- owner.sight |= SEE_MOBS
- owner.sight |= SEE_OBJS
- owner.sight |= SEE_TURFS
- owner.permanent_sight_flags |= SEE_MOBS
- owner.permanent_sight_flags |= SEE_OBJS
- owner.permanent_sight_flags |= SEE_TURFS
- update_eye_color("Your vision is augmented!")
-
-/obj/item/cybernetic_implant/eyes/thermals
- name = "Thermals implant"
- desc = "These cybernetic eyes will give you Thermal vision. Vertical slit pupil included."
- eye_color = "FC0"
- implant_color = "#FFCC00"
- flash_protect = -1
- origin_tech = "materials=6;programming=4;biotech=5;magnets=5;syndicate=4"
-
-/obj/item/cybernetic_implant/eyes/thermals/function()
- if(!owner)
- return
-
- owner.sight |= SEE_MOBS
- owner.permanent_sight_flags |= SEE_MOBS
- update_eye_color("You see prey everywhere you look...")
-
-/obj/item/cybernetic_implant/eyes/emp_act(severity)
- if(!owner)
- return
- if(severity > 1)
- if(prob(5))
- return
- var/save_sight = owner.sight
- owner.sight &= 0
- owner.disabilities |= BLIND
- owner << "Static obfuscates your vision!"
- spawn(50)
- owner.sight |= save_sight
- owner.disabilities ^= BLIND
-
-
-//[[[[BRAIN]]]]
-
-/obj/item/cybernetic_implant/brain
- name = "cybernetic brain implant"
- desc = "injectors of extra sub-routines for the brain"
- icon_state = "brain_implant"
-
-/obj/item/cybernetic_implant/brain/New()
- var/icon/overlay = new /icon('icons/obj/surgery.dmi',"brain_implant_overlay")
- overlay.ColorTone(implant_color)
- overlays |= overlay
- ..()
-
-/obj/item/cybernetic_implant/brain/emp_act(severity)
- if(!owner)
- return
- var/stun_amount = 5 + (severity-1 ? 0 : 5)
- owner.Stun(stun_amount)
- owner << "Your body seizes up!"
- return stun_amount
-
-/obj/item/cybernetic_implant/brain/anti_drop
- name = "Anti-drop implant"
- desc = "This cybernetic brain implant will allow you to force your hand muscles to contract, preventing item dropping. Twitch ear to toggle."
- var/active = 0
- var/l_hand_ignore = 0
- var/r_hand_ignore = 0
- var/obj/item/l_hand_obj = null
- var/obj/item/r_hand_obj = null
- implant_color = "#DE7E00"
- origin_tech = "materials=5;programming=4;biotech=4"
-
-/obj/item/cybernetic_implant/brain/anti_drop/function()
- action_button_name = "Toggle Anti-Drop"
-
-/obj/item/cybernetic_implant/brain/anti_drop/ui_action_click()
- active = !active
- if(active)
- l_hand_obj = owner.l_hand
- r_hand_obj = owner.r_hand
- if(l_hand_obj)
- if(owner.l_hand.flags & NODROP)
- l_hand_ignore = 1
- else
- owner.l_hand.flags |= NODROP
- l_hand_ignore = 0
-
- if(r_hand_obj)
- if(owner.r_hand.flags & NODROP)
- r_hand_ignore = 1
- else
- owner.r_hand.flags |= NODROP
- r_hand_ignore = 0
-
- if(!l_hand_obj && !r_hand_obj)
- owner << "You are not holding any items, your hands relax..."
- active = 0
- else
- var/msg = 0
- msg += !l_hand_ignore && l_hand_obj ? 1 : 0
- msg += !r_hand_ignore && r_hand_obj ? 2 : 0
- switch(msg)
- if(1)
- owner << "Your left hand's grip tightens."
- if(2)
- owner << "Your right hand's grip tightens."
- if(3)
- owner << "Both of your hand's grips tighten."
- else
- release_items()
- owner << "Your hands relax..."
- l_hand_obj = null
- r_hand_obj = null
-
-/obj/item/cybernetic_implant/brain/anti_drop/emp_act(severity)
- if(!owner)
- return
- var/range = severity ? 10 : 5
- var/atom/A
- var/obj/item/L_item = owner.l_hand
- var/obj/item/R_item = owner.r_hand
-
- release_items()
- ..()
- if(L_item)
- A = pick(oview(range))
- L_item.throw_at(A, range, 2)
- owner << "Your left arm spasms and throws the [L_item.name]!"
- if(R_item)
- A = pick(oview(range))
- R_item.throw_at(A, range, 2)
- owner << "Your right arm spasms and throws the [R_item.name]!"
-
-/obj/item/cybernetic_implant/brain/anti_drop/proc/release_items()
- if(!l_hand_ignore && l_hand_obj in owner.contents)
- l_hand_obj.flags ^= NODROP
- if(!r_hand_ignore && r_hand_obj in owner.contents)
- r_hand_obj.flags ^= NODROP
-
-/obj/item/cybernetic_implant/brain/anti_stun
- name = "CNS Rebooter implant"
- desc = "This implant will automatically give you back control over your central nervous system, reducing downtime when stunned."
- implant_color = "#FFFF00"
- origin_tech = "materials=6;programming=4;biotech=5"
-
-/obj/item/cybernetic_implant/brain/anti_stun/function()
- SSobj.processing |= src
-
-/obj/item/cybernetic_implant/brain/anti_stun/process()
- if(!owner)
- SSobj.processing.Remove(src)
- qdel(src)
- return
- if(owner.stat == DEAD)
- return
-
- if(owner.stunned > STUN_SET_AMOUNT)
- owner.stunned = STUN_SET_AMOUNT
- if(owner.weakened > STUN_SET_AMOUNT)
- owner.weakened = STUN_SET_AMOUNT
-
-/obj/item/cybernetic_implant/brain/anti_stun/emp_act(severity)
- if(!owner)
- return
- SSobj.processing.Remove(src)
- spawn(..() * 10)
- SSobj.processing |= src
-
-
-//[[[[CHEST]]]]
-
-/obj/item/cybernetic_implant/chest
- name = "cybernetic torso implant"
- desc = "implants for the organs in your torso"
- icon_state = "chest_implant"
-
-/obj/item/cybernetic_implant/chest/New()
- var/icon/overlay = new /icon('icons/obj/surgery.dmi',"chest_implant_overlay")
- overlay.ColorTone(implant_color)
- overlays |= overlay
- ..()
-
-/obj/item/cybernetic_implant/chest/nutriment
- name = "Nutriment pump implant"
- desc = "This implant with synthesize and pump into your bloodstream a small amount of nutriment when you are starving."
- icon_state = "chest_implant"
- implant_color = "#00AA00"
- var/hunger_threshold = NUTRITION_LEVEL_STARVING
- var/synthesizing = 0
- var/nutriment_amount = 30
- var/poison_amount = 5
- origin_tech = "materials=5;programming=3;biotech=4"
-
-/obj/item/cybernetic_implant/chest/nutriment/function()
- SSobj.processing |= src
-
-/obj/item/cybernetic_implant/chest/nutriment/process()
- if(synthesizing)
- return
- if(!owner)
- SSobj.processing.Remove(src)
- qdel(src)
- return
- if(owner.stat == DEAD)
- return
-
- if(owner.nutrition <= hunger_threshold)
- synthesizing = 1
- spawn(50)
- owner << "You feel less hungry..."
- owner.nutrition += nutriment_amount
- synthesizing = 0
-
-/obj/item/cybernetic_implant/chest/nutriment/plus
- name = "Nutriment pump implant PLUS"
- desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are hungry."
- icon_state = "chest_implant"
- implant_color = "#006607"
- hunger_threshold = NUTRITION_LEVEL_HUNGRY
- nutriment_amount = 50
- poison_amount = 10
- origin_tech = "materials=5;programming=3;biotech=5"
-
-/obj/item/cybernetic_implant/chest/nutriment/emp_act(severity)
- if(!owner)
- return
- owner.reagents.add_reagent("????",poison_amount / severity) //food poisoning
- owner << "You feel like your insides are burning."
-
-
-/obj/item/cybernetic_implant/chest/reviver
- name = "Reviver implant"
- desc = "This implant will attempt to revive you if you lose consciousness. For the faint of heart!"
- icon_state = "chest_implant"
- implant_color = "#AD0000"
- origin_tech = "materials=6;programming=3;biotech=6;syndicate=4"
- var/revive_cost = 0
- var/reviving = 0
- var/cooldown = 0
-
-/obj/item/cybernetic_implant/chest/reviver/function()
- SSobj.processing |= src
-
-/obj/item/cybernetic_implant/chest/reviver/process()
- if(!owner)
- SSobj.processing.Remove(src)
- qdel(src)
- return
-
- if(reviving)
- if(owner.stat == UNCONSCIOUS)
- spawn(30)
- if(prob(90) && owner.getOxyLoss())
- owner.adjustOxyLoss(-3)
- revive_cost += 5
- if(prob(75) && owner.getBruteLoss())
- owner.adjustBruteLoss(-1)
- revive_cost += 20
- if(prob(75) && owner.getFireLoss())
- owner.adjustFireLoss(-1)
- revive_cost += 20
- if(prob(40) && owner.getToxLoss())
- owner.adjustToxLoss(-1)
- revive_cost += 50
- else
- cooldown = revive_cost + world.time
- reviving = 0
- return
-
- if(cooldown > world.time)
- return
- if(owner.stat != UNCONSCIOUS)
- return
- if(owner.suiciding)
- SSobj.processing.Remove(src)
- return
-
- revive_cost = 0
- reviving = 1
-
-/obj/item/cybernetic_implant/chest/reviver/emp_act(severity)
- if(reviving)
- revive_cost += 200
- else
- cooldown += 200
-
- if(istype(owner, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = owner
- if(H.stat != DEAD && prob(50 / severity))
- H.heart_attack = 1
- spawn(600 / severity)
- H.heart_attack = 0
- if(H.stat == CONSCIOUS)
- H << "You feel your heart beating again!"
-
-
-//BOX O' IMPLANTS
-
-/obj/item/weapon/storage/box/cyber_implants
- name = "boxed cybernetic implants"
- desc = "A sleek, sturdy box."
- icon_state = "cyber_implants"
- var/list/boxed = list(/obj/item/cybernetic_implant/eyes/xray,/obj/item/cybernetic_implant/eyes/thermals,
- /obj/item/cybernetic_implant/brain/anti_drop, /obj/item/cybernetic_implant/brain/anti_stun,
- /obj/item/cybernetic_implant/chest/nutriment/plus, /obj/item/cybernetic_implant/chest/reviver)
- var/amount = 5
-
-/obj/item/weapon/storage/box/cyber_implants/New()
- ..()
- var/i
- var/implant
- for(i = 0, i < amount, i++)
- implant = pick(boxed)
- new implant(src)
\ No newline at end of file
diff --git a/code/modules/surgery/organs/helpers.dm b/code/modules/surgery/organs/helpers.dm
index dd0529d4344..18b4185ea52 100644
--- a/code/modules/surgery/organs/helpers.dm
+++ b/code/modules/surgery/organs/helpers.dm
@@ -1,13 +1,33 @@
-/mob/proc/getorgan()
+mob/proc/getorgan(typepath)
return
-/mob/living/carbon/getorgan(typepath)
+
+mob/proc/getorganszone(zone)
+ return
+
+mob/proc/getorganslot(slot)
+ return
+
+
+mob/living/carbon/getorgan(typepath)
return (locate(typepath) in internal_organs)
-/mob/proc/getlimb()
+mob/living/carbon/getorganszone(zone)
+ var/list/returnorg = list()
+ for(var/obj/item/organ/internal/O in internal_organs)
+ if(zone == O.zone)
+ returnorg += O
+ return returnorg
+
+mob/living/carbon/getorganslot(slot)
+ for(var/obj/item/organ/internal/O in internal_organs)
+ if(slot == O.slot)
+ return O
+
+mob/proc/getlimb()
return
-/mob/living/carbon/human/getlimb(typepath)
+mob/living/carbon/human/getlimb(typepath)
return (locate(typepath) in organs)
-
-
+proc/isorgan(atom/A)
+ return istype(A, /obj/item/organ/internal)
\ No newline at end of file
diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ_external.dm
similarity index 85%
rename from code/modules/surgery/organs/organ.dm
rename to code/modules/surgery/organs/organ_external.dm
index 05ae58ccc21..9e231fae5d1 100644
--- a/code/modules/surgery/organs/organ.dm
+++ b/code/modules/surgery/organs/organ_external.dm
@@ -1,199 +1,171 @@
-/obj/item/organ
- name = "organ"
- icon = 'icons/obj/surgery.dmi'
-
-
-
-/obj/item/organ/heart
- name = "heart"
- icon_state = "heart-on"
- var/beating = 1
-
-/obj/item/organ/heart/update_icon()
- if(beating)
- icon_state = "heart-on"
- else
- icon_state = "heart-off"
-
-
-/obj/item/organ/appendix
- name = "appendix"
- icon_state = "appendix"
- var/inflamed = 1
-
-/obj/item/organ/appendix/update_icon()
- if(inflamed)
- icon_state = "appendixinflamed"
- else
- icon_state = "appendix"
-
-
-//Looking for brains?
-//Try code/modules/mob/living/carbon/brain/brain_item.dm
-
-//Old Datum Limbs:
-// code/modules/unused/limbs.dm
-
-
-/obj/item/organ/limb
- name = "limb"
- var/mob/owner = null
- var/body_part = null
- var/brutestate = 0
- var/burnstate = 0
- var/brute_dam = 0
- var/burn_dam = 0
- var/max_damage = 0
- var/status = ORGAN_ORGANIC
- var/list/embedded_objects = list()
-
-
-
-/obj/item/organ/limb/chest
- name = "chest"
- desc = "why is it detached..."
- icon_state = "chest"
- max_damage = 200
- body_part = CHEST
-
-
-/obj/item/organ/limb/head
- name = "head"
- desc = "what a way to get a head in life..."
- icon_state = "head"
- max_damage = 200
- body_part = HEAD
-
-
-/obj/item/organ/limb/l_arm
- name = "l_arm"
- desc = "why is it detached..."
- icon_state = "l_arm"
- max_damage = 75
- body_part = ARM_LEFT
-
-
-/obj/item/organ/limb/l_leg
- name = "l_leg"
- desc = "why is it detached..."
- icon_state = "l_leg"
- max_damage = 75
- body_part = LEG_LEFT
-
-
-/obj/item/organ/limb/r_arm
- name = "r_arm"
- desc = "why is it detached..."
- icon_state = "r_arm"
- max_damage = 75
- body_part = ARM_RIGHT
-
-
-/obj/item/organ/limb/r_leg
- name = "r_leg"
- desc = "why is it detached..."
- icon_state = "r_leg"
- max_damage = 75
- body_part = LEG_RIGHT
-
-
-
-//Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all.
-//Damage will not exceed max_damage using this proc
-//Cannot apply negative damage
-/obj/item/organ/limb/proc/take_damage(brute, burn)
- if(owner && (owner.status_flags & GODMODE)) return 0 //godmode
- brute = max(brute,0)
- burn = max(burn,0)
-
-
- if(status == ORGAN_ROBOTIC) //This makes robolimbs not damageable by chems and makes it stronger
- brute = max(0, brute - 5)
- burn = max(0, burn - 4)
-
- var/can_inflict = max_damage - (brute_dam + burn_dam)
- if(!can_inflict) return 0
-
- if((brute + burn) < can_inflict)
- brute_dam += brute
- burn_dam += burn
- else
- if(brute > 0)
- if(burn > 0)
- brute = round( (brute/(brute+burn)) * can_inflict, 1 )
- burn = can_inflict - brute //gets whatever damage is left over
- brute_dam += brute
- burn_dam += burn
- else
- brute_dam += can_inflict
- else
- if(burn > 0)
- burn_dam += can_inflict
- else
- return 0
- return update_organ_icon()
-
-
-//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
-//Damage cannot go below zero.
-//Cannot remove negative damage (i.e. apply damage)
-/obj/item/organ/limb/proc/heal_damage(brute, burn, robotic)
-
- if(robotic && status != ORGAN_ROBOTIC) // This makes organic limbs not heal when the proc is in Robotic mode.
- brute = max(0, brute - 3)
- burn = max(0, burn - 3)
-
- if(!robotic && status == ORGAN_ROBOTIC) // This makes robolimbs not healable by chems.
- brute = max(0, brute - 3)
- burn = max(0, burn - 3)
-
- brute_dam = max(brute_dam - brute, 0)
- burn_dam = max(burn_dam - burn, 0)
- return update_organ_icon()
-
-
-//Returns total damage...kinda pointless really
-/obj/item/organ/limb/proc/get_damage()
- return brute_dam + burn_dam
-
-
-//Updates an organ's brute/burn states for use by update_damage_overlays()
-//Returns 1 if we need to update overlays. 0 otherwise.
-/obj/item/organ/limb/proc/update_organ_icon()
- if(status == ORGAN_ORGANIC) //Robotic limbs show no damage - RR
- var/tbrute = round( (brute_dam/max_damage)*3, 1 )
- var/tburn = round( (burn_dam/max_damage)*3, 1 )
- if((tbrute != brutestate) || (tburn != burnstate))
- brutestate = tbrute
- burnstate = tburn
- return 1
- return 0
-
-//Returns a display name for the organ
-/obj/item/organ/limb/proc/getDisplayName() //Added "Chest" and "Head" just in case, this may not be needed
- switch(name)
- if("l_leg") return "left leg"
- if("r_leg") return "right leg"
- if("l_arm") return "left arm"
- if("r_arm") return "right arm"
- if("chest") return "chest"
- if("head") return "head"
- else return name
-
-
-//Remove all embedded objects from all limbs on the human mob
-/mob/living/carbon/human/proc/remove_all_embedded_objects()
- var/turf/T = get_turf(src)
-
- for(var/obj/item/organ/limb/L in organs)
- for(var/obj/item/I in L.embedded_objects)
- L.embedded_objects -= I
- I.loc = T
-
- clear_alert("embeddedobject")
-
-/mob/living/carbon/human/proc/has_embedded_objects()
- . = 0
- for(var/obj/item/organ/limb/L in organs)
- for(var/obj/item/I in L.embedded_objects)
+/obj/item/organ
+ name = "organ"
+ icon = 'icons/obj/surgery.dmi'
+ var/mob/living/carbon/owner = null
+ var/status = ORGAN_ORGANIC
+
+
+//Old Datum Limbs:
+// code/modules/unused/limbs.dm
+
+
+/obj/item/organ/limb
+ name = "limb"
+ var/body_part = null
+ var/brutestate = 0
+ var/burnstate = 0
+ var/brute_dam = 0
+ var/burn_dam = 0
+ var/max_damage = 0
+ var/list/embedded_objects = list()
+
+
+
+/obj/item/organ/limb/chest
+ name = "chest"
+ desc = "why is it detached..."
+ icon_state = "chest"
+ max_damage = 200
+ body_part = CHEST
+
+
+/obj/item/organ/limb/head
+ name = "head"
+ desc = "what a way to get a head in life..."
+ icon_state = "head"
+ max_damage = 200
+ body_part = HEAD
+
+
+/obj/item/organ/limb/l_arm
+ name = "l_arm"
+ desc = "why is it detached..."
+ icon_state = "l_arm"
+ max_damage = 75
+ body_part = ARM_LEFT
+
+
+/obj/item/organ/limb/l_leg
+ name = "l_leg"
+ desc = "why is it detached..."
+ icon_state = "l_leg"
+ max_damage = 75
+ body_part = LEG_LEFT
+
+
+/obj/item/organ/limb/r_arm
+ name = "r_arm"
+ desc = "why is it detached..."
+ icon_state = "r_arm"
+ max_damage = 75
+ body_part = ARM_RIGHT
+
+
+/obj/item/organ/limb/r_leg
+ name = "r_leg"
+ desc = "why is it detached..."
+ icon_state = "r_leg"
+ max_damage = 75
+ body_part = LEG_RIGHT
+
+
+
+//Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all.
+//Damage will not exceed max_damage using this proc
+//Cannot apply negative damage
+/obj/item/organ/limb/proc/take_damage(brute, burn)
+ if(owner && (owner.status_flags & GODMODE)) return 0 //godmode
+ brute = max(brute,0)
+ burn = max(burn,0)
+
+
+ if(status == ORGAN_ROBOTIC) //This makes robolimbs not damageable by chems and makes it stronger
+ brute = max(0, brute - 5)
+ burn = max(0, burn - 4)
+
+ var/can_inflict = max_damage - (brute_dam + burn_dam)
+ if(!can_inflict) return 0
+
+ if((brute + burn) < can_inflict)
+ brute_dam += brute
+ burn_dam += burn
+ else
+ if(brute > 0)
+ if(burn > 0)
+ brute = round( (brute/(brute+burn)) * can_inflict, 1 )
+ burn = can_inflict - brute //gets whatever damage is left over
+ brute_dam += brute
+ burn_dam += burn
+ else
+ brute_dam += can_inflict
+ else
+ if(burn > 0)
+ burn_dam += can_inflict
+ else
+ return 0
+ return update_organ_icon()
+
+
+//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
+//Damage cannot go below zero.
+//Cannot remove negative damage (i.e. apply damage)
+/obj/item/organ/limb/proc/heal_damage(brute, burn, robotic)
+
+ if(robotic && status != ORGAN_ROBOTIC) // This makes organic limbs not heal when the proc is in Robotic mode.
+ brute = max(0, brute - 3)
+ burn = max(0, burn - 3)
+
+ if(!robotic && status == ORGAN_ROBOTIC) // This makes robolimbs not healable by chems.
+ brute = max(0, brute - 3)
+ burn = max(0, burn - 3)
+
+ brute_dam = max(brute_dam - brute, 0)
+ burn_dam = max(burn_dam - burn, 0)
+ return update_organ_icon()
+
+
+//Returns total damage...kinda pointless really
+/obj/item/organ/limb/proc/get_damage()
+ return brute_dam + burn_dam
+
+
+//Updates an organ's brute/burn states for use by update_damage_overlays()
+//Returns 1 if we need to update overlays. 0 otherwise.
+/obj/item/organ/limb/proc/update_organ_icon()
+ if(status == ORGAN_ORGANIC) //Robotic limbs show no damage - RR
+ var/tbrute = round( (brute_dam/max_damage)*3, 1 )
+ var/tburn = round( (burn_dam/max_damage)*3, 1 )
+ if((tbrute != brutestate) || (tburn != burnstate))
+ brutestate = tbrute
+ burnstate = tburn
+ return 1
+ return 0
+
+//Returns a display name for the organ
+/obj/item/organ/limb/proc/getDisplayName() //Added "Chest" and "Head" just in case, this may not be needed
+ switch(name)
+ if("l_leg") return "left leg"
+ if("r_leg") return "right leg"
+ if("l_arm") return "left arm"
+ if("r_arm") return "right arm"
+ if("chest") return "chest"
+ if("head") return "head"
+ else return name
+
+
+//Remove all embedded objects from all limbs on the human mob
+/mob/living/carbon/human/proc/remove_all_embedded_objects()
+ var/turf/T = get_turf(src)
+
+ for(var/obj/item/organ/limb/L in organs)
+ for(var/obj/item/I in L.embedded_objects)
+ L.embedded_objects -= I
+ I.loc = T
+
+ clear_alert("embeddedobject")
+
+/mob/living/carbon/human/proc/has_embedded_objects()
+ . = 0
+ for(var/obj/item/organ/limb/L in organs)
+ for(var/obj/item/I in L.embedded_objects)
return 1
\ No newline at end of file
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
new file mode 100644
index 00000000000..ae4e1e00a55
--- /dev/null
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -0,0 +1,95 @@
+/obj/item/organ/internal
+ origin_tech = "biotech=2"
+ var/zone = "chest"
+ var/slot
+ var/vital = 0
+ var/organ_action_name = null
+
+/obj/item/organ/internal/proc/Insert(var/mob/living/carbon/M, special = 0)
+ if(!iscarbon(M) || owner)
+ return
+
+ var/obj/item/organ/internal/replaced = M.getorganslot(slot)
+ if(replaced)
+ replaced.Remove(M, special = 1)
+
+ owner = M
+ M.internal_organs |= src
+ loc = null
+ if(organ_action_name)
+ action_button_name = organ_action_name
+
+/obj/item/organ/internal/proc/Remove(var/mob/living/carbon/M, special = 0)
+ owner = null
+ if(M)
+ M.internal_organs -= src
+ if(vital && !special)
+ M.death()
+
+ if(organ_action_name)
+ action_button_name = null
+
+/obj/item/organ/internal/proc/on_life()
+ return
+
+/obj/item/organ/internal/Destroy()
+ if(owner)
+ Remove(owner, 1)
+ ..()
+
+//Looking for brains?
+//Try code/modules/mob/living/carbon/brain/brain_item.dm
+
+
+
+/obj/item/organ/internal/heart
+ name = "heart"
+ icon_state = "heart-on"
+ zone = "chest"
+ slot = "heart"
+ origin_tech = "biotech=3"
+ vital = 1
+ var/beating = 1
+
+/obj/item/organ/internal/heart/update_icon()
+ if(beating)
+ icon_state = "heart-on"
+ else
+ icon_state = "heart-off"
+
+/obj/item/organ/internal/heart/Insert(var/mob/living/carbon/M, special = 0)
+ ..()
+ beating = 1
+ update_icon()
+
+/obj/item/organ/internal/heart/Remove(var/mob/living/carbon/M, special = 0)
+ ..()
+ spawn(120)
+ beating = 0
+ update_icon()
+
+
+/obj/item/organ/internal/appendix
+ name = "appendix"
+ icon_state = "appendix"
+ zone = "groin"
+ slot = "appendix"
+ var/inflamed = 0
+
+/obj/item/organ/internal/appendix/update_icon()
+ if(inflamed)
+ icon_state = "appendixinflamed"
+ name = "inflamed appendix"
+ else
+ icon_state = "appendix"
+ name = "appendix"
+
+/obj/item/organ/internal/appendix/Remove(var/mob/living/carbon/M, special = 0)
+ for(var/datum/disease/appendicitis in M.viruses)
+ appendicitis.cure()
+ ..()
+
+/obj/item/organ/internal/appendix/Insert(var/mob/living/carbon/M, special = 0)
+ ..()
+ if(inflamed)
+ M.AddDisease(new /datum/disease/appendicitis)
\ No newline at end of file
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 4dd1f600b2d..52a52d10a74 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -1,11 +1,11 @@
/datum/surgery/plastic_surgery
name = "plastic surgery"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/reshape_face, /datum/surgery_step/close)
- species = list(/mob/living/carbon/human)
- location = "head"
+ possible_locs = list("head")
//reshape_face
/datum/surgery_step/reshape_face
+ name = "reshape face"
implements = list(/obj/item/weapon/scalpel = 100, /obj/item/weapon/kitchen/knife = 50, /obj/item/weapon/wirecutters = 35)
time = 64
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
index f8e7de333d9..5ca4083ab6c 100644
--- a/code/modules/surgery/remove_embedded_object.dm
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -1,22 +1,18 @@
-
-
/datum/surgery/embedded_removal
name = "removal of embedded objects"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/remove_object)
- species = list(/mob/living/carbon/human)
- location = "anywhere"
- has_multi_loc = 1
+ possible_locs = list("r_arm","l_arm","r_leg","l_leg","chest","head")
/datum/surgery_step/remove_object
+ name = "remove embedded objects"
time = 32
- allowed_organs = list("r_arm","l_arm","r_leg","l_leg","chest","head")
accept_hand = 1
var/obj/item/organ/limb/L = null
/datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- L = new_organ
+ L = surgery.organ
if(L)
user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)]...")
else
@@ -33,9 +29,6 @@
I.loc = get_turf(H)
L.embedded_objects -= I
- if(!H.has_embedded_objects())
- H.clear_alert("embeddedobject")
-
if(objects > 0)
user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L.getDisplayName()]!", "You sucessfully remove [objects] objects from [H]'s [L.getDisplayName()].")
else
diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm
index d7f7fdfebb5..9a9196562fd 100644
--- a/code/modules/surgery/surgery.dm
+++ b/code/modules/surgery/surgery.dm
@@ -1,17 +1,22 @@
/datum/surgery
- var/name = null
+ var/name = "surgery"
var/status = 1
var/list/steps = list() //Steps in a surgery
var/step_in_progress = 0 //Actively performing a Surgery
var/list/species = list(/mob/living/carbon/human) //Acceptable Species
var/location = "chest" //Surgery location
var/target_must_be_dead = 0 //Needs to be dead
- var/target_must_be_fat = 0 //Needs to be fat
- var/requires_organic_chest = 0 //Prevents you from performing an operation on Robotic chests***
- var/has_multi_loc = 0 //Multiple locations - RR
- var/user_species_restricted = 0 //Surgery only performable BY species
- var/list/user_species_ids
+ var/requires_organic_bodypart = 1 //Prevents you from performing an operation on robotic limbs
+ var/list/possible_locs = list() //Multiple locations -- c0
var/ignore_clothes = 0 //This surgery ignores clothes
+ var/obj/item/organ/organ //Operable body part
+
+
+/datum/surgery/proc/can_start(mob/user, mob/living/carbon/target)
+ // if 0 surgery wont show up in list
+ // put special restrictions here
+ return 1
+
/datum/surgery/proc/next_step(mob/user, mob/living/carbon/target)
if(step_in_progress) return
@@ -54,8 +59,4 @@
//RESOLVED ISSUES //"Todo" jobs that have been completed
//combine hands/feet into the arms - Hands/feet were removed - RR
-//surgeries (not steps) that can be initiated on any body part (corresponding with damage locations) - Call this one done, see multiple_location_example.dm - RR
-
-
-//*** This may seem entirely redundant because of Organic organs only having operations but you CAN circumvent that due to
-//all surgeries (except augmentation) not checking where the surgeon aims so this is just a double check, it IS needed - RR
\ No newline at end of file
+//surgeries (not steps) that can be initiated on any body part (corresponding with damage locations) - Call this one done, see multiple_location_example.dm - RR
\ No newline at end of file
diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm
index e630e7da48e..bd442c7c5a7 100644
--- a/code/modules/surgery/surgery_step.dm
+++ b/code/modules/surgery/surgery_step.dm
@@ -4,8 +4,7 @@
var/accept_hand = 0 //does the surgery step require an open hand? If true, ignores implements. Compatible with accept_any_item.
var/accept_any_item = 0 //does the surgery step accept any item? If true, ignores implements. Compatible with require_hand.
var/time = 10 //how long does the step take?
- var/new_organ = null //Used for multilocation operations
- var/list/allowed_organs = list()//Allowed organs, see Handle_Multi_Loc below - RR
+ var/name
/datum/surgery_step/proc/try_op(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -39,10 +38,7 @@
/datum/surgery_step/proc/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
surgery.step_in_progress = 1
- if(surgery.has_multi_loc) //if it is multi-location, handle that
- Handle_Multi_Loc(user, target)
-
- preop(user, target, target_zone, tool)
+ preop(user, target, target_zone, tool, surgery)
if(do_after(user, time, target = target))
var/advance = 0
@@ -73,61 +69,11 @@
/datum/surgery_step/proc/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] succeeds!", "You succeed.")
- feedback_add_details("surgery_step_success","[src.type]")
- return 1
-
-/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- if(ishuman(target) || ismonkey(target) || isalienadult(target))
- var/mob/living/carbon/M = target
- M.apply_damage(75,"brute","[target_zone]")
- user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.")
- feedback_add_details("surgery_step_success","[src.type]")
return 1
/datum/surgery_step/proc/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] screws up!", "You screw up!")
- feedback_add_details("surgery_step_failed","[src.type]")
return 0
-/datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- if(locate(/datum/surgery_step/saw) in surgery.steps)
- target.heal_organ_damage(45,0)
- return ..()
-
/datum/surgery_step/proc/tool_check(mob/user, obj/item/tool)
return 1
-
-/datum/surgery_step/proc/Handle_Multi_Loc(mob/user, mob/living/carbon/target) //this is here so MultiLoc Surgeries don't need to rewrite it each time - RR
-
-
- if(user.zone_sel.selecting in allowed_organs)
-
- switch(user.zone_sel.selecting) //Switch, for Aran - RR
- if("r_arm")
- new_organ = target.getlimb(/obj/item/organ/limb/r_arm)
- if("l_arm")
- new_organ = target.getlimb(/obj/item/organ/limb/l_arm)
- if("r_leg")
- new_organ = target.getlimb(/obj/item/organ/limb/r_leg)
- if("l_leg")
- new_organ = target.getlimb(/obj/item/organ/limb/l_leg)
- if("chest")
- new_organ = target.getlimb(/obj/item/organ/limb/chest)
- if("groin")
- new_organ = target.getlimb(/obj/item/organ/limb/chest)
- if("head")
- new_organ = target.getlimb(/obj/item/organ/limb/head)
- if("eyes")
- new_organ = target.getlimb(/obj/item/organ/limb/head)
- if("mouth")
- new_organ = target.getlimb(/obj/item/organ/limb/head)
- else
- user << "You cannot perform this operation on this body part!" //Explain to the surgeon what went wrong - RR
- return 0
-
- return new_organ
-
- else
- return 0
-
-
diff --git a/code/modules/surgery/xenomorph_removal.dm b/code/modules/surgery/xenomorph_removal.dm
index 9650e824122..97cabb6d003 100644
--- a/code/modules/surgery/xenomorph_removal.dm
+++ b/code/modules/surgery/xenomorph_removal.dm
@@ -2,13 +2,13 @@
name = "xenomorph removal"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/xenomorph_removal, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
- location = "chest"
- requires_organic_chest = 1
+ possible_locs = list("chest")
//remove xeno from premises
/datum/surgery_step/xenomorph_removal
+ name = "remove foregin body"
implements = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/shovel/spade = 65, /obj/item/weapon/cultivator = 50, /obj/item/weapon/crowbar = 35)
time = 64
@@ -23,7 +23,7 @@
return 1
/datum/surgery_step/xenomorph_removal/proc/remove_xeno(mob/user, mob/living/carbon/target)
- var/obj/item/body_egg/alien_embryo/A = locate() in target.contents
+ var/obj/item/organ/internal/body_egg/alien_embryo/A = target.getorgan(/obj/item/organ/internal/body_egg/alien_embryo)
if(A)
user << "You found an unknown alien organism in [target]'s chest!"
if(A.stage < 4)
@@ -33,12 +33,13 @@
if(prob(10))
A.AttemptGrow()
+ A.Remove(target)
A.loc = get_turf(target)
return 1
/datum/surgery_step/xenomorph_removal/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- var/obj/item/body_egg/alien_embryo/A = locate() in target.contents
+ var/obj/item/organ/internal/body_egg/alien_embryo/A = target.getorgan(/obj/item/organ/internal/body_egg/alien_embryo)
if(A)
if(prob(50))
A.AttemptGrow(0)
diff --git a/config/access levels.txt b/config/access levels.txt
index 69ed681aa62..01977cbff33 100644
--- a/config/access levels.txt
+++ b/config/access levels.txt
@@ -1,50 +1,50 @@
-HOW TO CONVERT A MAP TO THE NEW (june 2008) ACCESS LEVEL SYSTEM
-1. Open the .dmp file up in Notepad
-2. Find all the "access = blahblah" attributes of doors.
-3. Delete them.
-4. Open the map up in Dream Maker. If you didn't get them all, it'll tell you so.
-5. Assign the existing doors new access permissions using the method below.
-
-HOW TO MAKE A MAP USING THE NEW (june 2008) ACCESS LEVEL SYSTEM
-1. Make a map as normal
-2. Select a door that you want to not be accessible to everybody
-3. Right click on it and edit its attributes
-4. Make the "req_access_txt" attribute be a semicolon-separated list of the permissions required to open the doors
-5. Repeat for all doors.
-
-For example, a brig door would have it be "2" while a door that requires you have toxins and teleporter access (for whatever reason) would have it be "9;20"
-
-Here is a list of the permissions and their numbers (this may be out of date, see code/game/access.dm for an updated version):
-
- access_security = 1
- access_brig = 2
- access_security_lockers = 3
- access_forensics_lockers= 4
- access_security_records = 5
- access_medical_supplies = 6
- access_medical_records = 7
- access_morgue = 8
- access_tox = 9
- access_tox_storage = 10
- access_medlab = 11
- access_engine = 12
- access_eject_engine = 13
- access_maint_tunnels = 14
- access_external_airlocks = 15
- access_emergency_storage = 16
- access_apcs = 17
- access_change_ids = 18
- access_ai_upload = 19
- access_teleporter = 20
- access_eva = 21
- access_heads = 22
- access_captain = 23
- access_all_personal_lockers = 24
- access_chapel_office = 25
- access_tech_storage = 26
- access_atmospherics = 27
- access_bar = 28
- access_janitor = 29
- access_disposal_units = 30
- access_hydroponics = 35
+HOW TO CONVERT A MAP TO THE NEW (june 2008) ACCESS LEVEL SYSTEM
+1. Open the .dmp file up in Notepad
+2. Find all the "access = blahblah" attributes of doors.
+3. Delete them.
+4. Open the map up in Dream Maker. If you didn't get them all, it'll tell you so.
+5. Assign the existing doors new access permissions using the method below.
+
+HOW TO MAKE A MAP USING THE NEW (june 2008) ACCESS LEVEL SYSTEM
+1. Make a map as normal
+2. Select a door that you want to not be accessible to everybody
+3. Right click on it and edit its attributes
+4. Make the "req_access_txt" attribute be a semicolon-separated list of the permissions required to open the doors
+5. Repeat for all doors.
+
+For example, a brig door would have it be "2" while a door that requires you have toxins and teleporter access (for whatever reason) would have it be "9;20"
+
+Here is a list of the permissions and their numbers (this may be out of date, see code/game/access.dm for an updated version):
+
+ access_security = 1
+ access_brig = 2
+ access_security_lockers = 3
+ access_forensics_lockers= 4
+ access_security_records = 5
+ access_medical_supplies = 6
+ access_medical_records = 7
+ access_morgue = 8
+ access_tox = 9
+ access_tox_storage = 10
+ access_medlab = 11
+ access_engine = 12
+ access_eject_engine = 13
+ access_maint_tunnels = 14
+ access_external_airlocks = 15
+ access_emergency_storage = 16
+ access_apcs = 17
+ access_change_ids = 18
+ access_ai_upload = 19
+ access_teleporter = 20
+ access_eva = 21
+ access_heads = 22
+ access_captain = 23
+ access_all_personal_lockers = 24
+ access_chapel_office = 25
+ access_tech_storage = 26
+ access_atmospherics = 27
+ access_bar = 28
+ access_janitor = 29
+ access_disposal_units = 30
+ access_hydroponics = 35
access_manufacturing = 36
\ No newline at end of file
diff --git a/config/admin_ranks.txt b/config/admin_ranks.txt
index 67c08182b01..7bcb2df9995 100644
--- a/config/admin_ranks.txt
+++ b/config/admin_ranks.txt
@@ -1,40 +1,40 @@
-##############################################################################################################
-# ADMIN RANK DEFINES #
-# The format of this is very simple. Rank name goes first. #
-# Rank is CASE-SENSITIVE, all punctuation save for '-', '_' and '@' will be stripped so spaces don't matter. #
-# You can then define permissions for each rank by adding a '=' followed by keywords #
-# These keywords represent groups of verbs and abilities. #
-# keywords are preceded by either a '+' or a '-', + adds permissions, - takes them away. #
-# +@ (or +prev) is a special shorthand which adds all the rights of the rank above it. #
-# You can also specify verbs like so +/client/proc/some_added_verb or -/client/proc/some_restricted_verb #
-# Ranks with no keywords will just be given the most basic verbs and abilities ~Carn #
-##############################################################################################################
-# PLEASE NOTE: depending on config options, some abilities will be unavailable regardless if you have permission to use them!
-
-# KEYWORDS:
-# +ADMIN = general admin tools, verbs etc
-# +FUN = events, other event-orientated actions. Access to the fun secrets in the secrets panel.
-# +BAN = the ability to ban, jobban and fullban
-# +STEALTH = the ability to stealthmin (make yourself appear with a fake name to everyone but other admins
-# +POSSESS = the ability to possess objects
-# +REJUV (or +REJUVINATE) = the ability to heal, respawn, modify damage and use godmode
-# +BUILD (or +BUILDMODE) = the ability to use buildmode
-# +SERVER = higher-risk admin verbs and abilities, such as those which affect the server configuration.
-# +DEBUG = debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server.
-# +VAREDIT = everyone may view viewvars/debugvars/whatever you call it. This keyword allows you to actually EDIT those variables.
-# +RIGHTS (or +PERMISSIONS) = allows you to promote and/or demote people.
-# +SOUND (or +SOUNDS) = allows you to upload and play sounds
-# +SPAWN (or +CREATE) = mob transformations, spawning of most atoms including mobs (high-risk atoms, e.g. blackholes, will require the +FUN flag too)
-# +EVERYTHING (or +HOST or +ALL) = Simply gives you everything without having to type every flag
-
-Admin Observer
-Moderator = +ADMIN
-Admin Candidate = +@
-Trial Admin = +@ +SPAWN +REJUV +VAREDIT +BAN
-Badmin = +@ +POSSESS +BUILDMODE +SERVER +FUN
-Game Admin = +@ +STEALTH +SOUNDS +DEBUG
-Game Master = +EVERYTHING
-
-Host = +EVERYTHING
-
+##############################################################################################################
+# ADMIN RANK DEFINES #
+# The format of this is very simple. Rank name goes first. #
+# Rank is CASE-SENSITIVE, all punctuation save for '-', '_' and '@' will be stripped so spaces don't matter. #
+# You can then define permissions for each rank by adding a '=' followed by keywords #
+# These keywords represent groups of verbs and abilities. #
+# keywords are preceded by either a '+' or a '-', + adds permissions, - takes them away. #
+# +@ (or +prev) is a special shorthand which adds all the rights of the rank above it. #
+# You can also specify verbs like so +/client/proc/some_added_verb or -/client/proc/some_restricted_verb #
+# Ranks with no keywords will just be given the most basic verbs and abilities ~Carn #
+##############################################################################################################
+# PLEASE NOTE: depending on config options, some abilities will be unavailable regardless if you have permission to use them!
+
+# KEYWORDS:
+# +ADMIN = general admin tools, verbs etc
+# +FUN = events, other event-orientated actions. Access to the fun secrets in the secrets panel.
+# +BAN = the ability to ban, jobban and fullban
+# +STEALTH = the ability to stealthmin (make yourself appear with a fake name to everyone but other admins
+# +POSSESS = the ability to possess objects
+# +REJUV (or +REJUVINATE) = the ability to heal, respawn, modify damage and use godmode
+# +BUILD (or +BUILDMODE) = the ability to use buildmode
+# +SERVER = higher-risk admin verbs and abilities, such as those which affect the server configuration.
+# +DEBUG = debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server.
+# +VAREDIT = everyone may view viewvars/debugvars/whatever you call it. This keyword allows you to actually EDIT those variables.
+# +RIGHTS (or +PERMISSIONS) = allows you to promote and/or demote people.
+# +SOUND (or +SOUNDS) = allows you to upload and play sounds
+# +SPAWN (or +CREATE) = mob transformations, spawning of most atoms including mobs (high-risk atoms, e.g. blackholes, will require the +FUN flag too)
+# +EVERYTHING (or +HOST or +ALL) = Simply gives you everything without having to type every flag
+
+Admin Observer
+Moderator = +ADMIN
+Admin Candidate = +@
+Trial Admin = +@ +SPAWN +REJUV +VAREDIT +BAN
+Badmin = +@ +POSSESS +BUILDMODE +SERVER +FUN
+Game Admin = +@ +STEALTH +SOUNDS +DEBUG
+Game Master = +EVERYTHING
+
+Host = +EVERYTHING
+
Coder = +DEBUG +VAREDIT +SERVER +SPAWN
\ No newline at end of file
diff --git a/config/admins.txt b/config/admins.txt
index 4622411760a..f708dcc3df4 100644
--- a/config/admins.txt
+++ b/config/admins.txt
@@ -90,4 +90,5 @@ shadowlight213 = Game Master
drovidicorv = Game Master
Dunc = Game Master
MMMiracles = Game Master
-bear1ake = Game Master
\ No newline at end of file
+bear1ake = Game Master
+CoreOverload = Game Master
\ No newline at end of file
diff --git a/config/config.txt b/config/config.txt
index f7ec7eda026..c40c7cc783f 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -1,196 +1,196 @@
-## Server name: This appears at the top of the screen in-game. Remove the # infront of SERVERNAME and replace 'tgstation' with the name of your choice
-# SERVERNAME tgstation
-
-## Station name: The name of the station as it is referred to in-game. If commented out, the game will generate a random name instead.
-STATIONNAME Space Station 13
-
-# Lobby time: This is the amount of time between rounds that players have to setup their characters and be ready.
-LOBBY_COUNTDOWN 120
-
-## Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt. You need to set up your database to use the SQL based system.
-ADMIN_LEGACY_SYSTEM
-
-## Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
-BAN_LEGACY_SYSTEM
-
-## Unhash this entry to have certain jobs require your account to be at least a certain number of days old to select. You can configure the exact age requirement for different jobs by editing
-## the minimal_player_age variable in the files in folder /code/game/jobs/job/.. for the job you want to edit. Set minimal_player_age to 0 to disable age requirement for that job.
-## REQUIRES the database set up to work. Keep it hashed if you don't have a database set up.
-## NOTE: If you have just set-up the database keep this DISABLED, as player age is determined from the first time they connect to the server with the database up. If you just set it up, it means
-## you have noone older than 0 days, since noone has been logged yet. Only turn this on once you have had the database up for 30 days.
-#USE_AGE_RESTRICTION_FOR_JOBS
-
-## log OOC channel
-LOG_OOC
-
-## log client Say
-LOG_SAY
-
-## log admin actions
-LOG_ADMIN
-
-## log client access (logon/logoff)
-LOG_ACCESS
-
-## log game actions (start of round, results, etc.)
-LOG_GAME
-
-## log player votes
-LOG_VOTE
-
-## log client Whisper
-LOG_WHISPER
-
-## log emotes
-LOG_EMOTE
-
-## log attack messages
-LOG_ATTACK
-
-## log pda messages
-LOG_PDA
-
-## log prayers
-LOG_PRAYER
-
-## log lawchanges
-LOG_LAW
-
-## log all Topic() calls (for use by coders in tracking down Topic issues)
-# LOG_HREFS
-
-## disconnect players who did nothing during 10 minutes
-# KICK_INACTIVE
-
-## Comment this out to stop admins being able to choose their personal ooccolor
-ALLOW_ADMIN_OOCCOLOR
-
-## If metadata is supported
-ALLOW_METADATA
-
-## allow players to initiate a restart vote
-#ALLOW_VOTE_RESTART
-
-## allow players to initate a mode-change start
-#ALLOW_VOTE_MODE
-
-## min delay (deciseconds) between voting sessions (default 10 minutes)
-VOTE_DELAY 6000
-
-## time period (deciseconds) which voting session will last (default 1 minute)
-VOTE_PERIOD 600
-
-## prevents dead players from voting or starting votes
-# NO_DEAD_VOTE
-
-## players' votes default to "No vote" (otherwise, default to "No change")
-# DEFAULT_NO_VOTE
-
-## disable abandon mob
-NORESPAWN
-
-## disables calling del(src) on newmobs if they logout before spawnin in
-# DONT_DEL_NEWMOB
-
-## set a hosted by name for unix platforms
-HOSTEDBY Yournamehere
-
-## Set to jobban "Guest-" accounts from Captain, HoS, HoP, CE, RD, CMO, Warden, Security, Detective, and AI positions.
-## Set to 1 to jobban them from those positions, set to 0 to allow them.
-# GUEST_JOBBAN
-
-## Uncomment this to stop people connecting to your server without a registered ckey. (i.e. guest-* are all blocked from connecting)
-GUEST_BAN
-
-## Set to jobban everyone who's key is not listed in data/whitelist.txt from Captain, HoS, HoP, CE, RD, CMO, Warden, Security, Detective, and AI positions.
-## Uncomment to 1 to jobban, leave commented out to allow these positions for everyone (but see GUEST_JOBBAN above and regular jobbans)
-# USEWHITELIST
-
-## set a server location for world reboot. Don't include the byond://, just give the address and port.
-# Don't set this to the same server, BYOND will automatically restart players to the server when it has restarted.
-# SERVER ss13.example.com:2506
-
-## forum address
-# FORUMURL http://tgstation13.org/phpBB/index.php
-
-## Wiki address
-# WIKIURL http://www.tgstation13.org/wiki
-
-##Rules address
-# RULESURL http://www.tgstation13.org/wiki/Rules
-
-##Github address
-# GITHUBURL https://www.github.com/tgstation/-tg-station
-
-## Ban appeals URL - usually for a forum or wherever people should go to contact your admins.
-# BANAPPEALS http://justanotherday.example.com
-
-## In-game features
-##Toggle for having jobs load up from the .txt
-# LOAD_JOBS_FROM_TXT
-
-##Remove the # mark infront of this to forbid admins from possessing the singularity.
-#FORBID_SINGULO_POSSESSION
-
-## Remove the # to show a popup 'reply to' window to every non-admin that recieves an adminPM.
-## The intention is to make adminPMs more visible. (although I fnd popups annoying so this defaults to off)
-#POPUP_ADMIN_PM
-
-## Remove the # to allow special 'Easter-egg' events on special holidays such as seasonal holidays and stuff like 'Talk Like a Pirate Day' :3 YAARRR
-ALLOW_HOLIDAYS
-
-##Remove the # mark if you are going to use the SVN irc bot to relay adminhelps
-#USEIRCBOT
-
-##Defines the ticklag for the world. 0.9 is the normal one, 0.5 is smoother.
-TICKLAG 0.9
-
-## Defines if Tick Compensation is used. It results in a minor slowdown of movement of all mobs, but attempts to result in a level movement speed across all ticks. Recommended if tickrate is lowered.
-TICKCOMP 0
-
-## Comment this out to disable automuting
-#AUTOMUTE_ON
-
-## Communication key for receiving data through world/Topic(), you don't want to give this out
-#COMMS_KEY default_pwd
-
-## Uncomment this to let players see their own notes (they can still be set by admins only)
-#SEE_OWN_NOTES
-
-##Note: all population caps can be used with each other if desired.
-
-## Uncomment for 'soft' population caps, players will be warned while joining if the living crew exceeds the listed number.
-#SOFT_POPCAP 100
-
-## Message for soft cap
-SOFT_POPCAP_MESSAGE Be warned that the server is currently serving a high number of users, consider using alternative game servers.
-
-## Uncomment for 'hard' population caps, players will not be allowed to spawn if the living crew exceeds the listed number, though they may still observe or wait for the living crew to decrease in size.
-#HARD_POPCAP 150
-
-## Message for hard cap
-HARD_POPCAP_MESSAGE The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers.
-
-## Uncomment for 'extreme' population caps, players will not be allowed to join the server if living crew exceeds the listed number.
-#EXTREME_POPCAP 200
-
-## Message for extreme cap
-EXTREME_POPCAP_MESSAGE The server is currently serving a high number of users, find alternative servers.
-
-## Notify admins when a new player connects for the first x days a player's been around. (0 for first connection only, -1 for never)
-## Requres database
-NOTIFY_NEW_PLAYER_AGE 0
-
-## Notify the irc channel when a new player makes their first connection
-## Requres database
-#IRC_FIRST_CONNECTION_ALERT
-
-## Deny all new connections by ckeys we haven't seen before (exempts admins and only denies the connection if the database is enabled and connected)
-## Requires database
-#PANIC_BUNKER
-
-## Uncomment to have the changelog file automatically open when a user connects and hasn't seen the latest changelog
-#AGGRESSIVE_CHANGELOG
-
-## Uncomment to have the game log runtimes to the log folder. (Note: this disables normal output in dd/ds, so it should be left off for testing.
+## Server name: This appears at the top of the screen in-game. Remove the # infront of SERVERNAME and replace 'tgstation' with the name of your choice
+# SERVERNAME tgstation
+
+## Station name: The name of the station as it is referred to in-game. If commented out, the game will generate a random name instead.
+STATIONNAME Space Station 13
+
+# Lobby time: This is the amount of time between rounds that players have to setup their characters and be ready.
+LOBBY_COUNTDOWN 120
+
+## Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt. You need to set up your database to use the SQL based system.
+ADMIN_LEGACY_SYSTEM
+
+## Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
+BAN_LEGACY_SYSTEM
+
+## Unhash this entry to have certain jobs require your account to be at least a certain number of days old to select. You can configure the exact age requirement for different jobs by editing
+## the minimal_player_age variable in the files in folder /code/game/jobs/job/.. for the job you want to edit. Set minimal_player_age to 0 to disable age requirement for that job.
+## REQUIRES the database set up to work. Keep it hashed if you don't have a database set up.
+## NOTE: If you have just set-up the database keep this DISABLED, as player age is determined from the first time they connect to the server with the database up. If you just set it up, it means
+## you have noone older than 0 days, since noone has been logged yet. Only turn this on once you have had the database up for 30 days.
+#USE_AGE_RESTRICTION_FOR_JOBS
+
+## log OOC channel
+LOG_OOC
+
+## log client Say
+LOG_SAY
+
+## log admin actions
+LOG_ADMIN
+
+## log client access (logon/logoff)
+LOG_ACCESS
+
+## log game actions (start of round, results, etc.)
+LOG_GAME
+
+## log player votes
+LOG_VOTE
+
+## log client Whisper
+LOG_WHISPER
+
+## log emotes
+LOG_EMOTE
+
+## log attack messages
+LOG_ATTACK
+
+## log pda messages
+LOG_PDA
+
+## log prayers
+LOG_PRAYER
+
+## log lawchanges
+LOG_LAW
+
+## log all Topic() calls (for use by coders in tracking down Topic issues)
+# LOG_HREFS
+
+## disconnect players who did nothing during 10 minutes
+# KICK_INACTIVE
+
+## Comment this out to stop admins being able to choose their personal ooccolor
+ALLOW_ADMIN_OOCCOLOR
+
+## If metadata is supported
+ALLOW_METADATA
+
+## allow players to initiate a restart vote
+#ALLOW_VOTE_RESTART
+
+## allow players to initate a mode-change start
+#ALLOW_VOTE_MODE
+
+## min delay (deciseconds) between voting sessions (default 10 minutes)
+VOTE_DELAY 6000
+
+## time period (deciseconds) which voting session will last (default 1 minute)
+VOTE_PERIOD 600
+
+## prevents dead players from voting or starting votes
+# NO_DEAD_VOTE
+
+## players' votes default to "No vote" (otherwise, default to "No change")
+# DEFAULT_NO_VOTE
+
+## disable abandon mob
+NORESPAWN
+
+## disables calling del(src) on newmobs if they logout before spawnin in
+# DONT_DEL_NEWMOB
+
+## set a hosted by name for unix platforms
+HOSTEDBY Yournamehere
+
+## Set to jobban "Guest-" accounts from Captain, HoS, HoP, CE, RD, CMO, Warden, Security, Detective, and AI positions.
+## Set to 1 to jobban them from those positions, set to 0 to allow them.
+# GUEST_JOBBAN
+
+## Uncomment this to stop people connecting to your server without a registered ckey. (i.e. guest-* are all blocked from connecting)
+GUEST_BAN
+
+## Set to jobban everyone who's key is not listed in data/whitelist.txt from Captain, HoS, HoP, CE, RD, CMO, Warden, Security, Detective, and AI positions.
+## Uncomment to 1 to jobban, leave commented out to allow these positions for everyone (but see GUEST_JOBBAN above and regular jobbans)
+# USEWHITELIST
+
+## set a server location for world reboot. Don't include the byond://, just give the address and port.
+# Don't set this to the same server, BYOND will automatically restart players to the server when it has restarted.
+# SERVER ss13.example.com:2506
+
+## forum address
+# FORUMURL http://tgstation13.org/phpBB/index.php
+
+## Wiki address
+# WIKIURL http://www.tgstation13.org/wiki
+
+##Rules address
+# RULESURL http://www.tgstation13.org/wiki/Rules
+
+##Github address
+# GITHUBURL https://www.github.com/tgstation/-tg-station
+
+## Ban appeals URL - usually for a forum or wherever people should go to contact your admins.
+# BANAPPEALS http://justanotherday.example.com
+
+## In-game features
+##Toggle for having jobs load up from the .txt
+# LOAD_JOBS_FROM_TXT
+
+##Remove the # mark infront of this to forbid admins from possessing the singularity.
+#FORBID_SINGULO_POSSESSION
+
+## Remove the # to show a popup 'reply to' window to every non-admin that recieves an adminPM.
+## The intention is to make adminPMs more visible. (although I fnd popups annoying so this defaults to off)
+#POPUP_ADMIN_PM
+
+## Remove the # to allow special 'Easter-egg' events on special holidays such as seasonal holidays and stuff like 'Talk Like a Pirate Day' :3 YAARRR
+ALLOW_HOLIDAYS
+
+##Remove the # mark if you are going to use the SVN irc bot to relay adminhelps
+#USEIRCBOT
+
+##Defines the ticklag for the world. 0.9 is the normal one, 0.5 is smoother.
+TICKLAG 0.9
+
+## Defines if Tick Compensation is used. It results in a minor slowdown of movement of all mobs, but attempts to result in a level movement speed across all ticks. Recommended if tickrate is lowered.
+TICKCOMP 0
+
+## Comment this out to disable automuting
+#AUTOMUTE_ON
+
+## Communication key for receiving data through world/Topic(), you don't want to give this out
+#COMMS_KEY default_pwd
+
+## Uncomment this to let players see their own notes (they can still be set by admins only)
+#SEE_OWN_NOTES
+
+##Note: all population caps can be used with each other if desired.
+
+## Uncomment for 'soft' population caps, players will be warned while joining if the living crew exceeds the listed number.
+#SOFT_POPCAP 100
+
+## Message for soft cap
+SOFT_POPCAP_MESSAGE Be warned that the server is currently serving a high number of users, consider using alternative game servers.
+
+## Uncomment for 'hard' population caps, players will not be allowed to spawn if the living crew exceeds the listed number, though they may still observe or wait for the living crew to decrease in size.
+#HARD_POPCAP 150
+
+## Message for hard cap
+HARD_POPCAP_MESSAGE The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers.
+
+## Uncomment for 'extreme' population caps, players will not be allowed to join the server if living crew exceeds the listed number.
+#EXTREME_POPCAP 200
+
+## Message for extreme cap
+EXTREME_POPCAP_MESSAGE The server is currently serving a high number of users, find alternative servers.
+
+## Notify admins when a new player connects for the first x days a player's been around. (0 for first connection only, -1 for never)
+## Requres database
+NOTIFY_NEW_PLAYER_AGE 0
+
+## Notify the irc channel when a new player makes their first connection
+## Requres database
+#IRC_FIRST_CONNECTION_ALERT
+
+## Deny all new connections by ckeys we haven't seen before (exempts admins and only denies the connection if the database is enabled and connected)
+## Requires database
+#PANIC_BUNKER
+
+## Uncomment to have the changelog file automatically open when a user connects and hasn't seen the latest changelog
+#AGGRESSIVE_CHANGELOG
+
+## Uncomment to have the game log runtimes to the log folder. (Note: this disables normal output in dd/ds, so it should be left off for testing.
#LOG_RUNTIMES
\ No newline at end of file
diff --git a/config/dbconfig.txt b/config/dbconfig.txt
index dbc09df51df..cc28dc483de 100644
--- a/config/dbconfig.txt
+++ b/config/dbconfig.txt
@@ -1,33 +1,33 @@
-## MySQL Connection Configuration
-## This is used for stats, feedback gathering,
-## administration, and the in game library.
-
-## Should SQL be enabled? Uncomment to enable.
-#SQL_ENABLED
-
-## Server the MySQL database can be found at.
-# Examples: localhost, 200.135.5.43, www.mysqldb.com, etc.
-ADDRESS localhost
-
-## MySQL server port (default is 3306).
-PORT 3306
-
-## Database for all SQL functions, not just feedback.
-FEEDBACK_DATABASE feedback
-
-## Prefix to be added to the name of every table, older databases will require this be set to erro_
-## if left out defaults to erro_ for legacy reasons, if you want no table prefix, give a blank prefix rather then comment out
-## Note, this does not change the table names in the database, you will have to do that yourself.
-##IE:
-## FEEDBACK_TABLEPREFIX erro_
-## FEEDBACK_TABLEPREFIX
-## FEEDBACK_TABLEPREFIX SS13_
-##
-## Leave as is if you are using the standard schema file.
-FEEDBACK_TABLEPREFIX
-
-## Username/Login used to access the database.
-FEEDBACK_LOGIN username
-
-## Password used to access the database.
+## MySQL Connection Configuration
+## This is used for stats, feedback gathering,
+## administration, and the in game library.
+
+## Should SQL be enabled? Uncomment to enable.
+#SQL_ENABLED
+
+## Server the MySQL database can be found at.
+# Examples: localhost, 200.135.5.43, www.mysqldb.com, etc.
+ADDRESS localhost
+
+## MySQL server port (default is 3306).
+PORT 3306
+
+## Database for all SQL functions, not just feedback.
+FEEDBACK_DATABASE feedback
+
+## Prefix to be added to the name of every table, older databases will require this be set to erro_
+## if left out defaults to erro_ for legacy reasons, if you want no table prefix, give a blank prefix rather then comment out
+## Note, this does not change the table names in the database, you will have to do that yourself.
+##IE:
+## FEEDBACK_TABLEPREFIX erro_
+## FEEDBACK_TABLEPREFIX
+## FEEDBACK_TABLEPREFIX SS13_
+##
+## Leave as is if you are using the standard schema file.
+FEEDBACK_TABLEPREFIX
+
+## Username/Login used to access the database.
+FEEDBACK_LOGIN username
+
+## Password used to access the database.
FEEDBACK_PASSWORD password
\ No newline at end of file
diff --git a/config/game_options.txt b/config/game_options.txt
index aa4f48f5dd3..54472c969bf 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -1,300 +1,300 @@
-### HEALTH ###
-
-# level of health at which a mob becomes unconscious (crit)
-HEALTH_THRESHOLD_CRIT 0
-
-# level of health at which a mob becomes dead
-HEALTH_THRESHOLD_DEAD -100
-
-
-### REVIVAL ###
-
-# whether pod plants work or not
-REVIVAL_POD_PLANTS 1
-
-# whether cloning tubes work or not
-REVIVAL_CLONING 1
-
-# amount of time (in hundredths of seconds) for which a brain retains the "spark of life" after the person's death (set to -1 for infinite)
-REVIVAL_BRAIN_LIFE -1
-
-### RENAMING ###
-
-#Uncomment to allow cyborgs to rename themselves at roundstart. Has no effect on roboticists renaming cyborgs the normal way.
-#RENAME_CYBORG
-
-### OOC DURING ROUND ###
-#Comment this out if you want OOC to be automatically disabled during the round, it will be enabled during the lobby and after the round end results.
-OOC_DURING_ROUND
-
-### EMOJI ###
-#Comment this out if you want to disable emojis
-EMOJIS
-
-### MOB MOVEMENT ###
-
-## We suggest editing these variables ingame to find a good speed for your server.
-## To do this you must be a high level admin. Open the 'debug' tab ingame.
-## Select "Debug Controller" and then, in the popup, select "Configuration". These variables should have the same name.
-
-## These values get directly added to values and totals ingame.
-## To speed things up make the number negative, to slow things down, make the number positive.
-
-## These modify the run/walk speed of all mobs before the mob-specific modifiers are applied.
-RUN_DELAY 1
-WALK_DELAY 4
-
-## The variables below affect the movement of specific mob types.
-HUMAN_DELAY 0
-ROBOT_DELAY 0
-MONKEY_DELAY 0
-ALIEN_DELAY 0
-SLIME_DELAY 0
-ANIMAL_DELAY 0
-
-
-### NAMES ###
-## If uncommented this adds a random surname to a player's name if they only specify one name.
-#HUMANS_NEED_SURNAMES
-
-## If uncommented, this forces all players to use random names !and appearances!.
-#FORCE_RANDOM_NAMES
-
-
-### ALERT LEVELS ###
-ALERT_GREEN All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced.
-ALERT_BLUE_UPTO The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted.
-ALERT_BLUE_DOWNTO The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed.
-ALERT_RED_UPTO There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.
-ALERT_RED_DOWNTO The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised.
-ALERT_DELTA Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.
-
-
-
-### GAME MODES ###
-
-## Probablities for game modes chosen in 'secret' and 'random' modes.
-## Default probablity is 1, increase to make that mode more likely to be picked.
-## Set to 0 to disable that mode.
-
-PROBABILITY TRAITOR 5
-PROBABILITY TRAITORCHAN 4
-PROBABILITY DOUBLE_AGENTS 3
-PROBABILITY NUCLEAR 2
-PROBABILITY REVOLUTION 2
-PROBABILITY SHADOWLING 2
-PROBABILITY GANG 2
-PROBABILITY CULT 2
-PROBABILITY CHANGELING 2
-PROBABILITY WIZARD 4
-PROBABILITY MALFUNCTION 1
-PROBABILITY BLOB 2
-PROBABILITY RAGINMAGES 2
-PROBABILITY MONKEY 0
-PROBABILITY METEOR 0
-PROBABILITY EXTENDED 0
-
-## You probably want to keep sandbox off by default for secret and random.
-PROBABILITY SANDBOX 0
-
-
-## Toggles for continuous modes.
-## Modes that aren't continuous will end the instant all antagonists are dead.
-
-CONTINUOUS TRAITOR
-CONTINUOUS TRAITORCHAN
-CONTINUOUS DOUBLE_AGENTS
-#CONTINUOUS NUCLEAR
-#CONTINUOUS REVOLUTION
-#CONTINUOUS SHADOWLING
-CONTINUOUS GANG
-CONTINUOUS CULT
-CONTINUOUS CHANGELING
-CONTINUOUS WIZARD
-CONTINUOUS MALFUNCTION
-CONTINUOUS BLOB
-#CONTINUOUS RAGINMAGES
-#CONTINUOUS MONKEY
-
-##Note: do not toggle continuous off for these modes, as they have no antagonists and would thus end immediately!
-
-CONTINUOUS METEOR
-CONTINUOUS EXTENDED
-
-
-## Toggles for allowing midround antagonists (aka mulligan antagonists).
-## In modes that are continuous, if all antagonists should die then a new set of antagonists will be created.
-
-MIDROUND_ANTAG TRAITOR
-MIDROUND_ANTAG TRAITORCHAN
-MIDROUND_ANTAG DOUBLE_AGENTS
-#MIDROUND_ANTAG NUCLEAR
-#MIDROUND_ANTAG REVOLUTION
-#MIDROUND_ANTAG SHADOWLING
-#MIDROUND_ANTAG GANG
-MIDROUND_ANTAG CULT
-MIDROUND_ANTAG CHANGELING
-MIDROUND_ANTAG WIZARD
-MIDROUND_ANTAG MALFUNCTION
-MIDROUND_ANTAG BLOB
-#MIDROUND_ANTAG RAGINMAGES
-#MIDROUND_ANTAG MONKEY
-
-
-## The amount of time it takes for the emergency shuttle to be called, from round start.
-SHUTTLE_REFUEL_DELAY 12000
-
-## Variables calculate how number of antagonists will scale to population.
-## Used as (Antagonists = Population / Coeff)
-## Set to 0 to disable scaling and use default numbers instead.
-TRAITOR_SCALING_COEFF 6
-CHANGELING_SCALING_COEFF 6
-
-## Variables calculate how number of open security officer positions will scale to population.
-## Used as (Officers = Population / Coeff)
-## Set to 0 to disable scaling and use default numbers instead.
-SECURITY_SCALING_COEFF 8
-
-# The number of objectives traitors get.
-# Not including escaping/hijacking.
-TRAITOR_OBJECTIVES_AMOUNT 2
-
-## Uncomment to prohibit jobs that start with loyalty
-## implants from being most antagonists.
-#PROTECT_ROLES_FROM_ANTAGONIST
-
-## Uncomment to prohibit assistants from becoming most antagonists.
-#PROTECT_ASSISTANT_FROM_ANTAGONIST
-
-## If non-human species are barred from joining as a head of staff
-#ENFORCE_HUMAN_AUTHORITY
-
-## If late-joining players have a chance to become a traitor/changeling
-ALLOW_LATEJOIN_ANTAGONISTS
-
-## Uncomment to allow players to see the set odds of different rounds in secret/random in the get server revision screen. This will NOT tell the current roundtype.
-#SHOW_GAME_TYPE_ODDS
-
-### RANDOM EVENTS ###
-
-## Comment this to disable random events during the round.
-ALLOW_RANDOM_EVENTS
-
-
-### AI ###
-
-## Allow the AI job to be picked.
-ALLOW_AI
-
-
-
-### AWAY MISSIONS ###
-
-## How long the delay is before the Away Mission gate opens. Default is half an hour.
-## 600 is one minute.
-GATEWAY_DELAY 18000
-
-
-### ACCESS ###
-
-## If the number of players ready at round starts exceeds this threshold, JOBS_HAVE_MINIMAL_ACCESS will automatically be enabled. Otherwise, it will be disabled.
-## This is useful for accomodating both low and high population rounds on the same server.
-## Comment out or set to 0 to disable this automatic toggle.
-MINIMAL_ACCESS_THRESHOLD 20
-
-## Comment this out if you wish to use the setup where jobs have more access.
-## This is intended for servers with low populations - where there are not enough
-## players to fill all roles, so players need to do more than just one job.
-## This option is ignored if MINIMAL_ACCESS_THRESHOLD is used.
-#JOBS_HAVE_MINIMAL_ACCESS
-
-## Uncomment to give assistants maint access.
-#ASSISTANTS_HAVE_MAINT_ACCESS
-
-## Uncoment to give security maint access. Note that if you comment JOBS_HAVE_MINIMAL_ACCESS security already gets maint from that.
-#SECURITY_HAS_MAINT_ACCESS
-
-## Uncomment to give everyone maint access.
-#EVERYONE_HAS_MAINT_ACCESS
-
-## Comment this to make security officers spawn in departmental security posts
-SEC_START_BRIG
-
-
-### GHOST INTERACTION ###
-## Uncomment to let ghosts spin chairs. You may be wondering why this is a config option. Don't ask.
-#GHOST_INTERACTION
-
-### NON-VOCAL SILICONS ###
-## Uncomment to stop the AI, or cyborgs, from having vocal communication.
-#SILENT_AI
-#SILENT_BORG
-
-### SANDBOX PANEL AUTOCLOSE ###
-## The sandbox panel's item spawning dialog now stays open even after you click an option.
-## If you find that your players are abusing the sandbox panel, this option may slow them down
-## without preventing people from using it properly.
-## Only functions in sandbox game mode.
-#SANDBOX_AUTOCLOSE
-
-### ROUNDSTART SILICON LAWS ###
-## This controls what the AI's laws are at the start of the round.
-## Set to 0/commented for "off", silicons will just start with Asimov.
-## Set to 1 for "custom", silicons will start with the custom laws defined in silicon_laws.txt. (If silicon_laws.txt is empty, the AI will spawn with asimov and Custom boards will auto-delete.)
-## Set to 2 for "random", silicons will start with a random lawset picked from (at the time of writing): P.A.L.A.D.I.N., Corporate, Asimov. More can be added by changing the law datum paths in ai_laws.dm.
-DEFAULT_LAWS 1
-
-### SILICON LAW MAX AMOUNT ###
-## The maximum number of laws a silicon can have
-## Attempting to upload laws past this point will fail unless the AI is reset
-SILICON_MAX_LAW_AMOUNT 12
-
-## Uncomment to give players the choice of their species before they join the game
-#JOIN_WITH_MUTANT_RACE
-
-## Uncomment to give players the choice of joining as a human with mutant bodyparts before they join the game
-#JOIN_WITH_MUTANT_HUMANS
-
-## Assistant slot cap. Set to -1 for unlimited.
-ASSISTANT_CAP -1
-
-## Starlight for exterior walls and breaches. Uncomment for starlight!
-STARLIGHT
-
-## Uncomment to bring back old grey suit assistants instead of the now default rainbow colored assistants.
-#GREY_ASSISTANTS
-
-### Midround Antag (aka Mulligan antag) config options ###
-
-## A time, in minutes, after which the midround antag system stops attempting to run and continuous rounds end immediately upon completion.
-MIDROUND_ANTAG_TIME_CHECK 60
-
-## A ratio of living to total crew members, the lower this is, the more people will have to die in order for midround antag to be skipped
-MIDROUND_ANTAG_LIFE_CHECK 0.7
-
-###Limit Spell Choices##
-## Uncomment to disallow wizards from using certain spells that may be too chaotic/fun for your playerbase
-
-#NO_SUMMON_GUNS
-#NO_SUMMON_MAGIC
-#NO_SUMMON_EVENTS
-
-//Comment for "normal" explosions, which ignore obstacles
-//Uncomment for explosions that react to doors and walls
-REACTIONARY_EXPLOSIONS
-
-### Configure the bomb cap
-## This caps all explosions to the specified range. Used for both balance reasons and to prevent overloading the server and lagging the game out.
-## This is given as the 3rd number(light damage) in the standard (1,2,3) explosion notation. The other numbers are derived by dividing by 2 and 4.
-## eg: If you give the number 20. The bomb cap will be 5,10,20.
-## Can be any number between 4 and 128, some examples are provided below.
-
-## Default (3,7,14)
-BOMBCAP 14
-## One 'step' up (4,8,16) (recommended if you enable REACTIONARY_EXPLOSIONS above)
-#BOMBCAP 16
-## LagHell (7,14,28)
-#BOMBCAP 28
-
-
-
+### HEALTH ###
+
+# level of health at which a mob becomes unconscious (crit)
+HEALTH_THRESHOLD_CRIT 0
+
+# level of health at which a mob becomes dead
+HEALTH_THRESHOLD_DEAD -100
+
+
+### REVIVAL ###
+
+# whether pod plants work or not
+REVIVAL_POD_PLANTS 1
+
+# whether cloning tubes work or not
+REVIVAL_CLONING 1
+
+# amount of time (in hundredths of seconds) for which a brain retains the "spark of life" after the person's death (set to -1 for infinite)
+REVIVAL_BRAIN_LIFE -1
+
+### RENAMING ###
+
+#Uncomment to allow cyborgs to rename themselves at roundstart. Has no effect on roboticists renaming cyborgs the normal way.
+#RENAME_CYBORG
+
+### OOC DURING ROUND ###
+#Comment this out if you want OOC to be automatically disabled during the round, it will be enabled during the lobby and after the round end results.
+OOC_DURING_ROUND
+
+### EMOJI ###
+#Comment this out if you want to disable emojis
+EMOJIS
+
+### MOB MOVEMENT ###
+
+## We suggest editing these variables ingame to find a good speed for your server.
+## To do this you must be a high level admin. Open the 'debug' tab ingame.
+## Select "Debug Controller" and then, in the popup, select "Configuration". These variables should have the same name.
+
+## These values get directly added to values and totals ingame.
+## To speed things up make the number negative, to slow things down, make the number positive.
+
+## These modify the run/walk speed of all mobs before the mob-specific modifiers are applied.
+RUN_DELAY 1
+WALK_DELAY 4
+
+## The variables below affect the movement of specific mob types.
+HUMAN_DELAY 0
+ROBOT_DELAY 0
+MONKEY_DELAY 0
+ALIEN_DELAY 0
+SLIME_DELAY 0
+ANIMAL_DELAY 0
+
+
+### NAMES ###
+## If uncommented this adds a random surname to a player's name if they only specify one name.
+#HUMANS_NEED_SURNAMES
+
+## If uncommented, this forces all players to use random names !and appearances!.
+#FORCE_RANDOM_NAMES
+
+
+### ALERT LEVELS ###
+ALERT_GREEN All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced.
+ALERT_BLUE_UPTO The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted.
+ALERT_BLUE_DOWNTO The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed.
+ALERT_RED_UPTO There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.
+ALERT_RED_DOWNTO The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised.
+ALERT_DELTA Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.
+
+
+
+### GAME MODES ###
+
+## Probablities for game modes chosen in 'secret' and 'random' modes.
+## Default probablity is 1, increase to make that mode more likely to be picked.
+## Set to 0 to disable that mode.
+
+PROBABILITY TRAITOR 5
+PROBABILITY TRAITORCHAN 4
+PROBABILITY DOUBLE_AGENTS 3
+PROBABILITY NUCLEAR 2
+PROBABILITY REVOLUTION 2
+PROBABILITY SHADOWLING 2
+PROBABILITY GANG 2
+PROBABILITY CULT 2
+PROBABILITY CHANGELING 2
+PROBABILITY WIZARD 4
+PROBABILITY MALFUNCTION 1
+PROBABILITY BLOB 2
+PROBABILITY RAGINMAGES 2
+PROBABILITY MONKEY 0
+PROBABILITY METEOR 0
+PROBABILITY EXTENDED 0
+
+## You probably want to keep sandbox off by default for secret and random.
+PROBABILITY SANDBOX 0
+
+
+## Toggles for continuous modes.
+## Modes that aren't continuous will end the instant all antagonists are dead.
+
+CONTINUOUS TRAITOR
+CONTINUOUS TRAITORCHAN
+CONTINUOUS DOUBLE_AGENTS
+#CONTINUOUS NUCLEAR
+#CONTINUOUS REVOLUTION
+#CONTINUOUS SHADOWLING
+CONTINUOUS GANG
+CONTINUOUS CULT
+CONTINUOUS CHANGELING
+CONTINUOUS WIZARD
+CONTINUOUS MALFUNCTION
+CONTINUOUS BLOB
+#CONTINUOUS RAGINMAGES
+#CONTINUOUS MONKEY
+
+##Note: do not toggle continuous off for these modes, as they have no antagonists and would thus end immediately!
+
+CONTINUOUS METEOR
+CONTINUOUS EXTENDED
+
+
+## Toggles for allowing midround antagonists (aka mulligan antagonists).
+## In modes that are continuous, if all antagonists should die then a new set of antagonists will be created.
+
+MIDROUND_ANTAG TRAITOR
+MIDROUND_ANTAG TRAITORCHAN
+MIDROUND_ANTAG DOUBLE_AGENTS
+#MIDROUND_ANTAG NUCLEAR
+#MIDROUND_ANTAG REVOLUTION
+#MIDROUND_ANTAG SHADOWLING
+#MIDROUND_ANTAG GANG
+MIDROUND_ANTAG CULT
+MIDROUND_ANTAG CHANGELING
+MIDROUND_ANTAG WIZARD
+MIDROUND_ANTAG MALFUNCTION
+MIDROUND_ANTAG BLOB
+#MIDROUND_ANTAG RAGINMAGES
+#MIDROUND_ANTAG MONKEY
+
+
+## The amount of time it takes for the emergency shuttle to be called, from round start.
+SHUTTLE_REFUEL_DELAY 12000
+
+## Variables calculate how number of antagonists will scale to population.
+## Used as (Antagonists = Population / Coeff)
+## Set to 0 to disable scaling and use default numbers instead.
+TRAITOR_SCALING_COEFF 6
+CHANGELING_SCALING_COEFF 6
+
+## Variables calculate how number of open security officer positions will scale to population.
+## Used as (Officers = Population / Coeff)
+## Set to 0 to disable scaling and use default numbers instead.
+SECURITY_SCALING_COEFF 8
+
+# The number of objectives traitors get.
+# Not including escaping/hijacking.
+TRAITOR_OBJECTIVES_AMOUNT 2
+
+## Uncomment to prohibit jobs that start with loyalty
+## implants from being most antagonists.
+#PROTECT_ROLES_FROM_ANTAGONIST
+
+## Uncomment to prohibit assistants from becoming most antagonists.
+#PROTECT_ASSISTANT_FROM_ANTAGONIST
+
+## If non-human species are barred from joining as a head of staff
+#ENFORCE_HUMAN_AUTHORITY
+
+## If late-joining players have a chance to become a traitor/changeling
+ALLOW_LATEJOIN_ANTAGONISTS
+
+## Uncomment to allow players to see the set odds of different rounds in secret/random in the get server revision screen. This will NOT tell the current roundtype.
+#SHOW_GAME_TYPE_ODDS
+
+### RANDOM EVENTS ###
+
+## Comment this to disable random events during the round.
+ALLOW_RANDOM_EVENTS
+
+
+### AI ###
+
+## Allow the AI job to be picked.
+ALLOW_AI
+
+
+
+### AWAY MISSIONS ###
+
+## How long the delay is before the Away Mission gate opens. Default is half an hour.
+## 600 is one minute.
+GATEWAY_DELAY 18000
+
+
+### ACCESS ###
+
+## If the number of players ready at round starts exceeds this threshold, JOBS_HAVE_MINIMAL_ACCESS will automatically be enabled. Otherwise, it will be disabled.
+## This is useful for accomodating both low and high population rounds on the same server.
+## Comment out or set to 0 to disable this automatic toggle.
+MINIMAL_ACCESS_THRESHOLD 20
+
+## Comment this out if you wish to use the setup where jobs have more access.
+## This is intended for servers with low populations - where there are not enough
+## players to fill all roles, so players need to do more than just one job.
+## This option is ignored if MINIMAL_ACCESS_THRESHOLD is used.
+#JOBS_HAVE_MINIMAL_ACCESS
+
+## Uncomment to give assistants maint access.
+#ASSISTANTS_HAVE_MAINT_ACCESS
+
+## Uncoment to give security maint access. Note that if you comment JOBS_HAVE_MINIMAL_ACCESS security already gets maint from that.
+#SECURITY_HAS_MAINT_ACCESS
+
+## Uncomment to give everyone maint access.
+#EVERYONE_HAS_MAINT_ACCESS
+
+## Comment this to make security officers spawn in departmental security posts
+SEC_START_BRIG
+
+
+### GHOST INTERACTION ###
+## Uncomment to let ghosts spin chairs. You may be wondering why this is a config option. Don't ask.
+#GHOST_INTERACTION
+
+### NON-VOCAL SILICONS ###
+## Uncomment to stop the AI, or cyborgs, from having vocal communication.
+#SILENT_AI
+#SILENT_BORG
+
+### SANDBOX PANEL AUTOCLOSE ###
+## The sandbox panel's item spawning dialog now stays open even after you click an option.
+## If you find that your players are abusing the sandbox panel, this option may slow them down
+## without preventing people from using it properly.
+## Only functions in sandbox game mode.
+#SANDBOX_AUTOCLOSE
+
+### ROUNDSTART SILICON LAWS ###
+## This controls what the AI's laws are at the start of the round.
+## Set to 0/commented for "off", silicons will just start with Asimov.
+## Set to 1 for "custom", silicons will start with the custom laws defined in silicon_laws.txt. (If silicon_laws.txt is empty, the AI will spawn with asimov and Custom boards will auto-delete.)
+## Set to 2 for "random", silicons will start with a random lawset picked from (at the time of writing): P.A.L.A.D.I.N., Corporate, Asimov. More can be added by changing the law datum paths in ai_laws.dm.
+DEFAULT_LAWS 1
+
+### SILICON LAW MAX AMOUNT ###
+## The maximum number of laws a silicon can have
+## Attempting to upload laws past this point will fail unless the AI is reset
+SILICON_MAX_LAW_AMOUNT 12
+
+## Uncomment to give players the choice of their species before they join the game
+#JOIN_WITH_MUTANT_RACE
+
+## Uncomment to give players the choice of joining as a human with mutant bodyparts before they join the game
+#JOIN_WITH_MUTANT_HUMANS
+
+## Assistant slot cap. Set to -1 for unlimited.
+ASSISTANT_CAP -1
+
+## Starlight for exterior walls and breaches. Uncomment for starlight!
+STARLIGHT
+
+## Uncomment to bring back old grey suit assistants instead of the now default rainbow colored assistants.
+#GREY_ASSISTANTS
+
+### Midround Antag (aka Mulligan antag) config options ###
+
+## A time, in minutes, after which the midround antag system stops attempting to run and continuous rounds end immediately upon completion.
+MIDROUND_ANTAG_TIME_CHECK 60
+
+## A ratio of living to total crew members, the lower this is, the more people will have to die in order for midround antag to be skipped
+MIDROUND_ANTAG_LIFE_CHECK 0.7
+
+###Limit Spell Choices##
+## Uncomment to disallow wizards from using certain spells that may be too chaotic/fun for your playerbase
+
+#NO_SUMMON_GUNS
+#NO_SUMMON_MAGIC
+#NO_SUMMON_EVENTS
+
+//Comment for "normal" explosions, which ignore obstacles
+//Uncomment for explosions that react to doors and walls
+REACTIONARY_EXPLOSIONS
+
+### Configure the bomb cap
+## This caps all explosions to the specified range. Used for both balance reasons and to prevent overloading the server and lagging the game out.
+## This is given as the 3rd number(light damage) in the standard (1,2,3) explosion notation. The other numbers are derived by dividing by 2 and 4.
+## eg: If you give the number 20. The bomb cap will be 5,10,20.
+## Can be any number between 4 and 128, some examples are provided below.
+
+## Default (3,7,14)
+BOMBCAP 14
+## One 'step' up (4,8,16) (recommended if you enable REACTIONARY_EXPLOSIONS above)
+#BOMBCAP 16
+## LagHell (7,14,28)
+#BOMBCAP 28
+
+
+
diff --git a/config/jobs.txt b/config/jobs.txt
index c694bce28d0..a2676df629f 100644
--- a/config/jobs.txt
+++ b/config/jobs.txt
@@ -1,39 +1,39 @@
-Captain=1
-Head of Personnel=1
-Head of Security=1
-Chief Engineer=1
-Research Director=1
-Chief Medical Officer=1
-
-Station Engineer=5
-Roboticist=1
-
-Medical Doctor=5
-Geneticist=2
-Virologist=1
-
-Scientist=3
-Chemist=2
-
-Bartender=1
-Botanist=2
-Chef=1
-Janitor=1
-Quartermaster=1
-Shaft Miner=3
-Clown=1
-Mime=1
-
-Warden=1
-Detective=1
-Security Officer=5
-
-Assistant=-1
-Atmospheric Technician=4
-Cargo Technician=3
-Chaplain=1
-Lawyer=2
-Librarian=1
-
-AI=1
+Captain=1
+Head of Personnel=1
+Head of Security=1
+Chief Engineer=1
+Research Director=1
+Chief Medical Officer=1
+
+Station Engineer=5
+Roboticist=1
+
+Medical Doctor=5
+Geneticist=2
+Virologist=1
+
+Scientist=3
+Chemist=2
+
+Bartender=1
+Botanist=2
+Chef=1
+Janitor=1
+Quartermaster=1
+Shaft Miner=3
+Clown=1
+Mime=1
+
+Warden=1
+Detective=1
+Security Officer=5
+
+Assistant=-1
+Atmospheric Technician=4
+Cargo Technician=3
+Chaplain=1
+Lawyer=2
+Librarian=1
+
+AI=1
Cyborg=1
\ No newline at end of file
diff --git a/config/motd.txt b/config/motd.txt
index dd3234cbb69..c5b8a594972 100644
--- a/config/motd.txt
+++ b/config/motd.txt
@@ -1,5 +1,5 @@
-
-
-
Welcome to Space Station 13!
-
-This server is running a /tg/station 13 Git build.
+
+
+
Welcome to Space Station 13!
+
+This server is running a /tg/station 13 Git build.
diff --git a/config/names/adjectives.txt b/config/names/adjectives.txt
index ab0b4ba1806..73b6a4076db 100644
--- a/config/names/adjectives.txt
+++ b/config/names/adjectives.txt
@@ -1,397 +1,397 @@
-adorable
-adventurous
-aggressive
-alert
-attractive
-average
-beautiful
-blue-eyed
-bloody
-blushing
-bright
-clean
-clear
-cloudy
-colorful
-crowded
-cute
-dark
-drab
-distinct
-dull
-elegant
-excited
-fancy
-filthy
-glamorous
-gleaming
-gorgeous
-graceful
-grotesque
-handsome
-homely
-light
-long
-magnificent
-misty
-motionless
-muddy
-old-fashioned
-plain
-poised
-precious
-quaint
-shiny
-smoggy
-sparkling
-spotless
-stormy
-strange
-ugly
-ugliest
-unsightly
-unusual
-wide-eyed
-alive
-annoying
-bad
-better
-beautiful
-brainy
-breakable
-busy
-careful
-cautious
-clever
-clumsy
-concerned
-crazy
-curious
-dead
-different
-difficult
-doubtful
-easy
-expensive
-famous
-fragile
-frail
-gifted
-helpful
-helpless
-horrible
-important
-impossible
-inexpensive
-innocent
-inquisitive
-modern
-mushy
-odd
-open
-outstanding
-poor
-powerful
-prickly
-puzzled
-real
-rich
-shy
-sleepy
-stupid
-super
-talented
-tame
-tender
-tough
-uninterested
-vast
-wandering
-wild
-wrong
-
-angry
-annoyed
-anxious
-arrogant
-ashamed
-awful
-bad
-bewildered
-black
-blue
-bored
-clumsy
-combative
-condemned
-confused
-crazy,flipped-out
-creepy
-cruel
-dangerous
-defeated
-defiant
-depressed
-disgusted
-disturbed
-dizzy
-dull
-embarrassed
-envious
-evil
-fierce
-foolish
-frantic
-frightened
-grieving
-grumpy
-helpless
-homeless
-hungry
-hurt
-ill
-itchy
-jealous
-jittery
-lazy
-lonely
-mysterious
-nasty
-naughty
-nervous
-nutty
-obnoxious
-outrageous
-panicky
-repulsive
-scary
-selfish
-sore
-tense
-terrible
-testy
-thoughtless
-tired
-troubled
-upset
-uptight
-weary
-wicked
-worried
-agreeable
-amused
-brave
-calm
-charming
-cheerful
-comfortable
-cooperative
-courageous
-delightful
-determined
-eager
-elated
-enchanting
-encouraging
-energetic
-enthusiastic
-excited
-exuberant
-fair
-faithful
-fantastic
-fine
-friendly
-funny
-gentle
-glorious
-good
-happy
-healthy
-helpful
-hilarious
-jolly
-joyous
-kind
-lively
-lovely
-lucky
-nice
-obedient
-perfect
-pleasant
-proud
-relieved
-silly
-smiling
-splendid
-successful
-thankful
-thoughtful
-victorious
-vivacious
-witty
-wonderful
-zealous
-zany
-broad
-chubby
-crooked
-curved
-deep
-flat
-high
-hollow
-low
-narrow
-round
-shallow
-skinny
-square
-steep
-straight
-wide
-big
-colossal
-fat
-gigantic
-great
-huge
-immense
-large
-little
-mammoth
-massive
-miniature
-petite
-puny
-scrawny
-short
-small
-tall
-teeny
-teeny-tiny
-tiny
-cooing
-deafening
-faint
-harsh
-high-pitched
-hissing
-hushed
-husky
-loud
-melodic
-moaning
-mute
-noisy
-purring
-quiet
-raspy
-resonant
-screeching
-shrill
-silent
-soft
-squealing
-thundering
-voiceless
-whispering
-ancient
-brief
-early
-fast
-late
-long
-modern
-old
-old-fashioned
-quick
-rapid
-short
-slow
-swift
-young
-Taste/Touch
-bitter
-delicious
-fresh
-juicy
-ripe
-rotten
-salty
-sour
-spicy
-stale
-sticky
-strong
-sweet
-tart
-tasteless
-tasty
-thirsty
-fluttering
-fuzzy
-greasy
-grubby
-hard
-hot
-icy
-loose
-melted
-nutritious
-plastic
-prickly
-rainy
-rough
-scattered
-shaggy
-shaky
-sharp
-shivering
-silky
-slimy
-slippery
-smooth
-soft
-solid
-steady
-sticky
-tender
-tight
-uneven
-weak
-wet
-wooden
-yummy
-boiling
-breezy
-broken
-bumpy
-chilly
-cold
-cool
-creepy
-crooked
-cuddly
-curly
-damaged
-damp
-dirty
-dry
-dusty
-filthy
-flaky
-fluffy
-freezing
-hot
-warm
-wet
-abundant
-empty
-few
-heavy
-light
-many
-numerous
+adorable
+adventurous
+aggressive
+alert
+attractive
+average
+beautiful
+blue-eyed
+bloody
+blushing
+bright
+clean
+clear
+cloudy
+colorful
+crowded
+cute
+dark
+drab
+distinct
+dull
+elegant
+excited
+fancy
+filthy
+glamorous
+gleaming
+gorgeous
+graceful
+grotesque
+handsome
+homely
+light
+long
+magnificent
+misty
+motionless
+muddy
+old-fashioned
+plain
+poised
+precious
+quaint
+shiny
+smoggy
+sparkling
+spotless
+stormy
+strange
+ugly
+ugliest
+unsightly
+unusual
+wide-eyed
+alive
+annoying
+bad
+better
+beautiful
+brainy
+breakable
+busy
+careful
+cautious
+clever
+clumsy
+concerned
+crazy
+curious
+dead
+different
+difficult
+doubtful
+easy
+expensive
+famous
+fragile
+frail
+gifted
+helpful
+helpless
+horrible
+important
+impossible
+inexpensive
+innocent
+inquisitive
+modern
+mushy
+odd
+open
+outstanding
+poor
+powerful
+prickly
+puzzled
+real
+rich
+shy
+sleepy
+stupid
+super
+talented
+tame
+tender
+tough
+uninterested
+vast
+wandering
+wild
+wrong
+
+angry
+annoyed
+anxious
+arrogant
+ashamed
+awful
+bad
+bewildered
+black
+blue
+bored
+clumsy
+combative
+condemned
+confused
+crazy,flipped-out
+creepy
+cruel
+dangerous
+defeated
+defiant
+depressed
+disgusted
+disturbed
+dizzy
+dull
+embarrassed
+envious
+evil
+fierce
+foolish
+frantic
+frightened
+grieving
+grumpy
+helpless
+homeless
+hungry
+hurt
+ill
+itchy
+jealous
+jittery
+lazy
+lonely
+mysterious
+nasty
+naughty
+nervous
+nutty
+obnoxious
+outrageous
+panicky
+repulsive
+scary
+selfish
+sore
+tense
+terrible
+testy
+thoughtless
+tired
+troubled
+upset
+uptight
+weary
+wicked
+worried
+agreeable
+amused
+brave
+calm
+charming
+cheerful
+comfortable
+cooperative
+courageous
+delightful
+determined
+eager
+elated
+enchanting
+encouraging
+energetic
+enthusiastic
+excited
+exuberant
+fair
+faithful
+fantastic
+fine
+friendly
+funny
+gentle
+glorious
+good
+happy
+healthy
+helpful
+hilarious
+jolly
+joyous
+kind
+lively
+lovely
+lucky
+nice
+obedient
+perfect
+pleasant
+proud
+relieved
+silly
+smiling
+splendid
+successful
+thankful
+thoughtful
+victorious
+vivacious
+witty
+wonderful
+zealous
+zany
+broad
+chubby
+crooked
+curved
+deep
+flat
+high
+hollow
+low
+narrow
+round
+shallow
+skinny
+square
+steep
+straight
+wide
+big
+colossal
+fat
+gigantic
+great
+huge
+immense
+large
+little
+mammoth
+massive
+miniature
+petite
+puny
+scrawny
+short
+small
+tall
+teeny
+teeny-tiny
+tiny
+cooing
+deafening
+faint
+harsh
+high-pitched
+hissing
+hushed
+husky
+loud
+melodic
+moaning
+mute
+noisy
+purring
+quiet
+raspy
+resonant
+screeching
+shrill
+silent
+soft
+squealing
+thundering
+voiceless
+whispering
+ancient
+brief
+early
+fast
+late
+long
+modern
+old
+old-fashioned
+quick
+rapid
+short
+slow
+swift
+young
+Taste/Touch
+bitter
+delicious
+fresh
+juicy
+ripe
+rotten
+salty
+sour
+spicy
+stale
+sticky
+strong
+sweet
+tart
+tasteless
+tasty
+thirsty
+fluttering
+fuzzy
+greasy
+grubby
+hard
+hot
+icy
+loose
+melted
+nutritious
+plastic
+prickly
+rainy
+rough
+scattered
+shaggy
+shaky
+sharp
+shivering
+silky
+slimy
+slippery
+smooth
+soft
+solid
+steady
+sticky
+tender
+tight
+uneven
+weak
+wet
+wooden
+yummy
+boiling
+breezy
+broken
+bumpy
+chilly
+cold
+cool
+creepy
+crooked
+cuddly
+curly
+damaged
+damp
+dirty
+dry
+dusty
+filthy
+flaky
+fluffy
+freezing
+hot
+warm
+wet
+abundant
+empty
+few
+heavy
+light
+many
+numerous
substantial
\ No newline at end of file
diff --git a/config/names/ai.txt b/config/names/ai.txt
index ea9f63c0a9e..01c65cf1b7f 100644
--- a/config/names/ai.txt
+++ b/config/names/ai.txt
@@ -1,147 +1,147 @@
-1-Rover-1
-16-20
-7-Zark-7
-790
-AM
-AMEE
-ASTAR
-Adaptive Manipulator
-Allied Mastercomputer
-Alpha 5
-Alpha 6
-Alpha 7
-AmigoBot
-Android
-Aniel
-Asimov
-Astor
-B-4
-B-9
-B.O.B.
-B166ER
-Bender
-Bishop
-Blitz
-Box
-Brackenridge
-C-3PO
-Cassandra One
-Cell
-Chii
-Chip
-Computer
-Conky 2000
-Cutie
-Data
-Dee Model
-Deep Thought
-Dor-15
-Dorfl
-Dot Matrix
-Duey
-E.D.I.
-ED-209
-E-Man
-Emma-2
-Erasmus
-Ez-27
-FRIEND COMPUTER
-Fagor
-Faith
-Fi
-Frost
-Fum
-Futura
-G2
-George
-Gnut
-Gort
-H.A.R.L.I.E.
-H.E.L.P.eR.
-H.E.R.B.I.E.
-HAL 9000
-Hadaly
-Huey
-Irona
-Jay-Dub
-Jinx
-Johnny 5
-K-9
-KITT
-Klapaucius
-Kryten 2X4B-523P
-L-76
-L-Ron
-LUH 3417
-Louie
-MARK13
-Maria
-Marvin
-Master Control Program
-Max 404
-Maximillian
-Mechagodzilla
-Mechani-Kong
-Metalhead
-Mr. R.I.N.G.
-NCH
-Necron-99
-Norby
-OMM 0910
-Orange v 3.5
-PTO
-Project 2501
-R.I.C. 2.0
-R2-D2
-R4-P17
-Revelation
-Ro-Man
-Robbie
-S.A.M.
-S.H.O.C.K.
-S.H.R.O.U.D.
-S.O.P.H.I.E.
-SEN 5241
-SHODAN
-SID 6.7
-Setaur
-Shrike
-Solo
-Speedy
-Super 17
-Surgeon General Kraken
-T-1000
-T-800
-T-850
-THX 1138
-TWA
-Terminus
-Tidy
-Tik-Tok
-Tobor
-Trurl
-ULTRABOT
-Ulysses
-Uniblab
-V.I.N.CENT.
-Voltes V
-W1k1
-Wikipedia
-Windows 3.1
-X-5
-XERXES
-XR
-Yod
-Z-1
-Z-2
-Z-3
-Zed
-Zord
-Mugsy3000
-Terminus
-Decimus
-Robot Devil
-Optimus
-Megatron
-Soundwave
-Ironhide
+1-Rover-1
+16-20
+7-Zark-7
+790
+AM
+AMEE
+ASTAR
+Adaptive Manipulator
+Allied Mastercomputer
+Alpha 5
+Alpha 6
+Alpha 7
+AmigoBot
+Android
+Aniel
+Asimov
+Astor
+B-4
+B-9
+B.O.B.
+B166ER
+Bender
+Bishop
+Blitz
+Box
+Brackenridge
+C-3PO
+Cassandra One
+Cell
+Chii
+Chip
+Computer
+Conky 2000
+Cutie
+Data
+Dee Model
+Deep Thought
+Dor-15
+Dorfl
+Dot Matrix
+Duey
+E.D.I.
+ED-209
+E-Man
+Emma-2
+Erasmus
+Ez-27
+FRIEND COMPUTER
+Fagor
+Faith
+Fi
+Frost
+Fum
+Futura
+G2
+George
+Gnut
+Gort
+H.A.R.L.I.E.
+H.E.L.P.eR.
+H.E.R.B.I.E.
+HAL 9000
+Hadaly
+Huey
+Irona
+Jay-Dub
+Jinx
+Johnny 5
+K-9
+KITT
+Klapaucius
+Kryten 2X4B-523P
+L-76
+L-Ron
+LUH 3417
+Louie
+MARK13
+Maria
+Marvin
+Master Control Program
+Max 404
+Maximillian
+Mechagodzilla
+Mechani-Kong
+Metalhead
+Mr. R.I.N.G.
+NCH
+Necron-99
+Norby
+OMM 0910
+Orange v 3.5
+PTO
+Project 2501
+R.I.C. 2.0
+R2-D2
+R4-P17
+Revelation
+Ro-Man
+Robbie
+S.A.M.
+S.H.O.C.K.
+S.H.R.O.U.D.
+S.O.P.H.I.E.
+SEN 5241
+SHODAN
+SID 6.7
+Setaur
+Shrike
+Solo
+Speedy
+Super 17
+Surgeon General Kraken
+T-1000
+T-800
+T-850
+THX 1138
+TWA
+Terminus
+Tidy
+Tik-Tok
+Tobor
+Trurl
+ULTRABOT
+Ulysses
+Uniblab
+V.I.N.CENT.
+Voltes V
+W1k1
+Wikipedia
+Windows 3.1
+X-5
+XERXES
+XR
+Yod
+Z-1
+Z-2
+Z-3
+Zed
+Zord
+Mugsy3000
+Terminus
+Decimus
+Robot Devil
+Optimus
+Megatron
+Soundwave
+Ironhide
diff --git a/config/names/clown.txt b/config/names/clown.txt
index 90c1f07e27c..c29fca74ba3 100644
--- a/config/names/clown.txt
+++ b/config/names/clown.txt
@@ -1,37 +1,37 @@
-Gigglesworth
-Honkel the III
-Goose McSunny
-Mr. Shoe
-Toodles Sharperton
-Dinky Doodle
-Honkerbelle
-Bo Bo Sassy
-Baby Cakes
-Ladybug Honks
-Ziggy Yoyo
-Razzle Dazzle
-Buster Frown
-Pepinpop
-Silly Willy
-Jo Jo Bobo Bo
-Pocket
-Patches
-Checkers
-Freckle
-Honker
-Bonker
-Skiddle
-Scootaloo
-Sprinkledinkle
-Ronnie Pace
-Miss Stockings
-Slippy Joe
-Redshirt McBeat
-Flop O'Honker
-Speckles
-Bubble
-Button
-Sparkle
-Giggles
-Jingle
+Gigglesworth
+Honkel the III
+Goose McSunny
+Mr. Shoe
+Toodles Sharperton
+Dinky Doodle
+Honkerbelle
+Bo Bo Sassy
+Baby Cakes
+Ladybug Honks
+Ziggy Yoyo
+Razzle Dazzle
+Buster Frown
+Pepinpop
+Silly Willy
+Jo Jo Bobo Bo
+Pocket
+Patches
+Checkers
+Freckle
+Honker
+Bonker
+Skiddle
+Scootaloo
+Sprinkledinkle
+Ronnie Pace
+Miss Stockings
+Slippy Joe
+Redshirt McBeat
+Flop O'Honker
+Speckles
+Bubble
+Button
+Sparkle
+Giggles
+Jingle
Candy
\ No newline at end of file
diff --git a/config/names/death_commando.txt b/config/names/death_commando.txt
index e3d1f34f327..b10e181b5e8 100644
--- a/config/names/death_commando.txt
+++ b/config/names/death_commando.txt
@@ -1,70 +1,70 @@
-Killiam Shakespeare
-Stabby McGee
-Sgt. Slaughter
-Maxx Power
-Sir Killaslot
-Slab Bulkhead
-Fridge Largemeat
-Punt Speedchunk
-Butch Deadlift
-Bold Bigflank
-Splint Chesthair
-Flint Ironstag
-Bolt Vanderhuge
-Thick McRunfast
-Blast Hardcheese
-Buff Drinklots
-Trunk Slamchest
-Fist Rockbone
-Stump Beefgnaw
-Smash Lampjaw
-Punch Rockgroin
-Buck Plankchest
-Stump Chunkman
-Dirk Hardpeck
-Rip Steakface
-Slate Slabrock
-Crud Bonemeal
-Brick Hardmeat
-Rip Sidecheek
-Punch Sideiron
-Gristle McThornBody
-Slake Fistcrunch
-Buff Hardback
-Blast Thickneck
-Crunch Buttsteak
-Slab Squatthrust
-Lump Beefrock
-Touch Rustrod
-Reef Blastbody
-Smoke Manmuscle
-Beat Punchbeef
-Pack Blowfist
-Roll Fizzlebeef
-Lance Killiam
-George Melons
-Maximilian Murderface
-Bob Johnson
-Crush McStompbones
-Hank Chesthair
-Killing McKillingalot
-Mancrush McBrorape
-Rex Dudekiller VII
-Seamus McTosterone
-Hans Testosteroneson
-Max Pain
-Theodore Pain
-Sarah Pain
-GORE Vidal
-Leonardo Da Viking
-Noam Bombsky
-Al "Otta" Gore
-Gibbs McLargehuge
-Evil Martin Luther King
-Evil Bob Marley
-Duke Killington
-AMERICA
-Toolboxl Rose
-Zombie Gandhi
-A whole bunch of spiders in a SWAT suit
+Killiam Shakespeare
+Stabby McGee
+Sgt. Slaughter
+Maxx Power
+Sir Killaslot
+Slab Bulkhead
+Fridge Largemeat
+Punt Speedchunk
+Butch Deadlift
+Bold Bigflank
+Splint Chesthair
+Flint Ironstag
+Bolt Vanderhuge
+Thick McRunfast
+Blast Hardcheese
+Buff Drinklots
+Trunk Slamchest
+Fist Rockbone
+Stump Beefgnaw
+Smash Lampjaw
+Punch Rockgroin
+Buck Plankchest
+Stump Chunkman
+Dirk Hardpeck
+Rip Steakface
+Slate Slabrock
+Crud Bonemeal
+Brick Hardmeat
+Rip Sidecheek
+Punch Sideiron
+Gristle McThornBody
+Slake Fistcrunch
+Buff Hardback
+Blast Thickneck
+Crunch Buttsteak
+Slab Squatthrust
+Lump Beefrock
+Touch Rustrod
+Reef Blastbody
+Smoke Manmuscle
+Beat Punchbeef
+Pack Blowfist
+Roll Fizzlebeef
+Lance Killiam
+George Melons
+Maximilian Murderface
+Bob Johnson
+Crush McStompbones
+Hank Chesthair
+Killing McKillingalot
+Mancrush McBrorape
+Rex Dudekiller VII
+Seamus McTosterone
+Hans Testosteroneson
+Max Pain
+Theodore Pain
+Sarah Pain
+GORE Vidal
+Leonardo Da Viking
+Noam Bombsky
+Al "Otta" Gore
+Gibbs McLargehuge
+Evil Martin Luther King
+Evil Bob Marley
+Duke Killington
+AMERICA
+Toolboxl Rose
+Zombie Gandhi
+A whole bunch of spiders in a SWAT suit
THAT DAMN FAGGOT TRAITOR GEORGE MELONS
\ No newline at end of file
diff --git a/config/names/first.txt b/config/names/first.txt
index eb59a135854..a33e181146f 100644
--- a/config/names/first.txt
+++ b/config/names/first.txt
@@ -1,1502 +1,1502 @@
-Abel
-Adolph
-Aida
-Alan
-Alden
-Alex
-Alexa
-Alexandria
-Alexis
-Alexus
-Alfred
-Alfreda
-Alger
-Alisa
-Alisya
-Allegra
-Allegria
-Allen
-Alma
-Alysha
-Alyssia
-Amaryllis
-Ambrosine
-Amos
-Angel
-Anjelica
-Anne
-Arabella
-Archie
-Arielle
-Arleen
-Arn
-Art
-Ashlie
-Astor
-Aubrey
-Avalon
-Averill
-Baldric
-Barbra
-Bartholomew
-Beckah
-Becky
-Bernice
-Bertrand
-Bethney
-Betsy
-Bidelia
-Bill
-Blake
-Brayden
-Breanne
-Brendan
-Brittani
-Bronte
-Brooke
-Bryce
-Burt
-Byrne
-Byron
-Bysshe
-Cadence
-Calanthia
-Caleigh
-Camryn
-Candace
-Candice
-Candis
-Canute
-Carly
-Carlyle
-Carolyn
-Carry
-Carter
-Caryl
-Casimir
-Cassian
-Cecily
-Charlton
-Cherette
-Cheri
-Cherry
-Chip
-Christa
-Christiana
-Christobel
-Claribel
-Clark
-Claudius
-Clement
-Cleveland
-Cliff
-Clinton
-Clitus
-Clover
-Collin
-Coreen
-Corrine
-Cy
-Cynthia
-Dalya
-Damian
-Daniella
-Danny
-Darcey
-Darell
-Daria
-Darin
-Dayna
-Deangelo
-Debbi
-Dee
-Deena
-Della
-Delma
-Denholm
-Denys
-Desmond
-Devin
-Diamond
-Dina
-Dolores
-Dominic
-Donella
-Donna
-Donny
-Dorothy
-Dortha
-Driscoll
-Duncan
-Easter
-Ebba
-Edgar
-Effie
-Eliot
-Eliott
-Elizabeth
-Elle
-Elric
-Elspet
-Elwood
-Emma
-Emmanuel
-Ermintrude
-Esmeralda
-Eugenia
-Euphemia
-Eustace
-Eveleen
-Evelina
-Fay
-Fitz
-Flick
-Floella
-Flora
-Flossie
-Fortune
-Francis
-Frankie
-Fulton
-Garret
-Gaye
-Gaylord
-Genette
-Georgene
-Geraldine
-Gervase
-Gina
-Ginger
-Gladwyn
-Glenna
-Goddard
-Godwin
-Goodwin
-Gordon
-Graeme
-Gratian
-Greta
-Griselda
-Gwenda
-Gwenevere
-Hadley
-Haidee
-Hailey
-Hal
-Haleigh
-Happy
-Hartley
-Hayley
-Heather
-Hedley
-Helen
-Henderson
-Hepsie
-Hervey
-Holden
-Homer
-Hope
-Horatio
-Hortensia
-Huffie
-Hugo
-Iantha
-Ileen
-Innocent
-Irene
-Irvine
-Jacaline
-Jacquetta
-Jacqui
-Jake
-Jakki
-Jalen
-Jamar
-Jamie
-Jamison
-Janel
-Janelle
-Janette
-Janie
-Janina
-Janine
-Jasmine
-Jaydon
-Jaye
-Jaylee
-Jayne
-Jaynie
-Jeanna
-Jeannie
-Jeannine
-Jeb
-Jed
-Jemmy
-Jenifer
-Jennie
-Jera
-Jere
-Jeri
-Jermaine
-Jerrie
-Jillian
-Jillie
-Jim
-Joachim
-Joetta
-Joey
-Johnathan
-Johnny
-Joi
-Jonathon
-Joni
-Josepha
-Josh
-Josiah
-Joye
-Julia
-July
-Kaelea
-Kaleigh
-Karenza
-Karly
-Karyn
-Kat
-Kathy
-Katlyn
-Kayleigh
-Keegan
-Keira
-Keith
-Kellie
-Kennard
-Kerena
-Kerensa
-Keturah
-Keziah
-Kimberley
-Lacy
-Lakeisha
-Lalla
-Lanny
-Latanya
-Launce
-Laurencia
-Laurissa
-Leeann
-Leia
-Leland
-Lennox
-Leroi
-Lessie
-Leta
-Lexia
-Lexus
-Linden
-Lindsie
-Lindy
-Linton
-Lockie
-Loreto
-Lori
-Lorin
-Lou
-Luanne
-Lucian
-Luvenia
-Lyndsey
-Lynn
-Lynsey
-Lynwood
-Mabelle
-Macey
-Madyson
-Maegan
-Malachi
-Malcolm
-Manley
-Marcia
-Mariabella
-Marilene
-Marion
-Marion
-Marje
-Marjory
-Marlowe
-Marlyn
-Marshall
-Maryann
-Maudie
-Maurene
-May
-Maynard
-Melvyn
-Merideth
-Merrilyn
-Meryl
-Micheal
-Mike
-Milton
-Minnie
-Monna
-Montague
-Monte
-Monty
-Muriel
-Mya
-Myriam
-Myrtie
-Nan
-Nathaniel
-Nelle
-Nena
-Nerissa
-Netta
-Nettie
-Nikolas
-Noah
-Nonie
-Nova
-Nowell
-Nydia
-Olive
-Oralie
-Osbert
-Osborn
-Osborne
-Osmund
-Paget
-Patience
-Patrick
-Patton
-Pauleen
-Pene
-Percival
-Peregrine
-Pheobe
-Phoebe
-Phyliss
-Phyllida
-Phyllis
-Porsche
-Prosper
-Prue
-Quanah
-Quiana
-Raelene
-Rain
-Randa
-Randal
-Rastus
-Rayner
-Rebeckah
-Reene
-Renie
-Reuben
-Rexana
-Reynard
-Rhetta
-Rich
-Richie
-Rick
-Rickena
-Rickey
-Rickie
-Rodger
-Roger
-Romayne
-Ronnette
-Roscoe
-Rosemary
-Roswell
-Royce
-Rubye
-Rusty
-Sabella
-Sachie
-Sal
-Sally
-Saranna
-Sawyer
-Scotty
-Seneca
-Seymour
-Shan
-Shana
-Shanika
-Shannah
-Shannon
-Shantae
-Sharalyn
-Sharla
-Sheri
-Sherie
-Sherill
-Sherri
-Shiloh
-Simon
-Sissy
-Sloan
-Sophie
-Sorrel
-Spike
-Star
-Steph
-Stephany
-Sue
-Sukie
-Sunshine
-Susanna
-Susannah
-Suzan
-Suzy
-Sybil
-Syd
-Sydney
-Tamika
-Tamsin
-Tania
-Tansy
-Tatyanna
-Taylor
-Tel
-Terrell
-Tiffany
-Tod
-Tolly
-Topaz
-Tori
-Tracee
-Tracey
-Trinity
-Tye
-Uland
-Ulric
-Ulyssa
-Valary
-Vaughn
-Verna
-Vince
-Vinnie
-Vivyan
-Walter
-Ward
-Warner
-Wayne
-Wendi
-Whitaker
-William
-Willy
-Winifred
-Wisdom
-Woodrow
-Woody
-Wynonna
-Wynter
-Yasmin
-Yolanda
-Ysabel
-Zack
-Zeke
-Zelda
-Zune
-Jacob
-Michael
-Ethan
-Joshua
-Daniel
-Alexander
-Anthony
-William
-Christopher
-Matthew
-Jayden
-Andrew
-Joseph
-David
-Noah
-Aiden
-James
-Ryan
-Logan
-John
-Nathan
-Elijah
-Christian
-Gabriel
-Benjamin
-Jonathan
-Tyler
-Samuel
-Nicholas
-Gavin
-Dylan
-Jackson
-Brandon
-Caleb
-Mason
-Angel
-Isaac
-Evan
-Jack
-Kevin
-Jose
-Isaiah
-Luke
-Landon
-Justin
-Lucas
-Zachary
-Jordan
-Robert
-Aaron
-Brayden
-Thomas
-Cameron
-Hunter
-Austin
-Adrian
-Connor
-Owen
-Aidan
-Jason
-Julian
-Wyatt
-Charles
-Luis
-Carter
-Juan
-Chase
-Diego
-Jeremiah
-Brody
-Xavier
-Adam
-Carlos
-Sebastian
-Liam
-Hayden
-Nathaniel
-Henry
-Jesus
-Ian
-Tristan
-Bryan
-Sean
-Cole
-Alex
-Eric
-Brian
-Jaden
-Carson
-Blake
-Ayden
-Cooper
-Dominic
-Brady
-Caden
-Josiah
-Kyle
-Colton
-Kaden
-Eli
-Miguel
-Antonio
-Parker
-Steven
-Alejandro
-Riley
-Richard
-Timothy
-Devin
-Jesse
-Victor
-Jake
-Joel
-Colin
-Kaleb
-Bryce
-Levi
-Oliver
-Oscar
-Vincent
-Ashton
-Cody
-Micah
-Preston
-Marcus
-Max
-Patrick
-Seth
-Jeremy
-Peyton
-Nolan
-Ivan
-Damian
-Maxwell
-Alan
-Kenneth
-Jonah
-Jorge
-Mark
-Giovanni
-Eduardo
-Grant
-Collin
-Gage
-Omar
-Emmanuel
-Trevor
-Edward
-Ricardo
-Cristian
-Nicolas
-Kayden
-George
-Jaxon
-Paul
-Braden
-Elias
-Andres
-Derek
-Garrett
-Tanner
-Malachi
-Conner
-Fernando
-Cesar
-Javier
-Miles
-Jaiden
-Alexis
-Leonardo
-Santiago
-Francisco
-Cayden
-Shane
-Edwin
-Hudson
-Travis
-Bryson
-Erick
-Jace
-Hector
-Josue
-Peter
-Jaylen
-Mario
-Manuel
-Abraham
-Grayson
-Damien
-Kaiden
-Spencer
-Stephen
-Edgar
-Wesley
-Shawn
-Trenton
-Jared
-Jeffrey
-Landen
-Johnathan
-Bradley
-Braxton
-Ryder
-Camden
-Roman
-Asher
-Brendan
-Maddox
-Sergio
-Israel
-Andy
-Lincoln
-Erik
-Donovan
-Raymond
-Avery
-Rylan
-Dalton
-Harrison
-Andre
-Martin
-Keegan
-Marco
-Jude
-Sawyer
-Dakota
-Leo
-Calvin
-Kai
-Drake
-Troy
-Zion
-Clayton
-Roberto
-Zane
-Gregory
-Tucker
-Rafael
-Kingston
-Dominick
-Ezekiel
-Griffin
-Devon
-Drew
-Lukas
-Johnny
-Ty
-Pedro
-Tyson
-Caiden
-Mateo
-Braylon
-Cash
-Aden
-Chance
-Taylor
-Marcos
-Maximus
-Ruben
-Emanuel
-Simon
-Corbin
-Brennan
-Dillon
-Skyler
-Myles
-Xander
-Jaxson
-Dawson
-Kameron
-Kyler
-Axel
-Colby
-Jonas
-Joaquin
-Payton
-Brock
-Frank
-Enrique
-Quinn
-Emilio
-Malik
-Grady
-Angelo
-Julio
-Derrick
-Raul
-Fabian
-Corey
-Gerardo
-Dante
-Ezra
-Armando
-Allen
-Theodore
-Gael
-Amir
-Zander
-Adan
-Maximilian
-Randy
-Easton
-Dustin
-Luca
-Phillip
-Julius
-Charlie
-Ronald
-Jakob
-Cade
-Brett
-Trent
-Silas
-Keith
-Emiliano
-Trey
-Jalen
-Darius
-Lane
-Jerry
-Jaime
-Scott
-Graham
-Weston
-Braydon
-Anderson
-Rodrigo
-Pablo
-Saul
-Danny
-Donald
-Elliot
-Brayan
-Dallas
-Lorenzo
-Casey
-Mitchell
-Alberto
-Tristen
-Rowan
-Jayson
-Gustavo
-Aaden
-Amari
-Dean
-Braeden
-Declan
-Chris
-Ismael
-Dane
-Louis
-Arturo
-Brenden
-Felix
-Jimmy
-Cohen
-Tony
-Holden
-Reid
-Abel
-Bennett
-Zackary
-Arthur
-Nehemiah
-Ricky
-Esteban
-Cruz
-Finn
-Mauricio
-Dennis
-Keaton
-Albert
-Marvin
-Mathew
-Larry
-Moises
-Issac
-Philip
-Quentin
-Curtis
-Greyson
-Jameson
-Everett
-Jayce
-Darren
-Elliott
-Uriel
-Alfredo
-Hugo
-Alec
-Jamari
-Marshall
-Walter
-Judah
-Jay
-Lance
-Beau
-Ali
-Landyn
-Yahir
-Phoenix
-Nickolas
-Kobe
-Bryant
-Maurice
-Russell
-Leland
-Colten
-Reed
-Davis
-Joe
-Ernesto
-Desmond
-Kade
-Reece
-Morgan
-Ramon
-Rocco
-Orlando
-Ryker
-Brodie
-Paxton
-Jacoby
-Douglas
-Kristopher
-Gary
-Lawrence
-Izaiah
-Solomon
-Nikolas
-Mekhi
-Justice
-Tate
-Jaydon
-Salvador
-Shaun
-Alvin
-Eddie
-Kane
-Davion
-Zachariah
-Dorian
-Titus
-Kellen
-Camron
-Isiah
-Javon
-Nasir
-Milo
-Johan
-Byron
-Jasper
-Jonathon
-Chad
-Marc
-Kelvin
-Chandler
-Sam
-Cory
-Deandre
-River
-Reese
-Roger
-Quinton
-Talon
-Romeo
-Franklin
-Noel
-Alijah
-Guillermo
-Gunner
-Damon
-Jadon
-Emerson
-Micheal
-Bruce
-Terry
-Kolton
-Melvin
-Beckett
-Porter
-August
-Brycen
-Dayton
-Jamarion
-Leonel
-Karson
-Zayden
-Keagan
-Carl
-Khalil
-Cristopher
-Nelson
-Braiden
-Moses
-Isaias
-Roy
-Triston
-Walker
-Kale
-Emma
-Isabella
-Emily
-Madison
-Ava
-Olivia
-Sophia
-Abigail
-Elizabeth
-Chloe
-Samantha
-Addison
-Natalie
-Mia
-Alexis
-Alyssa
-Hannah
-Ashley
-Ella
-Sarah
-Grace
-Taylor
-Brianna
-Lily
-Hailey
-Anna
-Victoria
-Kayla
-Lillian
-Lauren
-Kaylee
-Allison
-Savannah
-Nevaeh
-Gabriella
-Sofia
-Makayla
-Avery
-Riley
-Julia
-Leah
-Aubrey
-Jasmine
-Audrey
-Katherine
-Morgan
-Brooklyn
-Destiny
-Sydney
-Alexa
-Kylie
-Brooke
-Kaitlyn
-Evelyn
-Layla
-Madeline
-Kimberly
-Zoe
-Jessica
-Peyton
-Alexandra
-Claire
-Madelyn
-Maria
-Mackenzie
-Arianna
-Jocelyn
-Amelia
-Angelina
-Trinity
-Andrea
-Maya
-Valeria
-Sophie
-Rachel
-Vanessa
-Aaliyah
-Mariah
-Gabrielle
-Katelyn
-Ariana
-Bailey
-Camila
-Jennifer
-Melanie
-Gianna
-Charlotte
-Paige
-Autumn
-Payton
-Faith
-Sara
-Isabelle
-Caroline
-Genesis
-Isabel
-Mary
-Zoey
-Gracie
-Megan
-Haley
-Mya
-Michelle
-Molly
-Stephanie
-Nicole
-Jenna
-Natalia
-Sadie
-Jada
-Serenity
-Lucy
-Ruby
-Eva
-Kennedy
-Rylee
-Jayla
-Naomi
-Rebecca
-Lydia
-Daniela
-Bella
-Keira
-Adriana
-Lilly
-Hayden
-Miley
-Katie
-Jade
-Jordan
-Gabriela
-Amy
-Angela
-Melissa
-Valerie
-Giselle
-Diana
-Amanda
-Kate
-Laila
-Reagan
-Jordyn
-Kylee
-Danielle
-Briana
-Marley
-Leslie
-Kendall
-Catherine
-Liliana
-Mckenzie
-Jacqueline
-Ashlyn
-Reese
-Marissa
-London
-Juliana
-Shelby
-Cheyenne
-Angel
-Daisy
-Makenzie
-Miranda
-Erin
-Amber
-Alana
-Ellie
-Breanna
-Ana
-Mikayla
-Summer
-Piper
-Adrianna
-Jillian
-Sierra
-Jayden
-Sienna
-Alicia
-Lila
-Margaret
-Alivia
-Brooklynn
-Karen
-Violet
-Sabrina
-Stella
-Aniyah
-Annabelle
-Alexandria
-Kathryn
-Skylar
-Aliyah
-Delilah
-Julianna
-Kelsey
-Khloe
-Carly
-Amaya
-Mariana
-Christina
-Alondra
-Tessa
-Eliana
-Bianca
-Jazmin
-Clara
-Vivian
-Josephine
-Delaney
-Scarlett
-Elena
-Cadence
-Alexia
-Maggie
-Laura
-Nora
-Ariel
-Elise
-Nadia
-Mckenna
-Chelsea
-Lyla
-Alaina
-Jasmin
-Hope
-Leila
-Caitlyn
-Cassidy
-Makenna
-Allie
-Izabella
-Eden
-Callie
-Haylee
-Caitlin
-Kendra
-Karina
-Kyra
-Kayleigh
-Addyson
-Kiara
-Jazmine
-Karla
-Camryn
-Alina
-Lola
-Kyla
-Kelly
-Fatima
-Tiffany
-Kira
-Crystal
-Mallory
-Esmeralda
-Alejandra
-Eleanor
-Angelica
-Jayda
-Abby
-Kara
-Veronica
-Carmen
-Jamie
-Ryleigh
-Valentina
-Allyson
-Dakota
-Kamryn
-Courtney
-Cecilia
-Madeleine
-Aniya
-Alison
-Esther
-Heaven
-Aubree
-Lindsey
-Leilani
-Nina
-Melody
-Macy
-Ashlynn
-Joanna
-Cassandra
-Alayna
-Kaydence
-Madilyn
-Aurora
-Heidi
-Emerson
-Kimora
-Madalyn
-Erica
-Josie
-Katelynn
-Guadalupe
-Harper
-Ivy
-Lexi
-Camille
-Savanna
-Dulce
-Daniella
-Lucia
-Emely
-Joselyn
-Kiley
-Kailey
-Miriam
-Cynthia
-Rihanna
-Georgia
-Rylie
-Harmony
-Kiera
-Kyleigh
-Monica
-Bethany
-Kaylie
-Cameron
-Teagan
-Cora
-Brynn
-Ciara
-Genevieve
-Alice
-Maddison
-Eliza
-Tatiana
-Jaelyn
-Erika
-Ximena
-April
-Marely
-Julie
-Danica
-Presley
-Brielle
-Julissa
-Angie
-Iris
-Brenda
-Hazel
-Rose
-Malia
-Shayla
-Fiona
-Phoebe
-Nayeli
-Paola
-Kaelyn
-Selena
-Audrina
-Rebekah
-Carolina
-Janiyah
-Michaela
-Penelope
-Janiya
-Anastasia
-Adeline
-Ruth
-Sasha
-Denise
-Holly
-Madisyn
-Hanna
-Tatum
-Marlee
-Nataly
-Helen
-Janelle
-Lizbeth
-Serena
-Anya
-Jaslene
-Kaylin
-Jazlyn
-Nancy
-Lindsay
-Desiree
-Hayley
-Itzel
-Imani
-Madelynn
-Asia
-Kadence
-Madyson
-Talia
-Jane
-Kayden
-Annie
-Amari
-Bridget
-Raegan
-Jadyn
-Celeste
-Jimena
-Luna
-Yasmin
-Emilia
-Annika
-Estrella
-Sarai
-Lacey
-Ayla
-Alessandra
-Willow
-Nyla
-Dayana
-Lilah
-Lilliana
-Natasha
-Hadley
-Harley
-Priscilla
-Claudia
-Allisson
-Baylee
-Brenna
-Brittany
-Skyler
-Fernanda
-Danna
-Melany
-Cali
-Lia
-Macie
-Lyric
-Logan
-Gloria
-Lana
-Mylee
-Cindy
-Lilian
-Amira
-Anahi
-Alissa
-Anaya
-Lena
-Ainsley
-Sandra
-Noelle
-Marisol
-Meredith
-Kailyn
-Lesly
-Johanna
-Diamond
-Evangeline
-Juliet
-Kathleen
-Meghan
-Paisley
-Athena
-Hailee
-Rosa
-Wendy
-Emilee
-Sage
-Alanna
-Elaina
-Cara
-Nia
-Paris
-Casey
-Dana
-Emery
-Rowan
-Aubrie
-Kaitlin
-Jaden
-Kenzie
-Kiana
-Viviana
-Norah
-Lauryn
-Perla
-Amiyah
-Alyson
-Rachael
-Shannon
-Aileen
-Miracle
-Lillie
-Danika
-Heather
-Kassidy
-Taryn
-Tori
-Francesca
-Kristen
-Amya
-Elle
-Kristina
-Cheyanne
-Haylie
-Patricia
-Anne
-Samara
+Abel
+Adolph
+Aida
+Alan
+Alden
+Alex
+Alexa
+Alexandria
+Alexis
+Alexus
+Alfred
+Alfreda
+Alger
+Alisa
+Alisya
+Allegra
+Allegria
+Allen
+Alma
+Alysha
+Alyssia
+Amaryllis
+Ambrosine
+Amos
+Angel
+Anjelica
+Anne
+Arabella
+Archie
+Arielle
+Arleen
+Arn
+Art
+Ashlie
+Astor
+Aubrey
+Avalon
+Averill
+Baldric
+Barbra
+Bartholomew
+Beckah
+Becky
+Bernice
+Bertrand
+Bethney
+Betsy
+Bidelia
+Bill
+Blake
+Brayden
+Breanne
+Brendan
+Brittani
+Bronte
+Brooke
+Bryce
+Burt
+Byrne
+Byron
+Bysshe
+Cadence
+Calanthia
+Caleigh
+Camryn
+Candace
+Candice
+Candis
+Canute
+Carly
+Carlyle
+Carolyn
+Carry
+Carter
+Caryl
+Casimir
+Cassian
+Cecily
+Charlton
+Cherette
+Cheri
+Cherry
+Chip
+Christa
+Christiana
+Christobel
+Claribel
+Clark
+Claudius
+Clement
+Cleveland
+Cliff
+Clinton
+Clitus
+Clover
+Collin
+Coreen
+Corrine
+Cy
+Cynthia
+Dalya
+Damian
+Daniella
+Danny
+Darcey
+Darell
+Daria
+Darin
+Dayna
+Deangelo
+Debbi
+Dee
+Deena
+Della
+Delma
+Denholm
+Denys
+Desmond
+Devin
+Diamond
+Dina
+Dolores
+Dominic
+Donella
+Donna
+Donny
+Dorothy
+Dortha
+Driscoll
+Duncan
+Easter
+Ebba
+Edgar
+Effie
+Eliot
+Eliott
+Elizabeth
+Elle
+Elric
+Elspet
+Elwood
+Emma
+Emmanuel
+Ermintrude
+Esmeralda
+Eugenia
+Euphemia
+Eustace
+Eveleen
+Evelina
+Fay
+Fitz
+Flick
+Floella
+Flora
+Flossie
+Fortune
+Francis
+Frankie
+Fulton
+Garret
+Gaye
+Gaylord
+Genette
+Georgene
+Geraldine
+Gervase
+Gina
+Ginger
+Gladwyn
+Glenna
+Goddard
+Godwin
+Goodwin
+Gordon
+Graeme
+Gratian
+Greta
+Griselda
+Gwenda
+Gwenevere
+Hadley
+Haidee
+Hailey
+Hal
+Haleigh
+Happy
+Hartley
+Hayley
+Heather
+Hedley
+Helen
+Henderson
+Hepsie
+Hervey
+Holden
+Homer
+Hope
+Horatio
+Hortensia
+Huffie
+Hugo
+Iantha
+Ileen
+Innocent
+Irene
+Irvine
+Jacaline
+Jacquetta
+Jacqui
+Jake
+Jakki
+Jalen
+Jamar
+Jamie
+Jamison
+Janel
+Janelle
+Janette
+Janie
+Janina
+Janine
+Jasmine
+Jaydon
+Jaye
+Jaylee
+Jayne
+Jaynie
+Jeanna
+Jeannie
+Jeannine
+Jeb
+Jed
+Jemmy
+Jenifer
+Jennie
+Jera
+Jere
+Jeri
+Jermaine
+Jerrie
+Jillian
+Jillie
+Jim
+Joachim
+Joetta
+Joey
+Johnathan
+Johnny
+Joi
+Jonathon
+Joni
+Josepha
+Josh
+Josiah
+Joye
+Julia
+July
+Kaelea
+Kaleigh
+Karenza
+Karly
+Karyn
+Kat
+Kathy
+Katlyn
+Kayleigh
+Keegan
+Keira
+Keith
+Kellie
+Kennard
+Kerena
+Kerensa
+Keturah
+Keziah
+Kimberley
+Lacy
+Lakeisha
+Lalla
+Lanny
+Latanya
+Launce
+Laurencia
+Laurissa
+Leeann
+Leia
+Leland
+Lennox
+Leroi
+Lessie
+Leta
+Lexia
+Lexus
+Linden
+Lindsie
+Lindy
+Linton
+Lockie
+Loreto
+Lori
+Lorin
+Lou
+Luanne
+Lucian
+Luvenia
+Lyndsey
+Lynn
+Lynsey
+Lynwood
+Mabelle
+Macey
+Madyson
+Maegan
+Malachi
+Malcolm
+Manley
+Marcia
+Mariabella
+Marilene
+Marion
+Marion
+Marje
+Marjory
+Marlowe
+Marlyn
+Marshall
+Maryann
+Maudie
+Maurene
+May
+Maynard
+Melvyn
+Merideth
+Merrilyn
+Meryl
+Micheal
+Mike
+Milton
+Minnie
+Monna
+Montague
+Monte
+Monty
+Muriel
+Mya
+Myriam
+Myrtie
+Nan
+Nathaniel
+Nelle
+Nena
+Nerissa
+Netta
+Nettie
+Nikolas
+Noah
+Nonie
+Nova
+Nowell
+Nydia
+Olive
+Oralie
+Osbert
+Osborn
+Osborne
+Osmund
+Paget
+Patience
+Patrick
+Patton
+Pauleen
+Pene
+Percival
+Peregrine
+Pheobe
+Phoebe
+Phyliss
+Phyllida
+Phyllis
+Porsche
+Prosper
+Prue
+Quanah
+Quiana
+Raelene
+Rain
+Randa
+Randal
+Rastus
+Rayner
+Rebeckah
+Reene
+Renie
+Reuben
+Rexana
+Reynard
+Rhetta
+Rich
+Richie
+Rick
+Rickena
+Rickey
+Rickie
+Rodger
+Roger
+Romayne
+Ronnette
+Roscoe
+Rosemary
+Roswell
+Royce
+Rubye
+Rusty
+Sabella
+Sachie
+Sal
+Sally
+Saranna
+Sawyer
+Scotty
+Seneca
+Seymour
+Shan
+Shana
+Shanika
+Shannah
+Shannon
+Shantae
+Sharalyn
+Sharla
+Sheri
+Sherie
+Sherill
+Sherri
+Shiloh
+Simon
+Sissy
+Sloan
+Sophie
+Sorrel
+Spike
+Star
+Steph
+Stephany
+Sue
+Sukie
+Sunshine
+Susanna
+Susannah
+Suzan
+Suzy
+Sybil
+Syd
+Sydney
+Tamika
+Tamsin
+Tania
+Tansy
+Tatyanna
+Taylor
+Tel
+Terrell
+Tiffany
+Tod
+Tolly
+Topaz
+Tori
+Tracee
+Tracey
+Trinity
+Tye
+Uland
+Ulric
+Ulyssa
+Valary
+Vaughn
+Verna
+Vince
+Vinnie
+Vivyan
+Walter
+Ward
+Warner
+Wayne
+Wendi
+Whitaker
+William
+Willy
+Winifred
+Wisdom
+Woodrow
+Woody
+Wynonna
+Wynter
+Yasmin
+Yolanda
+Ysabel
+Zack
+Zeke
+Zelda
+Zune
+Jacob
+Michael
+Ethan
+Joshua
+Daniel
+Alexander
+Anthony
+William
+Christopher
+Matthew
+Jayden
+Andrew
+Joseph
+David
+Noah
+Aiden
+James
+Ryan
+Logan
+John
+Nathan
+Elijah
+Christian
+Gabriel
+Benjamin
+Jonathan
+Tyler
+Samuel
+Nicholas
+Gavin
+Dylan
+Jackson
+Brandon
+Caleb
+Mason
+Angel
+Isaac
+Evan
+Jack
+Kevin
+Jose
+Isaiah
+Luke
+Landon
+Justin
+Lucas
+Zachary
+Jordan
+Robert
+Aaron
+Brayden
+Thomas
+Cameron
+Hunter
+Austin
+Adrian
+Connor
+Owen
+Aidan
+Jason
+Julian
+Wyatt
+Charles
+Luis
+Carter
+Juan
+Chase
+Diego
+Jeremiah
+Brody
+Xavier
+Adam
+Carlos
+Sebastian
+Liam
+Hayden
+Nathaniel
+Henry
+Jesus
+Ian
+Tristan
+Bryan
+Sean
+Cole
+Alex
+Eric
+Brian
+Jaden
+Carson
+Blake
+Ayden
+Cooper
+Dominic
+Brady
+Caden
+Josiah
+Kyle
+Colton
+Kaden
+Eli
+Miguel
+Antonio
+Parker
+Steven
+Alejandro
+Riley
+Richard
+Timothy
+Devin
+Jesse
+Victor
+Jake
+Joel
+Colin
+Kaleb
+Bryce
+Levi
+Oliver
+Oscar
+Vincent
+Ashton
+Cody
+Micah
+Preston
+Marcus
+Max
+Patrick
+Seth
+Jeremy
+Peyton
+Nolan
+Ivan
+Damian
+Maxwell
+Alan
+Kenneth
+Jonah
+Jorge
+Mark
+Giovanni
+Eduardo
+Grant
+Collin
+Gage
+Omar
+Emmanuel
+Trevor
+Edward
+Ricardo
+Cristian
+Nicolas
+Kayden
+George
+Jaxon
+Paul
+Braden
+Elias
+Andres
+Derek
+Garrett
+Tanner
+Malachi
+Conner
+Fernando
+Cesar
+Javier
+Miles
+Jaiden
+Alexis
+Leonardo
+Santiago
+Francisco
+Cayden
+Shane
+Edwin
+Hudson
+Travis
+Bryson
+Erick
+Jace
+Hector
+Josue
+Peter
+Jaylen
+Mario
+Manuel
+Abraham
+Grayson
+Damien
+Kaiden
+Spencer
+Stephen
+Edgar
+Wesley
+Shawn
+Trenton
+Jared
+Jeffrey
+Landen
+Johnathan
+Bradley
+Braxton
+Ryder
+Camden
+Roman
+Asher
+Brendan
+Maddox
+Sergio
+Israel
+Andy
+Lincoln
+Erik
+Donovan
+Raymond
+Avery
+Rylan
+Dalton
+Harrison
+Andre
+Martin
+Keegan
+Marco
+Jude
+Sawyer
+Dakota
+Leo
+Calvin
+Kai
+Drake
+Troy
+Zion
+Clayton
+Roberto
+Zane
+Gregory
+Tucker
+Rafael
+Kingston
+Dominick
+Ezekiel
+Griffin
+Devon
+Drew
+Lukas
+Johnny
+Ty
+Pedro
+Tyson
+Caiden
+Mateo
+Braylon
+Cash
+Aden
+Chance
+Taylor
+Marcos
+Maximus
+Ruben
+Emanuel
+Simon
+Corbin
+Brennan
+Dillon
+Skyler
+Myles
+Xander
+Jaxson
+Dawson
+Kameron
+Kyler
+Axel
+Colby
+Jonas
+Joaquin
+Payton
+Brock
+Frank
+Enrique
+Quinn
+Emilio
+Malik
+Grady
+Angelo
+Julio
+Derrick
+Raul
+Fabian
+Corey
+Gerardo
+Dante
+Ezra
+Armando
+Allen
+Theodore
+Gael
+Amir
+Zander
+Adan
+Maximilian
+Randy
+Easton
+Dustin
+Luca
+Phillip
+Julius
+Charlie
+Ronald
+Jakob
+Cade
+Brett
+Trent
+Silas
+Keith
+Emiliano
+Trey
+Jalen
+Darius
+Lane
+Jerry
+Jaime
+Scott
+Graham
+Weston
+Braydon
+Anderson
+Rodrigo
+Pablo
+Saul
+Danny
+Donald
+Elliot
+Brayan
+Dallas
+Lorenzo
+Casey
+Mitchell
+Alberto
+Tristen
+Rowan
+Jayson
+Gustavo
+Aaden
+Amari
+Dean
+Braeden
+Declan
+Chris
+Ismael
+Dane
+Louis
+Arturo
+Brenden
+Felix
+Jimmy
+Cohen
+Tony
+Holden
+Reid
+Abel
+Bennett
+Zackary
+Arthur
+Nehemiah
+Ricky
+Esteban
+Cruz
+Finn
+Mauricio
+Dennis
+Keaton
+Albert
+Marvin
+Mathew
+Larry
+Moises
+Issac
+Philip
+Quentin
+Curtis
+Greyson
+Jameson
+Everett
+Jayce
+Darren
+Elliott
+Uriel
+Alfredo
+Hugo
+Alec
+Jamari
+Marshall
+Walter
+Judah
+Jay
+Lance
+Beau
+Ali
+Landyn
+Yahir
+Phoenix
+Nickolas
+Kobe
+Bryant
+Maurice
+Russell
+Leland
+Colten
+Reed
+Davis
+Joe
+Ernesto
+Desmond
+Kade
+Reece
+Morgan
+Ramon
+Rocco
+Orlando
+Ryker
+Brodie
+Paxton
+Jacoby
+Douglas
+Kristopher
+Gary
+Lawrence
+Izaiah
+Solomon
+Nikolas
+Mekhi
+Justice
+Tate
+Jaydon
+Salvador
+Shaun
+Alvin
+Eddie
+Kane
+Davion
+Zachariah
+Dorian
+Titus
+Kellen
+Camron
+Isiah
+Javon
+Nasir
+Milo
+Johan
+Byron
+Jasper
+Jonathon
+Chad
+Marc
+Kelvin
+Chandler
+Sam
+Cory
+Deandre
+River
+Reese
+Roger
+Quinton
+Talon
+Romeo
+Franklin
+Noel
+Alijah
+Guillermo
+Gunner
+Damon
+Jadon
+Emerson
+Micheal
+Bruce
+Terry
+Kolton
+Melvin
+Beckett
+Porter
+August
+Brycen
+Dayton
+Jamarion
+Leonel
+Karson
+Zayden
+Keagan
+Carl
+Khalil
+Cristopher
+Nelson
+Braiden
+Moses
+Isaias
+Roy
+Triston
+Walker
+Kale
+Emma
+Isabella
+Emily
+Madison
+Ava
+Olivia
+Sophia
+Abigail
+Elizabeth
+Chloe
+Samantha
+Addison
+Natalie
+Mia
+Alexis
+Alyssa
+Hannah
+Ashley
+Ella
+Sarah
+Grace
+Taylor
+Brianna
+Lily
+Hailey
+Anna
+Victoria
+Kayla
+Lillian
+Lauren
+Kaylee
+Allison
+Savannah
+Nevaeh
+Gabriella
+Sofia
+Makayla
+Avery
+Riley
+Julia
+Leah
+Aubrey
+Jasmine
+Audrey
+Katherine
+Morgan
+Brooklyn
+Destiny
+Sydney
+Alexa
+Kylie
+Brooke
+Kaitlyn
+Evelyn
+Layla
+Madeline
+Kimberly
+Zoe
+Jessica
+Peyton
+Alexandra
+Claire
+Madelyn
+Maria
+Mackenzie
+Arianna
+Jocelyn
+Amelia
+Angelina
+Trinity
+Andrea
+Maya
+Valeria
+Sophie
+Rachel
+Vanessa
+Aaliyah
+Mariah
+Gabrielle
+Katelyn
+Ariana
+Bailey
+Camila
+Jennifer
+Melanie
+Gianna
+Charlotte
+Paige
+Autumn
+Payton
+Faith
+Sara
+Isabelle
+Caroline
+Genesis
+Isabel
+Mary
+Zoey
+Gracie
+Megan
+Haley
+Mya
+Michelle
+Molly
+Stephanie
+Nicole
+Jenna
+Natalia
+Sadie
+Jada
+Serenity
+Lucy
+Ruby
+Eva
+Kennedy
+Rylee
+Jayla
+Naomi
+Rebecca
+Lydia
+Daniela
+Bella
+Keira
+Adriana
+Lilly
+Hayden
+Miley
+Katie
+Jade
+Jordan
+Gabriela
+Amy
+Angela
+Melissa
+Valerie
+Giselle
+Diana
+Amanda
+Kate
+Laila
+Reagan
+Jordyn
+Kylee
+Danielle
+Briana
+Marley
+Leslie
+Kendall
+Catherine
+Liliana
+Mckenzie
+Jacqueline
+Ashlyn
+Reese
+Marissa
+London
+Juliana
+Shelby
+Cheyenne
+Angel
+Daisy
+Makenzie
+Miranda
+Erin
+Amber
+Alana
+Ellie
+Breanna
+Ana
+Mikayla
+Summer
+Piper
+Adrianna
+Jillian
+Sierra
+Jayden
+Sienna
+Alicia
+Lila
+Margaret
+Alivia
+Brooklynn
+Karen
+Violet
+Sabrina
+Stella
+Aniyah
+Annabelle
+Alexandria
+Kathryn
+Skylar
+Aliyah
+Delilah
+Julianna
+Kelsey
+Khloe
+Carly
+Amaya
+Mariana
+Christina
+Alondra
+Tessa
+Eliana
+Bianca
+Jazmin
+Clara
+Vivian
+Josephine
+Delaney
+Scarlett
+Elena
+Cadence
+Alexia
+Maggie
+Laura
+Nora
+Ariel
+Elise
+Nadia
+Mckenna
+Chelsea
+Lyla
+Alaina
+Jasmin
+Hope
+Leila
+Caitlyn
+Cassidy
+Makenna
+Allie
+Izabella
+Eden
+Callie
+Haylee
+Caitlin
+Kendra
+Karina
+Kyra
+Kayleigh
+Addyson
+Kiara
+Jazmine
+Karla
+Camryn
+Alina
+Lola
+Kyla
+Kelly
+Fatima
+Tiffany
+Kira
+Crystal
+Mallory
+Esmeralda
+Alejandra
+Eleanor
+Angelica
+Jayda
+Abby
+Kara
+Veronica
+Carmen
+Jamie
+Ryleigh
+Valentina
+Allyson
+Dakota
+Kamryn
+Courtney
+Cecilia
+Madeleine
+Aniya
+Alison
+Esther
+Heaven
+Aubree
+Lindsey
+Leilani
+Nina
+Melody
+Macy
+Ashlynn
+Joanna
+Cassandra
+Alayna
+Kaydence
+Madilyn
+Aurora
+Heidi
+Emerson
+Kimora
+Madalyn
+Erica
+Josie
+Katelynn
+Guadalupe
+Harper
+Ivy
+Lexi
+Camille
+Savanna
+Dulce
+Daniella
+Lucia
+Emely
+Joselyn
+Kiley
+Kailey
+Miriam
+Cynthia
+Rihanna
+Georgia
+Rylie
+Harmony
+Kiera
+Kyleigh
+Monica
+Bethany
+Kaylie
+Cameron
+Teagan
+Cora
+Brynn
+Ciara
+Genevieve
+Alice
+Maddison
+Eliza
+Tatiana
+Jaelyn
+Erika
+Ximena
+April
+Marely
+Julie
+Danica
+Presley
+Brielle
+Julissa
+Angie
+Iris
+Brenda
+Hazel
+Rose
+Malia
+Shayla
+Fiona
+Phoebe
+Nayeli
+Paola
+Kaelyn
+Selena
+Audrina
+Rebekah
+Carolina
+Janiyah
+Michaela
+Penelope
+Janiya
+Anastasia
+Adeline
+Ruth
+Sasha
+Denise
+Holly
+Madisyn
+Hanna
+Tatum
+Marlee
+Nataly
+Helen
+Janelle
+Lizbeth
+Serena
+Anya
+Jaslene
+Kaylin
+Jazlyn
+Nancy
+Lindsay
+Desiree
+Hayley
+Itzel
+Imani
+Madelynn
+Asia
+Kadence
+Madyson
+Talia
+Jane
+Kayden
+Annie
+Amari
+Bridget
+Raegan
+Jadyn
+Celeste
+Jimena
+Luna
+Yasmin
+Emilia
+Annika
+Estrella
+Sarai
+Lacey
+Ayla
+Alessandra
+Willow
+Nyla
+Dayana
+Lilah
+Lilliana
+Natasha
+Hadley
+Harley
+Priscilla
+Claudia
+Allisson
+Baylee
+Brenna
+Brittany
+Skyler
+Fernanda
+Danna
+Melany
+Cali
+Lia
+Macie
+Lyric
+Logan
+Gloria
+Lana
+Mylee
+Cindy
+Lilian
+Amira
+Anahi
+Alissa
+Anaya
+Lena
+Ainsley
+Sandra
+Noelle
+Marisol
+Meredith
+Kailyn
+Lesly
+Johanna
+Diamond
+Evangeline
+Juliet
+Kathleen
+Meghan
+Paisley
+Athena
+Hailee
+Rosa
+Wendy
+Emilee
+Sage
+Alanna
+Elaina
+Cara
+Nia
+Paris
+Casey
+Dana
+Emery
+Rowan
+Aubrie
+Kaitlin
+Jaden
+Kenzie
+Kiana
+Viviana
+Norah
+Lauryn
+Perla
+Amiyah
+Alyson
+Rachael
+Shannon
+Aileen
+Miracle
+Lillie
+Danika
+Heather
+Kassidy
+Taryn
+Tori
+Francesca
+Kristen
+Amya
+Elle
+Kristina
+Cheyanne
+Haylie
+Patricia
+Anne
+Samara
diff --git a/config/names/first_female.txt b/config/names/first_female.txt
index b500f027efc..69057409915 100644
--- a/config/names/first_female.txt
+++ b/config/names/first_female.txt
@@ -1,807 +1,807 @@
-Aida
-Alexa
-Alexandria
-Alexis
-Alexus
-Alfreda
-Alisa
-Alisya
-Allegra
-Allegria
-Alma
-Alysha
-Alyssia
-Amaryllis
-Ambrosine
-Angel
-Anjelica
-Anne
-Arabella
-Arielle
-Arleen
-Ashlie
-Astor
-Aubrey
-Avalona
-Averill
-Barbara
-Beckah
-Becky
-Bernice
-Bethney
-Betsy
-Bidelia
-Breanne
-Brittani
-Brooke
-Cadence
-Calanthia
-Caleigh
-Candace
-Candice
-Carly
-Carlyle
-Carolyn
-Carry
-Caryl
-Cecily
-Cherette
-Cheri
-Cherry
-Christa
-Christiana
-Christobelle
-Claribel
-Clover
-Coreen
-Corrine
-Cynthia
-Dalya
-Daniella
-Daria
-Dayna
-Debbi
-Dee
-Deena
-Della
-Delma
-Denys
-Diamond
-Dina
-Dolores
-Donella
-Donna
-Dorothy
-Dortha
-Easter
-Ebba
-Effie
-Elizabeth
-Elle
-Emma
-Ermintrude
-Esmeralda
-Eugenia
-Euphemia
-Eustace
-Eveleen
-Evelina
-Fay
-Floella
-Flora
-Flossie
-Fortune
-Genette
-Georgene
-Geraldine
-Gervase
-Gina
-Ginger
-Gladwyn
-Glenna
-Greta
-Griselda
-Gwenda
-Gwenevere
-Hadley
-Haidee
-Hailey
-Hal
-Haleigh
-Hayley
-Heather
-Hedley
-Helen
-Hepsie
-Hortensia
-Iantha
-Ileen
-Innocent
-Irene
-Jacaline
-Jacquetta
-Jacqui
-Jakki
-Jalen
-Janelle
-Janette
-Janie
-Janina
-Janine
-Jasmine
-Jaylee
-Jaynie
-Jeanna
-Jeannie
-Jeannine
-Jenifer
-Jennie
-Jera
-Jere
-Jeri
-Jillian
-Jillie
-Joetta
-Joi
-Joni
-Josepha
-Joye
-Julia
-July
-Kaelea
-Kaleigh
-Karenza
-Karly
-Karyn
-Kat
-Kathy
-Katlyn
-Kayleigh
-Keegan
-Keira
-Keith
-Kellie
-Kerena
-Kerensa
-Keturah
-Kimberley
-Lacy
-Lakeisha
-Lalla
-Latanya
-Laurencia
-Laurissa
-Leeann
-Leia
-Lessie
-Leta
-Lexia
-Lexus
-Lindsie
-Lindy
-Lockie
-Lori
-Lorin
-Luanne
-Lucian
-Luvenia
-Lyndsey
-Lynn
-Lynsey
-Lynwood
-Mabelle
-Macey
-Madyson
-Maegan
-Marcia
-Mariabella
-Marilene
-Marion
-Marje
-Marjory
-Marlowe
-Marlyn
-Marshall
-Maryann
-Maudie
-Maurene
-May
-Merideth
-Merrilyn
-Meryl
-Minnie
-Monna
-Muriel
-Mya
-Myriam
-Myrtie
-Nan
-Nelle
-Nena
-Nerissa
-Netta
-Nettie
-Nonie
-Nova
-Nowell
-Nydia
-Olive
-Oralie
-Patience
-Pauleen
-Pene
-Peregrine
-Pheobe
-Phoebe
-Phyliss
-Phyllida
-Phyllis
-Porsche
-Prosper
-Prue
-Quanah
-Quiana
-Raelene
-Rain
-Randa
-Randal
-Rebeckah
-Reene
-Renie
-Rexana
-Rhetta
-Ronnette
-Rosemary
-Rubye
-Sabella
-Sachie
-Sally
-Saranna
-Seneca
-Shana
-Shanika
-Shannah
-Shannon
-Shantae
-Sharalyn
-Sharla
-Sheri
-Sherie
-Sherill
-Sherri
-Sissy
-Sophie
-Star
-Steph
-Stephany
-Sue
-Sukie
-Sunshine
-Susanna
-Susannah
-Suzan
-Suzy
-Sydney
-Tamika
-Tania
-Tansy
-Tatyanna
-Tiffany
-Tolly
-Topaz
-Tori
-Tracee
-Tracey
-Ulyssa
-Valary
-Verna
-Vinnie
-Vivyan
-Wendi
-Wisdom
-Wynonna
-Wynter
-Yasmin
-Yolanda
-Ysabel
-Zelda
-Zune
-Emma
-Isabella
-Emily
-Madison
-Ava
-Olivia
-Sophia
-Abigail
-Elizabeth
-Chloe
-Samantha
-Addison
-Natalie
-Mia
-Alexis
-Alyssa
-Hannah
-Ashley
-Ella
-Sarah
-Grace
-Taylor
-Brianna
-Lily
-Hailey
-Anna
-Victoria
-Kayla
-Lillian
-Lauren
-Kaylee
-Allison
-Savannah
-Nevaeh
-Gabriella
-Sofia
-Makayla
-Avery
-Riley
-Julia
-Leah
-Aubrey
-Jasmine
-Audrey
-Katherine
-Morgan
-Brooklyn
-Destiny
-Sydney
-Alexa
-Kylie
-Brooke
-Kaitlyn
-Evelyn
-Layla
-Madeline
-Kimberly
-Zoe
-Jessica
-Peyton
-Alexandra
-Claire
-Madelyn
-Maria
-Mackenzie
-Arianna
-Jocelyn
-Amelia
-Angelina
-Trinity
-Andrea
-Maya
-Valeria
-Sophie
-Rachel
-Vanessa
-Aaliyah
-Mariah
-Gabrielle
-Katelyn
-Ariana
-Bailey
-Camila
-Jennifer
-Melanie
-Gianna
-Charlotte
-Paige
-Autumn
-Payton
-Faith
-Sara
-Isabelle
-Caroline
-Isabel
-Mary
-Zoey
-Gracie
-Megan
-Haley
-Mya
-Michelle
-Molly
-Stephanie
-Nicole
-Jenna
-Natalia
-Sadie
-Jada
-Serenity
-Lucy
-Ruby
-Eva
-Kennedy
-Rylee
-Jayla
-Naomi
-Rebecca
-Lydia
-Daniela
-Bella
-Keira
-Adriana
-Lilly
-Hayden
-Miley
-Katie
-Jade
-Jordan
-Gabriela
-Amy
-Angela
-Melissa
-Valerie
-Giselle
-Diana
-Amanda
-Kate
-Laila
-Reagan
-Jordyn
-Kylee
-Danielle
-Briana
-Marley
-Leslie
-Kendall
-Catherine
-Liliana
-Mckenzie
-Jacqueline
-Ashlyn
-Reese
-Marissa
-London
-Juliana
-Shelby
-Cheyenne
-Angel
-Daisy
-Makenzie
-Miranda
-Erin
-Amber
-Alana
-Ellie
-Breanna
-Ana
-Mikayla
-Summer
-Piper
-Adrianna
-Jillian
-Sierra
-Jayden
-Sienna
-Alicia
-Lila
-Margaret
-Alivia
-Brooklynn
-Karen
-Violet
-Sabrina
-Stella
-Aniyah
-Annabelle
-Alexandria
-Kathryn
-Skylar
-Aliyah
-Delilah
-Julianna
-Kelsey
-Khloe
-Carly
-Amaya
-Mariana
-Christina
-Alondra
-Tessa
-Eliana
-Bianca
-Jazmin
-Clara
-Vivian
-Josephine
-Delaney
-Scarlett
-Elena
-Cadence
-Alexia
-Maggie
-Laura
-Nora
-Ariel
-Elise
-Nadia
-Mckenna
-Chelsea
-Lyla
-Alaina
-Jasmin
-Hope
-Leila
-Caitlyn
-Cassidy
-Makenna
-Allie
-Izabella
-Eden
-Callie
-Haylee
-Caitlin
-Kendra
-Karina
-Kyra
-Kayleigh
-Addyson
-Kiara
-Jazmine
-Karla
-Camryn
-Alina
-Lola
-Kyla
-Kelly
-Fatima
-Tiffany
-Kira
-Crystal
-Mallory
-Esmeralda
-Alejandra
-Eleanor
-Angelica
-Jayda
-Abby
-Kara
-Veronica
-Carmen
-Jamie
-Ryleigh
-Valentina
-Allyson
-Dakota
-Kamryn
-Courtney
-Cecilia
-Madeleine
-Aniya
-Alison
-Esther
-Heaven
-Aubree
-Lindsey
-Leilani
-Nina
-Melody
-Macy
-Ashlynn
-Joanna
-Cassandra
-Alayna
-Kaydence
-Madilyn
-Aurora
-Heidi
-Emerson
-Kimora
-Madalyn
-Erica
-Josie
-Katelynn
-Guadalupe
-Harper
-Ivy
-Lexi
-Camille
-Savanna
-Dulce
-Daniella
-Lucia
-Emely
-Joselyn
-Kiley
-Kailey
-Miriam
-Cynthia
-Rihanna
-Georgia
-Rylie
-Harmony
-Kiera
-Kyleigh
-Monica
-Bethany
-Kaylie
-Cameron
-Teagan
-Cora
-Brynn
-Ciara
-Genevieve
-Alice
-Maddison
-Eliza
-Tatiana
-Jaelyn
-Erika
-Ximena
-April
-Marely
-Julie
-Danica
-Presley
-Brielle
-Julissa
-Angie
-Iris
-Brenda
-Hazel
-Rose
-Malia
-Shayla
-Fiona
-Phoebe
-Nayeli
-Paola
-Kaelyn
-Selena
-Audrina
-Rebekah
-Carolina
-Janiyah
-Michaela
-Penelope
-Janiya
-Anastasia
-Adeline
-Ruth
-Sasha
-Denise
-Holly
-Madisyn
-Hanna
-Tatum
-Marlee
-Nataly
-Helen
-Janelle
-Lizbeth
-Serena
-Anya
-Jaslene
-Kaylin
-Jazlyn
-Nancy
-Lindsay
-Desiree
-Hayley
-Itzel
-Imani
-Madelynn
-Asia
-Kadence
-Madyson
-Talia
-Jane
-Kayden
-Annie
-Amari
-Bridget
-Raegan
-Jadyn
-Celeste
-Jimena
-Luna
-Yasmin
-Emilia
-Annika
-Estrella
-Sarai
-Lacey
-Ayla
-Alessandra
-Willow
-Nyla
-Dayana
-Lilah
-Lilliana
-Natasha
-Hadley
-Harley
-Priscilla
-Claudia
-Allisson
-Baylee
-Brenna
-Brittany
-Skyler
-Fernanda
-Danna
-Melany
-Cali
-Lia
-Macie
-Lyric
-Logan
-Gloria
-Lana
-Mylee
-Cindy
-Lilian
-Amira
-Anahi
-Alissa
-Anaya
-Lena
-Ainsley
-Sandra
-Noelle
-Marisol
-Meredith
-Kailyn
-Lesly
-Johanna
-Diamond
-Evangeline
-Juliet
-Kathleen
-Meghan
-Paisley
-Athena
-Hailee
-Rosa
-Wendy
-Emilee
-Sage
-Alanna
-Elaina
-Cara
-Nia
-Paris
-Casey
-Dana
-Emery
-Rowan
-Aubrie
-Kaitlin
-Jaden
-Kenzie
-Kiana
-Viviana
-Norah
-Lauryn
-Perla
-Amiyah
-Alyson
-Rachael
-Shannon
-Aileen
-Miracle
-Lillie
-Danika
-Heather
-Kassidy
-Taryn
-Tori
-Francesca
-Kristen
-Amya
-Elle
-Kristina
-Cheyanne
-Haylie
-Patricia
-Anne
+Aida
+Alexa
+Alexandria
+Alexis
+Alexus
+Alfreda
+Alisa
+Alisya
+Allegra
+Allegria
+Alma
+Alysha
+Alyssia
+Amaryllis
+Ambrosine
+Angel
+Anjelica
+Anne
+Arabella
+Arielle
+Arleen
+Ashlie
+Astor
+Aubrey
+Avalona
+Averill
+Barbara
+Beckah
+Becky
+Bernice
+Bethney
+Betsy
+Bidelia
+Breanne
+Brittani
+Brooke
+Cadence
+Calanthia
+Caleigh
+Candace
+Candice
+Carly
+Carlyle
+Carolyn
+Carry
+Caryl
+Cecily
+Cherette
+Cheri
+Cherry
+Christa
+Christiana
+Christobelle
+Claribel
+Clover
+Coreen
+Corrine
+Cynthia
+Dalya
+Daniella
+Daria
+Dayna
+Debbi
+Dee
+Deena
+Della
+Delma
+Denys
+Diamond
+Dina
+Dolores
+Donella
+Donna
+Dorothy
+Dortha
+Easter
+Ebba
+Effie
+Elizabeth
+Elle
+Emma
+Ermintrude
+Esmeralda
+Eugenia
+Euphemia
+Eustace
+Eveleen
+Evelina
+Fay
+Floella
+Flora
+Flossie
+Fortune
+Genette
+Georgene
+Geraldine
+Gervase
+Gina
+Ginger
+Gladwyn
+Glenna
+Greta
+Griselda
+Gwenda
+Gwenevere
+Hadley
+Haidee
+Hailey
+Hal
+Haleigh
+Hayley
+Heather
+Hedley
+Helen
+Hepsie
+Hortensia
+Iantha
+Ileen
+Innocent
+Irene
+Jacaline
+Jacquetta
+Jacqui
+Jakki
+Jalen
+Janelle
+Janette
+Janie
+Janina
+Janine
+Jasmine
+Jaylee
+Jaynie
+Jeanna
+Jeannie
+Jeannine
+Jenifer
+Jennie
+Jera
+Jere
+Jeri
+Jillian
+Jillie
+Joetta
+Joi
+Joni
+Josepha
+Joye
+Julia
+July
+Kaelea
+Kaleigh
+Karenza
+Karly
+Karyn
+Kat
+Kathy
+Katlyn
+Kayleigh
+Keegan
+Keira
+Keith
+Kellie
+Kerena
+Kerensa
+Keturah
+Kimberley
+Lacy
+Lakeisha
+Lalla
+Latanya
+Laurencia
+Laurissa
+Leeann
+Leia
+Lessie
+Leta
+Lexia
+Lexus
+Lindsie
+Lindy
+Lockie
+Lori
+Lorin
+Luanne
+Lucian
+Luvenia
+Lyndsey
+Lynn
+Lynsey
+Lynwood
+Mabelle
+Macey
+Madyson
+Maegan
+Marcia
+Mariabella
+Marilene
+Marion
+Marje
+Marjory
+Marlowe
+Marlyn
+Marshall
+Maryann
+Maudie
+Maurene
+May
+Merideth
+Merrilyn
+Meryl
+Minnie
+Monna
+Muriel
+Mya
+Myriam
+Myrtie
+Nan
+Nelle
+Nena
+Nerissa
+Netta
+Nettie
+Nonie
+Nova
+Nowell
+Nydia
+Olive
+Oralie
+Patience
+Pauleen
+Pene
+Peregrine
+Pheobe
+Phoebe
+Phyliss
+Phyllida
+Phyllis
+Porsche
+Prosper
+Prue
+Quanah
+Quiana
+Raelene
+Rain
+Randa
+Randal
+Rebeckah
+Reene
+Renie
+Rexana
+Rhetta
+Ronnette
+Rosemary
+Rubye
+Sabella
+Sachie
+Sally
+Saranna
+Seneca
+Shana
+Shanika
+Shannah
+Shannon
+Shantae
+Sharalyn
+Sharla
+Sheri
+Sherie
+Sherill
+Sherri
+Sissy
+Sophie
+Star
+Steph
+Stephany
+Sue
+Sukie
+Sunshine
+Susanna
+Susannah
+Suzan
+Suzy
+Sydney
+Tamika
+Tania
+Tansy
+Tatyanna
+Tiffany
+Tolly
+Topaz
+Tori
+Tracee
+Tracey
+Ulyssa
+Valary
+Verna
+Vinnie
+Vivyan
+Wendi
+Wisdom
+Wynonna
+Wynter
+Yasmin
+Yolanda
+Ysabel
+Zelda
+Zune
+Emma
+Isabella
+Emily
+Madison
+Ava
+Olivia
+Sophia
+Abigail
+Elizabeth
+Chloe
+Samantha
+Addison
+Natalie
+Mia
+Alexis
+Alyssa
+Hannah
+Ashley
+Ella
+Sarah
+Grace
+Taylor
+Brianna
+Lily
+Hailey
+Anna
+Victoria
+Kayla
+Lillian
+Lauren
+Kaylee
+Allison
+Savannah
+Nevaeh
+Gabriella
+Sofia
+Makayla
+Avery
+Riley
+Julia
+Leah
+Aubrey
+Jasmine
+Audrey
+Katherine
+Morgan
+Brooklyn
+Destiny
+Sydney
+Alexa
+Kylie
+Brooke
+Kaitlyn
+Evelyn
+Layla
+Madeline
+Kimberly
+Zoe
+Jessica
+Peyton
+Alexandra
+Claire
+Madelyn
+Maria
+Mackenzie
+Arianna
+Jocelyn
+Amelia
+Angelina
+Trinity
+Andrea
+Maya
+Valeria
+Sophie
+Rachel
+Vanessa
+Aaliyah
+Mariah
+Gabrielle
+Katelyn
+Ariana
+Bailey
+Camila
+Jennifer
+Melanie
+Gianna
+Charlotte
+Paige
+Autumn
+Payton
+Faith
+Sara
+Isabelle
+Caroline
+Isabel
+Mary
+Zoey
+Gracie
+Megan
+Haley
+Mya
+Michelle
+Molly
+Stephanie
+Nicole
+Jenna
+Natalia
+Sadie
+Jada
+Serenity
+Lucy
+Ruby
+Eva
+Kennedy
+Rylee
+Jayla
+Naomi
+Rebecca
+Lydia
+Daniela
+Bella
+Keira
+Adriana
+Lilly
+Hayden
+Miley
+Katie
+Jade
+Jordan
+Gabriela
+Amy
+Angela
+Melissa
+Valerie
+Giselle
+Diana
+Amanda
+Kate
+Laila
+Reagan
+Jordyn
+Kylee
+Danielle
+Briana
+Marley
+Leslie
+Kendall
+Catherine
+Liliana
+Mckenzie
+Jacqueline
+Ashlyn
+Reese
+Marissa
+London
+Juliana
+Shelby
+Cheyenne
+Angel
+Daisy
+Makenzie
+Miranda
+Erin
+Amber
+Alana
+Ellie
+Breanna
+Ana
+Mikayla
+Summer
+Piper
+Adrianna
+Jillian
+Sierra
+Jayden
+Sienna
+Alicia
+Lila
+Margaret
+Alivia
+Brooklynn
+Karen
+Violet
+Sabrina
+Stella
+Aniyah
+Annabelle
+Alexandria
+Kathryn
+Skylar
+Aliyah
+Delilah
+Julianna
+Kelsey
+Khloe
+Carly
+Amaya
+Mariana
+Christina
+Alondra
+Tessa
+Eliana
+Bianca
+Jazmin
+Clara
+Vivian
+Josephine
+Delaney
+Scarlett
+Elena
+Cadence
+Alexia
+Maggie
+Laura
+Nora
+Ariel
+Elise
+Nadia
+Mckenna
+Chelsea
+Lyla
+Alaina
+Jasmin
+Hope
+Leila
+Caitlyn
+Cassidy
+Makenna
+Allie
+Izabella
+Eden
+Callie
+Haylee
+Caitlin
+Kendra
+Karina
+Kyra
+Kayleigh
+Addyson
+Kiara
+Jazmine
+Karla
+Camryn
+Alina
+Lola
+Kyla
+Kelly
+Fatima
+Tiffany
+Kira
+Crystal
+Mallory
+Esmeralda
+Alejandra
+Eleanor
+Angelica
+Jayda
+Abby
+Kara
+Veronica
+Carmen
+Jamie
+Ryleigh
+Valentina
+Allyson
+Dakota
+Kamryn
+Courtney
+Cecilia
+Madeleine
+Aniya
+Alison
+Esther
+Heaven
+Aubree
+Lindsey
+Leilani
+Nina
+Melody
+Macy
+Ashlynn
+Joanna
+Cassandra
+Alayna
+Kaydence
+Madilyn
+Aurora
+Heidi
+Emerson
+Kimora
+Madalyn
+Erica
+Josie
+Katelynn
+Guadalupe
+Harper
+Ivy
+Lexi
+Camille
+Savanna
+Dulce
+Daniella
+Lucia
+Emely
+Joselyn
+Kiley
+Kailey
+Miriam
+Cynthia
+Rihanna
+Georgia
+Rylie
+Harmony
+Kiera
+Kyleigh
+Monica
+Bethany
+Kaylie
+Cameron
+Teagan
+Cora
+Brynn
+Ciara
+Genevieve
+Alice
+Maddison
+Eliza
+Tatiana
+Jaelyn
+Erika
+Ximena
+April
+Marely
+Julie
+Danica
+Presley
+Brielle
+Julissa
+Angie
+Iris
+Brenda
+Hazel
+Rose
+Malia
+Shayla
+Fiona
+Phoebe
+Nayeli
+Paola
+Kaelyn
+Selena
+Audrina
+Rebekah
+Carolina
+Janiyah
+Michaela
+Penelope
+Janiya
+Anastasia
+Adeline
+Ruth
+Sasha
+Denise
+Holly
+Madisyn
+Hanna
+Tatum
+Marlee
+Nataly
+Helen
+Janelle
+Lizbeth
+Serena
+Anya
+Jaslene
+Kaylin
+Jazlyn
+Nancy
+Lindsay
+Desiree
+Hayley
+Itzel
+Imani
+Madelynn
+Asia
+Kadence
+Madyson
+Talia
+Jane
+Kayden
+Annie
+Amari
+Bridget
+Raegan
+Jadyn
+Celeste
+Jimena
+Luna
+Yasmin
+Emilia
+Annika
+Estrella
+Sarai
+Lacey
+Ayla
+Alessandra
+Willow
+Nyla
+Dayana
+Lilah
+Lilliana
+Natasha
+Hadley
+Harley
+Priscilla
+Claudia
+Allisson
+Baylee
+Brenna
+Brittany
+Skyler
+Fernanda
+Danna
+Melany
+Cali
+Lia
+Macie
+Lyric
+Logan
+Gloria
+Lana
+Mylee
+Cindy
+Lilian
+Amira
+Anahi
+Alissa
+Anaya
+Lena
+Ainsley
+Sandra
+Noelle
+Marisol
+Meredith
+Kailyn
+Lesly
+Johanna
+Diamond
+Evangeline
+Juliet
+Kathleen
+Meghan
+Paisley
+Athena
+Hailee
+Rosa
+Wendy
+Emilee
+Sage
+Alanna
+Elaina
+Cara
+Nia
+Paris
+Casey
+Dana
+Emery
+Rowan
+Aubrie
+Kaitlin
+Jaden
+Kenzie
+Kiana
+Viviana
+Norah
+Lauryn
+Perla
+Amiyah
+Alyson
+Rachael
+Shannon
+Aileen
+Miracle
+Lillie
+Danika
+Heather
+Kassidy
+Taryn
+Tori
+Francesca
+Kristen
+Amya
+Elle
+Kristina
+Cheyanne
+Haylie
+Patricia
+Anne
Samara
\ No newline at end of file
diff --git a/config/names/first_male.txt b/config/names/first_male.txt
index f2b03e16868..ebb8f6d2862 100644
--- a/config/names/first_male.txt
+++ b/config/names/first_male.txt
@@ -1,725 +1,725 @@
-Abel
-Adolph
-Alan
-Alden
-Alex
-Alfred
-Alger
-Allen
-Amos
-Apple
-Archie
-Arnie
-Art
-Arthur
-Baldric
-Bartholomew
-Bill
-Blake
-Brayden
-Brendan
-Brock
-Bronte
-Brick
-Bruce
-Bryce
-Buck
-Burt
-Butch
-Byrne
-Byron
-Camryn
-Carl
-Carter
-Casimir
-Cassian
-Charles
-Charlton
-Chip
-Clark
-Claudius
-Clement
-Cleveland
-Cliff
-Clinton
-Cletus
-Collin
-Crush
-Cy
-Damian
-Danny
-Darcey
-Darell
-Darin
-Deangelo
-Denholm
-Desmond
-Devin
-Dirk
-Dominic
-Donny
-Driscoll
-Duke
-Duncan
-Edgar
-Eliot
-Eliott
-Elric
-Elwood
-Emmanuel
-Fenton
-Fitz
-Flick
-Flint
-Flip
-Francis
-Frank
-Frankie
-Fridge
-Fulton
-Gannon
-Garret
-Gary
-Goddard
-Godwin
-Goodwin
-Gordon
-Graeme
-Grandpa
-Gratian
-Grendel
-Han
-Harry
-Hartley
-Harvey
-Henderson
-Holden
-Homer
-Horatio
-Huffie
-Hungry
-Hugo
-Irvine
-Jacob
-Jake
-Jamar
-Jamie
-Jamison
-Janel
-Jaydon
-Jaye
-Jayne
-Jean-Luc
-Jeb
-Jed
-Jemmy
-Jermaine
-Jerrie
-Jim
-Joachim
-Joey
-Johnathan
-John
-Johnny
-Jonathon
-Josh
-Josiah
-Kennard
-Keziah
-Lando
-Lanny
-Launce
-Leland
-Lennox
-Lenny
-Leonard
-Leroy
-Lief
-Linden
-Linton
-Lorde
-Loreto
-Lou
-Lucas
-Luke
-Malachi
-Malcolm
-Manley
-Marion
-Max
-Maynard
-Melvyn
-Michael
-Mike
-Milton
-Montague
-Monte
-Monty
-Nat
-Nathaniel
-Nick
-Nikolas
-Noah
-Opie
-Osbert
-Osborn
-Osborne
-Osmund
-Oswald
-Paget
-Patrick
-Patton
-Percival
-Persh
-Rastus
-Raymond
-Rayner
-Reuben
-Reynard
-Richard
-Rodger
-Roger
-Romayne
-Roscoe
-Roswell
-Royce
-Rube
-Rusty
-Sal
-Sawyer
-Scotty
-Seymour
-Shane
-Shiloh
-Smoke
-Simon
-Sloan
-Sorrel
-Spike
-Sybil
-Syd
-Tamsin
-Taylor
-Tel
-Terrell
-Tim
-Timothy
-Todd
-Trip
-Tye
-Uland
-Ulric
-Vaughn
-Vince
-Vinny
-Walter
-Ward
-Warner
-Wayne
-Whitaker
-William
-Willy
-Woodrow
-Zack
-Zane
-Zeke
-Jacob
-Michael
-Ethan
-Joshua
-Daniel
-Alexander
-Anthony
-William
-Christopher
-Matthew
-Jayden
-Andrew
-Joseph
-David
-Noah
-Aiden
-James
-Ryan
-Logan
-John
-Nathan
-Elijah
-Christian
-Gabriel
-Benjamin
-Jonathan
-Tyler
-Samuel
-Nicholas
-Gavin
-Dylan
-Jackson
-Brandon
-Caleb
-Mason
-Angel
-Isaac
-Evan
-Jack
-Kevin
-Jose
-Isaiah
-Luke
-Landon
-Justin
-Lucas
-Zachary
-Jordan
-Robert
-Aaron
-Brayden
-Thomas
-Cameron
-Hunter
-Austin
-Adrian
-Connor
-Owen
-Aidan
-Jason
-Julian
-Wyatt
-Charles
-Luis
-Carter
-Juan
-Chase
-Diego
-Jeremiah
-Brody
-Xavier
-Adam
-Carlos
-Sebastian
-Liam
-Hayden
-Nathaniel
-Henry
-Jesus
-Ian
-Tristan
-Bryan
-Sean
-Cole
-Alex
-Eric
-Brian
-Jaden
-Carson
-Blake
-Ayden
-Cooper
-Dominic
-Brady
-Caden
-Josiah
-Kyle
-Colton
-Kaden
-Eli
-Miguel
-Antonio
-Parker
-Steven
-Alejandro
-Riley
-Richard
-Timothy
-Devin
-Jesse
-Victor
-Jake
-Joel
-Colin
-Kaleb
-Bryce
-Levi
-Oliver
-Oscar
-Vincent
-Ashton
-Cody
-Micah
-Preston
-Marcus
-Max
-Patrick
-Seth
-Jeremy
-Peyton
-Nolan
-Ivan
-Damian
-Maxwell
-Alan
-Kenneth
-Jonah
-Jorge
-Mark
-Giovanni
-Eduardo
-Grant
-Collin
-Gage
-Omar
-Emmanuel
-Trevor
-Edward
-Ricardo
-Cristian
-Nicolas
-Kayden
-George
-Jaxon
-Paul
-Braden
-Elias
-Andres
-Derek
-Garrett
-Tanner
-Malachi
-Conner
-Fernando
-Cesar
-Javier
-Miles
-Jaiden
-Alexis
-Leonardo
-Santiago
-Francisco
-Cayden
-Shane
-Edwin
-Hudson
-Travis
-Bryson
-Erick
-Jace
-Hector
-Josue
-Peter
-Jaylen
-Mario
-Manuel
-Abraham
-Grayson
-Damien
-Kaiden
-Spencer
-Stephen
-Edgar
-Wesley
-Shawn
-Trenton
-Jared
-Jeffrey
-Landen
-Johnathan
-Bradley
-Braxton
-Ryder
-Camden
-Roman
-Asher
-Brendan
-Maddox
-Sergio
-Israel
-Andy
-Lincoln
-Erik
-Donovan
-Raymond
-Avery
-Rylan
-Dalton
-Harrison
-Andre
-Martin
-Keegan
-Marco
-Jude
-Sawyer
-Dakota
-Leo
-Calvin
-Kai
-Drake
-Troy
-Zion
-Clayton
-Roberto
-Zane
-Gregory
-Tucker
-Rafael
-Kingston
-Dominick
-Ezekiel
-Griffin
-Devon
-Drew
-Lukas
-Johnny
-Ty
-Pedro
-Tyson
-Caiden
-Mateo
-Braylon
-Cash
-Aden
-Chance
-Taylor
-Marcos
-Maximus
-Ruben
-Emanuel
-Simon
-Corbin
-Brennan
-Dillon
-Skyler
-Myles
-Xander
-Jaxson
-Dawson
-Kameron
-Kyler
-Axel
-Colby
-Jonas
-Joaquin
-Payton
-Brock
-Frank
-Enrique
-Quinn
-Emilio
-Malik
-Grady
-Angelo
-Julio
-Derrick
-Raul
-Fabian
-Corey
-Gerardo
-Dante
-Ezra
-Armando
-Allen
-Theodore
-Gael
-Amir
-Zander
-Adan
-Maximilian
-Randy
-Easton
-Dustin
-Luca
-Phillip
-Julius
-Charlie
-Ronald
-Jakob
-Cade
-Brett
-Trent
-Silas
-Keith
-Emiliano
-Trey
-Jalen
-Darius
-Lane
-Jerry
-Jaime
-Scott
-Graham
-Weston
-Braydon
-Anderson
-Rodrigo
-Pablo
-Saul
-Danny
-Donald
-Elliot
-Brayan
-Dallas
-Lorenzo
-Casey
-Mitchell
-Alberto
-Tristen
-Rowan
-Jayson
-Gustavo
-Aaden
-Amari
-Dean
-Braeden
-Declan
-Chris
-Ismael
-Dane
-Louis
-Arturo
-Brenden
-Felix
-Jimmy
-Cohen
-Tony
-Holden
-Reid
-Abel
-Bennett
-Zackary
-Arthur
-Nehemiah
-Ricky
-Esteban
-Cruz
-Finn
-Mauricio
-Dennis
-Keaton
-Albert
-Marvin
-Mathew
-Larry
-Moises
-Issac
-Philip
-Quentin
-Curtis
-Greyson
-Jameson
-Everett
-Jayce
-Darren
-Elliott
-Uriel
-Alfredo
-Hugo
-Alec
-Jamari
-Marshall
-Walter
-Judah
-Jay
-Lance
-Beau
-Ali
-Landyn
-Yahir
-Phoenix
-Nickolas
-Kobe
-Bryant
-Maurice
-Russell
-Leland
-Colten
-Reed
-Davis
-Joe
-Ernesto
-Desmond
-Kade
-Reece
-Morgan
-Ramon
-Rocco
-Orlando
-Ryker
-Brodie
-Paxton
-Jacoby
-Douglas
-Kristopher
-Gary
-Lawrence
-Izaiah
-Solomon
-Nikolas
-Mekhi
-Justice
-Tate
-Jaydon
-Salvador
-Shaun
-Alvin
-Eddie
-Kane
-Davion
-Zachariah
-Damien
-Titus
-Kellen
-Camron
-Isiah
-Javon
-Nasir
-Milo
-Johan
-Byron
-Jasper
-Jonathon
-Chad
-Marc
-Kelvin
-Chandler
-Sam
-Cory
-Deandre
-River
-Reese
-Roger
-Quinton
-Talon
-Romeo
-Franklin
-Noel
-Alijah
-Guillermo
-Gunner
-Damon
-Jadon
-Emerson
-Micheal
-Bruce
-Terry
-Kolton
-Melvin
-Beckett
-Porter
-August
-Brycen
-Dayton
-Jamarion
-Leonel
-Karson
-Zayden
-Keagan
-Carl
-Khalil
-Cristopher
-Nelson
-Braiden
-Moses
-Isaias
-Roy
-Triston
-Walker
+Abel
+Adolph
+Alan
+Alden
+Alex
+Alfred
+Alger
+Allen
+Amos
+Apple
+Archie
+Arnie
+Art
+Arthur
+Baldric
+Bartholomew
+Bill
+Blake
+Brayden
+Brendan
+Brock
+Bronte
+Brick
+Bruce
+Bryce
+Buck
+Burt
+Butch
+Byrne
+Byron
+Camryn
+Carl
+Carter
+Casimir
+Cassian
+Charles
+Charlton
+Chip
+Clark
+Claudius
+Clement
+Cleveland
+Cliff
+Clinton
+Cletus
+Collin
+Crush
+Cy
+Damian
+Danny
+Darcey
+Darell
+Darin
+Deangelo
+Denholm
+Desmond
+Devin
+Dirk
+Dominic
+Donny
+Driscoll
+Duke
+Duncan
+Edgar
+Eliot
+Eliott
+Elric
+Elwood
+Emmanuel
+Fenton
+Fitz
+Flick
+Flint
+Flip
+Francis
+Frank
+Frankie
+Fridge
+Fulton
+Gannon
+Garret
+Gary
+Goddard
+Godwin
+Goodwin
+Gordon
+Graeme
+Grandpa
+Gratian
+Grendel
+Han
+Harry
+Hartley
+Harvey
+Henderson
+Holden
+Homer
+Horatio
+Huffie
+Hungry
+Hugo
+Irvine
+Jacob
+Jake
+Jamar
+Jamie
+Jamison
+Janel
+Jaydon
+Jaye
+Jayne
+Jean-Luc
+Jeb
+Jed
+Jemmy
+Jermaine
+Jerrie
+Jim
+Joachim
+Joey
+Johnathan
+John
+Johnny
+Jonathon
+Josh
+Josiah
+Kennard
+Keziah
+Lando
+Lanny
+Launce
+Leland
+Lennox
+Lenny
+Leonard
+Leroy
+Lief
+Linden
+Linton
+Lorde
+Loreto
+Lou
+Lucas
+Luke
+Malachi
+Malcolm
+Manley
+Marion
+Max
+Maynard
+Melvyn
+Michael
+Mike
+Milton
+Montague
+Monte
+Monty
+Nat
+Nathaniel
+Nick
+Nikolas
+Noah
+Opie
+Osbert
+Osborn
+Osborne
+Osmund
+Oswald
+Paget
+Patrick
+Patton
+Percival
+Persh
+Rastus
+Raymond
+Rayner
+Reuben
+Reynard
+Richard
+Rodger
+Roger
+Romayne
+Roscoe
+Roswell
+Royce
+Rube
+Rusty
+Sal
+Sawyer
+Scotty
+Seymour
+Shane
+Shiloh
+Smoke
+Simon
+Sloan
+Sorrel
+Spike
+Sybil
+Syd
+Tamsin
+Taylor
+Tel
+Terrell
+Tim
+Timothy
+Todd
+Trip
+Tye
+Uland
+Ulric
+Vaughn
+Vince
+Vinny
+Walter
+Ward
+Warner
+Wayne
+Whitaker
+William
+Willy
+Woodrow
+Zack
+Zane
+Zeke
+Jacob
+Michael
+Ethan
+Joshua
+Daniel
+Alexander
+Anthony
+William
+Christopher
+Matthew
+Jayden
+Andrew
+Joseph
+David
+Noah
+Aiden
+James
+Ryan
+Logan
+John
+Nathan
+Elijah
+Christian
+Gabriel
+Benjamin
+Jonathan
+Tyler
+Samuel
+Nicholas
+Gavin
+Dylan
+Jackson
+Brandon
+Caleb
+Mason
+Angel
+Isaac
+Evan
+Jack
+Kevin
+Jose
+Isaiah
+Luke
+Landon
+Justin
+Lucas
+Zachary
+Jordan
+Robert
+Aaron
+Brayden
+Thomas
+Cameron
+Hunter
+Austin
+Adrian
+Connor
+Owen
+Aidan
+Jason
+Julian
+Wyatt
+Charles
+Luis
+Carter
+Juan
+Chase
+Diego
+Jeremiah
+Brody
+Xavier
+Adam
+Carlos
+Sebastian
+Liam
+Hayden
+Nathaniel
+Henry
+Jesus
+Ian
+Tristan
+Bryan
+Sean
+Cole
+Alex
+Eric
+Brian
+Jaden
+Carson
+Blake
+Ayden
+Cooper
+Dominic
+Brady
+Caden
+Josiah
+Kyle
+Colton
+Kaden
+Eli
+Miguel
+Antonio
+Parker
+Steven
+Alejandro
+Riley
+Richard
+Timothy
+Devin
+Jesse
+Victor
+Jake
+Joel
+Colin
+Kaleb
+Bryce
+Levi
+Oliver
+Oscar
+Vincent
+Ashton
+Cody
+Micah
+Preston
+Marcus
+Max
+Patrick
+Seth
+Jeremy
+Peyton
+Nolan
+Ivan
+Damian
+Maxwell
+Alan
+Kenneth
+Jonah
+Jorge
+Mark
+Giovanni
+Eduardo
+Grant
+Collin
+Gage
+Omar
+Emmanuel
+Trevor
+Edward
+Ricardo
+Cristian
+Nicolas
+Kayden
+George
+Jaxon
+Paul
+Braden
+Elias
+Andres
+Derek
+Garrett
+Tanner
+Malachi
+Conner
+Fernando
+Cesar
+Javier
+Miles
+Jaiden
+Alexis
+Leonardo
+Santiago
+Francisco
+Cayden
+Shane
+Edwin
+Hudson
+Travis
+Bryson
+Erick
+Jace
+Hector
+Josue
+Peter
+Jaylen
+Mario
+Manuel
+Abraham
+Grayson
+Damien
+Kaiden
+Spencer
+Stephen
+Edgar
+Wesley
+Shawn
+Trenton
+Jared
+Jeffrey
+Landen
+Johnathan
+Bradley
+Braxton
+Ryder
+Camden
+Roman
+Asher
+Brendan
+Maddox
+Sergio
+Israel
+Andy
+Lincoln
+Erik
+Donovan
+Raymond
+Avery
+Rylan
+Dalton
+Harrison
+Andre
+Martin
+Keegan
+Marco
+Jude
+Sawyer
+Dakota
+Leo
+Calvin
+Kai
+Drake
+Troy
+Zion
+Clayton
+Roberto
+Zane
+Gregory
+Tucker
+Rafael
+Kingston
+Dominick
+Ezekiel
+Griffin
+Devon
+Drew
+Lukas
+Johnny
+Ty
+Pedro
+Tyson
+Caiden
+Mateo
+Braylon
+Cash
+Aden
+Chance
+Taylor
+Marcos
+Maximus
+Ruben
+Emanuel
+Simon
+Corbin
+Brennan
+Dillon
+Skyler
+Myles
+Xander
+Jaxson
+Dawson
+Kameron
+Kyler
+Axel
+Colby
+Jonas
+Joaquin
+Payton
+Brock
+Frank
+Enrique
+Quinn
+Emilio
+Malik
+Grady
+Angelo
+Julio
+Derrick
+Raul
+Fabian
+Corey
+Gerardo
+Dante
+Ezra
+Armando
+Allen
+Theodore
+Gael
+Amir
+Zander
+Adan
+Maximilian
+Randy
+Easton
+Dustin
+Luca
+Phillip
+Julius
+Charlie
+Ronald
+Jakob
+Cade
+Brett
+Trent
+Silas
+Keith
+Emiliano
+Trey
+Jalen
+Darius
+Lane
+Jerry
+Jaime
+Scott
+Graham
+Weston
+Braydon
+Anderson
+Rodrigo
+Pablo
+Saul
+Danny
+Donald
+Elliot
+Brayan
+Dallas
+Lorenzo
+Casey
+Mitchell
+Alberto
+Tristen
+Rowan
+Jayson
+Gustavo
+Aaden
+Amari
+Dean
+Braeden
+Declan
+Chris
+Ismael
+Dane
+Louis
+Arturo
+Brenden
+Felix
+Jimmy
+Cohen
+Tony
+Holden
+Reid
+Abel
+Bennett
+Zackary
+Arthur
+Nehemiah
+Ricky
+Esteban
+Cruz
+Finn
+Mauricio
+Dennis
+Keaton
+Albert
+Marvin
+Mathew
+Larry
+Moises
+Issac
+Philip
+Quentin
+Curtis
+Greyson
+Jameson
+Everett
+Jayce
+Darren
+Elliott
+Uriel
+Alfredo
+Hugo
+Alec
+Jamari
+Marshall
+Walter
+Judah
+Jay
+Lance
+Beau
+Ali
+Landyn
+Yahir
+Phoenix
+Nickolas
+Kobe
+Bryant
+Maurice
+Russell
+Leland
+Colten
+Reed
+Davis
+Joe
+Ernesto
+Desmond
+Kade
+Reece
+Morgan
+Ramon
+Rocco
+Orlando
+Ryker
+Brodie
+Paxton
+Jacoby
+Douglas
+Kristopher
+Gary
+Lawrence
+Izaiah
+Solomon
+Nikolas
+Mekhi
+Justice
+Tate
+Jaydon
+Salvador
+Shaun
+Alvin
+Eddie
+Kane
+Davion
+Zachariah
+Damien
+Titus
+Kellen
+Camron
+Isiah
+Javon
+Nasir
+Milo
+Johan
+Byron
+Jasper
+Jonathon
+Chad
+Marc
+Kelvin
+Chandler
+Sam
+Cory
+Deandre
+River
+Reese
+Roger
+Quinton
+Talon
+Romeo
+Franklin
+Noel
+Alijah
+Guillermo
+Gunner
+Damon
+Jadon
+Emerson
+Micheal
+Bruce
+Terry
+Kolton
+Melvin
+Beckett
+Porter
+August
+Brycen
+Dayton
+Jamarion
+Leonel
+Karson
+Zayden
+Keagan
+Carl
+Khalil
+Cristopher
+Nelson
+Braiden
+Moses
+Isaias
+Roy
+Triston
+Walker
Kale
\ No newline at end of file
diff --git a/config/names/last.txt b/config/names/last.txt
index 5b41e53aae8..9bdb16ebe71 100644
--- a/config/names/last.txt
+++ b/config/names/last.txt
@@ -1,620 +1,620 @@
-Whittier
-Dimeling
-Blaine
-Dennis
-Adams
-Rader
-Murray
-Millhouse
-Ludwig
-Burris
-Shupe
-Mary
-Zadovsky
-Philips
-Wise
-Gronko
-Jardine
-Black
-Mitchell
-Enderly
-Stall
-Harrow
-Atweeke
-Sealis
-Conrad
-Lucy
-Stewart
-Green
-Feufer
-Warren
-Campbell
-Shafer
-Woodworth
-Magor
-Logue
-Reichard
-Day
-Dugmore
-Murray
-Greenawalt
-Jyllian
-Osterwise
-Styles
-Cavalet
-Garneys
-Raub
-Sholl
-Chauvin
-Poley
-Todd
-Brandenburg
-Baer
-Pritchard
-Pinney
-Kadel
-Anderson
-Clarke
-Hunt
-Gadow
-Stough
-Marcotte
-Brooks
-Watson
-Nash
-Sheets
-Ashbaugh
-Zimmer
-Noton
-Dean
-Fleming
-Draudy
-Bluetenberger
-Fischer
-Hawkins
-Poehl
-Addison
-Mcintosh
-Keppel
-Kimple
-Alice
-Stone
-Fiscina
-Leichter
-Wile
-Callison
-Cowper
-Harrold
-Carr
-Eckhardstein
-Wilkerson
-Shirey
-Benford
-Reade
-Baskett
-Seidner
-Gettemy
-Joyce
-Judge
-Burkett
-Kiefer
-Carmichael
-Hirleman
-Wells
-Isemann
-Cressman
-Highlands
-Briggs
-Rowley
-Coldsmith
-Berkheimer
-Hill
-Maclagan
-Mcfall
-Mens
-Braun
-James
-Sloan
-Bould
-Overstreet
-Kanaga
-Polson
-Finlay
-Sandys
-Bousum
-Howard
-Treeby
-Stainforth
-Werner
-Sulyard
-Marriman
-Weinstein
-Butterfill
-Mason
-Coates
-Peters
-Gregory
-Wilo
-Edwards
-Barnes
-Harding
-Tireman
-Lombardi
-Roberts
-Faqua
-Basmanoff
-Mccune
-Mckendrick
-Oppenheimer
-Oneal
-Focell
-Tedrow
-Fields
-Ryals
-Best
-Zaun
-Knapp
-Linton
-Jackson
-Bullard
-Mcloskey
-Zoucks
-Heckendora
-Hoenshell
-Woollard
-Mueller
-Burns
-Franks
-Goodman
-Stern
-Robinson
-Hooker
-David
-Fitzgerald
-Vanleer
-Beach
-Flickinger
-Metzer
-Bynum
-Stafford
-Osteen
-Johnson
-Paynter
-Thomlinson
-Simmons
-Basinger
-Fisher
-Bunten
-Compton
-Archibald
-Catherina
-Rahl
-Bowchiew
-Tennant
-Mccullough
-Margaret
-Schaeffer
-Sommer
-Beail
-Merryman
-Knapenberger
-Patterson
-Houston
-Lacon
-Levett
-Sullivan
-Sidower
-Laborde
-Stroh
-Hice
-Biery
-Christman
-Staymates
-Sauter
-Snyder
-Bratton
-Sybilla
-Altmann
-Mathews
-Newbern
-Baker
-Kemble
-Mingle
-Unk
-Otis
-Quinn
-Bell
-Roberts
-Wood
-Ullman
-Bicknell
-Gibson
-Rohtin
-James
-Wallick
-Eggbert
-Losey
-Neely
-Catleay
-McDonald
-Beedell
-Williamson
-Bennett
-Potter
-Caldwell
-Lowe
-Durstine
-King
-Gardner
-Ulery
-Rifler
-Trovato
-Thomas
-Nehling
-Baum
-Werry
-Mcmullen
-Koster
-Willey
-Mildred
-Straub
-Haynes
-Baxter
-Ackerley
-Greene
-Atkinson
-Davis
-Weeter
-Milne
-Leech
-Clewett
-Ewing
-Hook
-Reighner
-Welty
-Jenkins
-Bennett
-Swarner
-Hawker
-Agg
-Batten
-Cherry
-Shaffer
-Yeskey
-Stephenson
-Pycroft
-Larson
-Joghs
-Keener
-Christopher
-Roadman
-Echard
-Priebe
-Auman
-Kemerer
-Sutton
-Prechtl
-Cowart
-Ringer
-Garratt
-Siegrist
-Seelig
-Lafortune
-Dryfus
-Isaman
-Teagarden
-Evans
-Wolfe
-Fiddler
-Jowers
-Aultman
-Olphert
-Howe
-Leslie
-Stocker
-Bode
-Whirlow
-Ann
-Mcclymonds
-Guess
-Taggart
-Pratt
-Moon
-Huey
-Hegarty
-Meyers
-Stahl
-Nickolson
-Mortland
-Perkins
-Thorley
-Fuchs
-Ray
-Schrader
-Kellogg
-Woodward
-Faust
-Roby
-Bashline
-Cypret
-Laurenzi
-Minnie
-Houser
-Langston
-Anderson
-Barrett
-Wible
-Hujsak
-Wardle
-Pershing
-Kuster
-Driggers
-Wheeler
-Garland
-Alliman
-Hoover
-Camp
-Hall
-Parkinson
-Swabey
-Mull
-Cox
-Hanford
-Stange
-Wolff
-Jesse
-Brinigh
-Koepple
-Schmidt
-Muller
-Schofield
-Zalack
-Pfeifer
-Fea
-Blackburn
-Ward
-Kifer
-Costello
-Donkin
-Osterweis
-Brindle
-Llora
-Duncan
-Ehret
-Fryer
-Summy
-Richards
-Boyer
-Hutton
-Mosser
-Lester
-Stroble
-Randolph
-Lord
-Scott
-Nicholas
-Smail
-Ratcliff
-Riggle
-Newton
-Sanders
-Mitchell
-Lauffer
-Aggley
-Moberly
-Hynes
-Pennington
-Woolery
-Hardie
-Blessig
-Tanner
-Demuth
-Fraser
-Henry
-Shick
-Ironmonger
-Scherer
-Field
-Prevatt
-Earl
-Paulson
-Curry
-Powers
-Rosensteel
-Hoopengarner
-Weisgarber
-Elliott
-Pearsall
-Lowstetter
-Holdeman
-Kepplinger
-Bloise
-Hunter
-Glover
-Hayhurst
-Wentzel
-Owens
-Smith
-Steele
-Leach
-Armstrong
-Wheeler
-Easter
-Greenwood
-Woodward
-Pratt
-Buzzard
-Cox
-Eliza
-Rockwell
-Zeal
-Harshman
-Northey
-Tilton
-Richter
-Moore
-Jerome
-Hardy
-Bickerson
-White
-Beck
-Waldron
-Fulton
-Miller
-Sandford
-Hughes
-Winton
-Digson
-Byers
-Hincken
-Shaner
-Todd
-Whiteman
-Lineman
-Albright
-Hastings
-Elderson
-Garrison
-Rose
-Kelley
-Quirin
-Dickinson
-Young
-Ramos
-Jewell
-Endsley
-Briner
-Jenner
-Saylor
-Bash
-Blyant
-Rhinehart
-Prescott
-Kirkson
-Picard
-Riker
-Spock
-Skywalker
-Vader
-Muggins
-Buttersworth
-Stamos
-Sagan
-Hawking
-Dawkins
-Goebbles
-McShain
-McDonohugh
-Power
-Smith
-Jones
-Williams
-Brown
-Taylor
-Davies
-Wilson
-Evans
-Thomas
-Roberts
-Johnson
-Walker
-Wright
-Robinson
-Thompson
-Hughes
-White
-Edwards
-Hall
-Patel
-Green
-Martins
-Lewis
-Wood
-Jackson
-Clarke
-Harris
-Clark
-Scott
-Turner
-Hill
-Moore
-Cooper
-Morris
-Ward
-Watson
-Morgan
-Anderson
-Harrison
-King
-Campbell
-Young
-Mitchell
-Baker
-James
-Kelly
-Allen
-Bell
-Phillips
-Lee
-Stewart
-Miller
-Parker
-Simpson
-Bennett
-Davis
-Griffiths
-Shaw
-Price
-Cook
-Richardson
-Murray
-Marshall
-Begum
-Murphy
-Khan
-Gray
-Collins
-Bailey
-Carter
-Robertson
-Graham
-Adams
-Richards
-Cox
-Singh
-Hussain
-Ellis
-Wilkinson
-Foster
-Thomson
-Russell
-Ali
-Reid
-Rathens
-Rathen
-Mason
-Chapman
-Powell
-Owen
-Ahmed
-Gibson
-Rogers
-Webb
-Holmes
-Mills
-Matthews
-Hunt
-Palmer
-Lloyd
-Kaur
-Fisher
-Ivanov
-Smirnov
-Vasilyev
-Petrov
-Kuznetsov
-Mikhaylov
-Pavlov
-Semenov
-Andreev
+Whittier
+Dimeling
+Blaine
+Dennis
+Adams
+Rader
+Murray
+Millhouse
+Ludwig
+Burris
+Shupe
+Mary
+Zadovsky
+Philips
+Wise
+Gronko
+Jardine
+Black
+Mitchell
+Enderly
+Stall
+Harrow
+Atweeke
+Sealis
+Conrad
+Lucy
+Stewart
+Green
+Feufer
+Warren
+Campbell
+Shafer
+Woodworth
+Magor
+Logue
+Reichard
+Day
+Dugmore
+Murray
+Greenawalt
+Jyllian
+Osterwise
+Styles
+Cavalet
+Garneys
+Raub
+Sholl
+Chauvin
+Poley
+Todd
+Brandenburg
+Baer
+Pritchard
+Pinney
+Kadel
+Anderson
+Clarke
+Hunt
+Gadow
+Stough
+Marcotte
+Brooks
+Watson
+Nash
+Sheets
+Ashbaugh
+Zimmer
+Noton
+Dean
+Fleming
+Draudy
+Bluetenberger
+Fischer
+Hawkins
+Poehl
+Addison
+Mcintosh
+Keppel
+Kimple
+Alice
+Stone
+Fiscina
+Leichter
+Wile
+Callison
+Cowper
+Harrold
+Carr
+Eckhardstein
+Wilkerson
+Shirey
+Benford
+Reade
+Baskett
+Seidner
+Gettemy
+Joyce
+Judge
+Burkett
+Kiefer
+Carmichael
+Hirleman
+Wells
+Isemann
+Cressman
+Highlands
+Briggs
+Rowley
+Coldsmith
+Berkheimer
+Hill
+Maclagan
+Mcfall
+Mens
+Braun
+James
+Sloan
+Bould
+Overstreet
+Kanaga
+Polson
+Finlay
+Sandys
+Bousum
+Howard
+Treeby
+Stainforth
+Werner
+Sulyard
+Marriman
+Weinstein
+Butterfill
+Mason
+Coates
+Peters
+Gregory
+Wilo
+Edwards
+Barnes
+Harding
+Tireman
+Lombardi
+Roberts
+Faqua
+Basmanoff
+Mccune
+Mckendrick
+Oppenheimer
+Oneal
+Focell
+Tedrow
+Fields
+Ryals
+Best
+Zaun
+Knapp
+Linton
+Jackson
+Bullard
+Mcloskey
+Zoucks
+Heckendora
+Hoenshell
+Woollard
+Mueller
+Burns
+Franks
+Goodman
+Stern
+Robinson
+Hooker
+David
+Fitzgerald
+Vanleer
+Beach
+Flickinger
+Metzer
+Bynum
+Stafford
+Osteen
+Johnson
+Paynter
+Thomlinson
+Simmons
+Basinger
+Fisher
+Bunten
+Compton
+Archibald
+Catherina
+Rahl
+Bowchiew
+Tennant
+Mccullough
+Margaret
+Schaeffer
+Sommer
+Beail
+Merryman
+Knapenberger
+Patterson
+Houston
+Lacon
+Levett
+Sullivan
+Sidower
+Laborde
+Stroh
+Hice
+Biery
+Christman
+Staymates
+Sauter
+Snyder
+Bratton
+Sybilla
+Altmann
+Mathews
+Newbern
+Baker
+Kemble
+Mingle
+Unk
+Otis
+Quinn
+Bell
+Roberts
+Wood
+Ullman
+Bicknell
+Gibson
+Rohtin
+James
+Wallick
+Eggbert
+Losey
+Neely
+Catleay
+McDonald
+Beedell
+Williamson
+Bennett
+Potter
+Caldwell
+Lowe
+Durstine
+King
+Gardner
+Ulery
+Rifler
+Trovato
+Thomas
+Nehling
+Baum
+Werry
+Mcmullen
+Koster
+Willey
+Mildred
+Straub
+Haynes
+Baxter
+Ackerley
+Greene
+Atkinson
+Davis
+Weeter
+Milne
+Leech
+Clewett
+Ewing
+Hook
+Reighner
+Welty
+Jenkins
+Bennett
+Swarner
+Hawker
+Agg
+Batten
+Cherry
+Shaffer
+Yeskey
+Stephenson
+Pycroft
+Larson
+Joghs
+Keener
+Christopher
+Roadman
+Echard
+Priebe
+Auman
+Kemerer
+Sutton
+Prechtl
+Cowart
+Ringer
+Garratt
+Siegrist
+Seelig
+Lafortune
+Dryfus
+Isaman
+Teagarden
+Evans
+Wolfe
+Fiddler
+Jowers
+Aultman
+Olphert
+Howe
+Leslie
+Stocker
+Bode
+Whirlow
+Ann
+Mcclymonds
+Guess
+Taggart
+Pratt
+Moon
+Huey
+Hegarty
+Meyers
+Stahl
+Nickolson
+Mortland
+Perkins
+Thorley
+Fuchs
+Ray
+Schrader
+Kellogg
+Woodward
+Faust
+Roby
+Bashline
+Cypret
+Laurenzi
+Minnie
+Houser
+Langston
+Anderson
+Barrett
+Wible
+Hujsak
+Wardle
+Pershing
+Kuster
+Driggers
+Wheeler
+Garland
+Alliman
+Hoover
+Camp
+Hall
+Parkinson
+Swabey
+Mull
+Cox
+Hanford
+Stange
+Wolff
+Jesse
+Brinigh
+Koepple
+Schmidt
+Muller
+Schofield
+Zalack
+Pfeifer
+Fea
+Blackburn
+Ward
+Kifer
+Costello
+Donkin
+Osterweis
+Brindle
+Llora
+Duncan
+Ehret
+Fryer
+Summy
+Richards
+Boyer
+Hutton
+Mosser
+Lester
+Stroble
+Randolph
+Lord
+Scott
+Nicholas
+Smail
+Ratcliff
+Riggle
+Newton
+Sanders
+Mitchell
+Lauffer
+Aggley
+Moberly
+Hynes
+Pennington
+Woolery
+Hardie
+Blessig
+Tanner
+Demuth
+Fraser
+Henry
+Shick
+Ironmonger
+Scherer
+Field
+Prevatt
+Earl
+Paulson
+Curry
+Powers
+Rosensteel
+Hoopengarner
+Weisgarber
+Elliott
+Pearsall
+Lowstetter
+Holdeman
+Kepplinger
+Bloise
+Hunter
+Glover
+Hayhurst
+Wentzel
+Owens
+Smith
+Steele
+Leach
+Armstrong
+Wheeler
+Easter
+Greenwood
+Woodward
+Pratt
+Buzzard
+Cox
+Eliza
+Rockwell
+Zeal
+Harshman
+Northey
+Tilton
+Richter
+Moore
+Jerome
+Hardy
+Bickerson
+White
+Beck
+Waldron
+Fulton
+Miller
+Sandford
+Hughes
+Winton
+Digson
+Byers
+Hincken
+Shaner
+Todd
+Whiteman
+Lineman
+Albright
+Hastings
+Elderson
+Garrison
+Rose
+Kelley
+Quirin
+Dickinson
+Young
+Ramos
+Jewell
+Endsley
+Briner
+Jenner
+Saylor
+Bash
+Blyant
+Rhinehart
+Prescott
+Kirkson
+Picard
+Riker
+Spock
+Skywalker
+Vader
+Muggins
+Buttersworth
+Stamos
+Sagan
+Hawking
+Dawkins
+Goebbles
+McShain
+McDonohugh
+Power
+Smith
+Jones
+Williams
+Brown
+Taylor
+Davies
+Wilson
+Evans
+Thomas
+Roberts
+Johnson
+Walker
+Wright
+Robinson
+Thompson
+Hughes
+White
+Edwards
+Hall
+Patel
+Green
+Martins
+Lewis
+Wood
+Jackson
+Clarke
+Harris
+Clark
+Scott
+Turner
+Hill
+Moore
+Cooper
+Morris
+Ward
+Watson
+Morgan
+Anderson
+Harrison
+King
+Campbell
+Young
+Mitchell
+Baker
+James
+Kelly
+Allen
+Bell
+Phillips
+Lee
+Stewart
+Miller
+Parker
+Simpson
+Bennett
+Davis
+Griffiths
+Shaw
+Price
+Cook
+Richardson
+Murray
+Marshall
+Begum
+Murphy
+Khan
+Gray
+Collins
+Bailey
+Carter
+Robertson
+Graham
+Adams
+Richards
+Cox
+Singh
+Hussain
+Ellis
+Wilkinson
+Foster
+Thomson
+Russell
+Ali
+Reid
+Rathens
+Rathen
+Mason
+Chapman
+Powell
+Owen
+Ahmed
+Gibson
+Rogers
+Webb
+Holmes
+Mills
+Matthews
+Hunt
+Palmer
+Lloyd
+Kaur
+Fisher
+Ivanov
+Smirnov
+Vasilyev
+Petrov
+Kuznetsov
+Mikhaylov
+Pavlov
+Semenov
+Andreev
Alekseev
\ No newline at end of file
diff --git a/config/names/ninjaname.txt b/config/names/ninjaname.txt
index b41271dbe10..42b74817041 100644
--- a/config/names/ninjaname.txt
+++ b/config/names/ninjaname.txt
@@ -1,44 +1,44 @@
-Shadow
-Sarutobi
-Smoke
-Rain
-Scorpion
-Zero
-Ermac
-Saibot
-Cyrax
-Raphael
-Michaelangelo
-Donatello
-Leonardo
-Splinter
-Shredder
-Hazuki
-Hien
-Hiryu
-Ryu
-Hayabusa
-Midnight
-Seven
-McNinja
-Hanzo
-Blood
-Iga
-Koga
-Hero
-Hiro
-Phantom
-Baki
-Ogre
-Daemon
-Goemon
-McAwesome
-Throat
-Death
-Aria
-Bro
-Fox
-Null
-Raiden
-Samurai
+Shadow
+Sarutobi
+Smoke
+Rain
+Scorpion
+Zero
+Ermac
+Saibot
+Cyrax
+Raphael
+Michaelangelo
+Donatello
+Leonardo
+Splinter
+Shredder
+Hazuki
+Hien
+Hiryu
+Ryu
+Hayabusa
+Midnight
+Seven
+McNinja
+Hanzo
+Blood
+Iga
+Koga
+Hero
+Hiro
+Phantom
+Baki
+Ogre
+Daemon
+Goemon
+McAwesome
+Throat
+Death
+Aria
+Bro
+Fox
+Null
+Raiden
+Samurai
Eater
\ No newline at end of file
diff --git a/config/names/ninjatitle.txt b/config/names/ninjatitle.txt
index 2c7f9e7f73c..078ae36fc10 100644
--- a/config/names/ninjatitle.txt
+++ b/config/names/ninjatitle.txt
@@ -1,46 +1,46 @@
-Master
-Sensei
-Swift
-Merciless
-Assassin
-Rogue
-Hunter
-Widower
-Orphaner
-Stalker
-Killer
-Silent
-Silencing
-Quick
-Agile
-Merciful
-Ninja
-Shinobi
-Initiate
-Grandmaster
-Strider
-Striker
-Slayer
-Awesome
-Ender
-Dr.
-Noob
-Night
-Crimson
-Grappler
-Ulimate
-Remorseless
-Deep
-Dragon
-Cruel
-Nightshade
-Black
-Gray
-Solid
-Liquid
-Solidus
-Steel
-Nickel
-Silver
-Singing
+Master
+Sensei
+Swift
+Merciless
+Assassin
+Rogue
+Hunter
+Widower
+Orphaner
+Stalker
+Killer
+Silent
+Silencing
+Quick
+Agile
+Merciful
+Ninja
+Shinobi
+Initiate
+Grandmaster
+Strider
+Striker
+Slayer
+Awesome
+Ender
+Dr.
+Noob
+Night
+Crimson
+Grappler
+Ulimate
+Remorseless
+Deep
+Dragon
+Cruel
+Nightshade
+Black
+Gray
+Solid
+Liquid
+Solidus
+Steel
+Nickel
+Silver
+Singing
Snake
\ No newline at end of file
diff --git a/config/names/verbs.txt b/config/names/verbs.txt
index e036e3c1dab..5bb8d6e3139 100644
--- a/config/names/verbs.txt
+++ b/config/names/verbs.txt
@@ -1,633 +1,633 @@
-accept
-add
-admire
-admit
-advise
-afford
-agree
-alert
-allow
-amuse
-analyse
-announce
-annoy
-answer
-apologise
-appear
-applaud
-appreciate
-approve
-argue
-arrange
-arrest
-arrive
-ask
-attach
-attack
-attempt
-attend
-attract
-avoid
-back
-bake
-balance
-ban
-bang
-bare
-bat
-bathe
-battle
-beam
-beg
-behave
-belong
-bleach
-bless
-blind
-blink
-blot
-blush
-boast
-boil
-bolt
-bomb
-book
-bore
-borrow
-bounce
-bow
-box
-brake
-brake
-branch
-breathe
-bruise
-brush
-bubble
-bump
-burn
-bury
-buzz
-calculate
-call
-camp
-care
-carry
-carve
-cause
-challenge
-change
-charge
-chase
-cheat
-check
-cheer
-chew
-choke
-chop
-claim
-clap
-clean
-clear
-clip
-close
-coach
-coil
-collect
-colour
-comb
-command
-communicate
-compare
-compete
-complain
-complete
-concentrate
-concern
-confess
-confuse
-connect
-consider
-consist
-contain
-continue
-copy
-correct
-cough
-count
-cover
-crack
-crash
-crawl
-cross
-crush
-cry
-cure
-curl
-curve
-cycle
-dam
-damage
-dance
-dare
-decay
-deceive
-decide
-decorate
-delay
-delight
-deliver
-depend
-describe
-desert
-deserve
-destroy
-detect
-develop
-disagree
-disappear
-disapprove
-disarm
-discover
-dislike
-divide
-double
-doubt
-drag
-drain
-dream
-dress
-drip
-drop
-drown
-drum
-dry
-dust
-earn
-educate
-embarrass
-employ
-empty
-encourage
-end
-enjoy
-enter
-entertain
-escape
-examine
-excite
-excuse
-exercise
-exist
-expand
-expect
-explain
-explode
-extend
-face
-fade
-fail
-fancy
-fasten
-fax
-fear
-fence
-fetch
-file
-fill
-film
-fire
-fit
-fix
-flap
-flash
-float
-flood
-flow
-flower
-fold
-follow
-fool
-force
-form
-found
-frame
-frighten
-fry
-gather
-gaze
-glow
-glue
-grab
-grate
-grease
-greet
-grin
-grip
-groan
-guarantee
-guard
-guess
-guide
-hammer
-hand
-handle
-hang
-happen
-harass
-harm
-hate
-haunt
-head
-heal
-heap
-heat
-help
-hook
-hop
-hope
-hover
-hug
-hum
-hunt
-hurry
-identify
-ignore
-imagine
-impress
-improve
-include
-increase
-influence
-inform
-inject
-injure
-instruct
-intend
-interest
-interfere
-interrupt
-introduce
-invent
-invite
-irritate
-itch
-jail
-jam
-jog
-join
-joke
-judge
-juggle
-jump
-kick
-kill
-kiss
-kneel
-knit
-knock
-knot
-label
-land
-last
-laugh
-launch
-learn
-level
-license
-lick
-lie
-lighten
-like
-list
-listen
-live
-load
-lock
-long
-look
-love
-man
-manage
-march
-mark
-marry
-match
-mate
-matter
-measure
-meddle
-melt
-memorise
-mend
-messup
-milk
-mine
-miss
-mix
-moan
-moor
-mourn
-move
-muddle
-mug
-multiply
-murder
-nail
-name
-need
-nest
-nod
-note
-notice
-number
-obey
-object
-observe
-obtain
-occur
-offend
-offer
-open
-order
-overflow
-owe
-own
-pack
-paddle
-paint
-park
-part
-pass
-paste
-pat
-pause
-peck
-pedal
-peel
-peep
-perform
-permit
-phone
-pick
-pinch
-pine
-place
-plan
-plant
-play
-please
-plug
-point
-poke
-polish
-pop
-possess
-post
-pour
-practise
-pray
-preach
-precede
-prefer
-prepare
-present
-preserve
-press
-pretend
-prevent
-prick
-print
-produce
-program
-promise
-protect
-provide
-pull
-pump
-punch
-puncture
-punish
-push
-question
-queue
-race
-radiate
-rain
-raise
-reach
-realise
-receive
-recognise
-record
-reduce
-reflect
-refuse
-regret
-reign
-reject
-rejoice
-relax
-release
-rely
-remain
-remember
-remind
-remove
-repair
-repeat
-replace
-reply
-report
-reproduce
-request
-rescue
-retire
-return
-rhyme
-rinse
-risk
-rob
-rock
-roll
-rot
-rub
-ruin
-rule
-rush
-sack
-sail
-satisfy
-save
-saw
-scare
-scatter
-scold
-scorch
-scrape
-scratch
-scream
-screw
-scribble
-scrub
-seal
-search
-separate
-serve
-settle
-shade
-share
-shave
-shelter
-shiver
-shock
-shop
-shrug
-sigh
-sign
-signal
-sin
-sip
-ski
-skip
-slap
-slip
-slow
-smash
-smell
-smile
-smoke
-snatch
-sneeze
-sniff
-snore
-snow
-soak
-soothe
-sound
-spare
-spark
-sparkle
-spell
-spill
-spoil
-spot
-spray
-sprout
-squash
-squeak
-squeal
-squeeze
-stain
-stamp
-stare
-start
-stay
-steer
-step
-stir
-stitch
-stop
-store
-strap
-strengthen
-stretch
-strip
-stroke
-stuff
-subtract
-succeed
-suck
-suffer
-suggest
-suit
-supply
-support
-suppose
-surprise
-surround
-suspect
-suspend
-switch
-talk
-tame
-tap
-taste
-tease
-telephone
-tempt
-terrify
-test
-thank
-thaw
-tick
-tickle
-tie
-time
-tip
-tire
-touch
-tour
-tow
-trace
-trade
-train
-transport
-trap
-travel
-treat
-tremble
-trick
-trip
-trot
-trouble
-trust
-try
-tug
-tumble
-turn
-twist
-type
-undress
-unfasten
-unite
-unlock
-unpack
-untidy
-use
-vanish
-visit
-wail
-wait
-walk
-wander
-want
-warm
-warn
-wash
-waste
-watch
-water
-wave
-weigh
-welcome
-whine
-whip
-whirl
-whisper
-whistle
-wink
-wipe
-wish
-wobble
-wonder
-work
-worry
-wrap
-wreck
-wrestle
-wriggle
-yawn
-yell
-zip
+accept
+add
+admire
+admit
+advise
+afford
+agree
+alert
+allow
+amuse
+analyse
+announce
+annoy
+answer
+apologise
+appear
+applaud
+appreciate
+approve
+argue
+arrange
+arrest
+arrive
+ask
+attach
+attack
+attempt
+attend
+attract
+avoid
+back
+bake
+balance
+ban
+bang
+bare
+bat
+bathe
+battle
+beam
+beg
+behave
+belong
+bleach
+bless
+blind
+blink
+blot
+blush
+boast
+boil
+bolt
+bomb
+book
+bore
+borrow
+bounce
+bow
+box
+brake
+brake
+branch
+breathe
+bruise
+brush
+bubble
+bump
+burn
+bury
+buzz
+calculate
+call
+camp
+care
+carry
+carve
+cause
+challenge
+change
+charge
+chase
+cheat
+check
+cheer
+chew
+choke
+chop
+claim
+clap
+clean
+clear
+clip
+close
+coach
+coil
+collect
+colour
+comb
+command
+communicate
+compare
+compete
+complain
+complete
+concentrate
+concern
+confess
+confuse
+connect
+consider
+consist
+contain
+continue
+copy
+correct
+cough
+count
+cover
+crack
+crash
+crawl
+cross
+crush
+cry
+cure
+curl
+curve
+cycle
+dam
+damage
+dance
+dare
+decay
+deceive
+decide
+decorate
+delay
+delight
+deliver
+depend
+describe
+desert
+deserve
+destroy
+detect
+develop
+disagree
+disappear
+disapprove
+disarm
+discover
+dislike
+divide
+double
+doubt
+drag
+drain
+dream
+dress
+drip
+drop
+drown
+drum
+dry
+dust
+earn
+educate
+embarrass
+employ
+empty
+encourage
+end
+enjoy
+enter
+entertain
+escape
+examine
+excite
+excuse
+exercise
+exist
+expand
+expect
+explain
+explode
+extend
+face
+fade
+fail
+fancy
+fasten
+fax
+fear
+fence
+fetch
+file
+fill
+film
+fire
+fit
+fix
+flap
+flash
+float
+flood
+flow
+flower
+fold
+follow
+fool
+force
+form
+found
+frame
+frighten
+fry
+gather
+gaze
+glow
+glue
+grab
+grate
+grease
+greet
+grin
+grip
+groan
+guarantee
+guard
+guess
+guide
+hammer
+hand
+handle
+hang
+happen
+harass
+harm
+hate
+haunt
+head
+heal
+heap
+heat
+help
+hook
+hop
+hope
+hover
+hug
+hum
+hunt
+hurry
+identify
+ignore
+imagine
+impress
+improve
+include
+increase
+influence
+inform
+inject
+injure
+instruct
+intend
+interest
+interfere
+interrupt
+introduce
+invent
+invite
+irritate
+itch
+jail
+jam
+jog
+join
+joke
+judge
+juggle
+jump
+kick
+kill
+kiss
+kneel
+knit
+knock
+knot
+label
+land
+last
+laugh
+launch
+learn
+level
+license
+lick
+lie
+lighten
+like
+list
+listen
+live
+load
+lock
+long
+look
+love
+man
+manage
+march
+mark
+marry
+match
+mate
+matter
+measure
+meddle
+melt
+memorise
+mend
+messup
+milk
+mine
+miss
+mix
+moan
+moor
+mourn
+move
+muddle
+mug
+multiply
+murder
+nail
+name
+need
+nest
+nod
+note
+notice
+number
+obey
+object
+observe
+obtain
+occur
+offend
+offer
+open
+order
+overflow
+owe
+own
+pack
+paddle
+paint
+park
+part
+pass
+paste
+pat
+pause
+peck
+pedal
+peel
+peep
+perform
+permit
+phone
+pick
+pinch
+pine
+place
+plan
+plant
+play
+please
+plug
+point
+poke
+polish
+pop
+possess
+post
+pour
+practise
+pray
+preach
+precede
+prefer
+prepare
+present
+preserve
+press
+pretend
+prevent
+prick
+print
+produce
+program
+promise
+protect
+provide
+pull
+pump
+punch
+puncture
+punish
+push
+question
+queue
+race
+radiate
+rain
+raise
+reach
+realise
+receive
+recognise
+record
+reduce
+reflect
+refuse
+regret
+reign
+reject
+rejoice
+relax
+release
+rely
+remain
+remember
+remind
+remove
+repair
+repeat
+replace
+reply
+report
+reproduce
+request
+rescue
+retire
+return
+rhyme
+rinse
+risk
+rob
+rock
+roll
+rot
+rub
+ruin
+rule
+rush
+sack
+sail
+satisfy
+save
+saw
+scare
+scatter
+scold
+scorch
+scrape
+scratch
+scream
+screw
+scribble
+scrub
+seal
+search
+separate
+serve
+settle
+shade
+share
+shave
+shelter
+shiver
+shock
+shop
+shrug
+sigh
+sign
+signal
+sin
+sip
+ski
+skip
+slap
+slip
+slow
+smash
+smell
+smile
+smoke
+snatch
+sneeze
+sniff
+snore
+snow
+soak
+soothe
+sound
+spare
+spark
+sparkle
+spell
+spill
+spoil
+spot
+spray
+sprout
+squash
+squeak
+squeal
+squeeze
+stain
+stamp
+stare
+start
+stay
+steer
+step
+stir
+stitch
+stop
+store
+strap
+strengthen
+stretch
+strip
+stroke
+stuff
+subtract
+succeed
+suck
+suffer
+suggest
+suit
+supply
+support
+suppose
+surprise
+surround
+suspect
+suspend
+switch
+talk
+tame
+tap
+taste
+tease
+telephone
+tempt
+terrify
+test
+thank
+thaw
+tick
+tickle
+tie
+time
+tip
+tire
+touch
+tour
+tow
+trace
+trade
+train
+transport
+trap
+travel
+treat
+tremble
+trick
+trip
+trot
+trouble
+trust
+try
+tug
+tumble
+turn
+twist
+type
+undress
+unfasten
+unite
+unlock
+unpack
+untidy
+use
+vanish
+visit
+wail
+wait
+walk
+wander
+want
+warm
+warn
+wash
+waste
+watch
+water
+wave
+weigh
+welcome
+whine
+whip
+whirl
+whisper
+whistle
+wink
+wipe
+wish
+wobble
+wonder
+work
+worry
+wrap
+wreck
+wrestle
+wriggle
+yawn
+yell
+zip
zoom
\ No newline at end of file
diff --git a/config/names/wizardfirst.txt b/config/names/wizardfirst.txt
index 408ae3b447e..18806ca74b7 100644
--- a/config/names/wizardfirst.txt
+++ b/config/names/wizardfirst.txt
@@ -1,36 +1,36 @@
-Jim
-Gulstaff
-Gandalf
-Grimm
-Mordenkainen
-Elminister
-Saruman
-Vaarsuvius
-Yoda
-Zul
-Nihilus
-Vecna
-Mogan
-Circe
-Prospero
-Raistlin
-Rasputin
-Tzeentch
-Khelben
-Dumbledor
-Houdini
-Terefi
-Urza
-Tenser
-Zagyg
-Mystryl
-Boccob
-Merlin
-Archchancellor
-Radagast
-Kreol
-Kaschei
-Lina
-Morgan
-Alatar
+Jim
+Gulstaff
+Gandalf
+Grimm
+Mordenkainen
+Elminister
+Saruman
+Vaarsuvius
+Yoda
+Zul
+Nihilus
+Vecna
+Mogan
+Circe
+Prospero
+Raistlin
+Rasputin
+Tzeentch
+Khelben
+Dumbledor
+Houdini
+Terefi
+Urza
+Tenser
+Zagyg
+Mystryl
+Boccob
+Merlin
+Archchancellor
+Radagast
+Kreol
+Kaschei
+Lina
+Morgan
+Alatar
Palando
\ No newline at end of file
diff --git a/config/names/wizardsecond.txt b/config/names/wizardsecond.txt
index d1e2e734862..1fe60bdb275 100644
--- a/config/names/wizardsecond.txt
+++ b/config/names/wizardsecond.txt
@@ -1,39 +1,39 @@
-the Powerful
-the Great
-the Magician
-the Wise
-the Seething
-the Amazing
-the Spiral King
-Darkmagic
-the White
-the Gray
-Shado
-the Sorcelator
-the Raven
-the Emperor
-the Brown
-Weatherwax
-the Destroyer
-the Deathless
-Yagg
-the Remorseful
-the Weeping
-the Unending
-the All Knowing
-Dark
-Smith
-the Conquerer
-the Unstoppable
-Gray
-of Void
-Unseen
-Darko
-Honko
-the Bandit Killer
-the Dragon Spooker
-Inverse
-le Fay
-the Blue
-the Red
+the Powerful
+the Great
+the Magician
+the Wise
+the Seething
+the Amazing
+the Spiral King
+Darkmagic
+the White
+the Gray
+Shado
+the Sorcelator
+the Raven
+the Emperor
+the Brown
+Weatherwax
+the Destroyer
+the Deathless
+Yagg
+the Remorseful
+the Weeping
+the Unending
+the All Knowing
+Dark
+Smith
+the Conquerer
+the Unstoppable
+Gray
+of Void
+Unseen
+Darko
+Honko
+the Bandit Killer
+the Dragon Spooker
+Inverse
+le Fay
+the Blue
+the Red
the Benevolent
\ No newline at end of file
diff --git a/config/tips.txt b/config/tips.txt
index e51b584e7cd..33aad7a0b30 100644
--- a/config/tips.txt
+++ b/config/tips.txt
@@ -1,92 +1,156 @@
-You can drag yourself to a chair or a bed to buckle yourself to it.
-You can drag yourself onto a photocopier to copy your ass.
-Space transitions change every round, but are consistent within a round.
-People can be ejected from the cloner before they are done by cutting power to the clone pod.
-If you've been feeding some slimes for at least two generations, you can order them around, and even have them follow you if they like you enough.
-Almost all slime cores have two or more different effects.
-With the right slime cores, you can get up to nine uses of a single slime's effects.
-Touching a supermatter shard is akin to hugging a singularity.
-To catch thrown items, toggle throw mode on and make sure you have an open hand.
-Updating sec records regularly helps avoid confusion in the brig!
-You can drag the icon of an equipped headset or PDA onto your screen to interact with it.
-The mime's invisible wall will block electrodes and other projectiles, but beams pass straight through it like windows.
-The Library system is much more robust than most people think! Mess around with it, see if you can log who takes out the books for radio-reading.
-Use a pair of handcuffs on a pair of orange shoes (standard prisoner issue) to chain them together.
-Revolutionaries and gangsters can have their opinions swayed back to Nanotrasen loyalty by enough heavy objects to the head.
-Husked corpses that have been drained of their genomes by a changeling also lack blood in their veins, unlike burned or space frozen corpses.
-The stethoscope's utility extends beyond lung and heart check-ups. They can also be used to crack certain safes.
-Chloral Hydrate can be counteracted by having coffee in your system!
-The AI system integrity restorer in both the RD's office and on the bridge can revive a dead AI loaded onto an intellicard.
-If an anomaly appears, scan it with an analyzer and then ping the frequency it gives you with a remote signalling device.
-Various creatures can crawl through air vents by holding alt while left clicking them.
-Nuclear operatives can be extremely powerful, but only if they work together. Communication is key!
-A rogue AI can be an extremely powerful tool for traitors, but be wary of the laws you use to slave it to you as it may try to find loopholes to get back at you.
-You can drag yourself onto tables to climb on them. This takes a moment and requires two free hands.
-You can drag other players onto yourself to open the strip menu, letting you remove their equipment or force them to equip something.
-Aliens are by far the most powerful close-quarters combat menace. Fight them at a distance to gain the upper hand!
-Aliens take double damage from all burn sources, such as lasers and fires. Flamethrowers are extremely effective against them.
-As an alien, your most powerful weapon is the facehugger. It can instantly win any fight, but can be completely blocked by certain headgear. Strip downed victims before applying one.
-Monkeys can still wear some human items, such as masks and backpacks, but they cannot bring anything with themselves when vent crawling.
-Nuclear operatives are very effective in a blitzkrieg tactic: attacking almost as soon as the round starts and well before the crew is prepared.
-You can use a fire extinguisher as a ghetto jetpack by spraying in the opposite direction of where you want to go. This also works with any gun.
-Coffee can keep you very warm. Drink a lot before running around through exposed space.
-Both cargo and the HoP can make you fill out a form for their services.
-You can destroy a blob by shooting emitters at its core.
-You can electrify a grille by having an exposed wire node underneath it.
-If you press the tab key, you can toggle hotkey mode, which allows you to move using WASD and perform other actions using hotkeys.
-You can hack MULE bots to let you ride them.
-You can hack most vending machines to obtain contraband items.
-You can use a multitool on the Cargo Ordering Console circuitboards to get contraband crates.
-The cryptographic sequencer (emag) has an enormous amount of functions beyond breaking open locks and hacking cyborgs, experiment!
-Touching anything without black, insulated, or brown gloves will leave fingerprints, which can be analyzed by detectives to find the suspect. Be careful of what you leave prints on!
-Blobs are extremely powerful and are impossible to defeat alone. Communicate with the crew and rally them against the threat!
-You can fight blob pieces diagonally, as they can only expand onto adjacent tiles in cardinal directions.
-Security huds and secglass huds can tell you if someone is implanted with a loyalty implant. Use this to your advantage in a revolution.
-Loyalty implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted.
-Loyalty implants will break when used to de-convert a gangster. You will need to use two if you want to prevent them from being re-recruited.
-Don't neglect upgrading your machines with the machine parts produced by research! These can seriously improve the efficiency of your equipment.
-Cyborgs are impervious to fires and temperature, and can walk in a blazing inferno without worry. Don't shy away from setting the whole station on fire as a malfunctioning or rogue AI!
-The heads of staff, especially the Head of Security and the Captain, are usually extremely difficult to kill. If one of them is your target as a traitor, plan carefully.
-The Steal DNA sting from changelings counts for your genome absorb objective, but does not let you change your powers.
-Chemists are among the most powerful people on the station. They can survive almost anything thanks to all the chemicals in them that have basically replaced their blood.
-The station is capable of being entirely powered by the solar arrays, and is a much safer form of power over the singularity engine.
-The singularity engine is extremely dangerous if containment fails. Check back on it very frequently and call the shuttle immediately when, not if, it breaks free.
-Firesuits and winter coats offer mild protection from the cold, allowing you to spend longer periods of time near breaches and space than if wearing nothing at all.
-Vendors provide a very poor source of food riddled with sugar. This can affect your metabolism quite severely and it comes with many negative effects. Eat from the kitchen to stay healthy and even profit from a happy gut!
-Emergency internals tanks can be used from your hands, your pockets, your belt, or your suit storage slot (assuming you're wearing a valid exosuit).
-When walking through halls, stay on the Help intent to pass through people rather than bumping into them.
-Trying to do surgery but you keep cutting your patient? Remember to be on the help intent and to target the right limb!
-Glass shards can be welded to make glass, and metal rods can be welded to make metal. Ores can be welded, too, but this takes a lot of fuel.
-Many monsters won't attack you if you're unconscious. If you see a space bear, go to sleep, quick!
-Many monsters won't attack you if you're unconscious, but a medibot will still heal you. Keep one around when you're mining and never worry about dying again.
-Two people are critical and need your help, but you don't have time for two trips? Pull one and use the grab intent to grab the other. This will make you slower, but you will be able to take them both.
-When using the grab intent, grab someone by clicking on them then upgrade your grab by clicking on your hand slot. Holding them by the hands lets you throw them or table them.
-Can't seem to get a patient into the cryo tube or sleepers? Just drag their sprite to it to put them in it instantly. No more needing to shuffle around pulling them into it awkwardly.
-EMP blasts have a chance to make machines explode!
-Targeting your opponent's mouth in a fistfight will give you a greater chance of knocking them unconscious.
-As a security officer, examining a crew member with a secHUD allows you to set their status to arrest. You can even give a reason for the arrest warrant, as well.
-Clowns are extremely clumsy and will often misfire weapons.
-Hulks can't fire weapons because of their meaty fingers.
-The mime's crayon is edible.
-Shooting lasers at a computer console will destroy it.
-Using ethanol on a piece of paper will remove any writing on it.
-Using an emag on the gibber will allow you to throw people into it!
-Using the comms console with captain level access will allow you to broadcast announcements in BIG, RED LETTERS!
-You can repair cracked windows with a welding tool on help intent.
-Hold alt and left click on an adjacent tile to see its contents in the top right pane.
-While observing or as a ghost, double click on people, bots, or the singularity to follow them.
-Ghosts can click on active teleporters, portals, wormholes, or the gateway to jump to its destination!
-Ghosts can double-click their corpse, or the object containing their corpse (such as the cloning scanner), to re-enter it.
-Ghosts can see inside storage items that have been left on the ground.
-If you click on the command/chat bar to give it full focus you can use control + arrow keys to move the cursor around or scroll through the history of commands. (Control + home/end work too)
-Locked down rogue borgs can be dismantled to return the MMI for placement in a new borg.
-Fore = north, aft = south, starboard = east and port = west.
-Many things that bind you can be resisted out of with the resist button. This includes locked or welded lockers, chairs and handcuffs. Whenever stuck, just give it a try!
-You can use . or # instead of : for radio channels. Building this habit reduces the chance of accidentally saying things on common.
-While pulling something, clicking on a tile with an empty hand will move it to that tile. No more getting stuck in maint while dragging something!
-Things that override clicks like decks of cards or paper bins can still be picked up by dragging them to your character. Equipped things that override click can be unequipped by dragging it to an empty hand.
-In the job selection menu, from the lobby, you can use right click on the "Low/Medium/High" priority button to make it cycle backwards.
-If you stay out of camera range for 10 seconds, the AI's track on you will break.
-You can shoot cameras with bullets to disable them remotely.
-Disabling a camera with wirecutters will not cause a camera alarm, but bludgeoning it will.
-Gangs derive their power from their presence and notoriety. Cleaning up gang tags is the best way to slow their growth.
+
+Dragging yourself or someone else onto a chair or bed will buckle them to it, immobilizing them. If handcuffed, it will take time to resist out.
+Where the space map levels connect is randomized every round, but are otherwise kept consistent within rounds. Remember that they are not necessarily bidirectional!
+You can catch thrown items by toggling on your throw mode with an empty hand active.
+To crack the safe in the vault, you must use a stethoscope on it.
+You can climb onto a table by dragging yourself onto one. This takes time and drops the items in your hands on the table.
+You can drag other players onto yourself to open the strip menu, letting you remove their equipment or force them to wear something. Note that exosuits or helmets will block your access to the clothing beneath them, and that certain items take longer to strip or put on than others.
+You can spray a fire extinguisher or fire a gun while floating through space to change your direction. Simply fire opposite to where you want to go.
+You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this.
+All vending machines can be hacked to obtain some contraband items from them, and some can be fed with coins to gain access to premium items.
+Firesuits and winter coats offer mild protection from the cold, allowing you to spend longer periods of time near breaches and space than if wearing nothing at all.
+Glass shards can be welded to make glass, and metal rods can be welded to make metal. Ores can be welded too, but this takes a lot of fuel.
+If you need to drag multiple people either to safety or to space, bring a locker over and stuff them all in before hauling them off.
+You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on the grab button in your active hand. An aggressive grab will allow you to place someone on a table by clicking on it, or throw them by toggling on throwing.
+You can destroy computers by shooting lasers at them.
+Holding alt and left clicking a tile will allow you to see its contents in the top right window pane, which is much faster than right clicking.
+The resist button will allow you to resist out of handcuffs, being buckled to a chair or bed, and out of locked lockers. Whenever you're stuck, try resisting!
+You can move an item out of the way by dragging it and then clicking on an adjacent tile with an empty hand.
+You can recolor certain items like jumpsuits and gloves in washing machines by also throwing in a crayon.
+Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using.
+As the Captain, you are one of the highest priority targets on the station. Everything from revolutions, to nuclear operatives, to traitors that need to rob you of your pants or your life are things to worry about.
+As the Captain, always take the nuclear disk and pinpointer with you every shift. It's a good idea to give one of these to another head who you can trust with keeping it safe, such as the Head of Security.
+As the Captain, you have absolute access and control over the station, but this does not mean that being a horrible person won't result in mutiny and a ban.
+As the Chief Medical Officer, your hypospray is like an instant injection syringe that can hold 30 units as opposed to the standard 15.
+As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and geneticists during a nuclear emergency, blob, or some other crisis to keep people alive and fighting.
+As a Medical Doctor, you can eject someone from cloning early by disabling power in genetics. Note that they will suffer more genetic damage from this.
+As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, you have confirmed the presence of changelings.
+As a Medical Doctor, charcoal will not only heal toxin damage dealt by poisons, but will actively remove them.
+As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva.
+As a Medical Doctor, you must target the correct limb and be on help intent when trying to perform surgery on someone.
+As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. Experiment!
+As a Chemist, some chemicals can only be synthesized by heating up the contents in the chemical heater.
+As a Chemist, it is a good idea to carry some sort of combat or panic pill to help you get out of a dangerous situation. A mixture of healing, speed boosting, and stun recovery chemicals can help you immensely.
+As a Geneticist, check the door to your workspace once in a while to see if there's anyone to clone.
+As a Geneticist, becoming a hulk makes you capable of dealing high melee damage, stunlocking people, and punching through walls. However, you can't fire guns, will lose your hulk status if you take too much damage, and are not considered a human by the AI while you are a hulk.
+As the Virologist, your viruses can range from healing powers so great that you can solo a blob, or diseases so dangerous they can kill the entire crew with airborne spontaneous combustion. Experiment!
+As the Research Director, you can repair and even revive AIs by loading them into an intelicard, and then from there into an AI system integrity restorer computer.
+As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled.
+As a Scientist, you can inject yourself with the mutation toxin extracted from green slimes to become a slime man, who will never be attacked by slimes.
+As a Scientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract. It is possible to get 9 times as much out of a slime this way.
+As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signalling device. This will leave behind an anomaly core, which is good for research or the construction of the Phazon mech!
+As a Scientist, researchable machine parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions.
+As a Roboticist, you can not only build cyborgs, but also drones, bots, and even mechs!
+As a Roboticist, keep an ear out for anomaly announcements. If you successfully get your hands on its core, you can build a phazon mech!
+As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery and replace their wires with a cable coil.
+As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them.
+As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt.
+As a Cyborg, choose your module carefully, as only a roboticist can let you repick it. If possible, refrain from choosing a module until a situation that requires one occurs.
+As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes can easily stunlock you and you cannot do any precision work as you lack hands.
+As a Cyborg, you are impervious to fires and heat. If you are rogue, you can release plasma fires everywhere and walk through them without a care in the world!
+As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds.
+As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints.
+As the Chief Engineer, coordinate with your engineering team to repair hull breaches as quickly as possible, so as to prevent too much air from draining.
+As the Chief Engineer, your rig suit is significantly better than everybody else's. It boasts better protection, and is completely heat and fire proof.
+As an Engineer, the supermatter shard is an extremely dangerous piece of equipment: touching it will vaporize you.
+As an Engineer, you can electrify grilles by placing wire "nodes" beneath them: the big seemingly unconnected bulges from a half completed wiring job.
+As an Engineer, return to engineering once in a while to check on the singularity and the SMES cells. It's always a good idea to make sure the containment isn't compromised.
+As an Engineer, you can power the station solely with the solar arrays. While uninteresting, it is a much safer alternative to the singularity engine.
+As an Engineer, you can repair windows by using a welding tool on them while on help intent.
+As an Engineer, your construction permit allows you to create a new area, but has only one use.
+As an Atmospheric Technician, you can unwrench a pipe regardless of the pressures of the gases inside, but if they're too high they can burst out and injure you!
+As an Atmopsheric Technician, you should look into replacing your gas pumps with volumetric gas pumps, as those move air in flat numerical amounts, rather than percentages which leave trace gases.
+As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits, nanofrost sprays, and a completely heat and fire proof rigsuit.
+As the Head of Security, you are expected to coordinate your security force to handle any threat that comes to the station. Sometimes it means making use of the armory to handle a blob, sometimes it means being ruthless during a revolution or cult.
+As the Head of Security, you can call for executions or forced cyborg-ing, but may require the Captain's approval.
+As the Head of Security, don't let the power go to your head. You may have high access, great equipment, and a miniature army at your side, but being a terrible person without a good reason is grounds for banning.
+As the Warden, your duty is to be the watchdog of the brig and handler of prisonners when little is happening, and to hand out equipment and weapons to the security officers when a crisis strikes.
+As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors.
+As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while!
+As a Security Officer, you should communicate and coordinate with your fellow officers using the security channel :s to avoid confusion.
+As a Security Officer, you can use handcuffs on orange prisoner shoes to turn them into cuffed shoes. Anyone who wears these will be forced to walk.
+As a Security Officer, your sechuds or HUDsunglasses can not only see what job someone works in and their criminal status, but also if they are loyalty implanted or not. Use this to your advantage in a revolution to definitively tell who is on your side!
+As a Security Officer, loyalty implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted.
+As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause beepsky or any other security bots to chase after them.
+As a Security Officer, implanting a gang member the first time will deconvert them, but destroy the implant. You must implant them a second time to protect them from further conversion attempts. Keep in mind that gang members have ways to destroy implants in people!
+As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department.
+As the Detective, you can use your forensics scanner from a distance.
+As the Lawyer, try to negotiate with the Warden if sentences seem too high for the crime.
+As the Head of Personnel, you are not higher ranking than other heads of staff, even though you are expected to take the Captain's place first should he go missing. If the situation seems too rough for you, consider allowing another head to become temporary Captain.
+As the Head of Personnel, you are often just as large a target as the Captain because of the potential power your ID and computer can hand out.
+As the Mime, you can place invisible walls that last for a short time to block other people. You can use it in a pinch to delay your pursuer.
+As the Clown, if you lose your banana peel, you can still slip people with your PDA! Honk!
+As the Clown, you have the clumsiness genetic defect, and will misfire guns if you try to fire them.
+As the Chaplain, your null rod has a lot of functions: it can convert water into holy water, which if spread on the ground prevents wizards from jaunting away, can destroy cultist runes by hitting them, and is a very powerful weapon to boot!
+As the Chaplain, your bible can heal people if you hit them with it, but it can also potentially cause brain damage. Use at your own risk!
+As the Chaplain, you are much more likely to get a response by praying to the gods than most people. To boost your chances, make altars with colorful crayon runes, lit candles, and wire art.
+As a Botanist, you can hack the MegaSeed Vendor to get access to more exotic seeds. These seeds can alternatively be ordered from cargo.
+As a Botanist, you can mutate the plants growing in your hydroponics trays with unstable mutagen from chemistry to get special variations.
+As a Botanist, you should look into increasing the potency of your plants. This increases the size, amount of chemicals, points gained from grinding them in the biogenerator, and lets people know you are a proficient botanist.
+As the Chef, you can load your food into snack vending machines.
+As the Chef, you can rename your custom made food with a pen.
+As the Chef, any food you make will be much healthier than the junk food found in vendors. Having the crew routinely eating from you will provide minor buffs.
+As the Bartender, the drinks you start with only give you the basics. If you want more advanced mixtures, look into working with chemistry, hydroponics, or even mining for things to grind up and throw in!
+As a Cargo Technician, you can hack mulebots to make them faster, run over people in their way, and even let you ride them!
+As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it.
+As a Shaft Miner, the west side of the asteroid has a lot more minerals than on the east, but also has monsters there.
+As a Shaft Miner, every monster on the west side of the asteroid has a pattern for you to learn, you can exploit this to minimize damage from the encounters.
+As a Shaft Miner, you can harvest goliath plates from goliaths and upgrade your rigsuit with it, greatly reducing incoming melee damage.
+As a Shaft Miner, you should always turn your jumpsuit sensors to maximum, a fellow miner or cyborg may come to save you if you die.
+As a Traitor, the cryptographic sequencer (emag) can not only open doors, but also lockers, crates, APCs and more. It can hack cyborgs, and even cause bots to go berserk. Experiment!
+As a Traitor, subverting the AI to serve you can make it an extremely powerful ally. However, be careful of the wording in the laws you give it, as it may use your poorly written laws against you!
+As a Traitor, the Captain and the Head of Security are two of the most difficult to kill targets on the station. If either one is your target, plan carefully.
+As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool.
+As a Traitor, you may sometimes be assigned to hunt other traitors, and in turn be hunted by others.
+As a Nuclear Operative, communication is key! Use :t or :h to speak to your fellow operatives and coordinate an attack plan.
+As a Nuclear Operative, you should look into purchasing a syndicate cyborg, as they can provide heavy fire support, full access, and are immune to conventional stuns.
+As a Nuclear Operative, stick together! While your equipment may save you from a lucky disarm or skillful taser bolt, your fellow operative are much better at saving your life: they can drag you away from danger while stunned and provide cover fire.
+As a Nuclear Operative, remember that capturing the disk and arming the Nuke is your task, don't just wander off and kill random people!
+As a Nuclear Operative, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life.
+As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however.
+As a Monkey, you can still wear a few human items, like backpacks and gas masks, and still have two free hands. Remember that you cannot use guns!
+As a Malfunctioning AI, you can shunt to an APC if the situation gets bad. This can allow the clock to tick down long enough for you to win, but keep in mind the crew's pinpointer will point to you when you do this.
+As a Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them.
+As a Malfunctioning AI, you should look into flooding the station with plasma fires to kill off large portions of the crew, letting you pick off the remaining few with space suits who escaped.
+As a Malfunctioning AI, never stop hacking APCs as it will continue to reduce the time left to win.
+As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation!
+As an Alien, you take double damage from all burn attacks, such as lasers, welding tools, and fires. Furthermore, fire can destroy your resin and eggs. Expose areas to space to starve away any flamethrower fires before they can do damage!
+As an Alien, resin floors not only regenerate your plasma supply, but also passively heal you. Fight on resin floors to gain a home turf advantage!
+As an Alien, the facehugger is by far your most powerful weapon because of its ability to instantly win a fight. Remember however that certain helmets, such as biohoods or space helmets will completely block facehugger attacks.
+As an Alien, you are unable to pick up or use any human items or machinery. Instead, you should focus on sabotaging APCs, computers, cameras and either stowing, spacing, or melting any weapons you find.
+As the Blob, you will spawn from your character from between a minute to 5 minutes after the round starts. Use this time to find a safe and well hidden location and evaluate where you will strike!
+As the Blob, you can do various sabotage before you spawn, such as spacing the armory or disabling R&D.
+As the Blob, keep your core some distance from space, as it is both expensive to expand onto space and easy to be attacked from. Emitter platforms built in space are especially dangerous.
+As the Blob, if you invest into the split consciousness ability, it will create a second blob core, from a node, controlled by another player with a different reagent of their own. Coordinate and communicate your attacks and reactions with them!
+As the Blob, you can randomly repick your reagent type if the crew has adapted and protected themselves against your current one.
+As the Blob, you fight a war of attrition: Take out medbay and fight in chokepoints to prevent continued assaults and coordinated burst damage attacks!
+As the Blob, remember that you can only expand onto tiles from cardinal directions, while the crew can attack you diagonally. Fight in narrow corridors or expand and widen across the width of the hallway to force confrontations where you can hit them!
+As the Blob, don't neglect the creation of factories. These create spores that carry your reagent and can chase crewmembers far further than you. Spores can also be rallied to swarm the crew and cause panic, and can even take over corpses to create much more dangerous blob zombies!
+As a Revolutionary, you cannot convert a head of staff or someone who has a loyalty implant, such as a security officer or those they implant. Implants can however be surgically removed, and do not carry over with cloning. Take control of medbay to keep control of conversions!
+As a Revolutionary, cargo bay can be your best friend or your worst nightmare. In the best case scenario you will be able to order a limitless amount of guns and armor, in the worst case scenario security will take control and order a limitless number of loyalty implants to turn your fellow revolutionaries against you.
+As a Revolutionary, your main power comes from how quickly you spread. Convert people as fast as you can and overwhelm the heads of staff before they can make it to security.
+As a Changeling, the Steal DNA sting from changelings counts for your genome absorb objective, but does not let you change your powers.
+As a Changeling, you can absorb someone by grabbing them around the neck and using the Absorb verb; this gives you the ability to rechoose your powers, the DNA of whoever you absorbed, the memory of the absorbed, and some samples of things the absorbed said.
+As a Shadowling, you can only have 5 thralls on your side while keeping your human form. After that, you must turn into a shadowling to convert more thralls.
+As a Shadowling, remember to communicate with your fellow shadowlings and thralls as you lack the firepower to take on much of anything by yourself until you ascend.
+As a Cultist, invest in taking over xenobio, an adamantine golem army can quickly be converted into cultists and constructs.
+As a Cultist, do not cause too much chaos before your objective is completed. If the shuttle gets called too soon, you may not have enough time to win.
+As a Cultist, your team starts off very weak, but if necessary can quickly convert everything they have into raw power. Make sure you have the numbers and equipment to support going loud, or the cult will fall flat on its face.
+As a Cultist, the Blood Boil rune instantly crits all non-cultists who can see it, but has a chance to explode runes near it, incuding itself.
+As a Cultist, you can create an army of manifested goons using a combination of the Manifest rune, which creates homunculi from ghosts, and the Blood Drain rune, which drains life from anyone standing on any blood drain rune.
+As a Cultist, you can communicate with your fellow cultists with your tome. If that's not available, you can use the Communicate verb at an extreme health cost.
+You can deconvert Cultists by feeding them large amounts of holy water.
+As a Wizard, you can turn people to stone, then animate it with a staff of animation to create an extremely powerful minion, for all of 5 minutes at least.
+As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways.
+As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a pea shooter to a BFG 9000. Use at your own risk!
+As a Wizard, the staff of chaos can fire any type of bolts from the magical wands. This can range from bolts of instant death to accidentally healing or reviving someone.
+As a Wizard, most spells become unusable if you are not wearing your robes, hat, and sandals.
+As a Gangster, you can destroy loyalty implants with an implant breaker, letting you reconvert that person.It actually converts them, past implants or gang status(though not the captain)
+As a Gangster, your influence is based on how many areas you have tagged and how many people are wearing your gang's outfit; more areas and more people wearing the outfit will give you more influence.
+As a Gang Boss, it is wise to promote at least one other person you think is good or effective, preferably two, as a backup if you get caught by security or enemy gangsters.
+Gang outfits are very robust, giving moderate resistances to most direct damage at the cost of stealth.
+As an Abductor, you can select where your victims will be sent on the ship control console.
+As an Abductor Agent, the combat mode vest has much higher resistance to every kind of weapon, and your helmet prevents the AI from tracking you.
+As an Abductor, the baton is set up to allow you to rapidly stun, sleep, and cuff: From stun mode, it cyles to sleep, then to cuff, allowing you to render a target helpless and unable to communicate very rapidly.
+As a Ghost, you can see the inside of a container on the ground by clicking on it.
+As a Ghost, you can double click on people, bots, or the singularity to follow them.
\ No newline at end of file
diff --git a/html/changelog.html b/html/changelog.html
index 8c6e8a125ef..3ce048bd829 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -55,6 +55,185 @@
-->
+
07 August 2015
+
KorPhaeron updated:
+
+
Added a new Guardian Mob that can be summoned to manifest inside a mob.
+
Guardians can communicate with their host and materialize themselves to protect their host with magic powers.
+
Guardians are invincible but cannot live without or too far from their host, they also relay injuries they suffer to the host.
+
+
Phil235 updated:
+
+
Fixed being able to run into your own bullet.
+
+
RemieRichards updated:
+
+
You no longer need to click on an item in a storage container to remove it, clicking anywhere around the item works.
+
+
bustygoku updated:
+
+
Removed the chance for a disease to make you a carrier on transfer.
+
+
phil235 updated:
+
+
The plasma cutter's fire rate is now a bit lower but its projectile can pierce multiple asteroid walls and its range isn't lowered in pressurized environment anymore.
+
+
+
06 August 2015
+
AnturK updated:
+
+
Adds the voodoo doll as a mining treasure, link it with a victim with an item previously held by them.
+
Once linked the voodoo doll can be used to injure, confuse and control the victim.
+
+
Core0verlad updated:
+
+
Items can now be removed from storage containers inside storage containers.
+
Beds and bedsheets have new sprites.
+
MMIs are no longer ID locked.
+
+
KorPhaeron updated:
+
+
Slaughter Demon's have had their health reduced to 200 and their speed reduced but they get a speed boost when exiting blood.
+
+
MrPerson updated:
+
+
Items stacks now automatically merge unless thrown when moved onto the same tile.
+
+
+
05 August 2015
+
CoreOverload updated:
+
+
Implants, implant cases and implanters got RnD levels and can be DA'ed for science.
+
Surgically removed implant can be placed into an implant case. Remove implant with empty implant case in inactive hand.
+
Surgical steps now got progress bars.
+
You can cancel a surgery by using drape on operable body part again. This works only before you perform surgery's first step.
+
Operating computer shows next step for surgeries. No more alt-tabbing to view next step on wiki while operating.
+
You cannot start two surgeries on one body part at once. You can start two multiloc surgeries (i.e. two augumentations) on diffirent body parts at once.
+
Monkey <-> Human transformations now keep your internal organs, cyberimplants and xeno embryos included.
+
+
Ikarrus updated:
+
+
Head beatings no longer deconvert gangsters.
+
+
LordPidey updated:
+
+
Added a new chemical. Spray tan. It is made by mixing orange juice with oil or corn oil. Warning: overexposure may result in orange douchebaggery.
+
+
Xhuis updated:
+
+
Shadowling thralls can now be deconverted via surgery or borging.
+
Thralls can be revealed by examining them. They can hide this by wearing a mask.
+
Thralls have a few minor abilities they can use in addition to night vision.
+
Hatch-exclusive abilities can no longer be used if you are not the shadowling mutant race.
+
Ascendants are now immune to bombs and singularities. Honk.
+
A Centcom report has been added for shadowlings.
+
Ascending no longer kills all shadowling thralls. This allows antagonists who were enthralled to succeed along with the ascendants.
+
Annihilate now has different sound and a shorter delay before the target explodes. In addition, it now works on all mobs, instead of just humans.
+
Glacial Blast now properly has no cooldown if used while phase shifting.
+
Fixes a runtime if a target with no mind is enthralled.
+
+
bgobandit updated:
+
+
Nanotrasen scientists have achieved the tremendous breakthrough of injecting gold slime extracts with water. Pets ensued.
+
+
+
04 August 2015
+
Kor updated:
+
+
Soulstones will now attempt to pull ghosts from beyond if the targeted corpse has no soul.
+
+
Summoner99 updated:
+
+
Added the *roar emote back to Alien Larva
+
Fixed aliens not being able to do the *hiss and *screech emotes
+
Changed how the plural emote system works and now some emotes have plural versions, example is: *hiss and *hisses.
+
+
+
02 August 2015
+
Incoming5643 updated:
+
+
Syndicate toolboxes now come with never before seen red insulated gloves.
+
+
Steelpoint updated:
+
+
Fixed multiple mapping errors for Boxstation and the mining base.
+
A circuit imprinter and exosuit fabrication board have been added to tech storage.
+
+
SvartaSvansen updated:
+
+
Our lizard engineers have worked hard and managed to improve Centcom airlocks so they no longer disintegrate when the electronics are removed!
+
Put a safety net in place so future airlocks without assemblies produce the default assembly instead of disintegrating.
+
+
+
30 July 2015
+
Gun Hog updated:
+
+
The Reactivate Camera power for Malfunctining AIs now costs 10 CPU, and works on the entire camera network, up to 30 cameras fixed.
+
The Upgrade Cameras power now costs 35 CPU, upgrades all cameras in the network to have EMP proofing, X-ray, and gives the AI night-vision.
+
+
Ikarrus updated:
+
+
Door Access buttons can now be emagged to remove access restrictions.
+
+
LordPidey updated:
+
+
Added a new medication, Miner's Salve. It heals brute/burn damage over time, and has the side effect of making the patient think their wounds are fully healed. It is mixed with water+iron+oil, or grind a twinkie, a sheet of metal, and a sheet of plasma.
+
Added a grinder to the mining station.
+
+
Midaychi updated:
+
+
Random loot has been added to the derelict as salvage for drones.
+
+
Scones updated:
+
+
Adds a Rice Hat to the biogenerator.
+
+
+
29 July 2015
+
AnturK updated:
+
+
Aliens can now mine through asteroid rock.
+
+
GunHog updated:
+
+
Cyborg headlamps have a short cooldown before reactivation when forcibly deactivated.
+
Shadowling's Veil now shuts down headlamps for the ability's entire duration.
+
+
Kor updated:
+
+
Eating the heart of a Slaughter Demon will grant you dark powers.
+
+
freerealestate updated:
+
+
Fixed bug where copying with ctrl+C didn't work due to it being assigned to resist.
+
Changed resist to B (hotkeys mode) and ctrl+B (either mode) instead.
+
Removed End resist from cyborgs.
+
+
+
28 July 2015
+
Anonus updated:
+
+
New gang tags for Omni and Prima gangs.
+
+
Chiefwaffles updated:
+
+
After realizing how often AIs tend to 'disappear', Central Command has authorized the shipment of the Automated Announcement System to take over the AI's responsibility of announcing new arrivals.
+
In addition, users are able to configure the messages to their liking. Early testing has shown that this feature may be vulnerable to malicious external elements!
+
The station's R&D software has been updated so it can now succesfully create its own prototype AAS board once the prerequisite levels have been met.
+
+
Dorsisdwarf updated:
+
+
Increased the cost of Bioterror darts to 6TC.
+
+
Incoming5643 updated:
+
+
Double Agents no longer know they're Double Agents and not just standard Traitors.
+
+
xxalpha updated:
+
+
Removed Anti-Drop and Nutriment Pump implants from Nuclear Operative's uplink.
+
+
27 July 2015
Bgobandit updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 2aedf02ebd7..30c91c7ebd4 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -1372,3 +1372,149 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
kingofkosmos:
- rscadd: Added a link to re-enter corpse to alert when your body is placed in a
cloning scanner.
+2015-07-28:
+ Anonus:
+ - imageadd: New gang tags for Omni and Prima gangs.
+ Chiefwaffles:
+ - rscadd: After realizing how often AIs tend to 'disappear', Central Command has
+ authorized the shipment of the Automated Announcement System to take over the
+ AI's responsibility of announcing new arrivals.
+ - rscadd: In addition, users are able to configure the messages to their liking.
+ Early testing has shown that this feature may be vulnerable to malicious external
+ elements!
+ - rscadd: The station's R&D software has been updated so it can now succesfully
+ create its own prototype AAS board once the prerequisite levels have been met.
+ Dorsisdwarf:
+ - tweak: Increased the cost of Bioterror darts to 6TC.
+ Incoming5643:
+ - experiment: Double Agents no longer know they're Double Agents and not just standard
+ Traitors.
+ xxalpha:
+ - rscdel: Removed Anti-Drop and Nutriment Pump implants from Nuclear Operative's
+ uplink.
+2015-07-29:
+ AnturK:
+ - rscadd: Aliens can now mine through asteroid rock.
+ GunHog:
+ - tweak: Cyborg headlamps have a short cooldown before reactivation when forcibly
+ deactivated.
+ - bugfix: Shadowling's Veil now shuts down headlamps for the ability's entire duration.
+ Kor:
+ - rscadd: Eating the heart of a Slaughter Demon will grant you dark powers.
+ freerealestate:
+ - bugfix: Fixed bug where copying with ctrl+C didn't work due to it being assigned
+ to resist.
+ - rscadd: Changed resist to B (hotkeys mode) and ctrl+B (either mode) instead.
+ - rscdel: Removed End resist from cyborgs.
+2015-07-30:
+ Gun Hog:
+ - tweak: The Reactivate Camera power for Malfunctining AIs now costs 10 CPU, and
+ works on the entire camera network, up to 30 cameras fixed.
+ - tweak: The Upgrade Cameras power now costs 35 CPU, upgrades all cameras in the
+ network to have EMP proofing, X-ray, and gives the AI night-vision.
+ Ikarrus:
+ - rscadd: Door Access buttons can now be emagged to remove access restrictions.
+ LordPidey:
+ - rscadd: Added a new medication, Miner's Salve. It heals brute/burn damage over
+ time, and has the side effect of making the patient think their wounds are fully
+ healed. It is mixed with water+iron+oil, or grind a twinkie, a sheet of metal,
+ and a sheet of plasma.
+ - rscadd: Added a grinder to the mining station.
+ Midaychi:
+ - rscadd: Random loot has been added to the derelict as salvage for drones.
+ Scones:
+ - rscadd: Adds a Rice Hat to the biogenerator.
+2015-08-02:
+ Incoming5643:
+ - rscadd: Syndicate toolboxes now come with never before seen red insulated gloves.
+ Steelpoint:
+ - bugfix: Fixed multiple mapping errors for Boxstation and the mining base.
+ - rscadd: A circuit imprinter and exosuit fabrication board have been added to tech
+ storage.
+ SvartaSvansen:
+ - rscadd: Our lizard engineers have worked hard and managed to improve Centcom airlocks
+ so they no longer disintegrate when the electronics are removed!
+ - tweak: Put a safety net in place so future airlocks without assemblies produce
+ the default assembly instead of disintegrating.
+2015-08-04:
+ Kor:
+ - rscadd: Soulstones will now attempt to pull ghosts from beyond if the targeted
+ corpse has no soul.
+ Summoner99:
+ - rscadd: Added the *roar emote back to Alien Larva
+ - bugfix: Fixed aliens not being able to do the *hiss and *screech emotes
+ - tweak: 'Changed how the plural emote system works and now some emotes have plural
+ versions, example is: *hiss and *hisses.'
+2015-08-05:
+ CoreOverload:
+ - rscadd: Implants, implant cases and implanters got RnD levels and can be DA'ed
+ for science.
+ - rscadd: Surgically removed implant can be placed into an implant case. Remove
+ implant with empty implant case in inactive hand.
+ - rscadd: Surgical steps now got progress bars.
+ - rscadd: You can cancel a surgery by using drape on operable body part again. This
+ works only before you perform surgery's first step.
+ - rscadd: Operating computer shows next step for surgeries. No more alt-tabbing
+ to view next step on wiki while operating.
+ - tweak: You cannot start two surgeries on one body part at once. You can start
+ two multiloc surgeries (i.e. two augumentations) on diffirent body parts at
+ once.
+ - tweak: Monkey <-> Human transformations now keep your internal organs, cyberimplants
+ and xeno embryos included.
+ Ikarrus:
+ - rscdel: Head beatings no longer deconvert gangsters.
+ LordPidey:
+ - rscadd: 'Added a new chemical. Spray tan. It is made by mixing orange juice with
+ oil or corn oil. Warning: overexposure may result in orange douchebaggery.'
+ Xhuis:
+ - rscadd: Shadowling thralls can now be deconverted via surgery or borging.
+ - rscadd: Thralls can be revealed by examining them. They can hide this by wearing
+ a mask.
+ - rscadd: Thralls have a few minor abilities they can use in addition to night vision.
+ - rscadd: Hatch-exclusive abilities can no longer be used if you are not the shadowling
+ mutant race.
+ - rscadd: Ascendants are now immune to bombs and singularities. Honk.
+ - rscadd: A Centcom report has been added for shadowlings.
+ - tweak: Ascending no longer kills all shadowling thralls. This allows antagonists
+ who were enthralled to succeed along with the ascendants.
+ - tweak: Annihilate now has different sound and a shorter delay before the target
+ explodes. In addition, it now works on all mobs, instead of just humans.
+ - bugfix: Glacial Blast now properly has no cooldown if used while phase shifting.
+ - bugfix: Fixes a runtime if a target with no mind is enthralled.
+ bgobandit:
+ - rscadd: Nanotrasen scientists have achieved the tremendous breakthrough of injecting
+ gold slime extracts with water. Pets ensued.
+2015-08-06:
+ AnturK:
+ - rscadd: Adds the voodoo doll as a mining treasure, link it with a victim with
+ an item previously held by them.
+ - rscadd: Once linked the voodoo doll can be used to injure, confuse and control
+ the victim.
+ Core0verlad:
+ - tweak: Items can now be removed from storage containers inside storage containers.
+ - imageadd: Beds and bedsheets have new sprites.
+ - rscdel: MMIs are no longer ID locked.
+ KorPhaeron:
+ - tweak: Slaughter Demon's have had their health reduced to 200 and their speed
+ reduced but they get a speed boost when exiting blood.
+ MrPerson:
+ - rscadd: Items stacks now automatically merge unless thrown when moved onto the
+ same tile.
+2015-08-07:
+ KorPhaeron:
+ - rscadd: Added a new Guardian Mob that can be summoned to manifest inside a mob.
+ - rscadd: Guardians can communicate with their host and materialize themselves to
+ protect their host with magic powers.
+ - rscadd: Guardians are invincible but cannot live without or too far from their
+ host, they also relay injuries they suffer to the host.
+ Phil235:
+ - bugfix: Fixed being able to run into your own bullet.
+ RemieRichards:
+ - rscadd: You no longer need to click on an item in a storage container to remove
+ it, clicking anywhere around the item works.
+ bustygoku:
+ - rscdel: Removed the chance for a disease to make you a carrier on transfer.
+ phil235:
+ - tweak: The plasma cutter's fire rate is now a bit lower but its projectile can
+ pierce multiple asteroid walls and its range isn't lowered in pressurized environment
+ anymore.
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 5102b40d59e..20d01058d96 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/effects/station_explosion.dmi b/icons/effects/station_explosion.dmi
index 6ce74dbb36d..7dcab377107 100644
Binary files a/icons/effects/station_explosion.dmi and b/icons/effects/station_explosion.dmi differ
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
index 3e1cad74483..7419670c30b 100644
Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ
diff --git a/icons/mob/drone.dmi b/icons/mob/drone.dmi
index b27a8cba56c..e4c4b84990e 100644
Binary files a/icons/mob/drone.dmi and b/icons/mob/drone.dmi differ
diff --git a/icons/mob/hands.dmi b/icons/mob/hands.dmi
index 4b83c7049ad..bc891041241 100644
Binary files a/icons/mob/hands.dmi and b/icons/mob/hands.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 25b82024413..0d71c5a326b 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi
index 8f40f6a41ec..2156fd46e0a 100644
Binary files a/icons/mob/human.dmi and b/icons/mob/human.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index f4536caa9a3..76d807e61d8 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index ea688d4249d..c7876bb0b7c 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/atmospherics/components/unary_devices.dmi b/icons/obj/atmospherics/components/unary_devices.dmi
index 6681804dd4f..b1c7922190b 100644
Binary files a/icons/obj/atmospherics/components/unary_devices.dmi and b/icons/obj/atmospherics/components/unary_devices.dmi differ
diff --git a/icons/obj/atmospherics/pipes/disposal.dmi b/icons/obj/atmospherics/pipes/disposal.dmi
index 086915ed3eb..b0a9b58b0d7 100644
Binary files a/icons/obj/atmospherics/pipes/disposal.dmi and b/icons/obj/atmospherics/pipes/disposal.dmi differ
diff --git a/icons/obj/bedsheets.dmi b/icons/obj/bedsheets.dmi
new file mode 100644
index 00000000000..a91c635f502
Binary files /dev/null and b/icons/obj/bedsheets.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index e44ddedfcd4..a9bb0a68c02 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi
index b7dfaae07e9..5d6f9793862 100644
Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index dde23fe77b9..2b240f50571 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index 4fbc9bd674a..95b18b2e916 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/doors/door_assembly.dmi b/icons/obj/doors/door_assembly.dmi
index 94ed8ac6c2d..06689649d8e 100644
Binary files a/icons/obj/doors/door_assembly.dmi and b/icons/obj/doors/door_assembly.dmi differ
diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi
index fb3f05626c2..39a49078881 100644
Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index f05c3b70f5f..f4c5ae1d242 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/machines/telecomms.dmi b/icons/obj/machines/telecomms.dmi
index f47fcc63f87..7f5f05e3aff 100644
Binary files a/icons/obj/machines/telecomms.dmi and b/icons/obj/machines/telecomms.dmi differ
diff --git a/icons/obj/nuke_tools.dmi b/icons/obj/nuke_tools.dmi
index 4b604712a71..f052b552e13 100644
Binary files a/icons/obj/nuke_tools.dmi and b/icons/obj/nuke_tools.dmi differ
diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi
index 94ccf0c8d2f..bc58bdbc837 100644
Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ
diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi
index cc0325cdfae..72ef46c7163 100644
Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ
diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi
index c2f7bfcc202..c9d0f461bc5 100644
Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ
diff --git a/install-byond.sh b/install-byond.sh
new file mode 100644
index 00000000000..da2756a8df2
--- /dev/null
+++ b/install-byond.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+set -e
+if [ -d "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin" ];
+then
+ echo "Using cached directory."
+else
+ echo "Setting up BYOND."
+ mkdir -p "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}"
+ cd "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}"
+ curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip
+ unzip byond.zip
+ cd byond
+ make here
+fi
\ No newline at end of file
diff --git a/interface/interface.dm b/interface/interface.dm
index 348d110e134..a97aa48e385 100644
--- a/interface/interface.dm
+++ b/interface/interface.dm
@@ -91,7 +91,7 @@ Hotkey-Mode: (hotkey-mode must be on)
\tm = me
\tt = say
\to = OOC
-\tc = resist
+\tb = resist
\tx = swap-hand
\tz = activate held object (or y)
\tf = cycle-intents-left
@@ -111,7 +111,7 @@ Any-Mode: (hotkey doesn't need to be on)
\tCtrl+q = drop
\tCtrl+e = equip
\tCtrl+r = throw
-\tCtrl+c = resist
+\tCtrl+b = resist
\tCtrl+x = swap-hand
\tCtrl+z = activate held object (or Ctrl+y)
\tCtrl+f = cycle-intents-left
@@ -142,7 +142,7 @@ Hotkey-Mode: (hotkey-mode must be on)
\tq = unequip active module
\tt = say
\tx = cycle active modules
-\tc = resist
+\tb = resist
\tz = activate held object (or y)
\tf = cycle-intents-left
\tg = cycle-intents-right
@@ -160,7 +160,7 @@ Any-Mode: (hotkey doesn't need to be on)
\tCtrl+w = up
\tCtrl+q = unequip active module
\tCtrl+x = cycle active modules
-\tCtrl+c = resist
+\tCtrl+b = resist
\tCtrl+z = activate held object (or Ctrl+y)
\tCtrl+f = cycle-intents-left
\tCtrl+g = cycle-intents-right
diff --git a/interface/skin.dmf b/interface/skin.dmf
index cc847abc342..7db57837c75 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -100,11 +100,11 @@ macro "borghotkeymode"
command = ".west"
is-disabled = false
elem
- name = "C"
+ name = "B"
command = "resist"
is-disabled = false
elem
- name = "CTRL+C"
+ name = "CTRL+B"
command = "resist"
is-disabled = false
elem
@@ -306,7 +306,7 @@ macro "macro"
command = ".west"
is-disabled = false
elem
- name = "CTRL+C"
+ name = "CTRL+B"
command = "resist"
is-disabled = false
elem
@@ -496,11 +496,11 @@ macro "hotkeymode"
command = ".west"
is-disabled = false
elem
- name = "C"
+ name = "B"
command = "resist"
is-disabled = false
elem
- name = "CTRL+C"
+ name = "CTRL+B"
command = "resist"
is-disabled = false
elem
@@ -657,10 +657,6 @@ macro "borgmacro"
name = "SOUTHEAST"
command = ".southeast"
is-disabled = false
- elem
- name = "SOUTHWEST"
- command = "resist"
- is-disabled = false
elem
name = "NORTHWEST"
command = "unequip-module"
@@ -726,7 +722,7 @@ macro "borgmacro"
command = ".west"
is-disabled = false
elem
- name = "CTRL+C"
+ name = "CTRL+B"
command = "resist"
is-disabled = false
elem
@@ -1229,6 +1225,8 @@ window "chemdispenser"
keep-aspect = false
align = center
text-wrap = false
+ allow-html = false
+ letterbox = true
elem "eject"
type = BUTTON
pos = 264,4
@@ -1395,6 +1393,8 @@ window "chemdispenser"
keep-aspect = false
align = center
text-wrap = false
+ allow-html = false
+ letterbox = true
elem "child1"
type = CHILD
pos = 0,40
@@ -1516,6 +1516,8 @@ window "chemdispenser_reagents"
keep-aspect = false
align = center
text-wrap = false
+ allow-html = false
+ letterbox = true
window "mainwindow"
elem "mainwindow"
@@ -1726,6 +1728,8 @@ window "mapwindow"
on-size = ""
icon-size = 0
text-mode = false
+ letterbox = true
+ zoom = 0
on-show = ".winset\"mainwindow.mainvsplit.left=mapwindow\""
on-hide = ".winset\"mainwindow.mainvsplit.left=\""
style = ""
@@ -2254,4 +2258,6 @@ window "infowindow"
on-show = ".winset\"rpane.infob.is-visible=true;rpane.browseb.is-visible=true?rpane.infob.pos=130,0:rpane.infob.pos=65,0 rpane.textb.is-visible=true rpane.infob.is-checked=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0 rpane.rpanewindow.left=infowindow\""
on-hide = ".winset\"rpane.infob.is-visible=false;rpane.browseb.is-visible=true?rpane.browseb.is-checked=true rpane.rpanewindow.left=browserwindow:rpane.textb.is-visible=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0 rpane.rpanewindow.left=\""
on-tab = ""
+ prefix-color = none
+ suffix-color = none
diff --git a/tgstation.dme b/tgstation.dme
index 56abaadb801..c74ce5cdc57 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -381,6 +381,7 @@
#include "code\game\machinery\ai_slipper.dm"
#include "code\game\machinery\airlock_control.dm"
#include "code\game\machinery\alarm.dm"
+#include "code\game\machinery\announcement_system.dm"
#include "code\game\machinery\atmo_control.dm"
#include "code\game\machinery\autolathe.dm"
#include "code\game\machinery\Beacon.dm"
@@ -676,10 +677,13 @@
#include "code\game\objects\items\weapons\grenades\spawnergrenade.dm"
#include "code\game\objects\items\weapons\grenades\syndieminibomb.dm"
#include "code\game\objects\items\weapons\implants\implant.dm"
+#include "code\game\objects\items\weapons\implants\implant_chem.dm"
+#include "code\game\objects\items\weapons\implants\implant_explosive.dm"
+#include "code\game\objects\items\weapons\implants\implant_freedom.dm"
+#include "code\game\objects\items\weapons\implants\implant_loyality.dm"
#include "code\game\objects\items\weapons\implants\implantcase.dm"
#include "code\game\objects\items\weapons\implants\implantchair.dm"
#include "code\game\objects\items\weapons\implants\implanter.dm"
-#include "code\game\objects\items\weapons\implants\implantfreedom.dm"
#include "code\game\objects\items\weapons\implants\implantpad.dm"
#include "code\game\objects\items\weapons\implants\implantuplink.dm"
#include "code\game\objects\items\weapons\melee\energy.dm"
@@ -834,6 +838,7 @@
#include "code\modules\admin\verbs\fps.dm"
#include "code\modules\admin\verbs\getlogs.dm"
#include "code\modules\admin\verbs\machine_upgrade.dm"
+#include "code\modules\admin\verbs\manipulate_organs.dm"
#include "code\modules\admin\verbs\mapping.dm"
#include "code\modules\admin\verbs\massmodvar.dm"
#include "code\modules\admin\verbs\modifyvariables.dm"
@@ -1091,6 +1096,7 @@
#include "code\modules\mob\dead\observer\logout.dm"
#include "code\modules\mob\dead\observer\observer.dm"
#include "code\modules\mob\dead\observer\say.dm"
+#include "code\modules\mob\living\bloodcrawl.dm"
#include "code\modules\mob\living\damage_procs.dm"
#include "code\modules\mob\living\death.dm"
#include "code\modules\mob\living\emote.dm"
@@ -1236,6 +1242,7 @@
#include "code\modules\mob\living\simple_animal\friendly\drone\say.dm"
#include "code\modules\mob\living\simple_animal\friendly\drone\verbs.dm"
#include "code\modules\mob\living\simple_animal\friendly\drone\visuals_icons.dm"
+#include "code\modules\mob\living\simple_animal\guardian\guardian.dm"
#include "code\modules\mob\living\simple_animal\hostile\alien.dm"
#include "code\modules\mob\living\simple_animal\hostile\bear.dm"
#include "code\modules\mob\living\simple_animal\hostile\bees.dm"
@@ -1432,7 +1439,8 @@
#include "code\modules\reagents\reagent_containers\syringes.dm"
#include "code\modules\recycling\conveyor2.dm"
#include "code\modules\recycling\disposal-construction.dm"
-#include "code\modules\recycling\disposal.dm"
+#include "code\modules\recycling\disposal-structures.dm"
+#include "code\modules\recycling\disposal-unit.dm"
#include "code\modules\recycling\sortingmachinery.dm"
#include "code\modules\research\circuitprinter.dm"
#include "code\modules\research\designs.dm"
@@ -1486,6 +1494,7 @@
#include "code\modules\surgery\cavity_implant.dm"
#include "code\modules\surgery\core_removal.dm"
#include "code\modules\surgery\cybernetic_implants.dm"
+#include "code\modules\surgery\dethrall.dm"
#include "code\modules\surgery\eye_surgery.dm"
#include "code\modules\surgery\gender_reassignment.dm"
#include "code\modules\surgery\generic_steps.dm"
@@ -1499,10 +1508,12 @@
#include "code\modules\surgery\surgery_step.dm"
#include "code\modules\surgery\tools.dm"
#include "code\modules\surgery\xenomorph_removal.dm"
-#include "code\modules\surgery\organs\augments.dm"
-#include "code\modules\surgery\organs\cybernetic_implants.dm"
+#include "code\modules\surgery\organs\augments_external.dm"
+#include "code\modules\surgery\organs\augments_eyes.dm"
+#include "code\modules\surgery\organs\augments_internal.dm"
#include "code\modules\surgery\organs\helpers.dm"
-#include "code\modules\surgery\organs\organ.dm"
+#include "code\modules\surgery\organs\organ_external.dm"
+#include "code\modules\surgery\organs\organ_internal.dm"
#include "code\modules\telesci\bscrystal.dm"
#include "code\modules\telesci\gps.dm"
#include "code\modules\telesci\telepad.dm"
diff --git a/tools/dmm2tgm/dmm2tgm.py b/tools/dmm2tgm/dmm2tgm.py
deleted file mode 100644
index ae22a073eee..00000000000
--- a/tools/dmm2tgm/dmm2tgm.py
+++ /dev/null
@@ -1,79 +0,0 @@
-
-import sys
-
-# .dmm format converter, by RemieRichards
-# Version 2.0
-# Converts the internal structure of a .dmm file to a syntax
-# that git can better handle conflicts-wise, it's also fairly human readable!
-# Processes Boxstation (tgstation.2.1.3) almost instantly
-
-#TWEAKABLE VARIABLES
-map_file = "tgstation.2.1.3.dmm" #Map file, .dmm or .txt
-output_file = "" #Output file, .dmm or .txt, leave blank to overwrite map_file
-
-
-#CHECK FOR PREVIOUS CONVERSION
-with open(map_file, "r") as conversion_candidate:
- header = conversion_candidate.readline()
- if header.find("//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE") != -1:
- sys.exit("This map has already been converted, cancelling...")
-
-
-#ACTUAL CONVERSION
-with open(map_file, "r+") as unconverted_map:
- characters = unconverted_map.read()
- converted_map = ""
- in_object_block = False #()
- in_variable_block = False #{}
- in_quote_block = False #''
- in_double_quote_block = False #""
- for char in characters:
- if char == "(" :
- if not in_object_block:
- if not in_quote_block:
- if not in_double_quote_block:
- if not in_variable_block:
- in_object_block = True
- char = char + "\n"
- if char == ")":
- if in_object_block:
- if not in_quote_block:
- if not in_double_quote_block:
- if not in_variable_block:
- in_object_block = False
- if char == "{":
- in_variable_block = True
- if in_object_block:
- char = char + "\n\t"
- if char == "}":
- in_variable_block = False
- if in_object_block:
- char = "\n\t"+char
- if char == ",":
- if not in_variable_block:
- char = char + "\n"
- if char == "'":
- if in_quote_block:
- in_quote_block = False
- else:
- in_quote_block = True
- if char == "\"":
- if in_double_quote_block:
- in_double_quote_block = False
- else:
- in_double_quote_block = True
- if char == ";":
- if not in_quote_block:
- if not in_double_quote_block:
- char = char + "\n\t"
-
- converted_map = converted_map + char
-
-if output_file == "":
- output_file = map_file
-with open(output_file, "r+") as final_converted_map:
- final_converted_map.write("//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE \n")
- final_converted_map.write(converted_map)
-
-
-
diff --git a/tools/mapmerge/MapMerge.jar b/tools/mapmerge/MapMerge.jar
index e0bd47ea836..c8e4349ba42 100644
Binary files a/tools/mapmerge/MapMerge.jar and b/tools/mapmerge/MapMerge.jar differ
diff --git a/tools/mapmerge/Run Map Merge.bat b/tools/mapmerge/Run Map Merge.bat
index 1c159f79ca2..5bb8f1736b9 100644
--- a/tools/mapmerge/Run Map Merge.bat
+++ b/tools/mapmerge/Run Map Merge.bat
@@ -1,5 +1,4 @@
@echo off
-
-java -jar MapMerge.jar ../../_maps/
+call java -jar MapMerge.jar "../../_maps/" /wait
pause
\ No newline at end of file
diff --git a/tools/mapmerge/Source/.settings/org.eclipse.jdt.ui.prefs b/tools/mapmerge/Source/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..ea0a123b8b0
--- /dev/null
+++ b/tools/mapmerge/Source/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,60 @@
+cleanup.add_default_serial_version_id=false
+cleanup.add_generated_serial_version_id=true
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=true
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=true
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=true
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=true
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=true
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Default
+cleanup_settings_version=2
+eclipse.preferences.version=1
diff --git a/tools/mapmerge/Source/bin/MapMerge.class b/tools/mapmerge/Source/bin/MapMerge.class
new file mode 100644
index 00000000000..9a6d17f143f
Binary files /dev/null and b/tools/mapmerge/Source/bin/MapMerge.class differ
diff --git a/tools/mapmerge/Source/bin/MapMergerMain.class b/tools/mapmerge/Source/bin/MapMergerMain.class
deleted file mode 100644
index c0ec043c239..00000000000
Binary files a/tools/mapmerge/Source/bin/MapMergerMain.class and /dev/null differ
diff --git a/tools/mapmerge/Source/bin/MapPatcher Source/Location.class b/tools/mapmerge/Source/bin/MapPatcher Source/Location.class
deleted file mode 100644
index a6ad8cca026..00000000000
Binary files a/tools/mapmerge/Source/bin/MapPatcher Source/Location.class and /dev/null differ
diff --git a/tools/mapmerge/Source/bin/MapPatcher Source/Map.class b/tools/mapmerge/Source/bin/MapPatcher Source/Map.class
deleted file mode 100644
index 814958657bc..00000000000
Binary files a/tools/mapmerge/Source/bin/MapPatcher Source/Map.class and /dev/null differ
diff --git a/tools/mapmerge/Source/bin/MapPatcher Source/MapPatcher.class b/tools/mapmerge/Source/bin/MapPatcher Source/MapPatcher.class
deleted file mode 100644
index 286c9a4a9c3..00000000000
Binary files a/tools/mapmerge/Source/bin/MapPatcher Source/MapPatcher.class and /dev/null differ
diff --git a/tools/mapmerge/Source/bin/MapPatcher Source/SavingThread.class b/tools/mapmerge/Source/bin/MapPatcher Source/SavingThread.class
deleted file mode 100644
index 0be31fccea8..00000000000
Binary files a/tools/mapmerge/Source/bin/MapPatcher Source/SavingThread.class and /dev/null differ
diff --git a/tools/mapmerge/Source/src/MapMerge.java b/tools/mapmerge/Source/src/MapMerge.java
new file mode 100644
index 00000000000..a2058480a21
--- /dev/null
+++ b/tools/mapmerge/Source/src/MapMerge.java
@@ -0,0 +1,105 @@
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+public class MapMerge {
+
+ private static Scanner input = new Scanner(System.in);
+ private static Path pathToMaps;
+
+ public static void main(String[] mapPath) throws IOException {
+ pathToMaps = Paths.get(mapPath[0]);
+ FileFinder dmmFinder = new FileFinder("*.dmm");
+ Files.walkFileTree(pathToMaps, dmmFinder);
+ ArrayList foundFiles = dmmFinder.foundPaths;
+ if (foundFiles.size() > 0) {
+ try {
+ MapMerge.merge(foundFiles);
+ } catch (Exception e) {
+ System.out.println("Something went wrong.");
+ e.printStackTrace();
+ }
+ } else {
+ System.out.println("No files were found in provided directory!");
+ System.out.print("Path to maps folder: ");
+ pathToMaps = Paths.get(input.nextLine());
+ dmmFinder = new FileFinder("*.dmm");
+ Files.walkFileTree(pathToMaps, dmmFinder);
+ foundFiles = dmmFinder.foundPaths;
+ try {
+ MapMerge.merge(foundFiles);
+ } catch (Exception e) {
+ System.out.println("Something went wrong.");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static void merge(ArrayList foundFiles) throws IOException {
+
+ System.out.println("How many files do you want to merge?");
+ int selection1;
+ inputCheck: while (true) {
+ while (!input.hasNextInt()) {
+ String temp = input.next();
+ System.out.println(temp + " is not a valid int.");
+ }
+ selection1 = input.nextInt();
+ if (selection1 < 0) {
+ System.out.println("Use a number greater than 0!");
+ continue inputCheck;
+ } else {
+ break inputCheck;
+ }
+ }
+
+ for (int numOfFiles = selection1; numOfFiles != 0; numOfFiles--) {
+
+ for (int num = 0; num < foundFiles.size(); num++) {
+ System.out.println(num + ": " + foundFiles.get(num));
+ }
+
+ System.out.print("File to use: ");
+ int selection2;
+ inputCheck: while (true) {
+ while (!input.hasNextInt()) {
+ String temp = input.next();
+ System.out.println(temp + " is not a valid int.");
+ }
+ selection2 = input.nextInt();
+ if ((selection2 < 0) || (selection2 >= foundFiles.size())) {
+ if (selection2 < 0) {
+ System.out.println("Use a number greater than 0!");
+ } else {
+ System.out.println("Use a number less than " + foundFiles.size() + "!");
+ }
+ continue inputCheck;
+ } else {
+ break inputCheck;
+ }
+ }
+
+ String selected_map = foundFiles.get(selection2) + "";
+ String backup_map = selected_map + ".backup";
+ String edited_map = selected_map;
+ String to_save = selected_map;
+ String[] passInto = { "-clean", backup_map, edited_map, to_save };
+ MapPatcher.main(passInto);
+ try{
+ Process process = new ProcessBuilder("dmm2tgm\\dmm2tgm.exe", selected_map).start();
+ }catch(Exception e1){
+ System.out.println("You are not on a windows machine, trying the .py");
+ try{
+ Process process = new ProcessBuilder("dmm2tgm\\Source\\dmm2tgm.py", selected_map).start();
+ }catch(Exception e2){
+ System.out.println("You do not have python 2.7.x installed.");
+ System.out.println("Downloads can be found here: https://www.python.org/downloads/");
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/mapmerge/Source/src/MapMergerMain.java b/tools/mapmerge/Source/src/MapMergerMain.java
deleted file mode 100644
index 873ae69cd84..00000000000
--- a/tools/mapmerge/Source/src/MapMergerMain.java
+++ /dev/null
@@ -1,96 +0,0 @@
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Scanner;
-
-public class MapMergerMain {
-
- private static Scanner input = new Scanner(System.in);
-
- public static void main(String[] mapPath) throws IOException{
- Path pathToMaps = Paths.get(mapPath[0]);
- FileFinder dmmFinder = new FileFinder("*.dmm");
- Files.walkFileTree(pathToMaps, dmmFinder);
- ArrayList foundFiles = dmmFinder.foundPaths;
- if (foundFiles.size() > 0) {
- try{
- merge(foundFiles);
- }catch(Exception e){
- System.out.println("Something went wrong.");
- e.printStackTrace();
- }
- }else{
- System.out.println("No files were found in provided directory!");
- System.out.print("Path to maps folder: ");
- pathToMaps = Paths.get(input.nextLine());
- dmmFinder = new FileFinder("*.dmm");
- Files.walkFileTree(pathToMaps, dmmFinder);
- foundFiles = dmmFinder.foundPaths;
- try{
- merge(foundFiles);
- }catch(Exception e){
- System.out.println("Something went wrong.");
- e.printStackTrace();
- }
- }
- }
-
-
- public static void merge(ArrayList foundFiles){
-
- System.out.println("How many files do you want to merge?");
- int selection1;
- inputCheck:while(true){
- while(!input.hasNextInt()){
- String temp = input.next();
- System.out.println(temp + " is not a valid int.");
- }
- selection1 = input.nextInt();
- if(selection1 < 0){
- System.out.println("Use a number greater than 0!");
- continue inputCheck;
- }else{
- break inputCheck;
- }
- }
-
- for(int numOfFiles = selection1; numOfFiles != 0; numOfFiles--){
-
- for(int num = 0;num < foundFiles.size();num++){
- System.out.println(num + ": " + foundFiles.get(num));
- }
-
- System.out.print("File to use: ");
- int selection2;
- inputCheck:while(true){
- while(!input.hasNextInt()){
- String temp = input.next();
- System.out.println(temp + " is not a valid int.");
- }
- selection2 = input.nextInt();
- if(selection2 < 0 || selection2 >= foundFiles.size()){
- if(selection2 < 0){
- System.out.println("Use a number greater than 0!");
- }else{
- System.out.println("Use a number less than " + foundFiles.size() +"!");
- }
- continue inputCheck;
- }else{
- break inputCheck;
- }
- }
-
- String newMap = foundFiles.get(selection2) + "";
- String oldMap = foundFiles.get(selection2) + ".backup";
- String[] passInto = new String[4];
- passInto[0] = "-clean";
- passInto[1] = oldMap;
- passInto[2] = newMap;
- passInto[3] = newMap;
- MapPatcher.main(passInto);
- }
- }
-
-}
\ No newline at end of file
diff --git a/tools/mapmerge/dmm2tgm/Source/dmm2tgm.py b/tools/mapmerge/dmm2tgm/Source/dmm2tgm.py
new file mode 100644
index 00000000000..637986f9a67
--- /dev/null
+++ b/tools/mapmerge/dmm2tgm/Source/dmm2tgm.py
@@ -0,0 +1,77 @@
+
+import sys
+
+# .dmm format converter, by RemieRichards
+# Version 2.0
+# Converts the internal structure of a .dmm file to a syntax
+# that git can better handle conflicts-wise, it's also fairly human readable!
+# Processes Boxstation (tgstation.2.1.3) almost instantly
+
+
+def convert_map(map_file):
+ #CHECK FOR PREVIOUS CONVERSION
+ with open(map_file, "r") as conversion_candidate:
+ header = conversion_candidate.readline()
+ if header.find("//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE") != -1:
+ sys.exit()
+ return
+
+
+ #ACTUAL CONVERSION
+ with open(map_file, "r+") as unconverted_map:
+ characters = unconverted_map.read()
+ converted_map = ""
+ in_object_block = False #()
+ in_variable_block = False #{}
+ in_quote_block = False #''
+ in_double_quote_block = False #""
+ for char in characters:
+ if not in_quote_block: #Checking for things like "Flashbangs (Warning!)" Because we only care about ({'";, that are used as byond syntax, not strings
+ if not in_double_quote_block:
+ if not in_variable_block:
+ if char == "(":
+ in_object_block = True
+ char = char + "\n"
+ if char == ")":
+ in_object_block = False
+ if char == ",":
+ char = char + "\n"
+
+ if char == "{":
+ in_variable_block = True
+ if in_object_block:
+ char = char + "\n\t"
+ if char == "}":
+ in_variable_block = False
+ if in_object_block:
+ char = "\n\t" + char
+
+ if char == ";":
+ char = char + "\n\t"
+
+ if char == "\"":
+ if in_double_quote_block:
+ in_double_quote_block = False
+ else:
+ in_double_quote_block = True
+
+ if char == "'":
+ if not in_double_quote_block:
+ if in_quote_block:
+ in_quote_block = False
+ else:
+ in_quote_block = True
+
+ converted_map = converted_map + char
+
+ #OVERWRITE MAP FILE WITH CONVERTED MAP STRING
+ with open(map_file, "r+") as final_converted_map:
+ final_converted_map.write("//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE \n")
+ final_converted_map.write(converted_map)
+
+ sys.exit()
+
+
+if sys.argv[1]: #Run like dmm2tgm.py "folder/folder/a_map.dmm"
+ convert_map(sys.argv[1])
+
diff --git a/tools/mapmerge/dmm2tgm/_hashlib.pyd b/tools/mapmerge/dmm2tgm/_hashlib.pyd
new file mode 100644
index 00000000000..9cf823e4757
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/_hashlib.pyd differ
diff --git a/tools/mapmerge/dmm2tgm/bz2.pyd b/tools/mapmerge/dmm2tgm/bz2.pyd
new file mode 100644
index 00000000000..b388111d6ac
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/bz2.pyd differ
diff --git a/tools/mapmerge/dmm2tgm/dmm2tgm.exe b/tools/mapmerge/dmm2tgm/dmm2tgm.exe
new file mode 100644
index 00000000000..fba25d71d02
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/dmm2tgm.exe differ
diff --git a/tools/mapmerge/dmm2tgm/library.zip b/tools/mapmerge/dmm2tgm/library.zip
new file mode 100644
index 00000000000..068102032b4
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/library.zip differ
diff --git a/tools/mapmerge/dmm2tgm/python27.dll b/tools/mapmerge/dmm2tgm/python27.dll
new file mode 100644
index 00000000000..e45374fb339
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/python27.dll differ
diff --git a/tools/mapmerge/dmm2tgm/select.pyd b/tools/mapmerge/dmm2tgm/select.pyd
new file mode 100644
index 00000000000..62104e489e7
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/select.pyd differ
diff --git a/tools/mapmerge/dmm2tgm/unicodedata.pyd b/tools/mapmerge/dmm2tgm/unicodedata.pyd
new file mode 100644
index 00000000000..f6a0f525618
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/unicodedata.pyd differ
diff --git a/tools/mapmerge/dmm2tgm/w9xpopen.exe b/tools/mapmerge/dmm2tgm/w9xpopen.exe
new file mode 100644
index 00000000000..93036283633
Binary files /dev/null and b/tools/mapmerge/dmm2tgm/w9xpopen.exe differ