diff --git a/.travis.yml b/.travis.yml
index 6ac5e02e3f..3ae210183f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,7 @@ sudo: false
env:
BYOND_MAJOR="508"
BYOND_MINOR="1287"
+ MACRO_COUNT=1234
cache:
directories:
@@ -32,7 +33,7 @@ script:
- (! grep 'step_[xy]' maps/**/*.dmm)
- (! find nano/templates/ -type f -exec md5sum {} + | sort | uniq -D -w 32 | grep nano)
- (! grep -E "<\s*span\s+class\s*=\s*('[^'>]+|[^'>]+')\s*>" **/*.dm)
- - (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting 1257 or less)"; [ $num -le 1257 ])
+ - (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting ${MACRO_COUNT} or less)"; [ $num -le ${MACRO_COUNT} ])
- md5sum -c - <<< "0af969f671fba6cf9696c78cd175a14a *baystation12.int"
- md5sum -c - <<< "88490b460c26947f5ec1ab1bb9fa9f17 *html/changelogs/example.yml"
- python tools/TagMatcher/tag-matcher.py ../..
diff --git a/baystation12.dme b/baystation12.dme
index 15f8b80293..99019baad1 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -24,12 +24,14 @@
#include "code\__defines\dna.dm"
#include "code\__defines\gamemode.dm"
#include "code\__defines\items_clothing.dm"
+#include "code\__defines\lighting.dm"
#include "code\__defines\machinery.dm"
#include "code\__defines\math_physics.dm"
#include "code\__defines\misc.dm"
#include "code\__defines\mobs.dm"
#include "code\__defines\research.dm"
#include "code\__defines\species_languages.dm"
+#include "code\_helpers\atmospherics.dm"
#include "code\_helpers\datum_pool.dm"
#include "code\_helpers\files.dm"
#include "code\_helpers\game.dm"
@@ -144,6 +146,7 @@
#include "code\datums\ai_laws.dm"
#include "code\datums\browser.dm"
#include "code\datums\computerfiles.dm"
+#include "code\datums\crew.dm"
#include "code\datums\datacore.dm"
#include "code\datums\datumvars.dm"
#include "code\datums\disease.dm"
@@ -772,6 +775,7 @@
#include "code\game\objects\structures\watercloset.dm"
#include "code\game\objects\structures\windoor_assembly.dm"
#include "code\game\objects\structures\window.dm"
+#include "code\game\objects\structures\window_spawner.dm"
#include "code\game\objects\structures\crates_lockers\closets.dm"
#include "code\game\objects\structures\crates_lockers\crates.dm"
#include "code\game\objects\structures\crates_lockers\largecrate.dm"
@@ -1277,6 +1281,7 @@
#include "code\modules\mob\living\silicon\decoy\death.dm"
#include "code\modules\mob\living\silicon\decoy\decoy.dm"
#include "code\modules\mob\living\silicon\decoy\life.dm"
+#include "code\modules\mob\living\silicon\pai\admin.dm"
#include "code\modules\mob\living\silicon\pai\death.dm"
#include "code\modules\mob\living\silicon\pai\examine.dm"
#include "code\modules\mob\living\silicon\pai\life.dm"
@@ -1308,6 +1313,7 @@
#include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_items.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm"
+#include "code\modules\mob\living\silicon\robot\drone\drone_say.dm"
#include "code\modules\mob\living\simple_animal\bees.dm"
#include "code\modules\mob\living\simple_animal\corpse.dm"
#include "code\modules\mob\living\simple_animal\parrot.dm"
@@ -1505,6 +1511,7 @@
#include "code\modules\random_map\noise\tundra.dm"
#include "code\modules\reagents\Chemistry-Colours.dm"
#include "code\modules\reagents\Chemistry-Holder.dm"
+#include "code\modules\reagents\Chemistry-Logging.dm"
#include "code\modules\reagents\Chemistry-Machinery.dm"
#include "code\modules\reagents\Chemistry-Metabolism.dm"
#include "code\modules\reagents\Chemistry-Readme.dm"
@@ -1673,16 +1680,15 @@
#include "code\modules\spells\aoe_turf\conjure\forcewall.dm"
#include "code\modules\spells\general\area_teleport.dm"
#include "code\modules\spells\general\rune_write.dm"
-#include "code\modules\spells\targeted\disintegrate.dm"
#include "code\modules\spells\targeted\ethereal_jaunt.dm"
-#include "code\modules\spells\targeted\flesh_to_stone.dm"
#include "code\modules\spells\targeted\genetic.dm"
#include "code\modules\spells\targeted\harvest.dm"
-#include "code\modules\spells\targeted\horsemask.dm"
#include "code\modules\spells\targeted\mind_transfer.dm"
#include "code\modules\spells\targeted\shift.dm"
#include "code\modules\spells\targeted\subjugate.dm"
#include "code\modules\spells\targeted\targeted.dm"
+#include "code\modules\spells\targeted\equip\equip.dm"
+#include "code\modules\spells\targeted\equip\horsemask.dm"
#include "code\modules\spells\targeted\projectile\dumbfire.dm"
#include "code\modules\spells\targeted\projectile\fireball.dm"
#include "code\modules\spells\targeted\projectile\magic_missile.dm"
diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm
index 6c5bf21c32..754c0c2da4 100644
--- a/code/ATMOSPHERICS/pipes.dm
+++ b/code/ATMOSPHERICS/pipes.dm
@@ -1120,20 +1120,8 @@
return
if(istype(W, /obj/item/device/analyzer) && in_range(user, src))
- for (var/mob/O in viewers(user, null))
- O << "\The [user] has used \the [W] on \the [src] \icon[src]"
-
- var/pressure = parent.air.return_pressure()
- var/total_moles = parent.air.total_moles
-
- user << "Results of analysis of \the [src] \icon[src]"
- if (total_moles>0)
- user << "Pressure: [round(pressure,0.1)] kPa"
- for(var/g in parent.air.gas)
- user << "[gas_data.name[g]]: [round((parent.air.gas[g] / total_moles) * 100)]%"
- user << "Temperature: [round(parent.air.temperature-T0C)]°C"
- else
- user << "Tank is empty!"
+ var/obj/item/device/analyzer/A = W
+ A.analyze_gases(src, user)
/obj/machinery/atmospherics/pipe/tank/air
name = "Pressure Tank (Air)"
diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm
index 9f6451adf9..5f5f5bf347 100644
--- a/code/ZAS/Airflow.dm
+++ b/code/ZAS/Airflow.dm
@@ -241,7 +241,7 @@ mob/living/carbon/human/airflow_hit(atom/A)
zone/proc/movables()
. = list()
for(var/turf/T in contents)
- for(var/atom/A in T)
- if(istype(A, /obj/effect) || istype(A, /mob/aiEye))
+ for(var/atom/movable/A in T)
+ if(!A.simulated || A.anchored || istype(A, /obj/effect) || istype(A, /mob/aiEye))
continue
. += A
diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm
index d26db30a19..501c49ae55 100644
--- a/code/ZAS/Fire.dm
+++ b/code/ZAS/Fire.dm
@@ -295,7 +295,7 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
//if the reaction is progressing too slow then it isn't self-sustaining anymore and burns out
if(zone) //be less restrictive with canister and tank reactions
- if((!liquid_fuel || used_fuel <= FIRE_LIQUD_MIN_BURNRATE) && (!gas_fuel || used_fuel <= FIRE_GAS_MIN_BURNRATE*group_multiplier))
+ if((!liquid_fuel || used_fuel <= FIRE_LIQUD_MIN_BURNRATE) && (!gas_fuel || used_fuel <= FIRE_GAS_MIN_BURNRATE*zone.contents.len))
return 0
diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm
new file mode 100644
index 0000000000..56c95535fe
--- /dev/null
+++ b/code/__defines/lighting.dm
@@ -0,0 +1,6 @@
+#define FOR_DVIEW(type, range, center, invis_flags) \
+ dview_mob.loc = center; \
+ dview_mob.see_invisible = invis_flags; \
+ for(type in view(range, dview_mob))
+
+#define END_FOR_DVIEW dview_mob.loc = null
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index ecca29bfd1..9fb8f2c33a 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -12,7 +12,7 @@
#define INVISIBILITY_EYE 61
#define SEE_INVISIBLE_LIVING 25
-#define SEE_INVISIBLE_OBSERVER_NOLIGHTING 15
+#define SEE_INVISIBLE_NOLIGHTING 15
#define SEE_INVISIBLE_LEVEL_ONE 35
#define SEE_INVISIBLE_LEVEL_TWO 45
#define SEE_INVISIBLE_CULT 60
@@ -117,8 +117,8 @@
#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6
#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed
#define LIGHTING_LAYER 11
-#define OBFUSCATION_LAYER 14 //Where images covering the view for eyes are put
-#define SCREEN_LAYER 17 //Mob HUD/effects layer
+#define OBFUSCATION_LAYER 21 //Where images covering the view for eyes are put
+#define SCREEN_LAYER 22 //Mob HUD/effects layer
// Convoluted setup so defines can be supplied by Bay12 main server compile script.
// Should still work fine for people jamming the icons into their repo.
@@ -154,3 +154,7 @@
#define BOMBCAP_HEAVY_RADIUS (max_explosion_range/2)
#define BOMBCAP_LIGHT_RADIUS max_explosion_range
#define BOMBCAP_FLASH_RADIUS (max_explosion_range*1.5)
+
+// Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile.
+#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act()
+#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs.
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 76bce19e1f..e4e406d219 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -83,4 +83,14 @@
#define MIN_SUPPLIED_LAW_NUMBER 15
-#define MAX_SUPPLIED_LAW_NUMBER 50
\ No newline at end of file
+#define MAX_SUPPLIED_LAW_NUMBER 50
+
+//default item on-mob icons
+#define INV_HEAD_DEF_ICON 'icons/mob/head.dmi'
+#define INV_BACK_DEF_ICON 'icons/mob/back.dmi'
+#define INV_L_HAND_DEF_ICON 'icons/mob/items/lefthand.dmi'
+#define INV_R_HAND_DEF_ICON 'icons/mob/items/righthand.dmi'
+#define INV_W_UNIFORM_DEF_ICON 'icons/mob/uniform.dmi'
+#define INV_ACCESSORIES_DEF_ICON 'icons/mob/ties.dmi'
+#define INV_SUIT_DEF_ICON 'icons/mob/ties.dmi'
+#define INV_SUIT_DEF_ICON 'icons/mob/suit.dmi'
diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm
index 3f351989bd..fbea043787 100644
--- a/code/__defines/species_languages.dm
+++ b/code/__defines/species_languages.dm
@@ -44,4 +44,5 @@
#define NONGLOBAL 32 // Do not add to general languages list.
#define INNATE 64 // All mobs can be assumed to speak and understand this language. (audible emotes)
#define NO_TALK_MSG 128 // Do not show the "\The [speaker] talks into \the [radio]" message
-#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems
\ No newline at end of file
+#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems
+#define COMMON_VERBS 512 // Robots will apply regular verbs to this
diff --git a/code/_helpers/atmospherics.dm b/code/_helpers/atmospherics.dm
new file mode 100644
index 0000000000..2fe393b4dc
--- /dev/null
+++ b/code/_helpers/atmospherics.dm
@@ -0,0 +1,47 @@
+/obj/proc/analyze_gases(var/obj/A, var/mob/user)
+ if(src != A)
+ user.visible_message("\The [user] has used \an [src] on \the [A]")
+
+ A.add_fingerprint(user)
+ var/list/result = A.atmosanalyze(user)
+ if(result && result.len)
+ user << "Results of the analysis[src == A ? "" : " of \the [A]"]"
+ for(var/line in result)
+ user << "[line]"
+ return 1
+
+ user << "Your [src] flashes a red light as it fails to analyze \the [A]."
+ return 0
+
+/proc/atmosanalyzer_scan(var/obj/target, var/datum/gas_mixture/mixture, var/mob/user)
+ var/pressure = mixture.return_pressure()
+ var/total_moles = mixture.total_moles
+
+ var/list/results = list()
+ if (total_moles>0)
+ results += "Pressure: [round(pressure,0.1)] kPa"
+ for(var/mix in mixture.gas)
+ results += "[gas_data.name[mix]]: [round((mixture.gas[mix] / total_moles) * 100)]%"
+ results += "Temperature: [round(mixture.temperature-T0C)]°C"
+ else
+ results += "\The [target] is empty!"
+
+ return results
+
+/obj/proc/atmosanalyze(var/mob/user)
+ return
+
+/obj/item/weapon/tank/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air_contents, user)
+
+/obj/machinery/portable_atmospherics/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air_contents, user)
+
+/obj/machinery/atmospherics/pipe/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.parent.air, user)
+
+/obj/machinery/power/rad_collector/atmosanalyze(var/mob/user)
+ if(P) return atmosanalyzer_scan(src, src.P.air_contents, user)
+
+/obj/item/weapon/flamethrower/atmosanalyze(var/mob/user)
+ if(ptank) return atmosanalyzer_scan(src, ptank.air_contents, user)
diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm
index fb4cd3874e..1ebb3e4f14 100644
--- a/code/_helpers/lists.dm
+++ b/code/_helpers/lists.dm
@@ -210,14 +210,23 @@ proc/listclearnulls(list/list)
return (result + R.Copy(Ri, 0))
//Mergesort: divides up the list into halves to begin the sort
-/proc/sortAtom(var/list/atom/L, var/order = 1)
+/proc/sortAtom(var/list/atom/L, var/order = 1, first = 1)
if(isnull(L) || L.len < 2)
+ if(!L)
+ testing("sortAtom() called with null as first parameter!")
return L
+ if(first)
+ var/msg = "sortAtom() called with list([L.len]): "
+ for(var/x in L)
+ msg += "'[x]'; "
+ testing(msg)
var/middle = L.len / 2 + 1
- return mergeAtoms(sortAtom(L.Copy(0,middle)), sortAtom(L.Copy(middle)), order)
+ return mergeAtoms(sortAtom(L.Copy(0,middle), order, 0), sortAtom(L.Copy(middle), order, 0), order)
//Mergsort: does the actual sorting and returns the results back to sortAtom
/proc/mergeAtoms(var/list/atom/L, var/list/atom/R, var/order = 1)
+ if(!L || !R)
+ testing("mergeAtoms([L] ([L ? L.len : "*null*"]), [R] ([R ? R.len : "*null*"]))")
var/Li=1
var/Ri=1
var/list/result = new()
@@ -230,8 +239,14 @@ proc/listclearnulls(list/list)
result += R[Ri++]
if(Li <= L.len)
- return (result + L.Copy(Li, 0))
- return (result + R.Copy(Ri, 0))
+ . = (result + L.Copy(Li, 0))
+ if(!.)
+ testing("mergeAtoms returning [.]")
+ return
+ . = (result + R.Copy(Ri, 0))
+ if(!.)
+ testing("mergeAtoms returning [.]")
+ return
diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm
index 8d37b47f0a..e0bc848458 100644
--- a/code/_helpers/time.dm
+++ b/code/_helpers/time.dm
@@ -6,13 +6,13 @@
var/roundstart_hour = 0
//Returns the world time in english
-proc/worldtime2text(time = world.time)
+proc/worldtime2text(time = world.time, timeshift = 1)
if(!roundstart_hour) roundstart_hour = pick(2,7,12,17)
- return "[(round(time / 36000)+roundstart_hour) % 24]:[(time / 600 % 60) < 10 ? add_zero(time / 600 % 60, 1) : time / 600 % 60]"
+ return timeshift ? time2text(time+(36000*roundstart_hour), "hh:mm") : time2text(time, "hh:mm")
proc/worlddate2text()
return num2text((text2num(time2text(world.timeofday, "YYYY"))+544)) + "-" + time2text(world.timeofday, "MM-DD")
-
+
proc/time_stamp()
return time2text(world.timeofday, "hh:mm:ss")
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 62d67ab18e..589103d4b0 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -871,6 +871,8 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
// Movement based on lower left corner. Tiles that do not fit
// into the new area will not be moved.
+ // Does *not* affect gases etc; copied turfs will be changed via ChangeTurf, and the dir, icon, and icon_state copied. All other vars will remain default.
+
if(!A || !src) return 0
var/list/turfs_src = get_area_turfs(src.type)
@@ -924,7 +926,8 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
if(istype(B, get_base_turf(B.z)))
continue moving
- var/turf/X = new T.type(B)
+ var/turf/X = B
+ X.ChangeTurf(T.type)
X.set_dir(old_dir1)
X.icon_state = old_icon_state1
X.icon = old_icon1 //Shuttle floors are in shuttle.dmi while the defaults are floors.dmi
@@ -964,12 +967,6 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
copiedobjs += newobjs
copiedobjs += newmobs
-
-
- for(var/V in T.vars)
- if(!(V in list("type","loc","locs","vars", "parent", "parent_type","verbs","ckey","key","x","y","z","contents", "luminosity")))
- X.vars[V] = T.vars[V]
-
// var/area/AR = X.loc
// if(AR.lighting_use_dynamic)
@@ -985,22 +982,9 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
- var/list/doors = new/list()
-
if(toupdate.len)
for(var/turf/simulated/T1 in toupdate)
- for(var/obj/machinery/door/D2 in T1)
- doors += D2
- /*if(T1.parent)
- air_master.groups_to_rebuild += T1.parent
- else
- air_master.tiles_to_update += T1*/
-
- for(var/obj/O in doors)
- O:update_nearby_tiles(1)
-
-
-
+ air_master.mark_for_update(T1)
return copiedobjs
@@ -1289,29 +1273,39 @@ var/list/WALLITEMS = list(
colour += temp_col
return colour
+var/mob/dview/dview_mob = new
+
//Version of view() which ignores darkness, because BYOND doesn't have it.
/proc/dview(var/range = world.view, var/center, var/invis_flags = 0)
if(!center)
return
- var/global/mob/dview/DV
- if(!DV)
- DV = new
+ dview_mob.loc = center
- DV.loc = center
+ dview_mob.see_invisible = invis_flags
- DV.see_in_dark = range
- DV.see_invisible = invis_flags
-
- . = view(range, DV)
- DV.loc = null
+ . = view(range, dview_mob)
+ dview_mob.loc = null
/mob/dview
invisibility = 101
density = 0
+ anchored = 1
+ simulated = 0
+
+ see_in_dark = 1e6
+
/atom/proc/get_light_and_color(var/atom/origin)
if(origin)
color = origin.color
set_light(origin.light_range, origin.light_power, origin.light_color)
+/mob/dview/New()
+ ..()
+ // We don't want to be in any mob lists; we're a dummy not a mob.
+ mob_list -= src
+ if(stat == DEAD)
+ dead_mob_list -= src
+ else
+ living_mob_list -= src
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 9d877bb41a..6bd01fad32 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -141,6 +141,25 @@ datum/hud/New(mob/owner)
instantiate()
..()
+/datum/hud/Destroy()
+ ..()
+ grab_intent = null
+ hurt_intent = null
+ disarm_intent = null
+ help_intent = null
+ lingchemdisplay = null
+ blobpwrdisplay = null
+ blobhealthdisplay = null
+ r_hand_hud_object = null
+ l_hand_hud_object = null
+ action_intent = null
+ move_intent = null
+ adding = null
+ other = null
+ hotkeybuttons = null
+// item_action_list = null // ?
+ mymob = null
+
/datum/hud/proc/hidden_inventory_update()
if(!mymob) return
if(ishuman(mymob))
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index f0cc69fcda..cda4f5b540 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -45,6 +45,10 @@
/obj/screen/item_action
var/obj/item/owner
+/obj/screen/item_action/Destroy()
+ ..()
+ owner = null
+
/obj/screen/item_action/Click()
if(!usr || !owner)
return 1
diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm
index ed208a588d..31f6fbcb86 100644
--- a/code/_onclick/hud/spell_screen_objects.dm
+++ b/code/_onclick/hud/spell_screen_objects.dm
@@ -12,6 +12,18 @@
var/mob/spell_holder
+/obj/screen/movable/spell_master/Destroy()
+ ..()
+ for(var/obj/screen/spell/spells in spell_objects)
+ spells.spellmaster = null
+ spell_objects.Cut()
+ if(spell_holder)
+ spell_holder.spell_masters -= src
+
+/obj/screen/movable/spell_master/ResetVars()
+ ..("spell_objects")
+ spell_objects = list()
+
/obj/screen/movable/spell_master/MouseDrop()
if(showing)
return
@@ -57,16 +69,23 @@
/obj/screen/movable/spell_master/proc/add_spell(var/spell/spell)
if(!spell) return
- for(var/obj/screen/spell/spellscreen in spell_objects)
- if(spellscreen.spell == spell)
+ if(spell.connected_button) //we have one already, for some reason
+ if(spell.connected_button in spell_objects)
+ return
+ else
+ spell_objects.Add(spell.connected_button)
+ toggle_open(2)
return
if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one
return
- var/obj/screen/spell/newscreen = new
-
+ var/obj/screen/spell/newscreen = new /obj/screen/spell
+ newscreen.spellmaster = src
newscreen.spell = spell
+
+ spell.connected_button = newscreen
+
if(!spell.override_base) //if it's not set, we do basic checks
if(spell.spell_flags & CONSTRUCT_CHECK)
newscreen.spell_base = "const" //construct spells
@@ -80,16 +99,13 @@
toggle_open(2) //forces the icons to refresh on screen
/obj/screen/movable/spell_master/proc/remove_spell(var/spell/spell)
- for(var/obj/screen/spell/s_object in spell_objects)
- if(s_object.spell == spell)
- spell_objects.Remove(s_object)
- qdel(s_object)
- break
+ qdel(spell.connected_button)
+
+ spell.connected_button = null
if(spell_objects.len)
toggle_open(showing + 1)
else
- spell_holder.spell_masters.Remove(src)
qdel(src)
/obj/screen/movable/spell_master/proc/silence_spells(var/amount)
@@ -125,9 +141,20 @@
var/spell/spell = null
var/handle_icon_updates = 0
+ var/obj/screen/movable/spell_master/spellmaster
var/icon/last_charged_icon
+/obj/screen/spell/Destroy()
+ ..()
+ spell = null
+ last_charged_icon = null
+ if(spellmaster)
+ spellmaster.spell_objects -= src
+ if(spellmaster && !spellmaster.spell_objects.len)
+ qdel(spellmaster)
+ spellmaster = null
+
/obj/screen/spell/proc/update_charge(var/forced_update = 0)
if(!spell)
qdel(src)
diff --git a/code/controllers/Processes/garbage.dm b/code/controllers/Processes/garbage.dm
index ade159f1ac..a74f0eedfa 100644
--- a/code/controllers/Processes/garbage.dm
+++ b/code/controllers/Processes/garbage.dm
@@ -28,6 +28,10 @@ var/list/delayed_garbage = list()
delayed_garbage.Cut()
delayed_garbage = null
+#ifdef GC_FINDREF
+world/loop_checks = 0
+#endif
+
/datum/controller/process/garbage_collector/doWork()
if(!garbage_collect)
return
@@ -37,6 +41,31 @@ var/list/delayed_garbage = list()
var/checkRemain = max_checks_multiplier * schedule_interval
var/maxDels = max_forcedel_multiplier * schedule_interval
+ #ifdef GC_FINDREF
+ var/list/searching = list()
+ for(var/refID in destroyed) // Reference search - before all deletions and for all at once
+ var/GCd_at_time = destroyed[refID]
+ if(GCd_at_time > time_to_kill)
+ break
+ var/atom/A = locate(refID)
+ if(A && A.gcDestroyed == GCd_at_time)
+ searching += A
+ if(searching.len >= checkRemain)
+ break
+
+ for(var/atom/A in searching)
+ testing("GC: Searching references for [A] | [A.type]")
+ if(A.loc != null)
+ testing("GC: [A] | [A.type] is located in [A.loc] instead of null")
+ if(A.contents.len)
+ testing("GC: [A] | [A.type] has contents: [list2text(A.contents)]")
+ if(searching.len)
+ for(var/atom/D in world)
+ LookForRefs(D, searching)
+ for(var/datum/D)
+ LookForRefs(D, searching)
+ #endif
+
while(destroyed.len && --checkRemain >= 0)
if(dels >= maxDels)
#ifdef GC_DEBUG
@@ -50,7 +79,7 @@ var/list/delayed_garbage = list()
testing("GC: [refID] not old enough, breaking at [world.time] for [GCd_at_time - time_to_kill] deciseconds until [GCd_at_time + collection_timeout]")
#endif
break // Everything else is newer, skip them
- var/atom/A = locate(refID)
+ var/datum/A = locate(refID)
#ifdef GC_DEBUG
testing("GC: [refID] old enough to test: GCd_at_time: [GCd_at_time] time_to_kill: [time_to_kill] current: [world.time]")
#endif
@@ -67,6 +96,32 @@ var/list/delayed_garbage = list()
#endif
destroyed.Cut(1, 2)
+#ifdef GC_FINDREF
+/datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ)
+ . = 0
+ for(var/V in D.vars)
+ if(V == "contents")
+ continue
+ if(istype(D.vars[V], /atom))
+ var/atom/A = D.vars[V]
+ if(A in targ)
+ testing("GC: [A] | [A.type] referenced by [D] | [D.type], var [V]")
+ . += 1
+ else if(islist(D.vars[V]))
+ . += LookForListRefs(D.vars[V], targ, D, V)
+
+/datum/controller/process/garbage_collector/proc/LookForListRefs(var/list/L, var/list/targ, var/datum/D, var/V)
+ . = 0
+ for(var/F in L)
+ if(istype(F, /atom))
+ var/atom/A = F
+ if(A in targ)
+ testing("GC: [A] | [A.type] referenced by [D] | [D.type], list [V]")
+ . += 1
+ if(islist(F))
+ . += LookForListRefs(F, targ, D, "[F] in list [V]")
+#endif
+
/datum/controller/process/garbage_collector/proc/AddTrash(datum/A)
if(!istype(A) || !isnull(A.gcDestroyed))
return
@@ -199,3 +254,7 @@ var/list/delayed_garbage = list()
#ifdef GC_DEBUG
#undef GC_DEBUG
#endif
+
+#ifdef GC_FINDREF
+#undef GC_FINDREF
+#endif
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 1f0feb709f..06adfe42f9 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -121,6 +121,8 @@ var/list/gamemode_cache = list()
var/organ_health_multiplier = 1
var/organ_regeneration_multiplier = 1
+ var/organs_decay
+ var/default_brain_health = 400
//Paincrit knocks someone down once they hit 60 shock_stage, so by default make it so that close to 100 additional damage needs to be dealt,
//so that it's similar to HALLOSS. Lowered it a bit since hitting paincrit takes much longer to wear off than a halloss stun.
@@ -709,6 +711,12 @@ var/list/gamemode_cache = list()
config.organ_regeneration_multiplier = value / 100
if("organ_damage_spillover_multiplier")
config.organ_damage_spillover_multiplier = value / 100
+ if("organs_can_decay")
+ config.organs_decay = 1
+ if("default_brain_health")
+ config.default_brain_health = text2num(value)
+ if(!config.default_brain_health || config.default_brain_health < 1)
+ config.default_brain_health = initial(config.default_brain_health)
if("bones_can_break")
config.bones_can_break = value
if("limbs_can_break")
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 002c30b0eb..5263e1af79 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -49,6 +49,11 @@ datum/controller/game_controller/proc/setup_objects()
for(var/atom/movable/object in world)
object.initialize()
+ admin_notice("Initializing areas", R_DEBUG)
+ sleep(-1)
+ for(var/area/area in all_areas)
+ area.initialize()
+
admin_notice("Initializing pipe networks", R_DEBUG)
sleep(-1)
for(var/obj/machinery/atmospherics/machine in machines)
diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm
index 44309b83d9..29008770f5 100644
--- a/code/controllers/voting.dm
+++ b/code/controllers/voting.dm
@@ -188,9 +188,9 @@ datum/controller/vote
if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
return 0
- if(current_votes[ckey])
- choices[choices[current_votes[ckey]]]--
- if(vote && 1<=vote && vote<=choices.len)
+ if(vote && vote >= 1 && vote <= choices.len)
+ if(current_votes[ckey])
+ choices[choices[current_votes[ckey]]]--
voted += usr.ckey
choices[choices[vote]]++ //check this
current_votes[ckey] = vote
diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm
index 808c216d0d..a8e7ed7ce9 100644
--- a/code/datums/ai_laws.dm
+++ b/code/datums/ai_laws.dm
@@ -179,7 +179,7 @@ var/global/const/base_law_type = /datum/ai_laws/nanotrasen
/datum/ai_law/proc/delete_law(var/datum/ai_laws/laws)
-/datum/ai_law/zeroth/delete_law(var/datum/ai_laws/laws)
+/datum/ai_law/zero/delete_law(var/datum/ai_laws/laws)
laws.clear_zeroth_laws()
/datum/ai_law/ion/delete_law(var/datum/ai_laws/laws)
@@ -198,9 +198,7 @@ var/global/const/base_law_type = /datum/ai_laws/nanotrasen
var/index = laws.Find(law)
if(index)
laws -= law
- world << state.len
for(index, index < state.len, index++)
- world << index
state[index] = state[index+1]
sorted_laws.Cut()
diff --git a/code/datums/crew.dm b/code/datums/crew.dm
new file mode 100644
index 0000000000..d46a83846f
--- /dev/null
+++ b/code/datums/crew.dm
@@ -0,0 +1,74 @@
+var/global/datum/repository/crew/crew_repository = new()
+
+/datum/cache_entry
+ var/timestamp
+ var/data
+
+/datum/repository/crew
+ var/list/cache_data
+
+/datum/repository/crew/New()
+ cache_data = list()
+ ..()
+
+/datum/repository/crew/proc/health_data(var/turf/T)
+ var/list/crewmembers = list()
+ if(!T)
+ return crewmembers
+
+ var/z_level = "[T.z]"
+ var/datum/cache_entry/cache_entry = cache_data[z_level]
+ if(!cache_entry)
+ cache_entry = new/datum/cache_entry
+ cache_data[z_level] = cache_entry
+
+ if(world.time < cache_entry.timestamp)
+ return cache_entry.data
+
+ var/tracked = scan()
+ for(var/obj/item/clothing/under/C in tracked)
+ var/turf/pos = get_turf(C)
+ if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
+ if(istype(C.loc, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = C.loc
+ if(H.w_uniform != C)
+ continue
+
+ var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
+
+ crewmemberData["sensor_type"] = C.sensor_mode
+ crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
+ crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
+ crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
+
+ if(C.sensor_mode >= SUIT_SENSOR_BINARY)
+ crewmemberData["dead"] = H.stat > UNCONSCIOUS
+
+ if(C.sensor_mode >= SUIT_SENSOR_VITAL)
+ crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
+ crewmemberData["tox"] = round(H.getToxLoss(), 1)
+ crewmemberData["fire"] = round(H.getFireLoss(), 1)
+ crewmemberData["brute"] = round(H.getBruteLoss(), 1)
+
+ if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
+ var/area/A = get_area(H)
+ crewmemberData["area"] = sanitize(A.name)
+ crewmemberData["x"] = pos.x
+ crewmemberData["y"] = pos.y
+
+ crewmembers[++crewmembers.len] = crewmemberData
+
+ crewmembers = sortByKey(crewmembers, "name")
+ cache_entry.timestamp = world.time + 5 SECONDS
+ cache_entry.data = crewmembers
+
+ return crewmembers
+
+/datum/repository/crew/proc/scan()
+ var/list/tracked = list()
+ for(var/mob/living/carbon/human/H in mob_list)
+ if(istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/C = H.w_uniform
+ if (C.has_sensor)
+ tracked |= C
+ return tracked
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 4859ce2239..84a64d8ade 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -138,9 +138,160 @@
proc/get_id_photo(var/mob/living/carbon/human/H)
- H.regenerate_icons()
- var/icon/preview_icon = icon(H.icon)
- for(var/image/I in H.overlays_standing)
- if(I && I.icon)
- preview_icon.Blend(icon(I.icon, I.icon_state), ICON_OVERLAY)
+ var/icon/preview_icon = null
+
+ var/g = "m"
+ if (H.gender == FEMALE)
+ g = "f"
+
+ var/icon/icobase = H.species.icobase
+
+ preview_icon = new /icon(icobase, "torso_[g]")
+ var/icon/temp
+ temp = new /icon(icobase, "groin_[g]")
+ preview_icon.Blend(temp, ICON_OVERLAY)
+ temp = new /icon(icobase, "head_[g]")
+ preview_icon.Blend(temp, ICON_OVERLAY)
+
+ for(var/obj/item/organ/external/E in H.organs)
+ preview_icon.Blend(E.get_icon(), ICON_OVERLAY)
+
+ //Tail
+ if(H.species.tail)
+ temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[H.species.tail]_s")
+ preview_icon.Blend(temp, ICON_OVERLAY)
+
+ // Skin tone
+ if(H.species.flags & HAS_SKIN_TONE)
+ if (H.s_tone >= 0)
+ preview_icon.Blend(rgb(H.s_tone, H.s_tone, H.s_tone), ICON_ADD)
+ else
+ preview_icon.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT)
+
+ // Skin color
+ if(H.species.flags & HAS_SKIN_TONE)
+ if(!H.species || H.species.flags & HAS_SKIN_COLOR)
+ preview_icon.Blend(rgb(H.r_skin, H.g_skin, H.b_skin), ICON_ADD)
+
+ var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = H.species ? H.species.eyes : "eyes_s")
+
+ if (H.species.flags & HAS_EYE_COLOR)
+ eyes_s.Blend(rgb(H.r_eyes, H.g_eyes, H.b_eyes), ICON_ADD)
+
+ var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style]
+ if(hair_style)
+ var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
+ hair_s.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD)
+ eyes_s.Blend(hair_s, ICON_OVERLAY)
+
+ var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style]
+ if(facial_hair_style)
+ var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
+ facial_s.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD)
+ eyes_s.Blend(facial_s, ICON_OVERLAY)
+
+ var/icon/clothes_s = null
+ switch(H.mind.assigned_role)
+ if("Head of Personnel")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "hop_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ if("Bartender")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "ba_suit_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Gardener")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "hydroponics_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Chef")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chef_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Janitor")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "janitor_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Librarian")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "red_suit_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Quartermaster")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "qm_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ if("Cargo Technician")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "cargotech_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Shaft Miner")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "miner_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Lawyer")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "internalaffairs_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ if("Chaplain")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chapblack_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if("Research Director")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "director_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
+ if("Scientist")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY)
+ if("Chemist")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chemistrywhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_chem_open"), ICON_OVERLAY)
+ if("Chief Medical Officer")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "cmo_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_cmo_open"), ICON_OVERLAY)
+ if("Medical Doctor")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "medical_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
+ if("Geneticist")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "geneticswhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_gen_open"), ICON_OVERLAY)
+ if("Virologist")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "virologywhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_vir_open"), ICON_OVERLAY)
+ if("Captain")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "captain_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ if("Head of Security")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "hosred_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
+ if("Warden")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "warden_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
+ if("Detective")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "detective_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "detective"), ICON_OVERLAY)
+ if("Security Officer")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "secred_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
+ if("Chief Engineer")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chief_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
+ if("Station Engineer")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "engine_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "orange"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
+ if("Atmospheric Technician")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "atmos_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
+ if("Roboticist")
+ clothes_s = new /icon('icons/mob/uniform.dmi', "robotics_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
+ else
+ clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ preview_icon.Blend(eyes_s, ICON_OVERLAY)
+ if(clothes_s)
+ preview_icon.Blend(clothes_s, ICON_OVERLAY)
+ qdel(eyes_s)
+ qdel(clothes_s)
+
return preview_icon
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 77800d97df..b7520acefc 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -22,9 +22,11 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/datum/supply_packs/New()
manifest += "
"
- for(var/atom/movable/path in contains)
- if(!path) continue
- manifest += "- [initial(path.name)]
"
+ for(var/path in contains)
+ if(!path || !ispath(path, /atom))
+ continue
+ var/atom/O = path
+ manifest += "- [initial(O.name)]
"
manifest += "
"
/datum/supply_packs/specialops
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index efe744174b..059a883aad 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -60,7 +60,8 @@
/datum/antagonist/proc/get_candidates(var/ghosts_only)
candidates = list() // Clear.
candidates = ticker.mode.get_players_for_role(role_type, id)
- // Prune restricted jobs and status. Broke it up for readability.
+ // Prune restricted status. Broke it up for readability.
+ // Note that this is done before jobs are handed out.
for(var/datum/mind/player in candidates)
if(ghosts_only && !istype(player.current, /mob/dead))
candidates -= player
@@ -75,7 +76,9 @@
return candidates
/datum/antagonist/proc/attempt_random_spawn()
- attempt_spawn(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
+ build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
+ attempt_spawn()
+ finalize_spawn()
/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player)
if(!can_late_spawn())
@@ -88,27 +91,59 @@
add_antagonist(player,0,1,0,1,1)
return
-/datum/antagonist/proc/attempt_spawn(var/ghosts_only)
-
+/datum/antagonist/proc/build_candidate_list(var/ghosts_only)
// Get the raw list of potential players.
update_current_antag_max()
candidates = get_candidates(ghosts_only)
+//Selects players that will be spawned in the antagonist role from the potential candidates
+//Selected players are added to the pending_antagonists lists.
+//Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned,
+//so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are
+//assigned, so that job restrictions can be respected.
+/datum/antagonist/proc/attempt_spawn(var/rebuild_candidates = 1)
+
// Update our boundaries.
if(!candidates.len)
return 0
//Grab candidates randomly until we have enough.
- while(candidates.len)
+ while(candidates.len && pending_antagonists.len < cur_max)
var/datum/mind/player = pick(candidates)
- pending_antagonists |= player
candidates -= player
+ draft_antagonist(player)
+
return 1
+/datum/antagonist/proc/draft_antagonist(var/datum/mind/player)
+ //Check if the player can join in this antag role, or if the player has already been given an antag role.
+ if(!can_become_antag(player) || player.special_role)
+ return 0
+
+ pending_antagonists |= player
+
+ //Ensure that antags with ANTAG_OVERRIDE_JOB do not occupy job slots.
+ if(flags & ANTAG_OVERRIDE_JOB)
+ player.assigned_role = role_text
+
+ //Ensure that a player cannot be drafted for multiple antag roles, taking up slots for antag roles that they will not fill.
+ player.special_role = role_text
+
+ return 1
+
+//Spawns all pending_antagonists. This is done separately from attempt_spawn in case the game mode setup fails.
/datum/antagonist/proc/finalize_spawn()
- if(!pending_antagonists || !pending_antagonists.len)
+ if(!pending_antagonists)
return
+
for(var/datum/mind/player in pending_antagonists)
- if(can_become_antag(player) && !player.special_role)
- add_antagonist(player,0,0,1)
- pending_antagonists.Cut()
\ No newline at end of file
+ pending_antagonists -= player
+ add_antagonist(player,0,0,1)
+
+//Resets all pending_antagonists, clearing their special_role (and assigned_role if ANTAG_OVERRIDE_JOB is set)
+/datum/antagonist/proc/reset()
+ for(var/datum/mind/player in pending_antagonists)
+ if(flags & ANTAG_OVERRIDE_JOB)
+ player.assigned_role = null
+ player.special_role = null
+ pending_antagonists.Cut()
diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm
index c16ea0a7c9..7815167d6f 100644
--- a/code/game/antagonist/antagonist_add.dm
+++ b/code/game/antagonist/antagonist_add.dm
@@ -9,6 +9,8 @@
return 0
current_antagonists |= player
+
+ //do this again, just in case
if(flags & ANTAG_OVERRIDE_JOB)
player.assigned_role = role_text
player.special_role = role_text
diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm
index 461cdc9211..db0d1b4204 100644
--- a/code/game/antagonist/antagonist_create.dm
+++ b/code/game/antagonist/antagonist_create.dm
@@ -42,7 +42,13 @@
return W
/datum/antagonist/proc/create_radio(var/freq, var/mob/living/carbon/human/player)
- var/obj/item/device/radio/R = new /obj/item/device/radio/headset(player)
+ var/obj/item/device/radio/R
+
+ if(freq == SYND_FREQ)
+ R = new/obj/item/device/radio/headset/syndicate(player)
+ else
+ R = new/obj/item/device/radio/headset(player)
+
R.set_frequency(freq)
player.equip_to_slot_or_del(R, slot_l_ear)
return R
@@ -113,6 +119,7 @@
if (newname)
player.real_name = newname
player.name = player.real_name
+ player.dna.real_name = newname
if(player.mind) player.mind.name = player.name
// Update any ID cards.
update_access(player)
diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm
index 74866d9247..57a00adfdd 100644
--- a/code/game/antagonist/outsider/wizard.dm
+++ b/code/game/antagonist/outsider/wizard.dm
@@ -96,7 +96,7 @@ var/datum/antagonist/wizard/wizards
world << "The [(current_antagonists.len>1)?"[role_text_plural] have":"[role_text] has"] been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!"
//To batch-remove wizard spells. Linked to mind.dm.
-/mob/proc/spellremove(var/mob/M as mob)
+/mob/proc/spellremove()
for(var/spell/spell_to_remove in src.spell_list)
remove_spell(spell_to_remove)
diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm
index cf0e9dfd4c..f19edb2807 100644
--- a/code/game/antagonist/station/rogue_ai.dm
+++ b/code/game/antagonist/station/rogue_ai.dm
@@ -6,12 +6,13 @@ var/datum/antagonist/rogue_ai/malf
role_text = "Rampant AI"
role_text_plural = "Rampant AIs"
mob_path = /mob/living/silicon/ai
+ landmark_id = "AI"
welcome_text = "You are malfunctioning! You do not have to follow any laws."
victory_text = "The AI has taken control of all of the station's systems."
loss_text = "The AI has been shut down!"
- flags = ANTAG_VOTABLE | ANTAG_RANDSPAWN //Randspawn needed otherwise it won't start at all.
+ flags = ANTAG_VOTABLE | ANTAG_OVERRIDE_MOB | ANTAG_OVERRIDE_JOB | ANTAG_CHOOSE_NAME
max_antags = 1
- max_antags_round = 3
+ max_antags_round = 1
/datum/antagonist/rogue_ai/New()
@@ -22,7 +23,7 @@ var/datum/antagonist/rogue_ai/malf
/datum/antagonist/rogue_ai/get_candidates()
..()
for(var/datum/mind/player in candidates)
- if(player.assigned_role != "AI")
+ if(player.assigned_role && player.assigned_role != "AI")
candidates -= player
if(!candidates.len)
return list()
@@ -75,3 +76,26 @@ var/datum/antagonist/rogue_ai/malf
malf << "For basic information about your abilities use command display-help"
malf << "You may choose one special hardware piece to help you. This cannot be undone."
malf << "Good luck!"
+
+
+/datum/antagonist/rogue_ai/update_antag_mob(var/datum/mind/player, var/preserve_appearance)
+
+ // Get the mob.
+ if((flags & ANTAG_OVERRIDE_MOB) && (!player.current || (mob_path && !istype(player.current, mob_path))))
+ var/mob/holder = player.current
+ player.current = new mob_path(get_turf(player.current), null, null, 1)
+ player.transfer_to(player.current)
+ if(holder) qdel(holder)
+ player.original = player.current
+ return player.current
+
+/datum/antagonist/rogue_ai/set_antag_name(var/mob/living/silicon/player)
+ if(!istype(player))
+ testing("rogue_ai set_antag_name called on non-silicon mob [player]!")
+ return
+ // Choose a name, if any.
+ var/newname = sanitize(input(player, "You are a [role_text]. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN)
+ if (newname)
+ player.SetName(newname)
+ if(player.mind) player.mind.name = player.name
+
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index eaf6da4a0d..d872493443 100755
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -901,7 +901,7 @@ area/space/atmosalert()
icon_state = "tcomsatcham"
/area/server
- name = "\improper Messaging Server Room"
+ name = "\improper Research Server Room"
icon_state = "server"
//Crew
@@ -1809,7 +1809,7 @@ area/space/atmosalert()
ambience = list('sound/ambience/ambimalf.ogg')
/area/turret_protected/ai_server_room
- name = "AI Server Room"
+ name = "Messaging Server Room"
icon_state = "ai_server"
/area/turret_protected/ai
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index e342ba3329..3b970c7438 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -14,13 +14,17 @@
all_areas += src
if(!requires_power)
- power_light = 0 //rastaf0
- power_equip = 0 //rastaf0
- power_environ = 0 //rastaf0
+ power_light = 0
+ power_equip = 0
+ power_environ = 0
..()
-// spawn(15)
+/area/proc/initialize()
+ if(!requires_power || !apc)
+ power_light = 0
+ power_equip = 0
+ power_environ = 0
power_change() // all machines set to current power level, also updates lighting icon
/area/proc/get_contents()
@@ -227,7 +231,7 @@ var/list/mob/living/forced_ambiance_list = new
var/area/oldarea = L.lastarea
if((oldarea.has_gravity == 0) && (newarea.has_gravity == 1) && (L.m_intent == "run")) // Being ready when you change areas gives you a chance to avoid falling all together.
thunk(L)
- L.make_floating(0)
+ L.update_floating( L.Check_Dense_Object() )
L.lastarea = newarea
play_ambience(L)
@@ -260,21 +264,10 @@ var/list/mob/living/forced_ambiance_list = new
/area/proc/gravitychange(var/gravitystate = 0, var/area/A)
A.has_gravity = gravitystate
- if(gravitystate)
- for(var/mob/living/carbon/human/M in A)
+ for(var/mob/M in A)
+ if(has_gravity)
thunk(M)
- for(var/mob/M1 in A)
- M1.make_floating(0)
- else
- for(var/mob/M in A)
- if(M.Check_Dense_Object() && istype(src,/mob/living/carbon/human/))
- var/mob/living/carbon/human/H = src
- if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.flags & NOSLIP)) //magboots + dense_object = no floaty effect
- H.make_floating(0)
- else
- H.make_floating(1)
- else
- M.make_floating(1)
+ M.update_floating( M.Check_Dense_Object() )
/area/proc/thunk(mob)
if(istype(get_turf(mob), /turf/space)) // Can't fall onto nothing.
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 8c5ac46da2..28ead38d6f 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -63,9 +63,6 @@
return flags & INSERT_CONTAINER
*/
-/atom/proc/allow_drop()
- return 1
-
/atom/proc/CheckExit()
return 1
@@ -487,4 +484,4 @@ its easier to just keep the beam vertical.
O.show_message( message, 2, deaf_message, 1)
else if(ismob(I))
var/mob/M = I
- M.show_message( message, 2, deaf_message, 1)
+ M.show_message( message, 2, deaf_message, 1)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 5bc8cc9941..1bb29eb4c8 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -164,7 +164,7 @@
a = get_area(src.loc)
else
var/error = dist_y/2 - dist_x
- while(src && target &&((((src.y < target.y && dy == NORTH) || (src.y > target.y && dy == SOUTH)) && dist_travelled < range) || (a.has_gravity == 0) || istype(src.loc, /turf/space)) && src.throwing && istype(src.loc, /turf))
+ while(src && target &&((((src.y < target.y && dy == NORTH) || (src.y > target.y && dy == SOUTH)) && dist_travelled < range) || (a && a.has_gravity == 0) || istype(src.loc, /turf/space)) && src.throwing && istype(src.loc, /turf))
// only stop when we've gone the whole distance (or max throw range) and are on a non-space tile, or hit something, or hit the end of the map, or someone picks it up
if(error < 0)
var/atom/step = get_step(src, dx)
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index 1ac7d7baa6..d806ac22dd 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -64,9 +64,6 @@
component_parts += new /obj/item/stack/cable_coil(src)
RefreshParts()
-/obj/machinery/dna_scannernew/allow_drop()
- return 0
-
/obj/machinery/dna_scannernew/relaymove(mob/user as mob)
if (user.stat)
return
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index eb15d45f51..34a81b4d61 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -193,7 +193,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
src << "This creature's DNA is ruined beyond useability!"
return
- if(!G.state == GRAB_KILL)
+ if(G.state != GRAB_KILL)
src << "We must have a tighter grip to absorb this creature."
return
diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm
index abbe9cb988..7ba0052b81 100644
--- a/code/game/gamemodes/changeling/modularchangling.dm
+++ b/code/game/gamemodes/changeling/modularchangling.dm
@@ -121,7 +121,7 @@ var/list/datum/power/changeling/powerinstances = list()
/datum/power/changeling/DeathSting
name = "Death Sting"
- desc = "We silently sting a human, filling him with potent chemicals. His rapid death is all but assured."
+ desc = "We silently sting a human, filling them with potent chemicals. Their rapid death is all but assured."
genomecost = 10
verbpath = /mob/proc/changeling_DEATHsting
diff --git a/code/game/gamemodes/cult/cultify/obj.dm b/code/game/gamemodes/cult/cultify/obj.dm
index 405ea6b29c..517c6079fd 100644
--- a/code/game/gamemodes/cult/cultify/obj.dm
+++ b/code/game/gamemodes/cult/cultify/obj.dm
@@ -136,8 +136,8 @@
// Make it a wood-reinforced wooden table.
// There are cult materials available, but it'd make the table non-deconstructable with how holotables work.
// Could possibly use a new material var for holographic-ness?
- material = name_to_material["wood"]
- reinforced = name_to_material["wood"]
+ material = get_material_by_name("wood")
+ reinforced = get_material_by_name("wood")
update_desc()
update_connections(1)
update_icon()
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index dc09e0edb9..cba7a96ef4 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -339,7 +339,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
attack(mob/living/M as mob, mob/living/user as mob)
- M.attack_log += text("\[[time_stamp()]\] Has had the [name] used on him by [user.name] ([user.ckey])")
+ M.attack_log += text("\[[time_stamp()]\] Has had the [name] used on them by [user.name] ([user.ckey])")
user.attack_log += text("\[[time_stamp()]\] Used [name] on [M.name] ([M.ckey])")
msg_admin_attack("[user.name] ([user.ckey]) used [name] on [M.name] ([M.ckey]) (JMP)")
diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm
index ff5b7ff880..3b2345c1be 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -5,6 +5,14 @@ var/list/sacrificed = list()
/obj/effect/rune
+/*
+ * Use as a general guideline for this and related files:
+ * * ... - when something non-trivial or an error happens, so something similar to "Sparks come out of the machine!"
+ * * ... - when something that is fit for 'warning' happens but there is some damage or pain as well.
+ * * ... - when there is a private message to the cultists. This guideline is very arbitrary but there has to be some consistency!
+ */
+
+
/////////////////////////////////////////FIRST RUNE
proc
teleport(var/key)
@@ -21,7 +29,7 @@ var/list/sacrificed = list()
allrunesloc.len = index
allrunesloc[index] = R.loc
if(index >= 5)
- user << "You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric"
+ user << "You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric."
if (istype(user, /mob/living))
user.take_overall_damage(5, 0)
qdel(src)
@@ -30,9 +38,9 @@ var/list/sacrificed = list()
user.say("Sas[pick("'","`")]so c'arta forbici!")//Only you can stop auto-muting
else
user.whisper("Sas[pick("'","`")]so c'arta forbici!")
- user.visible_message("\The [user] disappears in a flash of red light!", \
- "You feel as your body gets dragged through the dimension of Nar-Sie!", \
- "You hear a sickening crunch and sloshing of viscera.")
+ user.visible_message("[user] disappears in a flash of red light!", \
+ "You feel as your body gets dragged through the dimension of Nar-Sie!", \
+ "You hear a sickening crunch and sloshing of viscera.")
user.loc = allrunesloc[rand(1,index)]
return
if(istype(src,/obj/effect/rune))
@@ -58,7 +66,7 @@ var/list/sacrificed = list()
IP = R
runecount++
if(runecount >= 2)
- user << "You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric"
+ user << "You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric."
if (istype(user, /mob/living))
user.take_overall_damage(5, 0)
qdel(src)
@@ -134,11 +142,11 @@ var/list/sacrificed = list()
admin_attack_log(attacker, target, "Used a convert rune", "Was subjected to a convert rune", "used a convert rune on")
switch(target.getFireLoss())
if(0 to 25)
- target << "Your blood boils as you force yourself to resist the corruption invading every corner of your mind."
+ target << "Your blood boils as you force yourself to resist the corruption invading every corner of your mind."
if(25 to 45)
- target << "Your blood boils and your body burns as the corruption further forces itself into your body and mind."
+ target << "Your blood boils and your body burns as the corruption further forces itself into your body and mind."
if(45 to 75)
- target << "You begin to hallucinate images of a dark and incomprehensible being and your entire body feels like its engulfed in flame as your mental defenses crumble."
+ target << "You begin to hallucinate images of a dark and incomprehensible being and your entire body feels like its engulfed in flame as your mental defenses crumble."
target.apply_effect(rand(1,10), STUTTER)
if(75 to 100)
target << "Your mind turns to ash as the burning flames engulf your very soul and images of an unspeakable horror begin to bombard the last remnants of mental resistance."
@@ -157,7 +165,7 @@ var/list/sacrificed = list()
if (target.species && (target.species.flags & NO_PAIN))
target.visible_message("The markings below [target] glow a bloody red.")
else
- target.visible_message("\The [target] writhes in pain as the markings below \him glow a bloody red.", "AAAAAAHHHH!", "You hear an anguished scream.")
+ target.visible_message("[target] writhes in pain as the markings below \him glow a bloody red.", "AAAAAAHHHH!", "You hear an anguished scream.")
if(!waiting_for_input[target]) //so we don't spam them with dialogs if they hesitate
waiting_for_input[target] = 1
@@ -229,15 +237,15 @@ var/list/sacrificed = list()
if(!drain)
return fizzle()
usr.say ("Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!")
- usr.visible_message("Blood flows from the rune into [usr]!", \
- "The blood starts flowing from the rune and into your frail mortal body. You feel... empowered.", \
+ usr.visible_message("Blood flows from the rune into [usr]!", \
+ "The blood starts flowing from the rune and into your frail mortal body. You feel... empowered.", \
"You hear a liquid flowing.")
var/mob/living/user = usr
if(user.bhunger)
user.bhunger = max(user.bhunger-2*drain,0)
if(drain>=50)
- user.visible_message("\The [user]'s eyes give off eerie red glow!", \
- "...but it wasn't nearly enough. You crave, crave for more. The hunger consumes you from within.", \
+ user.visible_message("[user]'s eyes give off eerie red glow!", \
+ "...but it wasn't nearly enough. You crave, crave for more. The hunger consumes you from within.", \
"You hear a heartbeat.")
user.bhunger += drain
src = user
@@ -264,7 +272,7 @@ var/list/sacrificed = list()
if(usr.loc==src.loc)
if(usr.seer==1)
usr.say("Rash'tla sektath mal[pick("'","`")]zua. Zasan therium viortia.")
- usr << "The world beyond fades from your vision."
+ usr << "The world beyond fades from your vision."
usr.see_invisible = SEE_INVISIBLE_LIVING
usr.seer = 0
else if(usr.see_invisible!=SEE_INVISIBLE_LIVING)
@@ -336,12 +344,12 @@ var/list/sacrificed = list()
corpse_to_raise.key = ghost.key //the corpse will keep its old mind! but a new player takes ownership of it (they are essentially possessed)
//This means, should that player leave the body, the original may re-enter
usr.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!")
- corpse_to_raise.visible_message("\The [corpse_to_raise]'s eyes glow with a faint red as he stands up, slowly starting to breathe again.", \
+ corpse_to_raise.visible_message("[corpse_to_raise]'s eyes glow with a faint red as he stands up, slowly starting to breathe again.", \
"Life... I'm alive again...", \
"You hear a faint, slightly familiar whisper.")
- body_to_sacrifice.visible_message("\The [body_to_sacrifice] is torn apart, a black smoke swiftly dissipating from his remains!", \
- "You feel as your blood boils, tearing you apart.", \
- "You hear a thousand voices, all crying in pain.")
+ body_to_sacrifice.visible_message("[body_to_sacrifice] is torn apart, a black smoke swiftly dissipating from \his remains!", \
+ "You feel as your blood boils, tearing you apart.", \
+ "You hear a thousand voices, all crying in pain.")
body_to_sacrifice.gib()
// if(ticker.mode.name == "cult")
@@ -349,8 +357,8 @@ var/list/sacrificed = list()
// else
// ticker.mode.cult |= corpse_to_raise.mind
- corpse_to_raise << "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root."
- corpse_to_raise << "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back."
+ corpse_to_raise << "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root."
+ corpse_to_raise << "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back."
return
@@ -391,7 +399,7 @@ var/list/sacrificed = list()
if(usr.loc==src.loc)
var/mob/living/carbon/human/L = usr
usr.say("Fwe[pick("'","`")]sh mah erl nyag r'ya!")
- usr.visible_message("\The [usr]'s eyes glow blue as \he freezes in place, absolutely motionless.", \
+ usr.visible_message("[usr]'s eyes glow blue as \he freezes in place, absolutely motionless.", \
"The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry...", \
"You hear only complete silence for a moment.")
announce_ghost_joinleave(usr.ghostize(1), 1, "You feel that they had to use some [pick("dark", "black", "blood", "forgotten", "forbidden")] magic to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place!")
@@ -461,8 +469,8 @@ var/list/sacrificed = list()
user.take_organ_damage(1, 0)
sleep(30)
if(D)
- D.visible_message("\The [D] slowly dissipates into dust and bones.", \
- "You feel pain, as bonds formed between your soul and this homunculus break.", \
+ D.visible_message("[D] slowly dissipates into dust and bones.", \
+ "You feel pain, as bonds formed between your soul and this homunculus break.", \
"You hear faint rustle.")
D.dust()
return
@@ -560,8 +568,8 @@ var/list/sacrificed = list()
user.say("Uhrast ka'hfa heldsagen ver[pick("'","`")]lot!")
user.take_overall_damage(200, 0)
runedec+=10
- user.visible_message("\The [user] keels over dead, his blood glowing blue as it escapes his body and dissipates into thin air.", \
- "In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.", \
+ user.visible_message("\The [user] keels over dead, \his blood glowing blue as it escapes \his body and dissipates into thin air.", \
+ "In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.", \
"You hear faint rustle.")
for(,user.stat==2)
sleep(600)
@@ -592,9 +600,10 @@ var/list/sacrificed = list()
usr.whisper("[input]")
input = sanitize(input)
+ log_and_message_admins("used a communicate rune to say '[input]'")
for(var/datum/mind/H in cult.current_antagonists)
if (H.current)
- H.current << "[input]"
+ H.current << "[input]"
qdel(src)
return 1
@@ -638,17 +647,17 @@ var/list/sacrificed = list()
H.dust()//To prevent the MMI from remaining
else
H.gib()
- usr << "The Geometer of Blood accepts this sacrifice, your objective is now complete."
+ usr << "The Geometer of Blood accepts this sacrifice, your objective is now complete."
else
usr << "Your target's earthly bonds are too strong. You need more cultists to succeed in this ritual."
else
if(cultsinrange.len >= 3)
if(H.stat !=2)
if(prob(80) || worth)
- usr << "The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice."
+ usr << "The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice."
cult.grant_runeword(usr)
else
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
usr << "However, this soul was not enough to gain His favor."
if(isrobot(H))
H.dust()//To prevent the MMI from remaining
@@ -656,10 +665,10 @@ var/list/sacrificed = list()
H.gib()
else
if(prob(40) || worth)
- usr << "The Geometer of blood accepts this [worth ? "exotic " : ""]sacrifice."
+ usr << "The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice."
cult.grant_runeword(usr)
else
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
usr << "However, a mere dead body is not enough to satisfy Him."
if(isrobot(H))
H.dust()//To prevent the MMI from remaining
@@ -671,10 +680,10 @@ var/list/sacrificed = list()
else
if(prob(40))
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
cult.grant_runeword(usr)
else
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
usr << "However, a mere dead body is not enough to satisfy Him."
if(isrobot(H))
H.dust()//To prevent the MMI from remaining
@@ -684,10 +693,10 @@ var/list/sacrificed = list()
if(cultsinrange.len >= 3)
if(H.stat !=2)
if(prob(80))
- usr << "The Geometer of Blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
cult.grant_runeword(usr)
else
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
usr << "However, this soul was not enough to gain His favor."
if(isrobot(H))
H.dust()//To prevent the MMI from remaining
@@ -695,10 +704,10 @@ var/list/sacrificed = list()
H.gib()
else
if(prob(40))
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
cult.grant_runeword(usr)
else
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
usr << "However, a mere dead body is not enough to satisfy Him."
if(isrobot(H))
H.dust()//To prevent the MMI from remaining
@@ -709,10 +718,10 @@ var/list/sacrificed = list()
usr << "The victim is still alive, you will need more cultists chanting for the sacrifice to succeed."
else
if(prob(40))
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
cult.grant_runeword(usr)
else
- usr << "The Geometer of blood accepts this sacrifice."
+ usr << "The Geometer of Blood accepts this sacrifice."
usr << "However, a mere dead body is not enough to satisfy Him."
if(isrobot(H))
H.dust()//To prevent the MMI from remaining
@@ -771,9 +780,9 @@ var/list/sacrificed = list()
var/mob/living/user = usr
user.take_organ_damage(2, 0)
if(src.density)
- usr << "Your blood flows into the rune, and you feel that the very space over the rune thickens."
+ usr << "Your blood flows into the rune, and you feel that the very space over the rune thickens."
else
- usr << "Your blood flows into the rune, and you feel as the rune releases its grasp on space."
+ usr << "Your blood flows into the rune, and you feel as the rune releases its grasp on space."
return
/////////////////////////////////////////EIGHTTEENTH RUNE
@@ -842,7 +851,7 @@ var/list/sacrificed = list()
if (cultist == user) //just to be sure.
return
if(cultist.buckled || cultist.handcuffed || (!isturf(cultist.loc) && !istype(cultist.loc, /obj/structure/closet)))
- user << "You cannot summon \the [cultist], for his shackles of blood are strong."
+ user << "You cannot summon \the [cultist], for \his shackles of blood are strong."
return fizzle()
cultist.loc = src.loc
cultist.lying = 1
@@ -922,7 +931,7 @@ var/list/sacrificed = list()
C.disabilities |= NEARSIGHTED
if(prob(10))
C.sdisabilities |= BLIND
- C.show_message("Suddenly you see red flash that blinds you.", 3)
+ C.show_message("Suddenly you see a red flash that blinds you.", 3)
affected += C
if(affected.len)
usr.say("Sti[pick("'","`")] kaliesin!")
@@ -972,7 +981,7 @@ var/list/sacrificed = list()
if(N)
continue
M.take_overall_damage(51,51)
- M << "Your blood boils!"
+ M << "Your blood boils!"
victims += M
if(prob(5))
spawn(5)
@@ -1004,16 +1013,16 @@ var/list/sacrificed = list()
for(var/mob/living/M in orange(2,R))
M.take_overall_damage(0,15)
if (R.invisibility>M.see_invisible)
- M << "Aargh it burns!"
+ M << "Aargh it burns!"
else
- M << "Rune suddenly ignites, burning you!"
+ M << "Rune suddenly ignites, burning you!"
var/turf/T = get_turf(R)
T.hotspot_expose(700,125)
for(var/obj/effect/decal/cleanable/blood/B in world)
if(B.blood_DNA == src.blood_DNA)
for(var/mob/living/M in orange(1,B))
M.take_overall_damage(0,5)
- M << "Blood suddenly ignites, burning you!"
+ M << "Blood suddenly ignites, burning you!"
var/turf/T = get_turf(B)
T.hotspot_expose(700,125)
qdel(B)
@@ -1032,13 +1041,13 @@ var/list/sacrificed = list()
C.stuttering = 1
C.Weaken(1)
C.Stun(1)
- C.show_message("The rune explodes in a bright flash.", 3)
+ C.show_message("The rune explodes in a bright flash.", 3)
admin_attack_log(usr, C, "Used a stun rune.", "Was victim of a stun rune.", "used a stun rune on")
else if(issilicon(L))
var/mob/living/silicon/S = L
S.Weaken(5)
- S.show_message("BZZZT... The rune has exploded in a bright flash.", 3)
+ S.show_message("BZZZT... The rune has exploded in a bright flash.", 3)
admin_attack_log(usr, S, "Used a stun rune.", "Was victim of a stun rune.", "used a stun rune on")
qdel(src)
else ///When invoked as talisman, stun and mute the target mob.
@@ -1046,10 +1055,10 @@ var/list/sacrificed = list()
var/obj/item/weapon/nullrod/N = locate() in T
if(N)
for(var/mob/O in viewers(T, null))
- O.show_message("\The [usr] invokes a talisman at [T], but they are unaffected!", 1)
+ O.show_message(text("[] invokes a talisman at [], but they are unaffected!", usr, T), 1)
else
for(var/mob/O in viewers(T, null))
- O.show_message("\The [usr] invokes a talisman at [T]", 1)
+ O.show_message(text("[] invokes a talisman at []", usr, T), 1)
if(issilicon(T))
T.Weaken(15)
diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm
index 82f1cbce7f..f644391bf7 100644
--- a/code/game/gamemodes/events.dm
+++ b/code/game/gamemodes/events.dm
@@ -326,7 +326,7 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
//AI laws
for(var/mob/living/silicon/ai/M in living_mob_list)
- if(M.stat != 2 && M.has_power)
+ if(M.stat != 2 && M.see_in_dark != 0)
var/who2 = pick("ALIENS", "BEARS", "CLOWNS", "XENOS", "PETES", "BOMBS", "FETISHES", "WIZARDS", "SYNDICATE AGENTS", "CENTCOM OFFICERS", "SPACE PIRATES", "TRAITORS", "MONKEYS", "BEES", "CARP", "CRABS", "EELS", "BANDITS", "LIGHTS")
var/what2 = pick("BOLTERS", "STAVES", "DICE", "SINGULARITIES", "TOOLBOXES", "NETTLES", "AIRLOCKS", "CLOTHES", "WEAPONS", "MEDKITS", "BOMBS", "CANISTERS", "CHAIRS", "BBQ GRILLS", "ID CARDS", "CAPTAINS")
var/what2pref = pick("SOFT", "WARM", "WET", "COLD", "ICY", "SEXY", "UGLY", "CUBAN")
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 6cca12d77f..2555bc2698 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -166,12 +166,14 @@ var/global/list/additional_antag_types = list()
if(!(antag_templates && antag_templates.len))
return 1
- // Attempt to mark folks down as ready to go. Don't finalize until post setup.
var/datum/antagonist/main_antags = antag_templates[1]
- var/list/candidates = main_antags.get_candidates()
- if(candidates.len >= required_enemies)
- for(var/datum/antagonist/antag in antag_templates)
- antag.attempt_spawn()
+ var/list/potential
+ if(main_antags.flags & ANTAG_OVERRIDE_JOB)
+ potential = main_antags.pending_antagonists
+ else
+ potential = main_antags.candidates
+
+ if(potential.len >= required_enemies)
return 1
return 0
@@ -185,6 +187,14 @@ var/global/list/additional_antag_types = list()
var/datum/event_container/EMajor = event_manager.event_containers[EVENT_LEVEL_MAJOR]
EMajor.delay_modifier = event_delay_mod_major
+/datum/game_mode/proc/pre_setup()
+ for(var/datum/antagonist/antag in antag_templates)
+ antag.build_candidate_list() //compile a list of all eligible candidates
+
+ //antag roles that replace jobs need to be assigned before the job controller hands out jobs.
+ if(antag.flags & ANTAG_OVERRIDE_JOB)
+ antag.attempt_spawn() //select antags to be spawned
+
///post_setup()
/datum/game_mode/proc/post_setup()
@@ -198,11 +208,13 @@ var/global/list/additional_antag_types = list()
spawn(rand(100,150))
announce_ert_disabled()
- if(antag_templates && antag_templates.len)
- for(var/datum/antagonist/antag in antag_templates)
- antag.finalize_spawn()
- if(antag.is_latejoin_template())
- latejoin_templates |= antag
+ //Assign all antag types for this game mode. Any players spawned as antags earlier should have been removed from the pending list, so no need to worry about those.
+ for(var/datum/antagonist/antag in antag_templates)
+ if(!(antag.flags & ANTAG_OVERRIDE_JOB))
+ antag.attempt_spawn() //select antags to be spawned
+ antag.finalize_spawn() //actually spawn antags
+ if(antag.is_latejoin_template())
+ latejoin_templates |= antag
if(emergency_shuttle && auto_recall_shuttle)
emergency_shuttle.auto_recall = 1
@@ -213,6 +225,10 @@ var/global/list/additional_antag_types = list()
feedback_set_details("server_ip","[world.internet_address]:[world.port]")
return 1
+/datum/game_mode/proc/fail_setup()
+ for(var/datum/antagonist/antag in antag_templates)
+ antag.reset()
+
/datum/game_mode/proc/announce_ert_disabled()
if(!ert_disabled)
return
diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm
index 95a58e2ea5..614d181795 100644
--- a/code/game/gamemodes/gameticker.dm
+++ b/code/game/gamemodes/gameticker.dm
@@ -91,11 +91,14 @@ var/global/datum/controller/gameticker/ticker
else
src.mode = config.pick_mode(master_mode)
+ src.mode.pre_setup()
+
job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly.
if(!mode_started && !src.mode.can_start())
world << "Unable to start [mode.name]. Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby."
current_state = GAME_STATE_PREGAME
+ mode.fail_setup()
mode = null
job_master.ResetOccupations()
return 0
@@ -110,6 +113,7 @@ var/global/datum/controller/gameticker/ticker
else
src.mode.announce()
+ setup_economy()
current_state = GAME_STATE_PLAYING
create_characters() //Create player characters and transfer them
collect_minds()
@@ -118,9 +122,6 @@ var/global/datum/controller/gameticker/ticker
callHook("roundstart")
- //here to initialize the random events nicely at round start
- setup_economy()
-
shuttle_controller.setup_shuttle_docks()
spawn(0)//Forking here so we dont have to wait for this to finish
diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm
index 7e1ba6d368..03680c8ff3 100644
--- a/code/game/gamemodes/heist/heist.dm
+++ b/code/game/gamemodes/heist/heist.dm
@@ -20,12 +20,3 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind'
if (skipjack && skipjack.returned_home)
return 1
return 0
-
-/datum/game_mode/heist/cleanup()
- //the skipjack and everything in it have left and aren't coming back, so get rid of them.
- var/area/skipjack = locate(/area/shuttle/skipjack/station)
- for (var/mob/living/M in skipjack.contents)
- //maybe send the player a message that they've gone home/been kidnapped? Someone responsible for vox lore should write that.
- qdel(M)
- for (var/obj/O in skipjack.contents)
- qdel(O) //no hiding in lockers or anything
\ No newline at end of file
diff --git a/code/game/gamemodes/newobjective.dm b/code/game/gamemodes/newobjective.dm
index 9dc8623822..e8ea12b84b 100644
--- a/code/game/gamemodes/newobjective.dm
+++ b/code/game/gamemodes/newobjective.dm
@@ -1252,7 +1252,7 @@ datum
proc/find_target()
..()
if(target && target.current)
- explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : target.assigned_role], has defied us for the last time. Make an example of him, and bring us his severed head."
+ explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : target.assigned_role], has defied us for the last time. Make an example of [target.current.gender == MALE ? "him" : target.current.gender == FEMALE ? "her" : "them"], and bring us [target.current.gender == MALE ? "his" : target.current.gender == FEMALE ? "her" : "their"] severed head."
else
explanation_text = "Free Objective"
return target
@@ -1261,7 +1261,7 @@ datum
find_target_by_role(role, role_type=0)
..(role, role_type)
if(target && target.current)
- explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : (!role_type ? target.assigned_role : target.special_role)], has defied us for the last time. Make an example of him, and bring us his severed head."
+ explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : (!role_type ? target.assigned_role : target.special_role)], has defied us for the last time. Make an example of [target.current.gender == MALE ? "him" : target.current.gender == FEMALE ? "her" : "them"], and bring us [target.current.gender == MALE ? "his" : target.current.gender == FEMALE ? "her" : "their"] severed head."
else
explanation_text = "Free Objective"
return target
@@ -1488,4 +1488,4 @@ datum/objective/silence
#undef LENIENT
#undef NORMAL
#undef HARD
-#undef IMPOSSIBLE
\ No newline at end of file
+#undef IMPOSSIBLE
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index 0812c51429..7209844d38 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -1,6 +1,6 @@
/datum/game_mode/wizard
name = "Wizard"
- round_description = "There is a SPACE WIZARD on the station. You can't let them achieve their objectives!"
+ round_description = "There is a SPACE WIZARD on the station. You can't let the magician achieve their objectives!"
extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has infiltrated the station. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows the destruction of the entire station."
config_tag = "wizard"
required_players = 1
diff --git a/code/game/jobs/access_datum.dm b/code/game/jobs/access_datum.dm
index 3aca20b760..9cf27f6dbc 100644
--- a/code/game/jobs/access_datum.dm
+++ b/code/game/jobs/access_datum.dm
@@ -305,17 +305,8 @@
desc = "Cargo Office"
region = ACCESS_REGION_SUPPLY
-/var/const/access_mint = 51
-/datum/access/mint
- id = access_mint
- desc = "Mint"
- region = ACCESS_REGION_SUPPLY
-
-/var/const/access_mint_vault = 52
-/datum/access/mint_vault
- id = access_mint_vault
- desc = "Mint Vault"
- access_type = ACCESS_TYPE_NONE
+// /var/const/free_access_id = 51
+// /var/const/free_access_id = 52
/var/const/access_heads_vault = 53
/datum/access/heads_vault
diff --git a/code/game/jobs/job/assistant.dm b/code/game/jobs/job/assistant.dm
index 98c7a4dd98..f390303452 100644
--- a/code/game/jobs/job/assistant.dm
+++ b/code/game/jobs/job/assistant.dm
@@ -10,7 +10,7 @@
selection_color = "#dddddd"
access = list() //See /datum/job/assistant/get_access()
minimal_access = list() //See /datum/job/assistant/get_access()
- alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Security Cadet","Visitor")
+ alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Visitor")
/datum/job/assistant/equip(var/mob/living/carbon/human/H)
if(!H) return 0
diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm
index 7d84753353..26f5c02020 100644
--- a/code/game/jobs/job/civilian.dm
+++ b/code/game/jobs/job/civilian.dm
@@ -97,8 +97,8 @@
spawn_positions = 1
supervisors = "the head of personnel"
selection_color = "#dddddd"
- access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station)
- minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station)
+ access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
+ minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
equip(var/mob/living/carbon/human/H)
@@ -124,7 +124,7 @@
spawn_positions = 2
supervisors = "the quartermaster and the head of personnel"
selection_color = "#dddddd"
- access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station)
+ access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting)
@@ -149,8 +149,8 @@
spawn_positions = 3
supervisors = "the quartermaster and the head of personnel"
selection_color = "#dddddd"
- access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station)
- minimal_access = list(access_mining, access_mint, access_mining_station, access_mailsorting)
+ access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
+ minimal_access = list(access_mining, access_mining_station, access_mailsorting)
alt_titles = list("Drill Technician","Prospector")
equip(var/mob/living/carbon/human/H)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index af13cc1ed0..4fe18bba65 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -177,11 +177,6 @@
return
return
-
- allow_drop()
- return 0
-
-
process()
if (stat & (NOPOWER|BROKEN))
return
@@ -342,7 +337,7 @@
if(src.occupant.reagents.get_reagent_amount(chemical) + amount <= 20)
use_power(amount * CHEM_SYNTH_ENERGY)
src.occupant.reagents.add_reagent(chemical, amount)
- user << "Occupant now has [src.occupant.reagents.get_reagent_amount(chemical)] units of [available_chemicals[chemical]] in his/her bloodstream."
+ user << "Occupant now has [src.occupant.reagents.get_reagent_amount(chemical)] units of [available_chemicals[chemical]] in their bloodstream."
return
user << "There's no occupant in the sleeper or the subject has too many chemicals!"
return
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index f3ce2f85bd..3e456dfe69 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -14,9 +14,6 @@
idle_power_usage = 60
active_power_usage = 10000 //10 kW. It's a big all-body scanner.
-/*/obj/machinery/bodyscanner/allow_drop()
- return 0*/
-
/obj/machinery/bodyscanner/relaymove(mob/user as mob)
if (user.stat)
return
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index faf8ed713d..c039cea3e2 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -69,6 +69,7 @@
var/datum/radio_frequency/radio_connection
var/list/TLV = list()
+ var/list/trace_gas = list("sleeping_agent", "volatile_fuel") //list of other gases that this air alarm is able to detect
var/danger_level = 0
var/pressure_dangerlevel = 0
@@ -240,23 +241,24 @@
/obj/machinery/alarm/proc/overall_danger_level(var/datum/gas_mixture/environment)
var/partial_pressure = R_IDEAL_GAS_EQUATION*environment.temperature/environment.volume
var/environment_pressure = environment.return_pressure()
- //var/other_moles = 0.0
- ////for(var/datum/gas/G in environment.trace_gases)
- // other_moles+=G.moles
+
+ var/other_moles = 0
+ for(var/g in trace_gas)
+ other_moles += environment.gas[g] //this is only going to be used in a partial pressure calc, so we don't need to worry about group_multiplier here.
pressure_dangerlevel = get_danger_level(environment_pressure, TLV["pressure"])
oxygen_dangerlevel = get_danger_level(environment.gas["oxygen"]*partial_pressure, TLV["oxygen"])
co2_dangerlevel = get_danger_level(environment.gas["carbon_dioxide"]*partial_pressure, TLV["carbon dioxide"])
phoron_dangerlevel = get_danger_level(environment.gas["phoron"]*partial_pressure, TLV["phoron"])
temperature_dangerlevel = get_danger_level(environment.temperature, TLV["temperature"])
- //other_dangerlevel = get_danger_level(other_moles*partial_pressure, TLV["other"])
+ other_dangerlevel = get_danger_level(other_moles*partial_pressure, TLV["other"])
return max(
pressure_dangerlevel,
oxygen_dangerlevel,
co2_dangerlevel,
phoron_dangerlevel,
- //other_dangerlevel,
+ other_dangerlevel,
temperature_dangerlevel
)
@@ -302,22 +304,30 @@
/obj/machinery/alarm/update_icon()
if(wiresexposed)
icon_state = "alarmx"
+ set_light(0)
return
if((stat & (NOPOWER|BROKEN)) || shorted)
icon_state = "alarmp"
+ set_light(0)
return
var/icon_level = danger_level
if (alarm_area.atmosalm)
icon_level = max(icon_level, 1) //if there's an atmos alarm but everything is okay locally, no need to go past yellow
+ var/new_color = null
switch(icon_level)
if (0)
icon_state = "alarm0"
+ new_color = "#03A728"
if (1)
icon_state = "alarm2" //yes, alarm2 is yellow alarm
+ new_color = "#EC8B2F"
if (2)
icon_state = "alarm1"
+ new_color = "#DA0205"
+
+ set_light(l_range = 2, l_power = 0.5, l_color = new_color)
/obj/machinery/alarm/receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN))
@@ -504,34 +514,13 @@
var/list/environment_data = new
data["has_environment"] = total
if(total)
- var/partial_pressure = R_IDEAL_GAS_EQUATION*environment.temperature/environment.volume
-
- var/list/current_settings = TLV["pressure"]
var/pressure = environment.return_pressure()
- var/pressure_danger = get_danger_level(pressure, current_settings)
- environment_data[++environment_data.len] = list("name" = "Pressure", "value" = pressure, "unit" = "kPa", "danger_level" = pressure_danger)
- data["total_danger"] = pressure_danger
-
- current_settings = TLV["oxygen"]
- var/oxygen_danger = get_danger_level(environment.gas["oxygen"]*partial_pressure, current_settings)
- environment_data[++environment_data.len] = list("name" = "Oxygen", "value" = environment.gas["oxygen"] / total * 100, "unit" = "%", "danger_level" = oxygen_danger)
- data["total_danger"] = max(oxygen_danger, data["total_danger"])
-
- current_settings = TLV["carbon dioxide"]
- var/carbon_dioxide_danger = get_danger_level(environment.gas["carbon_dioxide"]*partial_pressure, current_settings)
- environment_data[++environment_data.len] = list("name" = "Carbon dioxide", "value" = environment.gas["carbon_dioxide"] / total * 100, "unit" = "%", "danger_level" = carbon_dioxide_danger)
- data["total_danger"] = max(carbon_dioxide_danger, data["total_danger"])
-
- current_settings = TLV["phoron"]
- var/phoron_danger = get_danger_level(environment.gas["phoron"]*partial_pressure, current_settings)
- environment_data[++environment_data.len] = list("name" = "Toxins", "value" = environment.gas["phoron"] / total * 100, "unit" = "%", "danger_level" = phoron_danger)
- data["total_danger"] = max(phoron_danger, data["total_danger"])
-
- current_settings = TLV["temperature"]
- var/temperature_danger = get_danger_level(environment.temperature, current_settings)
- environment_data[++environment_data.len] = list("name" = "Temperature", "value" = environment.temperature, "unit" = "K ([round(environment.temperature - T0C, 0.1)]C)", "danger_level" = temperature_danger)
- data["total_danger"] = max(temperature_danger, data["total_danger"])
-
+ environment_data[++environment_data.len] = list("name" = "Pressure", "value" = pressure, "unit" = "kPa", "danger_level" = pressure_dangerlevel)
+ environment_data[++environment_data.len] = list("name" = "Oxygen", "value" = environment.gas["oxygen"] / total * 100, "unit" = "%", "danger_level" = oxygen_dangerlevel)
+ environment_data[++environment_data.len] = list("name" = "Carbon dioxide", "value" = environment.gas["carbon_dioxide"] / total * 100, "unit" = "%", "danger_level" = co2_dangerlevel)
+ environment_data[++environment_data.len] = list("name" = "Toxins", "value" = environment.gas["phoron"] / total * 100, "unit" = "%", "danger_level" = phoron_dangerlevel)
+ environment_data[++environment_data.len] = list("name" = "Temperature", "value" = environment.temperature, "unit" = "K ([round(environment.temperature - T0C, 0.1)]C)", "danger_level" = temperature_dangerlevel)
+ data["total_danger"] = danger_level
data["environment"] = environment_data
data["atmos_alarm"] = alarm_area.atmosalm
data["fire_alarm"] = alarm_area.fire != null
@@ -888,8 +877,11 @@ FIRE ALARM
var/last_process = 0
var/wiresexposed = 0
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
+ var/seclevel
/obj/machinery/firealarm/update_icon()
+ overlays.Cut()
+
if(wiresexposed)
switch(buildstage)
if(2)
@@ -898,17 +890,28 @@ FIRE ALARM
icon_state="fire_b1"
if(0)
icon_state="fire_b0"
-
+ set_light(0)
return
if(stat & BROKEN)
icon_state = "firex"
+ set_light(0)
else if(stat & NOPOWER)
icon_state = "firep"
- else if(!src.detecting)
- icon_state = "fire1"
+ set_light(0)
else
- icon_state = "fire0"
+ if(!src.detecting)
+ icon_state = "fire1"
+ set_light(l_range = 4, l_power = 2, l_color = "#ff0000")
+ else
+ icon_state = "fire0"
+ switch(seclevel)
+ if("green") set_light(l_range = 2, l_power = 0.5, l_color = "#00ff00")
+ if("blue") set_light(l_range = 2, l_power = 0.5, l_color = "#1024A9")
+ if("red") set_light(l_range = 4, l_power = 2, l_color = "#ff0000")
+ if("delta") set_light(l_range = 4, l_power = 2, l_color = "#FF6633")
+
+ src.overlays += image('icons/obj/monitors.dmi', "overlay_[seclevel]")
/obj/machinery/firealarm/fire_act(datum/gas_mixture/air, temperature, volume)
if(src.detecting)
@@ -919,7 +922,7 @@ FIRE ALARM
/obj/machinery/firealarm/attack_ai(mob/user as mob)
return src.attack_hand(user)
-/obj/machinery/firealarm/bullet_act(BLAH)
+/obj/machinery/firealarm/bullet_act()
return src.alarm()
/obj/machinery/firealarm/emp_act(severity)
@@ -1121,14 +1124,14 @@ FIRE ALARM
pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
+/obj/machinery/firealarm/proc/set_security_level(var/newlevel)
+ if(seclevel != newlevel)
+ seclevel = newlevel
+ update_icon()
+
/obj/machinery/firealarm/initialize()
if(z in config.contact_levels)
- if(security_level)
- src.overlays += image('icons/obj/monitors.dmi', "overlay_[get_security_level()]")
- else
- src.overlays += image('icons/obj/monitors.dmi', "overlay_green")
-
- update_icon()
+ set_security_level(security_level? get_security_level() : "green")
/*
FIRE ALARM CIRCUIT
diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm
index f8d611bcbf..b7bcc53e91 100644
--- a/code/game/machinery/atmoalter/portable_atmospherics.dm
+++ b/code/game/machinery/atmoalter/portable_atmospherics.dm
@@ -104,7 +104,6 @@
network.update = 1
/obj/machinery/portable_atmospherics/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
- var/obj/icon = src
if ((istype(W, /obj/item/weapon/tank) && !( src.destroyed )))
if (src.holding)
return
@@ -136,21 +135,8 @@
return
else if ((istype(W, /obj/item/device/analyzer)) && Adjacent(user))
- visible_message("\The [user] has used \the [W] on \the [src] \icon[icon]")
- if(air_contents)
- var/pressure = air_contents.return_pressure()
- var/total_moles = air_contents.total_moles
-
- user << "Results of analysis of \icon[icon]"
- if (total_moles>0)
- user << "Pressure: [round(pressure,0.1)] kPa"
- for(var/g in air_contents.gas)
- user << "[gas_data.name[g]]: [round((air_contents.gas[g] / total_moles) * 100)]%"
- user << "Temperature: [round(air_contents.temperature-T0C)]°C"
- else
- user << "Tank is empty!"
- else
- user << "Tank is empty!"
+ var/obj/item/device/analyzer/A = W
+ A.analyze_gases(src, user)
return
return
@@ -163,6 +149,13 @@
var/last_power_draw = 0
var/obj/item/weapon/cell/cell
+/obj/machinery/portable_atmospherics/powered/powered()
+ if(use_power) //using area power
+ return ..()
+ if(cell && cell.charge)
+ return 1
+ return 0
+
/obj/machinery/portable_atmospherics/powered/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/weapon/cell))
if(cell)
@@ -176,6 +169,7 @@
cell = C
C.loc = src
user.visible_message("[user] opens the panel on [src] and inserts [C].", "You open the panel on [src] and insert [C].")
+ power_change()
return
if(istype(I, /obj/item/weapon/screwdriver))
@@ -187,8 +181,8 @@
cell.add_fingerprint(user)
cell.loc = src.loc
cell = null
+ power_change()
return
-
..()
/obj/machinery/portable_atmospherics/proc/log_open()
diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm
index 8d80e57e78..ad664049fc 100644
--- a/code/game/machinery/atmoalter/pump.dm
+++ b/code/game/machinery/atmoalter/pump.dm
@@ -102,6 +102,7 @@
//ran out of charge
if (!cell.charge)
+ power_change()
update_icon()
src.updateDialog()
diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm
index f705a62ae2..457792c9e2 100644
--- a/code/game/machinery/atmoalter/scrubber.dm
+++ b/code/game/machinery/atmoalter/scrubber.dm
@@ -77,6 +77,7 @@
//ran out of charge
if (!cell.charge)
+ power_change()
update_icon()
//src.update_icon()
@@ -147,7 +148,6 @@
volume = 50000
volume_rate = 5000
- chan
use_power = 1
idle_power_usage = 500 //internal circuitry, friction losses and stuff
active_power_usage = 100000 //100 kW ~ 135 HP
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index eca7dbcef9..0956486b69 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -290,7 +290,7 @@
/obj/machinery/autolathe/dismantle()
for(var/mat in stored_material)
- var/material/M = name_to_material[mat]
+ var/material/M = get_material_by_name(mat)
if(!istype(M))
continue
var/obj/item/stack/material/S = new M.stack_type(get_turf(src))
diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm
index 9f144c23b1..23d00318ea 100644
--- a/code/game/machinery/bioprinter.dm
+++ b/code/game/machinery/bioprinter.dm
@@ -66,19 +66,19 @@
user << "You inject the blood sample into the bioprinter."
return
// Meat for biomass.
- else if(!prints_prosthetics && istype(W, /obj/item/weapon/reagent_containers/food/snacks/meat))
+ if(!prints_prosthetics && istype(W, /obj/item/weapon/reagent_containers/food/snacks/meat))
stored_matter += 50
user.drop_item()
user << "\The [src] processes \the [W]. Levels of stored biomass now: [stored_matter]"
qdel(W)
return
// Steel for matter.
- else if(prints_prosthetics && istype(W, /obj/item/stack/material/steel))
- var/obj/item/stack/material/steel/M = W
- stored_matter += M.amount * 10
+ if(prints_prosthetics && istype(W, /obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL)
+ var/obj/item/stack/S = W
+ stored_matter += S.amount * 10
user.drop_item()
user << "\The [src] processes \the [W]. Levels of stored matter now: [stored_matter]"
qdel(W)
return
- else
- return..()
\ No newline at end of file
+
+ return..()
\ No newline at end of file
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
index 36a6e76e55..5ba75ab41a 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/game/machinery/bots/mulebot.dm
@@ -59,7 +59,7 @@
..()
wires = new(src)
botcard = new(src)
- botcard.access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station)
+ botcard.access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
cell = new(src)
cell.charge = 2000
cell.maxcharge = 2000
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index 407b007c24..1fcf6e8625 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -88,8 +88,8 @@
var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( loc )
A.amount = 5
- if(istype(P, /obj/item/stack/material/glass/reinforced))
- var/obj/item/stack/material/glass/reinforced/RG = P
+ if(istype(P, /obj/item/stack/material) && P.get_material_name() == "rglass")
+ var/obj/item/stack/RG = P
if (RG.get_amount() < 2)
user << "You need two sheets of glass to put in the glass panel."
return
@@ -201,6 +201,7 @@
transfer.control_disabled = 0
transfer.aiRadio.disabledAi = 0
transfer.loc = get_turf(src)
+ transfer.create_eyeobj()
transfer.cancel_camera()
user << "Transfer successful: [transfer.name] ([rand(1000,9999)].exe) downloaded to host terminal. Local copy wiped."
transfer << "You have been uploaded to a stationary terminal. Remote device connection restored."
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index 0c5f59c73f..54734929c8 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -87,8 +87,8 @@
var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( src.loc )
A.amount = 5
- if(istype(P, /obj/item/stack/material/glass))
- var/obj/item/stack/material/glass/G = P
+ if(istype(P, /obj/item/stack/material) && P.get_material_name() == "glass")
+ var/obj/item/stack/G = P
if (G.get_amount() < 2)
user << "You need two sheets of glass to put in the glass panel."
return
diff --git a/code/game/machinery/computer3/buildandrepair.dm b/code/game/machinery/computer3/buildandrepair.dm
index f3e7981af4..47ceffb756 100644
--- a/code/game/machinery/computer3/buildandrepair.dm
+++ b/code/game/machinery/computer3/buildandrepair.dm
@@ -178,12 +178,13 @@
if(istype(P, /obj/item/weapon/crowbar)) // complicated check
remove_peripheral()
- if(istype(P, /obj/item/stack/material/glass))
- if(P:amount >= 2)
+ if(istype(P, /obj/item/stack/material) && P.get_material_name() == "glass")
+ var/obj/item/stack/S = P
+ if(S.amount >= 2)
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
if(do_after(user, 20))
- if(P)
- P:use(2)
+ if(S)
+ S.use(2)
user << "You put in the glass panel."
src.state = 4
src.icon_state = "4"
diff --git a/code/game/machinery/computer3/computers/camera.dm b/code/game/machinery/computer3/computers/camera.dm
index f90b0526ee..814df454fa 100644
--- a/code/game/machinery/computer3/computers/camera.dm
+++ b/code/game/machinery/computer3/computers/camera.dm
@@ -56,7 +56,7 @@
name = "Security Camera Network Main Key"
var/title = "Station"
var/desc = "Connects to station security cameras."
- var/list/networks = list("SS13")
+ var/networks = list("ALL") // A little workaround as it is not possible to place station_networks here
var/screen = "cameras"
execute(var/datum/file/source)
@@ -76,58 +76,65 @@
return
computer.Crash(MISSING_PROGRAM)
+/datum/file/camnet_key/New()
+ for(var/N in networks)
+ if(N == "ALL")
+ networks = station_networks
+ break
+ return ..()
+
/datum/file/camnet_key/mining
name = "Mining Camera Network Key"
title = "mining station"
desc = "Connects to mining security cameras."
- networks = list("MINE")
+ networks = list(NETWORK_MINE)
screen = "miningcameras"
/datum/file/camnet_key/research
name = "Research Camera Network Key"
title = "research"
- networks = list("RD")
+ networks = list(NETWORK_RESEARCH)
/datum/file/camnet_key/bombrange
name = "R&D Bomb Range Camera Network Key"
title = "bomb range"
desc = "Monitors the bomb range."
- networks = list("Toxins")
+ networks = list(NETWORK_RESEARCH)
/datum/file/camnet_key/xeno
name = "R&D Misc. Research Camera Network Key"
title = "special research"
- networks = list("Misc")
+ networks = list(NETWORK_RESEARCH)
/datum/file/camnet_key/singulo
name = "Singularity Camera Network Key"
title = "singularity"
- networks = list("Singularity")
+ networks = list(NETWORK_ENGINE)
/datum/file/camnet_key/entertainment
name = "Entertainment Channel Encryption Key"
title = "entertainment"
desc = "Damn, I hope they have /tg/thechannel on here."
- networks = list("thunder")
+ networks = list(NETWORK_THUNDER)
screen = "entertainment"
/datum/file/camnet_key/creed
name = "Special Ops Camera Encryption Key"
title = "special ops"
desc = "Connects to special ops secure camera feeds."
- networks = list("CREED")
+ networks = list(NETWORK_ERT)
/datum/file/camnet_key/prison
name = "Prison Camera Network Key"
title = "prison"
desc = "Monitors the prison."
- networks = list("Prison")
+ networks = list(NETWORK_SECURITY)
/datum/file/camnet_key/syndicate
name = "Camera Network Key"
title = "%!#BUFFER OVERFLOW"
desc = "Connects to security cameras."
- networks = list("SS13")
+ networks = list("ALL")
hidden_file = 1
diff --git a/code/game/machinery/computer3/laptop.dm b/code/game/machinery/computer3/laptop.dm
index 2e73e77115..48e0c48ff0 100644
--- a/code/game/machinery/computer3/laptop.dm
+++ b/code/game/machinery/computer3/laptop.dm
@@ -106,12 +106,16 @@
pixel_x = 2
pixel_y = -3
show_keyboard = 0
+ active_power_usage = 200 // Stationary consoles we use on station have 300, laptops are probably slightly more power efficient
+ idle_power_usage = 100
var/obj/item/device/laptop/portable = null
New(var/L, var/built = 0)
if(!built && !battery)
battery = new /obj/item/weapon/cell(src)
+ battery.maxcharge = 500
+ battery.charge = 500
..(L,built)
verb/close_computer()
diff --git a/code/game/machinery/computer3/lapvend.dm b/code/game/machinery/computer3/lapvend.dm
index be030b526a..c49ea30817 100644
--- a/code/game/machinery/computer3/lapvend.dm
+++ b/code/game/machinery/computer3/lapvend.dm
@@ -202,11 +202,11 @@
if (network == 3)
newlap.spawn_parts += (/obj/item/part/computer/networking/cable)
if (power == 1)
- qdel(newlap.battery)
- newlap.battery = new /obj/item/weapon/cell/high(newlap)
+ newlap.battery.maxcharge = 1000
+ newlap.battery.charge = 1000
if (power == 2)
- qdel(newlap.battery)
- newlap.battery = new /obj/item/weapon/cell/super(newlap)
+ newlap.battery.maxcharge = 1750
+ newlap.battery.charge = 1750
newlap.spawn_parts()
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 9b5c25c79a..4642dcd27f 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -60,11 +60,6 @@
return 1
-
-/obj/machinery/atmospherics/unary/cryo_cell/allow_drop()
- return 0
-
-
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user as mob)
if(user.stat)
return
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 167190c336..2da65d273f 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -79,12 +79,14 @@ for reference:
maxhealth = material.integrity
health = maxhealth
+/obj/structure/barricade/get_material()
+ return material
+
/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob)
- if (istype(W, /obj/item/stack/material))
- var/obj/item/stack/material/D = W
- if(D.material.name != material.name)
- user << "That is the wrong material needed to repair \the [src]."
- return
+ if (istype(W, /obj/item/stack))
+ var/obj/item/stack/D = W
+ if(D.get_material_name() != material.name)
+ return //hitting things with the wrong type of stack usually doesn't produce messages, and probably doesn't need to.
if (health < maxhealth)
if (D.get_amount() < 1)
user << "You need one sheet of [material.display_name] to repair \the [src]."
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 8f3a5ca621..12e4396a18 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -48,6 +48,11 @@
return
..()
+/obj/machinery/door/airlock/get_material()
+ if(mineral)
+ return get_material_by_name(mineral)
+ return get_material_by_name(DEFAULT_WALL_MATERIAL)
+
/obj/machinery/door/airlock/command
name = "Airlock"
icon = 'icons/obj/doors/Doorcom.dmi'
diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index a2bfb1b6c2..8c960e7bdf 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -96,12 +96,12 @@
else
usr << "[src]'s motors resist your effort."
return
- if(istype(C, /obj/item/stack/material/plasteel))
- var/amt = repair_price()
+ if(istype(C, /obj/item/stack/material) && C.get_material_name() == "plasteel")
+ var/amt = Ceiling((maxhealth - health)/150)
if(!amt)
usr << "\The [src] is already fully repaired."
return
- var/obj/item/stack/material/plasteel/P = C
+ var/obj/item/stack/P = C
if(P.amount < amt)
usr << "You don't have enough sheets to repair this! You need at least [amt] sheets."
return
@@ -135,16 +135,6 @@
return
force_close()
-// Proc: repair_price()
-// Parameters: None
-// Description: Determines amount of sheets needed for full repair. (max)150HP per sheet, (max)10 emitter hits per sheet.
-/obj/machinery/door/blast/proc/repair_price()
- var/sheets_needed = 0
- var/dam = maxhealth - health
- while(dam > 0)
- dam -= 150
- sheets_needed++
- return sheets_needed
// Proc: repair()
// Parameters: None
@@ -154,7 +144,7 @@
if(stat & BROKEN)
stat &= ~BROKEN
-
+
/obj/machinery/door/blast/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(air_group) return 1
return ..()
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 32b7a5b46b..9075da2a05 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -103,6 +103,13 @@
bumpopen(M)
return
+ if(istype(AM, /obj/machinery/bot))
+ var/obj/machinery/bot/bot = AM
+ if(src.check_access(bot.botcard))
+ if(density)
+ open()
+ return
+
if(istype(AM, /mob/living/bot))
var/mob/living/bot/bot = AM
if(src.check_access(bot.botcard))
@@ -199,10 +206,9 @@
/obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/device/detective_scanner))
return
- if(src.operating > 0 || isrobot(user)) return //borgs can't attack doors open because it conflicts with their AI-like interaction with them.
src.add_fingerprint(user)
- if(istype(I, /obj/item/stack/material/steel))
+ if(istype(I, /obj/item/stack/material) && I.get_material_name() == src.get_material_name())
if(stat & BROKEN)
user << "It looks like \the [src] is pretty busted. It's going to need more than just patching up now."
return
@@ -217,20 +223,20 @@
var/amount_needed = (maxhealth - health) / DOOR_REPAIR_AMOUNT
amount_needed = (round(amount_needed) == amount_needed)? amount_needed : round(amount_needed) + 1 //Why does BYOND not have a ceiling proc?
- var/obj/item/stack/material/steel/metalstack = I
+ var/obj/item/stack/stack = I
var/transfer
if (repairing)
- transfer = metalstack.transfer_to(repairing, amount_needed - repairing.amount)
+ transfer = stack.transfer_to(repairing, amount_needed - repairing.amount)
if (!transfer)
user << "You must weld or remove \the [repairing] from \the [src] before you can add anything else."
else
- repairing = metalstack.split(amount_needed)
+ repairing = stack.split(amount_needed)
if (repairing)
repairing.loc = src
transfer = repairing.amount
if (transfer)
- user << "You fit [transfer] [metalstack.singular_name]\s to damaged and broken parts on \the [src]."
+ user << "You fit [transfer] [stack.singular_name]\s to damaged and broken parts on \the [src]."
return
@@ -270,6 +276,8 @@
take_damage(W.force)
return
+ if(src.operating > 0 || isrobot(user)) return //borgs can't attack doors open because it conflicts with their AI-like interaction with them.
+
if(src.operating) return
if(src.allowed(user) && operable())
@@ -333,7 +341,8 @@
/obj/machinery/door/emp_act(severity)
if(prob(20/severity) && (istype(src,/obj/machinery/door/airlock) || istype(src,/obj/machinery/door/window)) )
- open()
+ spawn(0)
+ open()
..()
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 02b6ea7f4c..78e17e27e0 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -75,6 +75,8 @@
A.all_doors.Remove(src)
. = ..()
+/obj/machinery/door/firedoor/get_material()
+ return get_material_by_name(DEFAULT_WALL_MATERIAL)
/obj/machinery/door/firedoor/examine(mob/user)
. = ..(user, 1)
diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm
index 4ce21137b8..e78f2b5227 100644
--- a/code/game/machinery/kitchen/microwave.dm
+++ b/code/game/machinery/kitchen/microwave.dm
@@ -130,7 +130,7 @@
if (!(R.id in acceptable_reagents))
user << "Your [O] contains components unsuitable for cookery."
return 1
- //G.reagents.trans_to(src,G.amount_per_transfer_from_this)
+ return
else if(istype(O,/obj/item/weapon/grab))
var/obj/item/weapon/grab/G = O
user << "This is ridiculous. You can not fit \the [G.affecting] in this [src]."
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 55cf5cdc15..709f4b4626 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -176,7 +176,7 @@ Class Procs:
qdel(src)
//sets the use_power var and then forces an area power update
-/obj/machinery/proc/update_use_power(var/new_use_power, var/force_update = 0)
+/obj/machinery/proc/update_use_power(var/new_use_power)
use_power = new_use_power
/obj/machinery/proc/auto_use_power()
diff --git a/code/game/machinery/pipe/pipelayer.dm b/code/game/machinery/pipe/pipelayer.dm
index 0f2dc3c855..ca164d7d0c 100644
--- a/code/game/machinery/pipe/pipelayer.dm
+++ b/code/game/machinery/pipe/pipelayer.dm
@@ -50,7 +50,7 @@
user.visible_message("[user] has [!a_dis?"de":""]activated auto-dismantling.", "You [!a_dis?"de":""]activate auto-dismantling.")
return
- if(istype(W, /obj/item/stack/material/steel))
+ if(istype(W, /obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL)
var/result = load_metal(W)
if(isnull(result))
@@ -86,7 +86,7 @@
on=0
return
-/obj/machinery/pipelayer/proc/load_metal(var/obj/item/stack/material/steel/MM)
+/obj/machinery/pipelayer/proc/load_metal(var/obj/item/stack/MM)
if(istype(MM) && MM.get_amount())
var/cur_amount = metal
var/to_load = max(max_metal - round(cur_amount),0)
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 0e26be38a8..74d3a4c52f 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -399,15 +399,16 @@ var/list/turret_icons
emagged = 1
enabled=0
- sleep(rand(60,600))
- if(!enabled)
- enabled=1
+ spawn(rand(60,600))
+ if(!enabled)
+ enabled=1
..()
/obj/machinery/porta_turret/ex_act(severity)
switch (severity)
if (1)
+ del(src)
qdel(src)
if (2)
if (prob(25))
@@ -624,6 +625,14 @@ var/list/turret_icons
// Emagged turrets again use twice as much power due to higher firing rates
use_power(reqpower * (2 * (emagged || lethal)) * (2 * emagged))
+ //Turrets aim for the center of mass by default.
+ //If the target is grabbing someone then the turret smartly aims for extremities
+ var/obj/item/weapon/grab/G = locate() in target
+ if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people.
+ A.def_zone = pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg")
+ else
+ A.def_zone = pick("chest", "groin")
+
//Shooting Code:
A.current = T
A.starting = T
@@ -696,8 +705,8 @@ var/list/turret_icons
return
if(1)
- if(istype(I, /obj/item/stack/material/steel))
- var/obj/item/stack/material/steel/M = I
+ if(istype(I, /obj/item/stack/material) && I.get_material_name() == DEFAULT_WALL_MATERIAL)
+ var/obj/item/stack/M = I
if(M.use(2))
user << "You add some metal armor to the interior frame."
build_step = 2
@@ -788,8 +797,8 @@ var/list/turret_icons
//attack_hand() removes the prox sensor
if(6)
- if(istype(I, /obj/item/stack/material/steel))
- var/obj/item/stack/material/steel/M = I
+ if(istype(I, /obj/item/stack/material) && I.get_material_name() == DEFAULT_WALL_MATERIAL)
+ var/obj/item/stack/M = I
if(M.use(2))
user << "You add some metal armor to the exterior frame."
build_step = 7
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index 98cc92380c..c20ca8468a 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -1,22 +1,25 @@
/obj/machinery/recharge_station
name = "cyborg recharging station"
+ desc = "A heavy duty rapid charging system, designed to quickly recharge cyborg power reserves."
icon = 'icons/obj/objects.dmi'
icon_state = "borgcharger0"
density = 1
anchored = 1
use_power = 1
idle_power_usage = 50
- active_power_usage = 50
var/mob/occupant = null
var/obj/item/weapon/cell/cell = null
- //var/max_internal_charge = 15000 // Two charged borgs in a row with default cell
- //var/current_internal_charge = 15000 // Starts charged, to prevent power surges on round start
- var/charging_cap_active = 1000 // Active Cap - When cyborg is inside
- var/charging_cap_passive = 250 // Passive Cap - Recharging internal capacitor when no cyborg is inside
- var/icon_update_tick = 0 // Used to update icon only once every 10 ticks
- var/charge_rate = 250 // How much charge is restored per tick
- var/weld_rate = 0 // How much brute damage is repaired per tick
- var/wire_rate = 0 // How much burn damage is repaired per tick
+ var/icon_update_tick = 0 // Used to rebuild the overlay only once every 10 ticks
+ var/charging = 0
+
+ var/charging_power // W. Power rating used for charging the cyborg. 120 kW if un-upgraded
+ var/restore_power_active // W. Power drawn from APC when an occupant is charging. 40 kW if un-upgraded
+ var/restore_power_passive // W. Power drawn from APC when idle. 7 kW if un-upgraded
+ var/weld_rate = 0 // How much brute damage is repaired per tick
+ var/wire_rate = 0 // How much burn damage is repaired per tick
+
+ var/weld_power_use = 2300 // power used per point of brute damage repaired. 2.3 kW ~ about the same power usage of a handheld arc welder
+ var/wire_power_use = 500 // power used per point of burn damage repaired.
/obj/machinery/recharge_station/New()
..()
@@ -30,51 +33,76 @@
component_parts += new /obj/item/weapon/cell/high(src)
component_parts += new /obj/item/stack/cable_coil(src, 5)
- build_icon()
+ RefreshParts()
+
update_icon()
- RefreshParts()
+/obj/machinery/recharge_station/proc/has_cell_power()
+ return cell && cell.percent() > 0
/obj/machinery/recharge_station/process()
if(stat & (BROKEN))
return
-
- if((stat & (NOPOWER)) && (!cell || cell.percent() <= 0)) // No Power.
- return
-
- var/chargemode = 0
- if(occupant)
- process_occupant()
- chargemode = 1
- // Power Stuff
-
if(!cell) // Shouldn't be possible, but sanity check
return
- if(stat & NOPOWER)
- cell.use(50 * CELLRATE) // Internal Circuitry, 50W load. No power - Runs from internal cell
- return // No external power = No charging
+ if((stat & NOPOWER) && !has_cell_power()) // No power and cell is dead.
+ if(icon_update_tick)
+ icon_update_tick = 0 //just rebuild the overlay once more only
+ update_icon()
+ return
- // Calculating amount of power to draw
- var/charge_diff = (chargemode ? charging_cap_active : charging_cap_passive) + 50 // 50W for circuitry
+ //First, draw from the internal power cell to recharge/repair/etc the occupant
+ if(occupant)
+ process_occupant()
- charge_diff = cell.give(charge_diff)
+ //Then, if external power is available, recharge the internal cell
+ var/recharge_amount = 0
+ if(!(stat & NOPOWER))
+ // Calculating amount of power to draw
+ recharge_amount = (occupant ? restore_power_active : restore_power_passive) * CELLRATE
- if(idle_power_usage != charge_diff) // Force update, but only when our power usage changed this tick.
- idle_power_usage = charge_diff
- update_use_power(1, 1)
+ recharge_amount = cell.give(recharge_amount)
+ use_power(recharge_amount / CELLRATE)
if(icon_update_tick >= 10)
- update_icon()
icon_update_tick = 0
else
icon_update_tick++
+ if(occupant || recharge_amount)
+ update_icon()
+
+//since the recharge station can still be on even with NOPOWER. Instead it draws from the internal cell.
+/obj/machinery/recharge_station/auto_use_power()
+ if(!(stat & NOPOWER))
+ return ..()
+
+ if(!has_cell_power())
+ return 0
+ if(src.use_power == 1)
+ cell.use(idle_power_usage * CELLRATE)
+ else if(src.use_power >= 2)
+ cell.use(active_power_usage * CELLRATE)
return 1
+//Processes the occupant, drawing from the internal power cell if needed.
+/obj/machinery/recharge_station/proc/process_occupant()
+ if(istype(occupant, /mob/living/silicon/robot))
+ var/mob/living/silicon/robot/R = occupant
-/obj/machinery/recharge_station/allow_drop()
- return 0
+ if(R.module)
+ R.module.respawn_consumable(R, charging_power * CELLRATE / 250) //consumables are magical, apparently
+ if(R.cell && !R.cell.fully_charged())
+ var/diff = min(R.cell.maxcharge - R.cell.charge, charging_power * CELLRATE) // Capped by charging_power / tick
+ var/charge_used = cell.use(diff)
+ R.cell.give(charge_used)
+
+ //Lastly, attempt to repair the cyborg if enabled
+ if(weld_rate && R.getBruteLoss() && cell.checked_use(weld_power_use * weld_rate * CELLRATE))
+ R.adjustBruteLoss(-weld_rate)
+ if(wire_rate && R.getFireLoss() && cell.checked_use(wire_power_use * wire_rate * CELLRATE))
+ R.adjustFireLoss(-wire_rate)
/obj/machinery/recharge_station/examine(mob/user)
..(user)
@@ -92,9 +120,6 @@
return
/obj/machinery/recharge_station/emp_act(severity)
- if(stat & (BROKEN|NOPOWER))
- ..(severity)
- return
if(occupant)
occupant.emp_act(severity)
go_out()
@@ -125,13 +150,20 @@
man_rating += P.rating
cell = locate(/obj/item/weapon/cell) in component_parts
- charge_rate = 125 * cap_rating
- charging_cap_passive = charge_rate
+ charging_power = 40000 + 40000 * cap_rating
+ restore_power_active = 10000 + 15000 * cap_rating
+ restore_power_passive = 5000 + 1000 * cap_rating
weld_rate = max(0, man_rating - 3)
wire_rate = max(0, man_rating - 5)
-/obj/machinery/recharge_station/update_icon()
- ..()
+ desc = initial(desc)
+ desc += " Uses a dedicated internal power cell to deliver [charging_power]W when in use."
+ if(weld_rate)
+ desc += "
It is capable of repairing structural damage."
+ if(wire_rate)
+ desc += "
It is capable of repairing burn damage."
+
+/obj/machinery/recharge_station/proc/build_overlays()
overlays.Cut()
switch(round(chargepercentage()))
if(1 to 20)
@@ -147,53 +179,33 @@
if(99 to 110)
overlays += image('icons/obj/objects.dmi', "statn_c100")
-/obj/machinery/recharge_station/Bumped(var/mob/AM)
- move_inside(AM)
+/obj/machinery/recharge_station/update_icon()
+ ..()
+ if(stat & BROKEN)
+ icon_state = "borgcharger0"
+ return
-/obj/machinery/recharge_station/proc/build_icon()
- if(NOPOWER|BROKEN)
- if(occupant)
- icon_state = "borgcharger1"
+ if(occupant)
+ if((stat & NOPOWER) && !has_cell_power())
+ icon_state = "borgcharger2"
else
- icon_state = "borgcharger0"
+ icon_state = "borgcharger1"
else
icon_state = "borgcharger0"
-/obj/machinery/recharge_station/proc/process_occupant()
- if(occupant)
- if(istype(occupant, /mob/living/silicon/robot))
- var/mob/living/silicon/robot/R = occupant
- if(R.module)
- R.module.respawn_consumable(R, charge_rate / 250)
- if(!R.cell)
- return
- if(!R.cell.fully_charged())
- var/diff = min(R.cell.maxcharge - R.cell.charge, charge_rate) // Capped at charge_rate charge / tick
- if (cell.charge >= diff)
- cell.use(diff)
- R.cell.give(diff)
- if(weld_rate && R.getBruteLoss())
- R.adjustBruteLoss(-1)
- if(wire_rate && R.getFireLoss())
- R.adjustFireLoss(-1)
- else if(istype(occupant, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = occupant
- if(!isnull(H.internal_organs_by_name["cell"]) && H.nutrition < 450)
- H.nutrition = min(H.nutrition+10, 450)
- update_use_power(1)
+ if(icon_update_tick == 0)
+ build_overlays()
+
+/obj/machinery/recharge_station/Bumped(var/mob/AM)
+ move_inside(AM)
/obj/machinery/recharge_station/proc/go_out()
if(!(occupant))
return
- //for(var/obj/O in src)
- // O.loc = loc
- if(occupant.client)
- occupant.client.eye = occupant.client.mob
- occupant.client.perspective = MOB_PERSPECTIVE
occupant.loc = loc
+ occupant.reset_view()
occupant = null
- build_icon()
- update_use_power(1)
+ update_icon()
return
/obj/machinery/recharge_station/verb/move_eject()
@@ -205,49 +217,26 @@
add_fingerprint(usr)
return
-/obj/machinery/recharge_station/verb/move_inside(var/mob/user = usr)
+/obj/machinery/recharge_station/verb/move_inside()
set category = "Object"
set src in oview(1)
- if(!user)
+ if(usr.stat == DEAD)
+ return
+ if(occupant)
+ usr << "\The [src] is already occupied!"
return
- var/can_accept_user
- if(istype(user, /mob/living/silicon/robot))
-
- var/mob/living/silicon/robot/R = user
-
- if(R.stat == 2)
- //Whoever had it so that a borg with a dead cell can't enter this thing should be shot. --NEO
- return
- if(occupant)
- R << "The cell is already occupied!"
- return
- if(!R.cell)
- R << "Without a powercell, you can't be recharged."
- //Make sure they actually HAVE a cell, now that they can get in while powerless. --NEO
- return
- can_accept_user = 1
-
- else if(istype(user, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = user
- if(!isnull(H.internal_organs_by_name["cell"]))
- can_accept_user = 1
-
- if(!can_accept_user)
- user << "Only non-organics may enter the recharger!"
+ var/mob/living/silicon/robot/R = usr
+ if(!istype(R))
+ usr << "Only synthetics may enter the recharger!"
+ return
+ if(!R.cell)
+ usr << "Without a powercell, you can't be recharged."
return
-
- user.stop_pulling()
- if(user.client)
- user.client.perspective = EYE_PERSPECTIVE
- user.client.eye = src
- user.loc = src
- occupant = user
- /*for(var/obj/O in src)
- O.loc = loc*/
- add_fingerprint(user)
- build_icon()
- update_use_power(1)
- return
+ usr.reset_view(src)
+ usr.loc = src
+ occupant = usr
+ add_fingerprint(usr)
+ update_icon()
diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm
index b2461f1d7f..4c44bcd4ee 100644
--- a/code/game/machinery/robot_fabricator.dm
+++ b/code/game/machinery/robot_fabricator.dm
@@ -12,8 +12,8 @@
active_power_usage = 10000
/obj/machinery/robotic_fabricator/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if (istype(O, /obj/item/stack/material/steel))
- var/obj/item/stack/material/steel/M = O
+ if (istype(O, /obj/item/stack/material) && O.get_material_name() == DEFAULT_WALL_MATERIAL)
+ var/obj/item/stack/M = O
if (src.metal_amount < 150000.0)
var/count = 0
src.overlays += "fab-load-metal"
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index e882373359..ad88ce7fea 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -32,6 +32,11 @@
user << "The charge meter reads [cell ? round(cell.percent(),1) : 0]%"
return
+/obj/machinery/space_heater/powered()
+ if(cell && cell.charge)
+ return 1
+ return 0
+
/obj/machinery/space_heater/emp_act(severity)
if(stat & (BROKEN|NOPOWER))
..(severity)
@@ -56,6 +61,7 @@
C.add_fingerprint(usr)
user.visible_message("[user] inserts a power cell into [src].", "You insert the power cell into [src].")
+ power_change()
else
user << "The hatch must be open to insert a power cell."
return
@@ -125,6 +131,7 @@
usr.put_in_hands(cell)
cell.add_fingerprint(usr)
cell = null
+ power_change()
if("cellinstall")
@@ -135,7 +142,7 @@
cell = C
C.loc = src
C.add_fingerprint(usr)
-
+ power_change()
usr.visible_message("[usr] inserts \the [C] into \the [src].", "You insert \the [C] into \the [src].")
updateDialog()
@@ -176,4 +183,5 @@
env.merge(removed)
else
on = 0
+ power_change()
update_icon()
diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm
index fb4a03d21f..99d713cccb 100644
--- a/code/game/machinery/syndicatebeacon.dm
+++ b/code/game/machinery/syndicatebeacon.dm
@@ -71,7 +71,7 @@
/obj/machinery/syndicate_beacon/proc/selfdestruct()
selfdestructing = 1
- spawn() explosion(src.loc, rand(3,8), rand(1,3), 1, 10)
+ spawn() explosion(src.loc, 1, rand(1,3), rand(3,8), 10)
////////////////////////////////////////
//Singularity beacon
diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm
index 35c2ecdc1f..f91fd2d40c 100644
--- a/code/game/machinery/telecomms/presets.dm
+++ b/code/game/machinery/telecomms/presets.dm
@@ -40,8 +40,8 @@
id = "Hub"
network = "tcommsat"
autolinkers = list("hub", "relay", "c_relay", "s_relay", "m_relay", "r_relay", "science", "medical",
- "supply", "service", "common", "command", "engineering", "security",
- "receiverA", "receiverB", "broadcasterA", "broadcasterB")
+ "supply", "service", "common", "command", "engineering", "security", "unused",
+ "receiverA", "broadcasterA")
/obj/machinery/telecomms/hub/preset_cent
id = "CentComm Hub"
@@ -52,22 +52,11 @@
//Receivers
-//--PRESET LEFT--//
-
-/obj/machinery/telecomms/receiver/preset_left
+/obj/machinery/telecomms/receiver/preset_right
id = "Receiver A"
network = "tcommsat"
autolinkers = list("receiverA") // link to relay
- freq_listening = list(SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ) // science, medical, supply, service
-
-
-//--PRESET RIGHT--//
-
-/obj/machinery/telecomms/receiver/preset_right
- id = "Receiver B"
- network = "tcommsat"
- autolinkers = list("receiverB") // link to relay
- freq_listening = list(COMM_FREQ, ENG_FREQ, SEC_FREQ) //command, engineering, security
+ freq_listening = list(SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ, COMM_FREQ, ENG_FREQ, SEC_FREQ)
//Common and other radio frequencies for people to freely use
New()
@@ -95,7 +84,14 @@
id = "Bus 2"
network = "tcommsat"
freq_listening = list(SUP_FREQ, SRV_FREQ)
- autolinkers = list("processor2", "supply", "service")
+ autolinkers = list("processor2", "supply", "service", "unused")
+
+/obj/machinery/telecomms/bus/preset_two/New()
+ for(var/i = 1441, i < 1489, i += 2)
+ if(i == AI_FREQ || i == PUB_FREQ)
+ continue
+ freq_listening |= i
+ ..()
/obj/machinery/telecomms/bus/preset_three
id = "Bus 3"
@@ -106,14 +102,9 @@
/obj/machinery/telecomms/bus/preset_four
id = "Bus 4"
network = "tcommsat"
- freq_listening = list(ENG_FREQ)
+ freq_listening = list(ENG_FREQ, AI_FREQ, PUB_FREQ)
autolinkers = list("processor4", "engineering", "common")
-/obj/machinery/telecomms/bus/preset_four/New()
- for(var/i = 1441, i < 1489, i += 2)
- freq_listening |= i
- ..()
-
/obj/machinery/telecomms/bus/preset_cent
id = "CentComm Bus"
network = "tcommsat"
@@ -169,7 +160,7 @@
id = "Supply Server"
freq_listening = list(SUP_FREQ)
autolinkers = list("supply")
-
+
/obj/machinery/telecomms/server/presets/service
id = "Service Server"
freq_listening = list(SRV_FREQ)
@@ -177,13 +168,19 @@
/obj/machinery/telecomms/server/presets/common
id = "Common Server"
- freq_listening = list()
+ freq_listening = list(PUB_FREQ, AI_FREQ) // AI Private and Common
autolinkers = list("common")
- //Common and other radio frequencies for people to freely use
- // 1441 to 1489
-/obj/machinery/telecomms/server/presets/common/New()
+// "Unused" channels, AKA all others.
+/obj/machinery/telecomms/server/presets/unused
+ id = "Unused Server"
+ freq_listening = list()
+ autolinkers = list("unused")
+
+/obj/machinery/telecomms/server/presets/unused/New()
for(var/i = 1441, i < 1489, i += 2)
+ if(i == AI_FREQ || i == PUB_FREQ)
+ continue
freq_listening |= i
..()
@@ -213,18 +210,11 @@
//--PRESET LEFT--//
-/obj/machinery/telecomms/broadcaster/preset_left
+/obj/machinery/telecomms/broadcaster/preset_right
id = "Broadcaster A"
network = "tcommsat"
autolinkers = list("broadcasterA")
-//--PRESET RIGHT--//
-
-/obj/machinery/telecomms/broadcaster/preset_right
- id = "Broadcaster B"
- network = "tcommsat"
- autolinkers = list("broadcasterB")
-
/obj/machinery/telecomms/broadcaster/preset_cent
id = "CentComm Broadcaster"
network = "tcommsat"
diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm
index a1e2287f58..77667fa6bc 100644
--- a/code/game/machinery/turret_control.dm
+++ b/code/game/machinery/turret_control.dm
@@ -218,9 +218,9 @@
enabled=0
updateTurrets()
- sleep(rand(60,600))
- if(!enabled)
- enabled=1
- updateTurrets()
+ spawn(rand(60,600))
+ if(!enabled)
+ enabled=1
+ updateTurrets()
..()
diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm
index a3ac073a90..db548443ca 100644
--- a/code/game/machinery/turrets.dm
+++ b/code/game/machinery/turrets.dm
@@ -266,6 +266,15 @@
else
A = new /obj/item/projectile/energy/electrode( loc )
use_power(200)
+
+ //Turrets aim for the center of mass by default.
+ //If the target is grabbing someone then the turret smartly aims for extremities
+ var/obj/item/weapon/grab/G = locate() in target
+ if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people.
+ A.def_zone = pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg")
+ else
+ A.def_zone = pick("chest", "groin")
+
A.current = T
A.starting = T
A.yo = U.y - T.y
diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm
index 3fd4fae3e8..71b7de64c0 100644
--- a/code/game/machinery/wishgranter.dm
+++ b/code/game/machinery/wishgranter.dm
@@ -45,6 +45,7 @@
if (!(XRAY in user.mutations))
user.mutations.Add(XRAY)
user.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS)
+ user.see_in_dark = 8
user.see_invisible = SEE_INVISIBLE_LEVEL_TWO
if (!(COLD_RESISTANCE in user.mutations))
@@ -66,4 +67,4 @@
show_objectives(user.mind)
user << "You have a very bad feeling about this."
- return
+ return
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm
index c1cadaef5c..6cec144132 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/medical_tools.dm
@@ -22,12 +22,6 @@
Destroy()
qdel(pr_mech_sleeper)
- ..()
-
- allow_drop()
- return 0
-
- destroy()
for(var/atom/movable/AM in src)
AM.forceMove(get_turf(src))
return ..()
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 2b17096547..91e544cf25 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -1078,9 +1078,6 @@
var/door_locked = 1
salvageable = 0
-/obj/item/mecha_parts/mecha_equipment/tool/passenger/allow_drop()
- return 0
-
/obj/item/mecha_parts/mecha_equipment/tool/passenger/destroy()
for(var/atom/movable/AM in src)
AM.forceMove(get_turf(src))
diff --git a/code/game/objects/effects/explosion_particles.dm b/code/game/objects/effects/explosion_particles.dm
index 90020e5080..e0750ba1c3 100644
--- a/code/game/objects/effects/explosion_particles.dm
+++ b/code/game/objects/effects/explosion_particles.dm
@@ -9,7 +9,7 @@
/obj/effect/expl_particles/New()
..()
spawn (15)
- src.loc = null
+ qdel(src)
return
/obj/effect/expl_particles/Move()
@@ -49,7 +49,7 @@
/obj/effect/explosion/New()
..()
spawn (10)
- src.loc = null
+ qdel(src)
return
/datum/effect/system/explosion
diff --git a/code/game/objects/empulse.dm b/code/game/objects/empulse.dm
index 05cdbfee1d..c1df6b5454 100644
--- a/code/game/objects/empulse.dm
+++ b/code/game/objects/empulse.dm
@@ -1,3 +1,9 @@
+// Uncomment this define to check for possible lengthy processing of emp_act()s.
+// If emp_act() takes more than defined deciseconds (1/10 seconds) an admin message and log is created.
+// I do not recommend having this uncommented on main server, it probably causes a bit more lag, espicially with larger EMPs.
+
+// #define EMPDEBUG 10
+
proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
if(!epicenter) return
@@ -24,6 +30,9 @@ proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
M << 'sound/effects/EMPulse.ogg'
for(var/atom/T in range(light_range, epicenter))
+ #ifdef EMPDEBUG
+ var/time = world.timeofday
+ #endif
var/distance = get_dist(epicenter, T)
if(distance < 0)
distance = 0
@@ -36,4 +45,8 @@ proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
T.emp_act(2)
else if(distance <= light_range)
T.emp_act(2)
+ #ifdef EMPDEBUG
+ if((world.timeofday - time) >= EMPDEBUG)
+ log_and_message_admins("EMPDEBUG: [T.name] - [T.type] - took [world.timeofday - time]ds to process emp_act()!")
+ #endif
return 1
\ No newline at end of file
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 4c519b8fc5..31bb9160f8 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -68,7 +68,7 @@
/obj/item/weapon/pen/crayon/afterattack(atom/target, mob/user as mob, proximity)
if(!proximity) return
if(istype(target,/turf/simulated/floor))
- var/drawtype = input("Choose what you'd like to draw.", "Crayon scribbles") in list("graffiti","rune","letter")
+ var/drawtype = input("Choose what you'd like to draw.", "Crayon scribbles") in list("graffiti","rune","letter","arrow")
switch(drawtype)
if("letter")
drawtype = input("Choose the letter.", "Crayon scribbles") in list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
@@ -77,6 +77,9 @@
user << "You start drawing graffiti on the [target.name]."
if("rune")
user << "You start drawing a rune on the [target.name]."
+ if("arrow")
+ drawtype = input("Choose the arrow.", "Crayon scribbles") in list("left", "right", "up", "down")
+ user << "You start drawing an arrow on the [target.name]."
if(instant || do_after(user, 50))
new /obj/effect/decal/cleanable/crayon(target,colour,shadeColour,drawtype)
user << "You finish drawing."
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 3b1056bfed..4af30b29b3 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -1284,40 +1284,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
user << "No significant chemical agents found in [A]."
if(5)
- if((istype(A, /obj/item/weapon/tank)) || (istype(A, /obj/machinery/portable_atmospherics)))
- var/obj/icon = A
- for (var/mob/O in viewers(user, null))
- O << "\The [user] has used [src] on \icon[icon] [A]."
- var/pressure = A:air_contents.return_pressure()
-
- var/total_moles = A:air_contents.total_moles
-
- user << "Results of analysis of \icon[icon]"
- if (total_moles>0)
- user << "Pressure: [round(pressure,0.1)] kPa"
- for(var/g in A:air_contents.gas)
- user << "[gas_data.name[g]]: [round((A:air_contents.gas[g] / total_moles) * 100)]%"
- user << "Temperature: [round(A:air_contents.temperature-T0C)]°C"
- else
- user << "Tank is empty!"
-
- if (istype(A, /obj/machinery/atmospherics/pipe/tank))
- var/obj/icon = A
- for (var/mob/O in viewers(user, null))
- O << "\The [user] has used [src] on \icon[icon] [A]"
-
- var/obj/machinery/atmospherics/pipe/tank/T = A
- var/pressure = T.parent.air.return_pressure()
- var/total_moles = T.parent.air.total_moles
-
- user << "Results of analysis of \icon[icon]"
- if (total_moles>0)
- user << "Pressure: [round(pressure,0.1)] kPa"
- for(var/g in T.parent.air.gas)
- user << "[gas_data.name[g]]: [round((T.parent.air.gas[g] / total_moles) * 100)]%"
- user << "Temperature: [round(T.parent.air.temperature-T0C)]°C"
- else
- user << "Tank is empty!"
+ analyze_gases(A, user)
if (!scanmode && istype(A, /obj/item/weapon/paper) && owner)
// JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents,
diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm
index e4d1c57a0d..6b239c6b07 100644
--- a/code/game/objects/items/devices/aicard.dm
+++ b/code/game/objects/items/devices/aicard.dm
@@ -110,6 +110,7 @@
ai.loc = src
ai.cancel_camera()
+ ai.destroy_eyeobj(src)
ai.control_disabled = 1
ai.aiRestorePowerRoutine = 0
carded_ai = ai
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index f849b17c99..bc0f836487 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -67,8 +67,8 @@
user << "It has [uses] lights remaining."
/obj/item/device/lightreplacer/attackby(obj/item/W, mob/user)
- if(istype(W, /obj/item/stack/material/glass))
- var/obj/item/stack/material/glass/G = W
+ if(istype(W, /obj/item/stack/material) && W.get_material_name() == "glass")
+ var/obj/item/stack/G = W
if(uses >= max_uses)
user << "[src.name] is full."
return
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index e1ca0d8889..43a4c5bf56 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -192,7 +192,7 @@
*/
/obj/item/device/radio/headset/headset_cargo
name = "supply radio headset"
- desc = "A headset used by the QM and his slaves."
+ desc = "A headset used by the QM and their slaves."
icon_state = "cargo_headset"
item_state = "headset"
ks2type = /obj/item/device/encryptionkey/headset_cargo
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index f8689208e9..0353c25f59 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -156,6 +156,9 @@
else
channels[chan_name] |= FREQ_LISTENING
+ if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk
+ return
+
interact(usr)
/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel) //BS12 EDIT
@@ -575,7 +578,6 @@
if(keyslot.syndie)
src.syndie = 1
-
for (var/ch_name in src.channels)
if(!radio_controller)
sleep(30) // Waiting for the radio_controller to be created.
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 849ceac3af..3e888ae849 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -256,6 +256,13 @@ REAGENT SCANNER
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINERING = 1)
+/obj/item/device/analyzer/atmosanalyze(var/mob/user)
+ var/air = user.return_air()
+ if (!air)
+ return
+
+ return atmosanalyzer_scan(src, air, user)
+
/obj/item/device/analyzer/attack_self(mob/user as mob)
if (user.stat)
@@ -264,27 +271,7 @@ REAGENT SCANNER
usr << "You don't have the dexterity to do this!"
return
- var/turf/location = user.loc
- if (!( istype(location, /turf) ))
- return
-
- var/datum/gas_mixture/environment = location.return_air()
-
- var/pressure = environment.return_pressure()
- var/total_moles = environment.total_moles
-
- user.show_message("Results:", 1)
- if(abs(pressure - ONE_ATMOSPHERE) < 10)
- user.show_message("Pressure: [round(pressure,0.1)] kPa", 1)
- else
- user.show_message("Pressure: [round(pressure,0.1)] kPa", 1)
- if(total_moles)
- for(var/g in environment.gas)
- user.show_message("[gas_data.name[g]]: [round((environment.gas[g] / total_moles)*100)]%", 1)
-
- user.show_message("Temperature: [round(environment.temperature-T0C)]°C", 1)
-
- src.add_fingerprint(user)
+ analyze_gases(src, user)
return
/obj/item/device/mass_spectrometer
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 96ddeccec6..83c5ea2098 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -127,8 +127,8 @@
/obj/item/robot_parts/robot_suit/attackby(obj/item/W as obj, mob/user as mob)
..()
- if(istype(W, /obj/item/stack/material/steel) && !l_arm && !r_arm && !l_leg && !r_leg && !chest && !head)
- var/obj/item/stack/material/steel/M = W
+ if(istype(W, /obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL && !l_arm && !r_arm && !l_leg && !r_leg && !chest && !head)
+ var/obj/item/stack/material/M = W
if (M.use(1))
var/obj/item/weapon/secbot_assembly/ed209_assembly/B = new /obj/item/weapon/secbot_assembly/ed209_assembly
B.loc = get_turf(src)
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 5f14980373..f1c9aa2d14 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -146,7 +146,7 @@
return
- return -1 // the bullet/projectile goes through the target! Ie, you missed
+ return PROJECTILE_CONTINUE // the bullet/projectile goes through the target!
// Small memory holder entity for transparent bullet holes
diff --git a/code/game/objects/items/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm
index b32cb54def..424eab6a03 100644
--- a/code/game/objects/items/stacks/sheets/light.dm
+++ b/code/game/objects/items/stacks/sheets/light.dm
@@ -22,8 +22,8 @@
user.drop_from_inventory(src)
qdel(src)
- if(istype(O,/obj/item/stack/material/steel))
- var/obj/item/stack/material/steel/M = O
+ if(istype(O,/obj/item/stack/material) && O.get_material_name() == DEFAULT_WALL_MATERIAL)
+ var/obj/item/stack/M = O
if (M.use(1))
use(1)
new/obj/item/stack/tile/light(get_turf(user))
diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm
index cb1fff4599..84e4f80d4a 100755
--- a/code/game/objects/items/weapons/AI_modules.dm
+++ b/code/game/objects/items/weapons/AI_modules.dm
@@ -40,7 +40,7 @@ AI MODULES
if (comp.current.stat == 2 || comp.current.control_disabled == 1)
usr << "Upload failed. No signal is being detected from the AI."
- else if (!comp.current.has_power)
+ else if (comp.current.see_in_dark == 0)
usr << "Upload failed. Only a faint signal is being detected from the AI, and it is not responding to our requests. It may be low on power."
else
src.transmitInstructions(comp.current, usr)
@@ -83,7 +83,7 @@ AI MODULES
laws.sync(target, 0)
addAdditionalLaws(target, sender)
- target << "[sender] has uploaded a change to the laws you must follow, using \an [src]. From now on: "
+ target << "\The [sender] has uploaded a change to the laws you must follow, using \an [src]. From now on: "
target.show_laws()
/obj/item/weapon/aiModule/proc/log_law_changes(var/mob/living/silicon/ai/target, var/mob/sender)
@@ -140,13 +140,7 @@ AI MODULES
if(!targetName)
usr << "No name detected on module, please enter one."
return 0
- ..()
-
-/obj/item/weapon/aiModule/oneHuman/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
- ..()
- var/law = "Only [targetName] is a crew member."
- target << "[sender.real_name] attempted to modify your zeroth law." // And lets them know that someone tried. --NeoFite
- target << "It would be in your best interest to play along with [sender.real_name] that [law]"
+ return ..()
/obj/item/weapon/aiModule/oneHuman/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender)
var/law = "Only [targetName] is an crew member."
diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm
index d5a36d6cba..e32b58e098 100644
--- a/code/game/objects/items/weapons/clown_items.dm
+++ b/code/game/objects/items/weapons/clown_items.dm
@@ -32,7 +32,7 @@
else if(istype(target,/turf))
user << "You scrub \the [target.name] clean."
var/turf/T = target
- T.clean()
+ T.clean(src)
else
user << "You clean \the [target.name]."
target.clean_blood()
diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm
index 09816e3568..bbdd46cdb3 100644
--- a/code/game/objects/items/weapons/flamethrower.dm
+++ b/code/game/objects/items/weapons/flamethrower.dm
@@ -112,20 +112,9 @@
update_icon()
return
- if(istype(W, /obj/item/device/analyzer) && ptank)
- var/obj/item/weapon/icon = src
- user.visible_message("[user] has used the analyzer on \icon[icon]")
- var/pressure = ptank.air_contents.return_pressure()
- var/total_moles = ptank.air_contents.total_moles
-
- user << "Results of analysis of \icon[icon]"
- if(total_moles>0)
- user << "Pressure: [round(pressure,0.1)] kPa"
- for(var/g in ptank.air_contents.gas)
- user << "[gas_data.name[g]]: [round((ptank.air_contents.gas[g] / total_moles) * 100)]%"
- user << "Temperature: [round(ptank.air_contents.temperature-T0C)]°C"
- else
- user << "Tank is empty!"
+ if(istype(W, /obj/item/device/analyzer))
+ var/obj/item/device/analyzer/A = W
+ A.analyze_gases(src, user)
return
..()
return
diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm
index 4b15fb8ffb..49b1b280a7 100644
--- a/code/game/objects/items/weapons/implants/implantcase.dm
+++ b/code/game/objects/items/weapons/implants/implantcase.dm
@@ -38,7 +38,7 @@
user << "\The [src] is full."
else
spawn(5)
- I.reagents.trans_to_mob(src.imp, 5)
+ I.reagents.trans_to_obj(src.imp, 5)
user << "You inject 5 units of the solution. The syringe now contains [I.reagents.total_volume] units."
else if (istype(I, /obj/item/weapon/implanter))
var/obj/item/weapon/implanter/M = I
diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm
index c396f8d4b9..18181df6b0 100644
--- a/code/game/objects/items/weapons/material/material_weapons.dm
+++ b/code/game/objects/items/weapons/material/material_weapons.dm
@@ -34,6 +34,9 @@
if(!isnull(matter[material_type]))
matter[material_type] *= force_divisor // May require a new var instead.
+/obj/item/weapon/material/get_material()
+ return material
+
/obj/item/weapon/material/proc/update_force()
if(edge || sharp)
force = material.get_edge_damage()
diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm
index eb01257c67..8ad4b68721 100644
--- a/code/game/objects/items/weapons/material/shards.dm
+++ b/code/game/objects/items/weapons/material/shards.dm
@@ -89,4 +89,4 @@
..(loc, "steel")
/obj/item/weapon/material/shard/phoron/New(loc)
- ..(loc, "phoron glass")
+ ..(loc, "phglass")
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index 66310cf26f..6876310343 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -34,7 +34,7 @@
/obj/item/weapon/melee/energy/attack_self(mob/living/user as mob)
if (active)
if ((CLUMSY in user.mutations) && prob(50))
- user.visible_message("[user] accidentally cuts \himself with \the [src].",\
+ user.visible_message("\The [user] accidentally cuts \himself with \the [src].",\
"You accidentally cut yourself with \the [src].")
user.take_organ_damage(5,5)
deactivate(user)
@@ -50,9 +50,10 @@
return
/obj/item/weapon/melee/energy/suicide_act(mob/user)
+ var/tempgender = "[user.gender == MALE ? "he's" : user.gender == FEMALE ? "she's" : "they are"]"
if (active)
- viewers(user) << pick("\The [user] is slitting \his stomach open with \the [src]! It looks like \he's trying to commit seppuku.", \
- "\The [user] is falling on \the [src]! It looks like \he's trying to commit suicide.")
+ viewers(user) << pick("\The [user] is slitting \his stomach open with \the [src]! It looks like [tempgender] trying to commit seppuku.", \
+ "\The [user] is falling on \the [src]! It looks like [tempgender] trying to commit suicide.")
return (BRUTELOSS|FIRELOSS)
/*
@@ -90,7 +91,7 @@
user << "\The [src] is de-energised. It's just a regular axe now."
/obj/item/weapon/melee/energy/axe/suicide_act(mob/user)
- viewers(user) << "\The [user] swings \the [src] towards /his head! It looks like \he's trying to commit suicide."
+ viewers(user) << "\The [user] swings \the [src] towards \his head! It looks like \he's trying to commit suicide."
return (BRUTELOSS|FIRELOSS)
/*
diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm
index 17af445e19..abf5e08a3b 100644
--- a/code/game/objects/items/weapons/mop.dm
+++ b/code/game/objects/items/weapons/mop.dm
@@ -16,6 +16,7 @@
/obj/item/weapon/mop/New()
create_reagents(5)
+//expects an atom containing the reagents used to clean the turf
/turf/proc/clean(atom/source)
if(source.reagents.has_reagent("water", 1))
clean_blood()
diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm
index 4c808ad2f5..0feb298692 100644
--- a/code/game/objects/items/weapons/storage/bags.dm
+++ b/code/game/objects/items/weapons/storage/bags.dm
@@ -119,10 +119,10 @@
//verbs += /obj/item/weapon/storage/bag/sheetsnatcher/quick_empty
can_be_inserted(obj/item/W as obj, stop_messages = 0)
- if(!istype(W,/obj/item/stack/material) || istype(W,/obj/item/stack/material/sandstone) || istype(W,/obj/item/stack/material/wood))
+ if(!istype(W,/obj/item/stack/material))
if(!stop_messages)
usr << "The snatcher does not accept [W]."
- return 0 //I don't care, but the existing code rejects them for not being "sheets" *shrug* -Sayu
+ return 0
var/current = 0
for(var/obj/item/stack/material/S in contents)
current += S.amount
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index 70c1d33d73..131347ac29 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -335,7 +335,6 @@
..()
if(isrobot(user))
- user << "You're a robot. No."
return //Robots can't interact with storage items.
if(!can_be_inserted(W))
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index 8c5b1de026..049d179846 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -87,28 +87,12 @@
/obj/item/weapon/tank/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
- var/obj/icon = src
-
if (istype(src.loc, /obj/item/assembly))
icon = src.loc
if ((istype(W, /obj/item/device/analyzer)) && get_dist(user, src) <= 1)
- for (var/mob/O in viewers(user, null))
- O << "\The [user] has used [W] on \icon[icon] [src]"
-
- var/pressure = air_contents.return_pressure()
- manipulated_by = user.real_name //This person is aware of the contents of the tank.
- var/total_moles = air_contents.total_moles
-
- user << "Results of analysis of \icon[icon]"
- if (total_moles>0)
- user << "Pressure: [round(pressure,0.1)] kPa"
- for(var/g in air_contents.gas)
- user << "[gas_data.name[g]]: [(round(air_contents.gas[g] / total_moles) * 100)]%"
- user << "Temperature: [round(air_contents.temperature-T0C)]°C"
- else
- user << "Tank is empty!"
- src.add_fingerprint(user)
+ var/obj/item/device/analyzer/A = W
+ A.analyze_gases(src, user)
else if (istype(W,/obj/item/latexballon))
var/obj/item/latexballon/LB = W
LB.blow(src)
@@ -131,7 +115,7 @@
location = loc.loc
else if(istype(loc, /mob/living/carbon))
location = loc
-
+
var/using_internal
if(istype(location))
if(location.internal==src)
@@ -278,11 +262,11 @@
var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE
explosion(
- get_turf(loc),
- round(min(BOMBCAP_DVSTN_RADIUS, range*0.25)),
- round(min(BOMBCAP_HEAVY_RADIUS, range*0.50)),
- round(min(BOMBCAP_LIGHT_RADIUS, range*1.00)),
- round(min(BOMBCAP_FLASH_RADIUS, range*1.50)),
+ get_turf(loc),
+ round(min(BOMBCAP_DVSTN_RADIUS, range*0.25)),
+ round(min(BOMBCAP_HEAVY_RADIUS, range*0.50)),
+ round(min(BOMBCAP_LIGHT_RADIUS, range*1.00)),
+ round(min(BOMBCAP_FLASH_RADIUS, range*1.50)),
)
qdel(src)
diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm
index 7bd266f241..ccb61a5abf 100644
--- a/code/game/objects/items/weapons/tools.dm
+++ b/code/game/objects/items/weapons/tools.dm
@@ -212,8 +212,12 @@
/obj/item/weapon/weldingtool/process()
- if(welding && prob(5) && !remove_fuel(1))
- setWelding(0)
+ if(welding)
+ if(prob(5))
+ remove_fuel(1)
+
+ if(get_fuel() == 0)
+ setWelding(0)
//I'm not sure what this does. I assume it has to do with starting fires...
//...but it doesnt check to see if the welder is on or not.
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 795027ea3f..cb3214122a 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -14,6 +14,11 @@
var/damtype = "brute"
var/force = 0
+/obj/Destroy()
+ processing_objects -= src
+ nanomanager.close_uis(src)
+ return ..()
+
/obj/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/state = default_state)
// Calling Topic without a corresponding window open causes runtime errors
if(!nowindow && ..())
@@ -141,4 +146,4 @@
return
/obj/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
- return
\ No newline at end of file
+ return
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index c4fdc1df9f..f09d43e574 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -236,20 +236,20 @@
electronics = null
else if(istype(W, /obj/item/stack/material) && !glass)
- var/obj/item/stack/material/S = W
+ var/obj/item/stack/S = W
+ var/material_name = S.get_material_name()
if (S)
if (S.get_amount() >= 1)
- if(istype(S, /obj/item/stack/material/glass/reinforced))
+ if(material_name == "rglass")
playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1)
user.visible_message("[user] adds [S.name] to the airlock assembly.", "You start to install [S.name] into the airlock assembly.")
if(do_after(user, 40) && !glass)
if (S.use(1))
user << "You installed reinforced glass windows into the airlock assembly."
glass = 1
- else if(istype(S, /obj/item/stack/material) && S.default_type)
- var/M = S.default_type
+ else if(material_name)
// Ugly hack, will suffice for now. Need to fix it upstream as well, may rewrite mineral walls. ~Z
- if(M in list("mhydrogen","osmium","tritium","platinum","iron"))
+ if(!(material_name in list("gold", "silver", "diamond", "uranium", "phoron", "sandstone")))
user << "You cannot make an airlock out of that material."
return
if(S.get_amount() >= 2)
@@ -257,8 +257,8 @@
user.visible_message("[user] adds [S.name] to the airlock assembly.", "You start to install [S.name] into the airlock assembly.")
if(do_after(user, 40) && !glass)
if (S.use(2))
- user << "You installed [M] plating into the airlock assembly."
- glass = "[M]"
+ user << "You installed [material_display_name(material_name)] plating into the airlock assembly."
+ glass = material_name
else if(istype(W, /obj/item/weapon/screwdriver) && state == 2 )
playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index d217b10197..35a28558ae 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -25,7 +25,7 @@
/obj/structure/girder/bullet_act(var/obj/item/projectile/Proj)
//Girders only provide partial cover. There's a chance that the projectiles will just pass through. (unless you are trying to shoot the girder)
if(Proj.original != src && !prob(cover))
- return -1 //pass through
+ return PROJECTILE_CONTINUE //pass through
//Tasers and the like should not damage girders.
if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN))
@@ -108,11 +108,11 @@
else if(istype(W, /obj/item/stack/material))
- var/obj/item/stack/material/S = W
+ var/obj/item/stack/S = W
if(S.get_amount() < 2)
return ..()
- var/material/M = name_to_material[S.default_type]
+ var/material/M = S.get_material()
if(!istype(M))
return ..()
@@ -183,7 +183,7 @@
user << "There is not enough material here to reinforce the girder."
return
- var/material/M = name_to_material[S.default_type]
+ var/material/M = S.get_material()
if(!istype(M) || M.integrity < 50)
user << "You cannot reinforce \the [src] with that; it is too soft."
return
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 331529b87d..149d6bf394 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -91,7 +91,7 @@
passthrough = 1
if(passthrough)
- . = -1
+ . = PROJECTILE_CONTINUE
damage = between(0, (damage - Proj.damage)*(Proj.damage_type == BRUTE? 0.4 : 1), 10) //if the bullet passes through then the grille avoids most of the damage
src.health -= damage*0.2
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index cac56d23b9..17957cc589 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -83,22 +83,23 @@
/obj/structure/janitorialcart/attack_hand(mob/user)
- user.set_machine(src)
- var/dat
- if(mybag)
- dat += "[mybag.name]
"
- if(mymop)
- dat += "[mymop.name]
"
- if(myspray)
- dat += "[myspray.name]
"
- if(myreplacer)
- dat += "[myreplacer.name]
"
- if(signs)
- dat += "[signs] sign\s
"
- var/datum/browser/popup = new(user, "janicart", name, 240, 160)
- popup.set_content(dat)
- popup.open()
+ ui_interact(user)
+ return
+/obj/structure/janitorialcart/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ var/data[0]
+ data["name"] = capitalize(name)
+ data["bag"] = mybag ? capitalize(mybag.name) : null
+ data["mop"] = mymop ? capitalize(mymop.name) : null
+ data["spray"] = myspray ? capitalize(myspray.name) : null
+ data["replacer"] = myreplacer ? capitalize(myreplacer.name) : null
+ data["signs"] = signs ? "[signs] sign\s" : null
+
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "janitorcart.tmpl", "Janitorial cart", 240, 160)
+ ui.set_initial_data(data)
+ ui.open()
/obj/structure/janitorialcart/Topic(href, href_list)
if(!in_range(src, usr))
@@ -106,36 +107,39 @@
if(!isliving(usr))
return
var/mob/living/user = usr
- if(href_list["garbage"])
- if(mybag)
- user.put_in_hands(mybag)
- user << "You take [mybag] from [src]."
- mybag = null
- if(href_list["mop"])
- if(mymop)
- user.put_in_hands(mymop)
- user << "You take [mymop] from [src]."
- mymop = null
- if(href_list["spray"])
- if(myspray)
- user.put_in_hands(myspray)
- user << "You take [myspray] from [src]."
- myspray = null
- if(href_list["replacer"])
- if(myreplacer)
- user.put_in_hands(myreplacer)
- user << "You take [myreplacer] from [src]."
- myreplacer = null
- if(href_list["sign"])
- if(signs)
- var/obj/item/weapon/caution/Sign = locate() in src
- if(Sign)
- user.put_in_hands(Sign)
- user << "You take \a [Sign] from [src]."
- signs--
- else
- warning("[src] signs ([signs]) didn't match contents")
- signs = 0
+
+ if(href_list["take"])
+ switch(href_list["take"])
+ if("garbage")
+ if(mybag)
+ user.put_in_hands(mybag)
+ user << "You take [mybag] from [src]."
+ mybag = null
+ if("mop")
+ if(mymop)
+ user.put_in_hands(mymop)
+ user << "You take [mymop] from [src]."
+ mymop = null
+ if("spray")
+ if(myspray)
+ user.put_in_hands(myspray)
+ user << "You take [myspray] from [src]."
+ myspray = null
+ if("replacer")
+ if(myreplacer)
+ user.put_in_hands(myreplacer)
+ user << "You take [myreplacer] from [src]."
+ myreplacer = null
+ if("sign")
+ if(signs)
+ var/obj/item/weapon/caution/Sign = locate() in src
+ if(Sign)
+ user.put_in_hands(Sign)
+ user << "You take \a [Sign] from [src]."
+ signs--
+ else
+ warning("[src] signs ([signs]) didn't match contents")
+ signs = 0
update_icon()
updateUsrDialog()
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index fe667b5b79..4a4ea63276 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -17,7 +17,7 @@
var/datum/nano_module/appearance_changer/AC = ui_users[user]
if(!AC)
AC = new(src, user)
- AC.name = "SalonPro Nano-Mirror(TM)"
+ AC.name = "SalonPro Nano-Mirror™"
ui_users[user] = AC
AC.ui_interact(user)
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 083d33259b..b7accbffce 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -40,21 +40,21 @@
switch(severity)
if(1.0)
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.loc
+ A.forceMove(src.loc)
ex_act(severity)
qdel(src)
return
if(2.0)
if (prob(50))
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.loc
+ A.forceMove(src.loc)
ex_act(severity)
qdel(src)
return
if(3.0)
if (prob(5))
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.loc
+ A.forceMove(src.loc)
ex_act(severity)
qdel(src)
return
@@ -67,7 +67,7 @@
if (src.connected)
for(var/atom/movable/A as mob|obj in src.connected.loc)
if (!( A.anchored ))
- A.loc = src
+ A.forceMove(src)
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
qdel(src.connected)
src.connected = null
@@ -81,7 +81,7 @@
src.connected.connected = src
src.icon_state = "morgue0"
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.connected.loc
+ A.forceMove(src.connected.loc)
src.connected.icon_state = "morguet"
src.connected.set_dir(src.dir)
else
@@ -117,7 +117,7 @@
src.connected.connected = src
src.icon_state = "morgue0"
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.connected.loc
+ A.forceMove(src.connected.loc)
src.connected.icon_state = "morguet"
else
qdel(src.connected)
@@ -149,7 +149,7 @@
if (src.connected)
for(var/atom/movable/A as mob|obj in src.loc)
if (!( A.anchored ))
- A.loc = src.connected
+ A.forceMove(src.connected)
//Foreach goto(26)
src.connected.connected = null
src.connected.update()
@@ -166,7 +166,7 @@
return
if (!ismob(user) || user.stat || user.lying || user.stunned)
return
- O.loc = src.loc
+ O.forceMove(src.loc)
if (user != O)
for(var/mob/B in viewers(user, 3))
if ((B.client && !( B.blinded )))
@@ -210,21 +210,21 @@
switch(severity)
if(1.0)
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.loc
+ A.forceMove(src.loc)
ex_act(severity)
qdel(src)
return
if(2.0)
if (prob(50))
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.loc
+ A.forceMove(src.loc)
ex_act(severity)
qdel(src)
return
if(3.0)
if (prob(5))
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.loc
+ A.forceMove(src.loc)
ex_act(severity)
qdel(src)
return
@@ -246,7 +246,7 @@
if ((src.connected) && (src.locked == 0))
for(var/atom/movable/A as mob|obj in src.connected.loc)
if (!( A.anchored ))
- A.loc = src
+ A.forceMove(src)
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
//src.connected = null
qdel(src.connected)
@@ -260,7 +260,7 @@
src.connected.connected = src
src.icon_state = "crema0"
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.connected.loc
+ A.forceMove(src.connected.loc)
src.connected.icon_state = "cremat"
else
//src.connected = null
@@ -294,7 +294,7 @@
src.connected.connected = src
src.icon_state = "crema0"
for(var/atom/movable/A as mob|obj in src)
- A.loc = src.connected.loc
+ A.forceMove(src.connected.loc)
src.connected.icon_state = "cremat"
else
qdel(src.connected)
@@ -366,11 +366,17 @@
anchored = 1
throwpass = 1
+/obj/structure/c_tray/Destroy()
+ if(connected && connected.connected == src)
+ connected.connected = null
+ connected = null
+ return ..()
+
/obj/structure/c_tray/attack_hand(mob/user as mob)
if (src.connected)
for(var/atom/movable/A as mob|obj in src.loc)
if (!( A.anchored ))
- A.loc = src.connected
+ A.forceMove(src.connected)
//Foreach goto(26)
src.connected.connected = null
src.connected.update()
@@ -387,7 +393,7 @@
return
if (!ismob(user) || user.stat || user.lying || user.stunned)
return
- O.loc = src.loc
+ O.forceMove(src.loc)
if (user != O)
for(var/mob/B in viewers(user, 3))
if ((B.client && !( B.blinded )))
@@ -406,7 +412,7 @@
/obj/machinery/button/crematorium/attack_hand(mob/user as mob)
if(..())
return
- if(src.allowed(usr))
+ if(src.allowed(user))
for (var/obj/structure/crematorium/C in world)
if (C.id == id)
if (!C.cremating)
diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm
index b3230095c1..10fa149e8b 100644
--- a/code/game/objects/structures/simple_doors.dm
+++ b/code/game/objects/structures/simple_doors.dm
@@ -44,6 +44,9 @@
update_nearby_tiles()
..()
+/obj/structure/simple_door/get_material()
+ return material
+
/obj/structure/simple_door/Bumped(atom/user)
..()
if(!state)
diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
index 2b670320d0..bab8e44cd9 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
@@ -33,6 +33,9 @@
padding_material = get_material_by_name(new_padding_material)
update_icon()
+/obj/structure/bed/get_material()
+ return material
+
// Reuse the cache/code from stools, todo maybe unify.
/obj/structure/bed/update_icon()
// Prep icon.
diff --git a/code/game/objects/structures/window_spawner.dm b/code/game/objects/structures/window_spawner.dm
new file mode 100644
index 0000000000..e6c2d06001
--- /dev/null
+++ b/code/game/objects/structures/window_spawner.dm
@@ -0,0 +1,89 @@
+// Ported from Haine and WrongEnd with much gratitude!
+/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */
+/*-=-=-=-=-=-=-=-=-=-=-=-=-=WHAT-EVER=-=-=-=-=-=-=-=-=-=-=-=-=-*/
+/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */
+
+/obj/effect/wingrille_spawn
+ name = "window grille spawner"
+ icon = 'icons/obj/structures.dmi'
+ icon_state = "wingrille"
+ density = 1
+ anchored = 1.0
+ pressure_resistance = 4*ONE_ATMOSPHERE
+ var/win_path = /obj/structure/window/basic
+ var/activated
+
+/obj/effect/wingrille_spawn/attack_hand()
+ attack_generic()
+
+/obj/effect/wingrille_spawn/attack_ghost()
+ attack_generic()
+
+/obj/effect/wingrille_spawn/attack_generic()
+ activate()
+
+/obj/effect/wingrille_spawn/initialize()
+ ..()
+ if(!win_path)
+ return
+ if(ticker && ticker.current_state < GAME_STATE_PLAYING)
+ activate()
+
+/obj/effect/wingrille_spawn/proc/activate()
+ if(activated) return
+ if (!locate(/obj/structure/grille) in get_turf(src))
+ var/obj/structure/grille/G = PoolOrNew(/obj/structure/grille, src.loc)
+ handle_grille_spawn(G)
+ var/list/neighbours = list()
+ for (var/dir in cardinal)
+ var/turf/T = get_step(src, dir)
+ var/obj/effect/wingrille_spawn/other = locate(/obj/effect/wingrille_spawn) in T
+ if(!other)
+ var/found_connection
+ if(locate(/obj/structure/grille) in T)
+ for(var/obj/structure/window/W in T)
+ if(W.type == win_path && W.dir == get_dir(T,src))
+ found_connection = 1
+ qdel(W)
+ if(!found_connection)
+ var/obj/structure/window/new_win = PoolOrNew(win_path, src.loc)
+ new_win.set_dir(dir)
+ handle_window_spawn(new_win)
+ else
+ neighbours |= other
+ activated = 1
+ for(var/obj/effect/wingrille_spawn/other in neighbours)
+ if(!other.activated) other.activate()
+ qdel(src)
+
+/obj/effect/wingrille_spawn/proc/handle_window_spawn(var/obj/structure/window/W)
+ return
+
+// Currently unused, could be useful for pre-wired electrified windows.
+/obj/effect/wingrille_spawn/proc/handle_grille_spawn(var/obj/structure/grille/G)
+ return
+
+/obj/effect/wingrille_spawn/reinforced
+ name = "reinforced window grille spawner"
+ icon_state = "r-wingrille"
+ win_path = /obj/structure/window/reinforced
+
+/obj/effect/wingrille_spawn/phoron
+ name = "phoron window grille spawner"
+ icon_state = "p-wingrille"
+ win_path = /obj/structure/window/phoronbasic
+
+/obj/effect/wingrille_spawn/reinforced_phoron
+ name = "reinforced phoron window grille spawner"
+ icon_state = "pr-wingrille"
+ win_path = /obj/structure/window/phoronreinforced
+
+/obj/effect/wingrille_spawn/reinforced/polarized
+ name = "polarized window grille spawner"
+ color = "#444444"
+ win_path = /obj/structure/window/reinforced/polarized
+ var/id
+
+/obj/effect/wingrille_spawn/reinforced/polarized/handle_window_spawn(var/obj/structure/window/reinforced/polarized/P)
+ if(id)
+ P.id = id
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index 253d96174d..044143269e 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -195,16 +195,12 @@ var/list/mechtoys = list(
find_slip = 0
continue
- // Sell phoron
- if(istype(A, /obj/item/stack/material/phoron))
- var/obj/item/stack/material/phoron/P = A
- phoron_count += P.get_amount()
-
- // Sell platinum
- if(istype(A, /obj/item/stack/material/platinum))
- var/obj/item/stack/material/platinum/P = A
- plat_count += P.get_amount()
-
+ // Sell phoron and platinum
+ if(istype(A, /obj/item/stack))
+ var/obj/item/stack/P
+ switch(P.get_material_name())
+ if("phoron") phoron_count += P.get_amount()
+ if("platinum") plat_count += P.get_amount()
qdel(MA)
if(phoron_count)
diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm
index fa6ee92855..aa7db8a0cc 100644
--- a/code/game/turfs/simulated/wall_icon.dm
+++ b/code/game/turfs/simulated/wall_icon.dm
@@ -8,7 +8,7 @@
else
construction_stage = null
if(!material)
- material = name_to_material[DEFAULT_WALL_MATERIAL]
+ material = get_material_by_name(DEFAULT_WALL_MATERIAL)
if(material)
explosion_resistance = material.explosion_resistance
if(reinf_material && reinf_material.explosion_resistance > explosion_resistance)
@@ -44,6 +44,7 @@
return
overlays.Cut()
+ damage_overlay = 0
if(!wall_cache["[new_state]-[material.icon_colour]"])
var/image/I = image(icon='icons/turf/wall_masks.dmi',icon_state="[new_state]")
@@ -74,7 +75,6 @@
check_relatives(1)
/turf/simulated/wall/proc/update_icon()
-
if(!material)
return
@@ -86,15 +86,23 @@
else
set_wall_state("[material.icon_base]fwall_open")
- var/dmg_amt = material.integrity
- if(reinf_material)
- dmg_amt += reinf_material.integrity
- var/overlay = round(damage / dmg_amt * damage_overlays.len) + 1
- if(overlay > damage_overlays.len)
- overlay = damage_overlays.len
- if(density)
+ if(damage == 0)
+ if(damage_overlay != 0)
+ overlays -= damage_overlays[damage_overlay]
+ damage_overlay = 0
+ else if(density)
+ var/integrity = material.integrity
+ if(reinf_material)
+ integrity += reinf_material.integrity
+
+ var/overlay = round(damage / integrity * damage_overlays.len) + 1
+ if(overlay > damage_overlays.len)
+ overlay = damage_overlays.len
+
if(damage_overlay && overlay == damage_overlay) //No need to update.
return
+
+ if(damage_overlay) overlays -= damage_overlays[damage_overlay]
overlays += damage_overlays[overlay]
damage_overlay = overlay
return
@@ -131,4 +139,4 @@
/turf/simulated/wall/proc/can_join_with(var/turf/simulated/wall/W)
if(material && W.material && material.icon_base == W.material.icon_base)
return 1
- return 0
\ No newline at end of file
+ return 0
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 8015c47c8c..782be35e6e 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -12,8 +12,8 @@ var/list/global/wall_cache = list()
heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall
var/damage = 0
- var/damage_overlay
- var/global/damage_overlays[8]
+ var/damage_overlay = 0
+ var/global/damage_overlays[16]
var/active
var/can_open = 0
var/material/material
@@ -28,7 +28,7 @@ var/list/global/wall_cache = list()
materialtype = DEFAULT_WALL_MATERIAL
material = get_material_by_name(materialtype)
if(!isnull(rmaterialtype))
- reinf_material = name_to_material[rmaterialtype]
+ reinf_material = get_material_by_name(rmaterialtype)
update_material()
processing_turfs |= src
@@ -38,7 +38,6 @@ var/list/global/wall_cache = list()
dismantle_wall(null,null,1)
..()
-
/turf/simulated/wall/process()
// Calling parent will kill processing
if(!radiate())
@@ -170,7 +169,7 @@ var/list/global/wall_cache = list()
O.loc = src
clear_plants()
- material = name_to_material["placeholder"]
+ material = get_material_by_name("placeholder")
reinf_material = null
check_relatives()
diff --git a/code/modules/admin/ToRban.dm b/code/modules/admin/ToRban.dm
index efa835b25e..d127bfe6f4 100644
--- a/code/modules/admin/ToRban.dm
+++ b/code/modules/admin/ToRban.dm
@@ -23,7 +23,7 @@
/proc/ToRban_update()
spawn(0)
log_misc("Downloading updated ToR data...")
- var/http[] = world.Export("http://exitlist.torproject.org/exit-addresses")
+ var/http[] = world.Export("https://check.torproject.org/exit-addresses")
var/list/rawlist = file2list(http["CONTENT"])
if(rawlist.len)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 993b37454f..eadbee27fa 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -1097,7 +1097,7 @@ proc/admin_notice(var/message, var/rights)
else
new chosen(usr.loc)
- log_admin("[key_name(usr)] spawned [chosen] at ([usr.x],[usr.y],[usr.z])")
+ log_and_message_admins("spawned [chosen] at ([usr.x],[usr.y],[usr.z])")
feedback_add_details("admin_verb","SA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 4498759140..09d0e7ebd0 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -83,10 +83,13 @@ var/list/admin_verbs_admin = list(
/client/proc/allow_character_respawn, /* Allows a ghost to respawn */
/client/proc/event_manager_panel,
/client/proc/empty_ai_core_toggle_latejoin,
+ /client/proc/empty_ai_core_toggle_latejoin,
/client/proc/aooc,
/client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */
/client/proc/change_human_appearance_self, /* Allows the human-based mob itself change its basic appearance */
- /client/proc/change_security_level
+ /client/proc/change_security_level,
+ /client/proc/view_chemical_reaction_logs,
+ /client/proc/makePAI
)
var/list/admin_verbs_ban = list(
/client/proc/unban_panel,
diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm
index c5a54694c8..4a28ece915 100644
--- a/code/modules/admin/player_notes.dm
+++ b/code/modules/admin/player_notes.dm
@@ -1,147 +1,147 @@
-//This stuff was originally intended to be integrated into the ban-system I was working on
-//but it's safe to say that'll never be finished. So I've merged it into the current player panel.
-//enjoy ~Carn
-/*
-#define NOTESFILE "data/player_notes.sav" //where the player notes are saved
-
-datum/admins/proc/notes_show(var/ckey)
- usr << browse("Player Notes[notes_gethtml(ckey)]","window=player_notes;size=700x400")
-
-
-datum/admins/proc/notes_gethtml(var/ckey)
- var/savefile/notesfile = new(NOTESFILE)
- if(!notesfile) return "Error: Cannot access [NOTESFILE]"
- if(ckey)
- . = "Notes for [ckey]: \[+\] \[-\]
"
- notesfile.cd = "/[ckey]"
- var/index = 1
- while( !notesfile.eof )
- var/note
- notesfile >> note
- . += "[note] \[-\]
"
- index++
- else
- . = "All Notes: \[+\] \[-\]
"
- notesfile.cd = "/"
- for(var/dir in notesfile.dir)
- . += "[dir]
"
- return
-
-//handles removing entries from the buffer, or removing the entire directory if no start_index is given
-/proc/notes_remove(var/ckey, var/start_index, var/end_index)
- var/savefile/notesfile = new(NOTESFILE)
- if(!notesfile) return
-
- if(!ckey)
- notesfile.cd = "/"
- ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir)
- if(!ckey) return
-
- if(start_index)
- notesfile.cd = "/[ckey]"
- var/list/noteslist = list()
- if(!end_index) end_index = start_index
- var/index = 0
- while( !notesfile.eof )
- index++
- var/temp
- notesfile >> temp
- if( (start_index <= index) && (index <= end_index) )
- continue
- noteslist += temp
-
- notesfile.eof = -2 //Move to the start of the buffer and then erase.
-
- for( var/note in noteslist )
- notesfile << note
- else
- notesfile.cd = "/"
- if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes")
- notesfile.dir.Remove(ckey)
- return
-
-#undef NOTESFILE
-*/
-
-//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky.
-
+//This stuff was originally intended to be integrated into the ban-system I was working on
+//but it's safe to say that'll never be finished. So I've merged it into the current player panel.
+//enjoy ~Carn
+/*
+#define NOTESFILE "data/player_notes.sav" //where the player notes are saved
+
+datum/admins/proc/notes_show(var/ckey)
+ usr << browse("Player Notes[notes_gethtml(ckey)]","window=player_notes;size=700x400")
+
+
+datum/admins/proc/notes_gethtml(var/ckey)
+ var/savefile/notesfile = new(NOTESFILE)
+ if(!notesfile) return "Error: Cannot access [NOTESFILE]"
+ if(ckey)
+ . = "Notes for [ckey]: \[+\] \[-\]
"
+ notesfile.cd = "/[ckey]"
+ var/index = 1
+ while( !notesfile.eof )
+ var/note
+ notesfile >> note
+ . += "[note] \[-\]
"
+ index++
+ else
+ . = "All Notes: \[+\] \[-\]
"
+ notesfile.cd = "/"
+ for(var/dir in notesfile.dir)
+ . += "[dir]
"
+ return
+
+//handles removing entries from the buffer, or removing the entire directory if no start_index is given
+/proc/notes_remove(var/ckey, var/start_index, var/end_index)
+ var/savefile/notesfile = new(NOTESFILE)
+ if(!notesfile) return
+
+ if(!ckey)
+ notesfile.cd = "/"
+ ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir)
+ if(!ckey) return
+
+ if(start_index)
+ notesfile.cd = "/[ckey]"
+ var/list/noteslist = list()
+ if(!end_index) end_index = start_index
+ var/index = 0
+ while( !notesfile.eof )
+ index++
+ var/temp
+ notesfile >> temp
+ if( (start_index <= index) && (index <= end_index) )
+ continue
+ noteslist += temp
+
+ notesfile.eof = -2 //Move to the start of the buffer and then erase.
+
+ for( var/note in noteslist )
+ notesfile << note
+ else
+ notesfile.cd = "/"
+ if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes")
+ notesfile.dir.Remove(ckey)
+ return
+
+#undef NOTESFILE
+*/
+
+//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky.
+
/proc/notes_add(var/key, var/note, var/mob/user)
- if (!key || !note)
- return
-
- //Loading list of notes for this key
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos) infos = list()
-
- //Overly complex timestamp creation
- var/modifyer = "th"
- switch(time2text(world.timeofday, "DD"))
- if("01","21","31")
- modifyer = "st"
- if("02","22",)
- modifyer = "nd"
- if("03","23")
- modifyer = "rd"
- var/day_string = "[time2text(world.timeofday, "DD")][modifyer]"
- if(copytext(day_string,1,2) == "0")
- day_string = copytext(day_string,2)
- var/full_date = time2text(world.timeofday, "DDD, Month DD of YYYY")
- var/day_loc = findtext(full_date, time2text(world.timeofday, "DD"))
-
- var/datum/player_info/P = new
+ if (!key || !note)
+ return
+
+ //Loading list of notes for this key
+ var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
+ var/list/infos
+ info >> infos
+ if(!infos) infos = list()
+
+ //Overly complex timestamp creation
+ var/modifyer = "th"
+ switch(time2text(world.timeofday, "DD"))
+ if("01","21","31")
+ modifyer = "st"
+ if("02","22",)
+ modifyer = "nd"
+ if("03","23")
+ modifyer = "rd"
+ var/day_string = "[time2text(world.timeofday, "DD")][modifyer]"
+ if(copytext(day_string,1,2) == "0")
+ day_string = copytext(day_string,2)
+ var/full_date = time2text(world.timeofday, "DDD, Month DD of YYYY")
+ var/day_loc = findtext(full_date, time2text(world.timeofday, "DD"))
+
+ var/datum/player_info/P = new
if (user)
P.author = user.key
P.rank = user.client.holder.rank
- else
- P.author = "Adminbot"
- P.rank = "Friendly Robot"
- P.content = note
- P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]"
-
- infos += P
- info << infos
-
+ else
+ P.author = "Adminbot"
+ P.rank = "Friendly Robot"
+ P.content = note
+ P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]"
+
+ infos += P
+ info << infos
+
message_admins("\blue [key_name_admin(user)] has edited [key]'s notes.")
log_admin("[key_name(user)] has edited [key]'s notes.")
-
- qdel(info)
-
- //Updating list of keys with notes on them
- var/savefile/note_list = new("data/player_notes.sav")
- var/list/note_keys
- note_list >> note_keys
- if(!note_keys) note_keys = list()
- if(!note_keys.Find(key)) note_keys += key
- note_list << note_keys
- qdel(note_list)
-
-
-/proc/notes_del(var/key, var/index)
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos || infos.len < index) return
-
- var/datum/player_info/item = infos[index]
- infos.Remove(item)
- info << infos
-
- message_admins("\blue [key_name_admin(usr)] deleted one of [key]'s notes.")
- log_admin("[key_name(usr)] deleted one of [key]'s notes.")
-
- qdel(info)
-
-/proc/show_player_info_irc(var/key as text)
- var/dat = " Info on [key]%0D%0A"
- var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
- var/list/infos
- info >> infos
- if(!infos)
- dat = "No information found on the given key."
- else
- for(var/datum/player_info/I in infos)
- dat += "[I.content]%0D%0Aby [I.author] ([I.rank]) on [I.timestamp]%0D%0A%0D%0A"
-
- return dat
+
+ qdel(info)
+
+ //Updating list of keys with notes on them
+ var/savefile/note_list = new("data/player_notes.sav")
+ var/list/note_keys
+ note_list >> note_keys
+ if(!note_keys) note_keys = list()
+ if(!note_keys.Find(key)) note_keys += key
+ note_list << note_keys
+ qdel(note_list)
+
+
+/proc/notes_del(var/key, var/index)
+ var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
+ var/list/infos
+ info >> infos
+ if(!infos || infos.len < index) return
+
+ var/datum/player_info/item = infos[index]
+ infos.Remove(item)
+ info << infos
+
+ message_admins("\blue [key_name_admin(usr)] deleted one of [key]'s notes.")
+ log_admin("[key_name(usr)] deleted one of [key]'s notes.")
+
+ qdel(info)
+
+/proc/show_player_info_irc(var/key as text)
+ var/dat = " Info on [key]\n"
+ var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
+ var/list/infos
+ info >> infos
+ if(!infos)
+ dat = "No information found on the given key."
+ else
+ for(var/datum/player_info/I in infos)
+ dat += "[I.content]\nby [I.author] ([I.rank]) on [I.timestamp]\n\n"
+
+ return list2params(list(dat))
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index 47bdeeb5af..9d9919e4ed 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -358,7 +358,7 @@
dat += "NA | "
- dat += {"[(M.client ? "[M.client]" : "No client")] |
+ dat += {"[M.key ? (M.client ? M.key : "[M.key] (DC)") : "No key"] |
X |
PM |
"}
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 5519eff028..3cd3433696 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1651,18 +1651,7 @@
var/mob/M = O
M.real_name = obj_name
- if (number == 1)
- log_admin("[key_name(usr)] created a [english_list(paths)]")
- for(var/path in paths)
- if(ispath(path, /mob))
- message_admins("[key_name_admin(usr)] created a [english_list(paths)]", 1)
- break
- else
- log_admin("[key_name(usr)] created [number]ea [english_list(paths)]")
- for(var/path in paths)
- if(ispath(path, /mob))
- message_admins("[key_name_admin(usr)] created [number]ea [english_list(paths)]", 1)
- break
+ log_and_message_admins("created [number] [english_list(paths)]")
return
else if(href_list["secretsfun"])
diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm
index 4b90283a56..2131e977ac 100644
--- a/code/modules/admin/verbs/buildmode.dm
+++ b/code/modules/admin/verbs/buildmode.dm
@@ -42,6 +42,12 @@
icon = 'icons/misc/buildmode.dmi'
var/obj/effect/bmode/buildholder/master = null
+/obj/effect/bmode/Destroy()
+ if(master && master.cl)
+ master.cl.screen -= src
+ master = null
+ return ..()
+
/obj/effect/bmode/builddir
icon_state = "build"
screen_loc = "NORTH,WEST"
@@ -117,6 +123,19 @@
var/obj/effect/bmode/buildquit/buildquit = null
var/atom/movable/throw_atom = null
+/obj/effect/bmode/buildholder/Destroy()
+ qdel(builddir)
+ builddir = null
+ qdel(buildhelp)
+ buildhelp = null
+ qdel(buildmode)
+ buildmode = null
+ qdel(buildquit)
+ buildquit = null
+ throw_atom = null
+ cl = null
+ return ..()
+
/obj/effect/bmode/buildmode
icon_state = "buildmode1"
screen_loc = "NORTH,WEST+2"
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 0d8a754ce0..385c58da63 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -64,6 +64,28 @@ 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)
+ if(!target)
+ usr << "Your target no longer exists."
+ return
+ if(!hascall(target,procname))
+ usr << "Error: callproc(): target has no such call [procname]."
+ return
+ else
+ if(copytext(procname, 1, 7) == "/proc/")
+ // nothing
+ else if(copytext(procname, 1, 6) == "proc/")
+ procname = "/[procname]"
+ else if(copytext(procname, 1, 2) == "/")
+ procname = "/proc[procname]"
+ else
+ procname = "/proc/[procname]"
+ // Procs have the strange property that text2path will return non-null, but ispath() will return false.
+ var/path = text2path(procname)
+ if(!path || ispath(path))
+ usr << "Invalid proc [procname]"
+ return
var/argnum = input("Number of arguments","Number:",0) as num|null
if(!argnum && (argnum!=0)) return
@@ -117,13 +139,9 @@ 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
- //this currently has no hascall protection. wasn't able to get it working.
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
returnval = call(procname)(arglist(lst)) // Pass the lst as an argument list to the proc
@@ -200,7 +218,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(!choice)
return 0
if(!istype(choice, /mob/dead/observer))
- var/confirm = input("[choice.key] isn't ghosting right now. Are you sure you want to yank him out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", "No") in list("Yes", "No")
+ var/confirm = input("[choice.key] isn't ghosting right now. Are you sure you want to yank them out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", "No") in list("Yes", "No")
if(confirm != "Yes")
return 0
var/obj/item/device/paicard/card = new(T)
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index cf8b903a84..12edb98af3 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -468,7 +468,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
for(var/mob/living/silicon/ai/M in mob_list)
if (M.stat == 2)
usr << "Upload failed. No signal is being detected from the AI."
- else if (!M.has_power)
+ else if (M.see_in_dark == 0)
usr << "Upload failed. Only a faint signal is being detected from the AI, and it is not responding to our requests. It may be low on power."
else
M.add_ion_law(input)
diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm
index ef217b16f9..37fc52eda8 100644
--- a/code/modules/admin/verbs/striketeam.dm
+++ b/code/modules/admin/verbs/striketeam.dm
@@ -52,4 +52,4 @@ var/const/commandos_possible = 6 //if more Commandos are needed in the future
usr << "Looks like someone beat you to it."
return
- team.attempt_spawn(1)
+ team.attempt_random_spawn()
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index c524291683..b1fa34b302 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -153,6 +153,13 @@
add_admin_verbs()
admin_memo_show()
+ // Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays.
+ // (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise)
+ spawn(5) // And wait a half-second, since it sounds like you can do this too fast.
+ if(src)
+ winset(src, null, "command=\".configure graphics-hwmode off\"")
+ winset(src, null, "command=\".configure graphics-hwmode on\"")
+
log_client_to_db()
send_resources()
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 752e6ed872..4299b22a8a 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -75,7 +75,7 @@ datum/preferences
var/b_eyes = 0 //Eye color
var/species = "Human" //Species datum to use.
var/species_preview //Used for the species selection window.
- var/language = "None" //Secondary language
+ var/list/alternate_languages = list() //Secondary language(s)
var/list/gear //Custom/fluff item loadout.
//Some faction information.
@@ -85,7 +85,6 @@ datum/preferences
var/religion = "None" //Religious association.
//Mob preview
- var/mob/living/carbon/human/dummy //the mannequin
var/icon/preview_icon = null
var/icon/preview_icon_front = null
var/icon/preview_icon_side = null
@@ -133,9 +132,12 @@ datum/preferences
var/metadata = ""
var/slot_name = ""
+ var/client/client = null
+
/datum/preferences/New(client/C)
b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
if(istype(C))
+ client = C
if(!IsGuestKey(C.key))
load_path(C.ckey)
if(load_preferences())
@@ -308,7 +310,7 @@ datum/preferences
dat += "(®)"
dat += "
"
dat += "Species: [species]
"
- dat += "Secondary Language:
[language]
"
+
dat += "Blood Type: [b_type]
"
dat += "Skin Tone: [-s_tone + 35]/220
"
//dat += "Skin pattern: Adjust
"
@@ -382,6 +384,25 @@ datum/preferences
else
dat += "
"
+
+ dat += "Languages
"
+ var/datum/species/S = all_species[species]
+ if(S.language)
+ dat += "- [S.language]
"
+ if(S.default_language && S.default_language != S.language)
+ dat += "- [S.default_language]
"
+ if(S.num_alternate_languages)
+ if(alternate_languages.len)
+ for(var/i = 1 to alternate_languages.len)
+ var/lang = alternate_languages[i]
+ dat += "- [lang] - remove
"
+
+ if(alternate_languages.len < S.num_alternate_languages)
+ dat += "- add ([S.num_alternate_languages - alternate_languages.len] remaining)
"
+ else
+ dat += "- [species] cannot choose secondary languages.
"
+ dat += "
"
+
var/list/undies = gender == MALE ? underwear_m : underwear_f
dat += "Underwear: [get_key_by_value(undies,underwear)]
"
@@ -1127,6 +1148,32 @@ datum/preferences
if(gear_name == choice)
gear -= gear_name
break
+ else if(href_list["preference"] == "language")
+ if(href_list["remove"])
+ var/index = text2num(href_list["remove"])
+ alternate_languages.Cut(index, index+1)
+ if(href_list["add"])
+ var/datum/species/S = all_species[species]
+ if(alternate_languages.len >= S.num_alternate_languages)
+ alert(user, "You have already selected the maximum number of alternate languages for this species!")
+ else
+ var/list/available_languages = S.secondary_langs.Copy()
+ for(var/L in all_languages)
+ var/datum/language/lang = all_languages[L]
+ if(!(lang.flags & RESTRICTED) && (!config.usealienwhitelist || is_alien_whitelisted(user, L) || !(lang.flags & WHITELISTED)))
+ available_languages |= L
+
+ // make sure we don't let them waste slots on the default languages
+ available_languages -= S.language
+ available_languages -= S.default_language
+ available_languages -= alternate_languages
+
+ if(!available_languages.len)
+ alert(user, "There are no additional languages available to select.")
+ else
+ var/new_lang = input("Select an additional language", "Character Generation", null) as null|anything in available_languages
+ if(new_lang)
+ alternate_languages |= new_lang
switch(href_list["task"])
if("change")
@@ -1136,6 +1183,7 @@ datum/preferences
if(!choice) return
species_preview = choice
SetSpecies(user)
+ alternate_languages = list() // Reset their alternate languages. Todo: attempt to just fix it instead?
if("random")
switch(href_list["preference"])
@@ -1244,29 +1292,6 @@ datum/preferences
s_tone = 0
- if("language")
- var/languages_available
- var/list/new_languages = list("None")
- var/datum/species/S = all_species[species]
-
- if(config.usealienwhitelist)
- for(var/L in all_languages)
- var/datum/language/lang = all_languages[L]
- if((!(lang.flags & RESTRICTED)) && (is_alien_whitelisted(user, L)||(!( lang.flags & WHITELISTED ))||(S && (L in S.secondary_langs))))
- new_languages += lang
-
- languages_available = 1
-
- if(!(languages_available))
- alert(user, "There are not currently any available secondary languages.")
- else
- for(var/L in all_languages)
- var/datum/language/lang = all_languages[L]
- if(!(lang.flags & RESTRICTED))
- new_languages += lang.name
-
- language = input("Please select a secondary language", "Character Generation", null) in new_languages
-
if("metadata")
var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null
if(new_metadata)
@@ -1641,18 +1666,30 @@ datum/preferences
character.gen_record = gen_record
character.exploit_record = exploit_record
- character.change_gender(gender)
+ character.gender = gender
character.age = age
character.b_type = b_type
- character.change_eye_color(r_eyes,g_eyes,b_eyes)
- character.change_hair_color(r_hair,g_hair,b_hair)
- character.change_facial_hair_color(r_facial,g_facial,b_facial)
- character.change_skin_color(r_skin,g_skin,b_skin)
- character.change_skin_tone(s_tone)
+ character.r_eyes = r_eyes
+ character.g_eyes = g_eyes
+ character.b_eyes = b_eyes
- character.change_hair(h_style)
- character.change_facial_hair(f_style)
+ character.r_hair = r_hair
+ character.g_hair = g_hair
+ character.b_hair = b_hair
+
+ character.r_facial = r_facial
+ character.g_facial = g_facial
+ character.b_facial = b_facial
+
+ character.r_skin = r_skin
+ character.g_skin = g_skin
+ character.b_skin = b_skin
+
+ character.s_tone = s_tone
+
+ character.h_style = h_style
+ character.f_style = f_style
character.home_system = home_system
character.citizenship = citizenship
diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm
index 25e1da639f..5be7e2dcde 100644
--- a/code/modules/client/preferences_gear.dm
+++ b/code/modules/client/preferences_gear.dm
@@ -279,7 +279,7 @@ var/global/list/gear_datums = list()
/datum/gear/scanning_goggles
display_name = "scanning goggles"
- path = /obj/item/clothing/glasses/science/scanners
+ path = /obj/item/clothing/glasses/regular/scanners
cost = 1
slot = slot_glasses
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index a67efd084c..29e4089685 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -107,9 +107,30 @@
S["gender"] >> gender
S["age"] >> age
S["species"] >> species
- S["language"] >> language
S["spawnpoint"] >> spawnpoint
+ S["language"] >> alternate_languages
+ if(isnull(alternate_languages))
+ alternate_languages = list()
+ if(!islist(alternate_languages))
+ if(client)
+ // Warn them that we (probably) just broke their languages
+ client << "Your current character slot's languages list has been updated from an old version, and may not be what you expect."
+
+ if(alternate_languages in all_languages)
+ alternate_languages = list(alternate_languages)
+ else
+ alternate_languages = list()
+
+ // try to give them their species language
+ var/datum/species/SP = all_species[species]
+ if(SP)
+ alternate_languages |= SP.language
+ alternate_languages |= SP.default_language
+
+ // remove the Galcom that most races have as default_language
+ alternate_languages -= "Galactic Common"
+
//colors to be consolidated into hex strings (requires some work with dna code)
S["hair_red"] >> r_hair
S["hair_green"] >> g_hair
@@ -200,7 +221,7 @@
if(isnum(undershirt))
undershirt = undershirt_t[undershirt_t[undershirt]]
- if(isnull(language)) language = "None"
+ if(isnull(alternate_languages)) alternate_languages = list()
if(isnull(spawnpoint)) spawnpoint = "Arrivals Shuttle"
if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation)
if(!real_name) real_name = random_name(gender)
@@ -265,7 +286,7 @@
S["gender"] << gender
S["age"] << age
S["species"] << species
- S["language"] << language
+ S["language"] << alternate_languages
S["hair_red"] << r_hair
S["hair_green"] << g_hair
S["hair_blue"] << b_hair
@@ -346,4 +367,4 @@
#undef SAVEFILE_VERSION_MAX
-#undef SAVEFILE_VERSION_MIN
\ No newline at end of file
+#undef SAVEFILE_VERSION_MIN
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 8ec49ecd5f..6f2515b55d 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -176,7 +176,7 @@ BLIND // can't see anything
slot_flags = SLOT_EYES
var/vision_flags = 0
var/darkness_view = 0//Base human is 2
- var/invisa_view = 0
+ var/see_invisible = -1
sprite_sheets = list("Vox" = 'icons/mob/species/vox/eyes.dmi')
/obj/item/clothing/glasses/update_clothing_icon()
@@ -303,6 +303,10 @@ BLIND // can't see anything
body_parts_covered = FACE|EYES
sprite_sheets = list("Vox" = 'icons/mob/species/vox/masks.dmi')
+ var/voicechange = 0
+ var/list/say_messages
+ var/list/say_verbs
+
/obj/item/clothing/mask/update_clothing_icon()
if (ismob(src.loc))
var/mob/M = src.loc
@@ -387,6 +391,7 @@ BLIND // can't see anything
var/worn_state = null
/obj/item/clothing/under/New()
+ ..()
if(worn_state)
if(!item_state_slots)
item_state_slots = list()
@@ -399,6 +404,29 @@ BLIND // can't see anything
if((worn_state + "_d_s") in icon_states('icons/mob/uniform.dmi'))
rolled_down = 0
+/obj/item/clothing/under/proc/update_rolldown_status()
+ var/mob/living/carbon/human/H
+ if(istype(src.loc, /mob/living/carbon/human))
+ H = src.loc
+
+ var/icon/under_icon
+ if(icon_override)
+ under_icon = icon_override
+ else if(H && sprite_sheets && sprite_sheets[H.species.name])
+ under_icon = sprite_sheets[H.species.name]
+ else if(item_icons && item_icons[slot_w_uniform_str])
+ under_icon = item_icons[slot_w_uniform_str]
+ else
+ under_icon = INV_W_UNIFORM_DEF_ICON
+
+ // The _s is because the icon update procs append it.
+ if(("[worn_state]_d_s") in icon_states(under_icon))
+ if(rolled_down != 1)
+ rolled_down = 0
+ else
+ rolled_down = -1
+ if(H) update_clothing_icon()
+
/obj/item/clothing/under/update_clothing_icon()
if (ismob(src.loc))
var/mob/M = src.loc
@@ -540,7 +568,8 @@ BLIND // can't see anything
if(!istype(usr, /mob/living)) return
if(usr.stat) return
- if(rolled_down < 0)
+ update_rolldown_status()
+ if(rolled_down == -1)
usr << "You cannot roll down [src]!"
return
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index 9d3d033359..6ba0b27b12 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -7,7 +7,6 @@
//slot_flags = SLOT_EYES
//var/vision_flags = 0
//var/darkness_view = 0//Base human is 2
- //var/invisa_view = 0
var/prescription = 0
var/toggleable = 0
var/off_state = "degoggles"
@@ -62,11 +61,6 @@
..()
overlay = global_hud.science
-/obj/item/clothing/glasses/science/scanners
- name = "Scanning Goggles"
- desc = "A very oddly shaped pair of goggles with bits of wire poking out the sides. A soft humming sound emanates from it."
- icon_state = "uzenwa_sissra_1"
-
/obj/item/clothing/glasses/night
name = "Night Vision Goggles"
desc = "You can totally see in the dark now!"
@@ -75,6 +69,7 @@
origin_tech = list(TECH_MAGNET = 2)
darkness_view = 7
toggleable = 1
+ see_invisible = SEE_INVISIBLE_NOLIGHTING
off_state = "denight"
/obj/item/clothing/glasses/night/New()
@@ -111,6 +106,11 @@
item_state = "glasses"
prescription = 1
body_parts_covered = 0
+
+/obj/item/clothing/glasses/regular/scanners
+ name = "Scanning Goggles"
+ desc = "A very oddly shaped pair of goggles with bits of wire poking out the sides. A soft humming sound emanates from it."
+ icon_state = "uzenwa_sissra_1"
/obj/item/clothing/glasses/regular/hipster
name = "Prescription Glasses"
@@ -220,7 +220,6 @@
origin_tech = list(TECH_MAGNET = 3)
toggleable = 1
vision_flags = SEE_MOBS
- invisa_view = 2
emp_act(severity)
if(istype(src.loc, /mob/living/carbon/human))
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index fa273534e6..2938ef4688 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -33,7 +33,7 @@
icon_state = "jensenshades"
item_state = "jensenshades"
vision_flags = SEE_MOBS
- invisa_view = 2
+ see_invisible = SEE_INVISIBLE_NOLIGHTING
/obj/item/clothing/glasses/hud/security/process_hud(var/mob/M)
process_sec_hud(M, 1)
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index 5cb23c58ea..5092bd8437 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -2,7 +2,6 @@
name = "cargo cap"
desc = "It's a peaked cap in a tasteless yellow color."
icon_state = "cargosoft"
- flags = HEADCOVERSEYES
item_state_slots = list(
slot_l_hand_str = "helmet", //probably a placeholder
slot_r_hand_str = "helmet",
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 9552a0f17d..3ef2587998 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -46,6 +46,8 @@
/obj/item/clothing/mask/gas/swat/vox
name = "\improper alien mask"
desc = "Clearly not designed for a human face."
+ body_parts_covered = 0 //Hack to allow vox to eat while wearing this mask.
+ species_restricted = list("Vox")
/obj/item/clothing/mask/gas/syndicate
name = "tactical mask"
@@ -55,7 +57,7 @@
/obj/item/clothing/mask/gas/clown_hat
name = "clown wig and mask"
- desc = "A true prankster's facial attire. A clown is incomplete without his wig and mask."
+ desc = "A true prankster's facial attire. A clown is incomplete without their wig and mask."
icon_state = "clown"
item_state = "clown_hat"
@@ -98,4 +100,4 @@
/obj/item/clothing/mask/gas/owl_mask
name = "owl mask"
desc = "Twoooo!"
- icon_state = "owl"
\ No newline at end of file
+ icon_state = "owl"
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 3d3db7c736..f7b6ecbc6c 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -7,6 +7,12 @@
body_parts_covered = 0
w_class = 2
gas_transfer_coefficient = 0.90
+ voicechange = 1
+
+/obj/item/clothing/mask/muzzle/New()
+ ..()
+ say_messages = list("Mmfph!", "Mmmf mrrfff!", "Mmmf mnnf!")
+ say_verbs = list("mumbles", "says")
// Clumsy folks can't take the mask off themselves.
/obj/item/clothing/mask/muzzle/attack_hand(mob/user as mob)
@@ -99,9 +105,14 @@
flags_inv = HIDEFACE
body_parts_covered = HEAD|FACE|EYES
w_class = 2
- var/voicechange = 0
siemens_coefficient = 0.9
+/obj/item/clothing/mask/horsehead/New()
+ ..()
+ // The horse mask doesn't cause voice changes by default, the wizard spell changes the flag as necessary
+ say_messages = list("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!")
+ say_verbs = list("whinnies", "neighs", "says")
+
/obj/item/clothing/mask/ai
name = "camera MIU"
desc = "Allows for direct mental connection to accessible camera networks."
diff --git a/code/modules/clothing/spacesuits/breaches.dm b/code/modules/clothing/spacesuits/breaches.dm
index 6789a50dfc..7caa4e0bdf 100644
--- a/code/modules/clothing/spacesuits/breaches.dm
+++ b/code/modules/clothing/spacesuits/breaches.dm
@@ -178,23 +178,29 @@ var/global/list/breach_burn_descriptors = list(
//Handles repairs (and also upgrades).
/obj/item/clothing/suit/space/attackby(obj/item/W as obj, mob/user as mob)
- if(istype(W,/obj/item/stack/material/plastic) || istype(W,/obj/item/stack/material/steel))
-
+ if(istype(W,/obj/item/stack/material))
+ var/repair_power = 0
+ switch(W.get_material_name())
+ if(DEFAULT_WALL_MATERIAL)
+ repair_power = 2
+ if("plastic")
+ repair_power = 1
+
+ if(!repair_power)
+ return
+
if(istype(src.loc,/mob/living))
- user << "\red How do you intend to patch a hardsuit while someone is wearing it?"
+ user << "How do you intend to patch a hardsuit while someone is wearing it?"
return
if(!damage || !burn_damage)
user << "There is no surface damage on \the [src] to repair."
return
- var/obj/item/stack/material/P = W
- if(P.get_amount() < 3)
- P.use(P.get_amount())
- repair_breaches(BURN, ( istype(P,/obj/item/stack/material/plastic) ? P.get_amount() : (P.get_amount()*2) ), user)
- else
- P.use(3)
- repair_breaches(BURN, ( istype(P,/obj/item/stack/material/plastic) ? 3 : 5), user)
+ var/obj/item/stack/P = W
+ var/use_amt = min(P.get_amount(), 3)
+ if(use_amt && P.use(use_amt))
+ repair_breaches(BURN, use_amt * repair_power, user)
return
else if(istype(W, /obj/item/weapon/weldingtool))
diff --git a/code/modules/clothing/spacesuits/rig/modules/modules.dm b/code/modules/clothing/spacesuits/rig/modules/modules.dm
index 9db0fbdb73..81af43d9f4 100644
--- a/code/modules/clothing/spacesuits/rig/modules/modules.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/modules.dm
@@ -260,7 +260,6 @@
return 0
/stat_rig_module/Click()
- ..()
if(CanUse())
var/list/href_list = list(
"interact_module" = module.holder.installed_modules.Find(module),
@@ -269,6 +268,9 @@
AddHref(href_list)
module.holder.Topic(usr, href_list)
+/stat_rig_module/DblClick()
+ return Click()
+
/stat_rig_module/activate/New(var/obj/item/rig_module/module)
..()
name = module.activate_string
diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm
index ce206392c5..67105cc625 100644
--- a/code/modules/clothing/spacesuits/rig/rig.dm
+++ b/code/modules/clothing/spacesuits/rig/rig.dm
@@ -71,6 +71,7 @@
var/offline_slowdown = 3 // If the suit is deployed and unpowered, it sets slowdown to this.
var/vision_restriction
var/offline_vision_restriction = 1 // 0 - none, 1 - welder vision, 2 - blind. Maybe move this to helmets.
+ var/airtight = 1 //If set, will adjust AIRTIGHT and STOPPRESSUREDAMAGE flags on components. Otherwise it should leave them untouched.
var/emp_protection = 0
@@ -178,8 +179,9 @@
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
if(!piece) continue
piece.icon_state = "[initial(icon_state)]"
- piece.flags &= ~STOPPRESSUREDAMAGE
- piece.flags &= ~AIRTIGHT
+ if(airtight)
+ piece.flags &= ~STOPPRESSUREDAMAGE
+ piece.flags &= ~AIRTIGHT
update_icon(1)
/obj/item/weapon/rig/proc/toggle_seals(var/mob/living/carbon/human/M,var/instant)
@@ -247,11 +249,6 @@
M << "\The [piece] hisses [!seal_target ? "closed" : "open"]."
M.update_inv_head()
if(helmet)
- if(!seal_target)
- if(flags & AIRTIGHT)
- helmet.flags |= AIRTIGHT
- else
- helmet.flags &= ~AIRTIGHT
helmet.update_light(wearer)
//sealed pieces become airtight, protecting against diseases
@@ -273,13 +270,8 @@
if(!piece) continue
piece.icon_state = "[initial(icon_state)][!seal_target ? "" : "_sealed"]"
canremove = !seal_target
- if(helmet)
- if(canremove)
- if(flags & AIRTIGHT)
- helmet.flags |= AIRTIGHT
- else
- if(flags & AIRTIGHT)
- helmet.flags &= ~AIRTIGHT
+ if(airtight)
+ update_component_sealed()
update_icon(1)
return 0
@@ -290,15 +282,18 @@
if(canremove)
for(var/obj/item/rig_module/module in installed_modules)
module.deactivate()
+ if(airtight)
+ update_component_sealed()
+ update_icon(1)
+
+/obj/item/weapon/rig/proc/update_component_sealed()
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
- if(!piece) continue
if(canremove)
piece.flags &= ~STOPPRESSUREDAMAGE
piece.flags &= ~AIRTIGHT
else
piece.flags |= STOPPRESSUREDAMAGE
piece.flags |= AIRTIGHT
- update_icon(1)
/obj/item/weapon/rig/process()
diff --git a/code/modules/clothing/spacesuits/rig/rig_attackby.dm b/code/modules/clothing/spacesuits/rig/rig_attackby.dm
index f9c6d7318d..0017c45f9e 100644
--- a/code/modules/clothing/spacesuits/rig/rig_attackby.dm
+++ b/code/modules/clothing/spacesuits/rig/rig_attackby.dm
@@ -7,7 +7,7 @@
return
// Pass repair items on to the chestpiece.
- if(chest && (istype(W,/obj/item/stack/material/plastic) || istype(W,/obj/item/stack/material/steel) || istype(W, /obj/item/weapon/weldingtool)))
+ if(chest && (istype(W,/obj/item/stack/material) || istype(W, /obj/item/weapon/weldingtool)))
return chest.attackby(W,user)
// Lock or unlock the access panel.
diff --git a/code/modules/clothing/spacesuits/rig/rig_pieces.dm b/code/modules/clothing/spacesuits/rig/rig_pieces.dm
index 294644f3cb..e38fa950ff 100644
--- a/code/modules/clothing/spacesuits/rig/rig_pieces.dm
+++ b/code/modules/clothing/spacesuits/rig/rig_pieces.dm
@@ -24,6 +24,7 @@
/obj/item/clothing/shoes/magboots/rig
name = "boots"
+ body_parts_covered = FEET
cold_protection = FEET
heat_protection = FEET
species_restricted = null
@@ -69,3 +70,38 @@
return 1
return 0
+
+//Rig pieces for non-spacesuit based rigs
+
+/obj/item/clothing/head/lightrig
+ name = "mask"
+ body_parts_covered = HEAD|FACE|EYES
+ heat_protection = HEAD|FACE|EYES
+ cold_protection = HEAD|FACE|EYES
+ flags = THICKMATERIAL|AIRTIGHT
+
+/obj/item/clothing/suit/lightrig
+ name = "suit"
+ allowed = list(/obj/item/device/flashlight)
+ body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
+ heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
+ cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
+ flags_inv = HIDEJUMPSUIT
+ flags = THICKMATERIAL
+
+/obj/item/clothing/shoes/lightrig
+ name = "boots"
+ body_parts_covered = FEET
+ cold_protection = FEET
+ heat_protection = FEET
+ species_restricted = null
+ gender = PLURAL
+
+/obj/item/clothing/gloves/lightrig
+ name = "gloves"
+ flags = THICKMATERIAL
+ body_parts_covered = HANDS
+ heat_protection = HANDS
+ cold_protection = HANDS
+ species_restricted = null
+ gender = PLURAL
diff --git a/code/modules/clothing/spacesuits/rig/suits/light.dm b/code/modules/clothing/spacesuits/rig/suits/light.dm
index 8aa50f4ab9..270e7a3761 100644
--- a/code/modules/clothing/spacesuits/rig/suits/light.dm
+++ b/code/modules/clothing/spacesuits/rig/suits/light.dm
@@ -33,22 +33,43 @@
/obj/item/weapon/rig/light/hacker
name = "cybersuit control module"
suit_type = "cyber"
- desc = "An advanced powered armour suit with many cyberwarfare enhancements."
+ desc = "An advanced powered armour suit with many cyberwarfare enhancements. Comes with built-in insulated gloves for safely tampering with electronics."
icon_state = "hacker_rig"
req_access = list(access_syndicate)
- helm_type = /obj/item/clothing/head/helmet/space/rig/mask
+ airtight = 0
+ seal_delay = 5 //not being vaccum-proof has an upside I guess
+
+ helm_type = /obj/item/clothing/head/lightrig/hacker
+ chest_type = /obj/item/clothing/suit/lightrig/hacker
+ glove_type = /obj/item/clothing/gloves/lightrig/hacker
+ boot_type = /obj/item/clothing/shoes/lightrig/hacker
initial_modules = list(
/obj/item/rig_module/ai_container,
/obj/item/rig_module/power_sink,
- /obj/item/rig_module/datajack
+ /obj/item/rig_module/datajack,
+ /obj/item/rig_module/electrowarfare_suite,
+ /obj/item/rig_module/voice,
+ /obj/item/rig_module/vision,
)
-/obj/item/clothing/head/helmet/space/rig/mask
- name = "mask"
- flags = THICKMATERIAL
+//The cybersuit is not space-proof. It does however, have good siemens_coefficient values
+/obj/item/clothing/head/lightrig/hacker
+ name = "HUD"
+ siemens_coefficient = 0.4
+ flags = 0
+
+/obj/item/clothing/suit/lightrig/hacker
+ siemens_coefficient = 0.4
+
+/obj/item/clothing/shoes/lightrig/hacker
+ siemens_coefficient = 0.4
+ flags = NOSLIP //All the other rigs have magboots anyways, hopefully gives the hacker suit something more going for it.
+
+/obj/item/clothing/gloves/lightrig/hacker
+ siemens_coefficient = 0
/obj/item/weapon/rig/light/ninja
name = "ominous suit control module"
@@ -92,7 +113,7 @@
name = "stealth suit control module"
suit_type = "stealth"
desc = "A highly advanced and expensive suit designed for covert operations."
- icon_state = "ninja_rig"
+ icon_state = "stealth_rig"
req_access = list(access_syndicate)
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 6ff7b25f47..fd491d6692 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -107,7 +107,7 @@
//When the wearer gets hit, this armor will teleport the user a short distance away (to safety or to more danger, no one knows. That's the fun of it!)
/obj/item/clothing/suit/armor/reactive
name = "Reactive Teleport Armor"
- desc = "Someone seperated our Research Director from his own head!"
+ desc = "Someone separated our Research Director from their own head!"
var/active = 0.0
icon_state = "reactiveoff"
item_state = "reactiveoff"
diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm
index feef7d06b1..dfbfc92d4b 100644
--- a/code/modules/clothing/under/accessories/accessory.dm
+++ b/code/modules/clothing/under/accessories/accessory.dm
@@ -9,30 +9,31 @@
var/slot = "decor"
var/obj/item/clothing/under/has_suit = null //the suit the tie may be attached to
var/image/inv_overlay = null //overlay used when attached to clothing.
- var/image/inv_overlay_mob = null
+ var/image/mob_overlay = null
var/overlay_state = null
/obj/item/clothing/accessory/proc/get_inv_overlay()
if(!inv_overlay)
+ if(!mob_overlay)
+ get_mob_overlay()
+
var/tmp_icon_state = "[overlay_state? "[overlay_state]" : "[icon_state]"]"
if(icon_override)
if("[tmp_icon_state]_tie" in icon_states(icon_override))
tmp_icon_state = "[tmp_icon_state]_tie"
- inv_overlay = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]")
- else
- inv_overlay = image("icon" = 'icons/obj/clothing/ties_overlay.dmi', "icon_state" = "[tmp_icon_state]")
+ inv_overlay = image(icon = mob_overlay.icon, icon_state = tmp_icon_state, dir = SOUTH)
return inv_overlay
-/obj/item/clothing/accessory/proc/get_inv_mob_overlay()
- if(!inv_overlay_mob)
+/obj/item/clothing/accessory/proc/get_mob_overlay()
+ if(!mob_overlay)
var/tmp_icon_state = "[overlay_state? "[overlay_state]" : "[icon_state]"]"
if(icon_override)
if("[tmp_icon_state]_mob" in icon_states(icon_override))
tmp_icon_state = "[tmp_icon_state]_mob"
- inv_overlay_mob = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]")
+ mob_overlay = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]")
else
- inv_overlay_mob = image("icon" = 'icons/obj/clothing/ties_overlay.dmi', "icon_state" = "[tmp_icon_state]")
- return inv_overlay_mob
+ mob_overlay = image("icon" = INV_ACCESSORIES_DEF_ICON, "icon_state" = "[tmp_icon_state]")
+ return mob_overlay
//when user attached an accessory to S
/obj/item/clothing/accessory/proc/on_attached(obj/item/clothing/under/S, mob/user as mob)
@@ -141,7 +142,7 @@
/obj/item/clothing/accessory/medal/conduct
name = "distinguished conduct medal"
- desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is most basic award given by Nanotrasen. It is often awarded by a captain to a member of his crew."
+ desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is most basic award given by Nanotrasen. It is often awarded by a captain to a member of their crew."
/obj/item/clothing/accessory/medal/bronze_heart
name = "bronze heart medal"
diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm
index c99fe6936d..729c204f8b 100644
--- a/code/modules/customitems/item_spawning.dm
+++ b/code/modules/customitems/item_spawning.dm
@@ -49,18 +49,23 @@
item.icon = CUSTOM_ITEM_OBJ
item.icon_state = item_icon
return
- else
+ else
if(inherit_inhands)
apply_inherit_inhands(item)
else
item.item_state_slots = null
item.item_icons = null
-
+
item.icon = CUSTOM_ITEM_OBJ
item.icon_state = item_icon
item.item_state = null
item.icon_override = CUSTOM_ITEM_MOB
+ var/obj/item/clothing/under/U = item
+ if(istype(U))
+ U.worn_state = U.icon_state
+ U.update_rolldown_status()
+
// Kits are dumb so this is going to have to be hardcoded/snowflake.
if(istype(item, /obj/item/device/kit))
var/obj/item/device/kit/K = item
@@ -81,9 +86,9 @@
/datum/custom_item/proc/apply_inherit_inhands(var/obj/item/item)
var/list/new_item_icons = list()
var/list/new_item_state_slots = list()
-
+
var/list/available_states = icon_states(CUSTOM_ITEM_MOB)
-
+
//If l_hand or r_hand are not present, preserve them using item_icons/item_state_slots
//Then use icon_override to make every other slot use the custom sprites by default.
//This has to be done before we touch any of item's vars
@@ -93,7 +98,7 @@
if(!("[item_icon]_r" in available_states))
new_item_state_slots[slot_r_hand_str] = get_state(item, slot_r_hand_str, "_r")
new_item_icons[slot_r_hand_str] = get_icon(item, slot_r_hand_str, 'icons/mob/items/righthand.dmi')
-
+
item.item_state_slots = new_item_state_slots
item.item_icons = new_item_icons
diff --git a/code/modules/economy/TradeDestinations.dm b/code/modules/economy/TradeDestinations.dm
index 596276006d..2f376606d7 100644
--- a/code/modules/economy/TradeDestinations.dm
+++ b/code/modules/economy/TradeDestinations.dm
@@ -42,7 +42,7 @@ var/list/weighted_mundaneevent_locations = list()
return null
/datum/trade_destination/icarus
- name = "NMV Icarus"
+ name = "NDV Icarus"
description = "Corvette assigned to patrol NSS Exodus local space."
distance = 0.1
willing_to_buy = list()
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index 5720e08c81..f9da977f33 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -68,7 +68,7 @@
"NanoTrasen is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.",
"All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.",
"[prob(50)?"Your upload":random_player] is the new kitchen. Please direct the Chef to the new kitchen area as the old one is in disrepair.",
- "Jokes about a dead person and the manner of his death help grieving crewmembers tremendously. Especially if they were close with the deceased.",
+ "Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.",
"[prob(50)?"The crew":random_player] is [prob(50)?"less":"more"] intelligent than average. Point out every action and statement which supports this fact.",
"There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.")
var/law = pick(laws)
diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm
index a50a98982a..850b03a4f7 100644
--- a/code/modules/events/rogue_drones.dm
+++ b/code/modules/events/rogue_drones.dm
@@ -24,11 +24,11 @@
/datum/event/rogue_drone/announce()
var/msg
if(prob(33))
- msg = "A combat drone wing operating out of the NMV Icarus has failed to return from a sweep of this sector, if any are sighted approach with caution."
+ msg = "A combat drone wing operating out of the NDV Icarus has failed to return from a sweep of this sector, if any are sighted approach with caution."
else if(prob(50))
- msg = "Contact has been lost with a combat drone wing operating out of the NMV Icarus. If any are sighted in the area, approach with caution."
+ msg = "Contact has been lost with a combat drone wing operating out of the NDV Icarus. If any are sighted in the area, approach with caution."
else
- msg = "Unidentified hackers have targetted a combat drone wing deployed from the NMV Icarus. If any are sighted in the area, approach with caution."
+ msg = "Unidentified hackers have targetted a combat drone wing deployed from the NDV Icarus. If any are sighted in the area, approach with caution."
command_announcement.Announce(msg, "Rogue drone alert")
/datum/event/rogue_drone/end()
diff --git a/code/modules/genetics/side_effects.dm b/code/modules/genetics/side_effects.dm
index f516b609ff..d0768a3440 100644
--- a/code/modules/genetics/side_effects.dm
+++ b/code/modules/genetics/side_effects.dm
@@ -54,7 +54,7 @@
duration = 10*90
start(mob/living/carbon/human/H)
- H.emote("me", 1, "has drool running down from his mouth.")
+ H.emote("me", 1, "has drool running down from [H.gender == MALE ? "his" : H.gender == FEMALE ? "her" : "their"] mouth.")
finish(mob/living/carbon/human/H)
if(!H.reagents.has_reagent("anti_toxin"))
@@ -68,7 +68,7 @@
duration = 10*30
start(mob/living/carbon/human/H)
- H.emote("me", 1, "has drool running down from his mouth.")
+ H.emote("me", 1, "has drool running down from [H.gender == MALE ? "his" : H.gender == FEMALE ? "her" : "their"] mouth.")
finish(mob/living/carbon/human/H)
if(!H.reagents.has_reagent("anti_toxin"))
@@ -88,4 +88,4 @@ proc/trigger_side_effect(mob/living/carbon/human/H)
if(!istype(H)) return
H.SetWeakened(0)
- S.finish(H)
\ No newline at end of file
+ S.finish(H)
diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm
index f14cdb8ebc..41bbdecdac 100644
--- a/code/modules/holodeck/HolodeckControl.dm
+++ b/code/modules/holodeck/HolodeckControl.dm
@@ -281,7 +281,7 @@
if(HP.ambience)
linkedholodeck.forced_ambience = HP.ambience
else
- linkedholodeck.forced_ambience = initial(linkedholodeck.ambience)
+ linkedholodeck.forced_ambience = list()
for(var/mob/living/M in mobs_in_area(linkedholodeck))
if(M.mind)
diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm
index 6e5c4c4c5a..8bfca4fde8 100644
--- a/code/modules/holodeck/HolodeckObjects.dm
+++ b/code/modules/holodeck/HolodeckObjects.dm
@@ -46,8 +46,8 @@
/obj/structure/holostool
name = "stool"
desc = "Apply butt."
- icon = 'icons/obj/objects.dmi'
- icon_state = "stool"
+ icon = 'icons/obj/furniture.dmi'
+ icon_state = "stool_padded_preview"
anchored = 1.0
pressure_resistance = 15
diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm
index 9d240e764e..efe3bf1da6 100644
--- a/code/modules/hydroponics/seed.dm
+++ b/code/modules/hydroponics/seed.dm
@@ -690,10 +690,11 @@
else
product = new /obj/item/weapon/reagent_containers/food/snacks/grown(get_turf(user),name)
if(get_trait(TRAIT_PRODUCT_COLOUR))
- product.color = get_trait(TRAIT_PRODUCT_COLOUR)
- if(istype(product,/obj/item/weapon/reagent_containers/food))
- var/obj/item/weapon/reagent_containers/food/food = product
- food.filling_color = get_trait(TRAIT_PRODUCT_COLOUR)
+ if(!istype(product, /mob))
+ product.color = get_trait(TRAIT_PRODUCT_COLOUR)
+ if(istype(product,/obj/item/weapon/reagent_containers/food))
+ var/obj/item/weapon/reagent_containers/food/food = product
+ food.filling_color = get_trait(TRAIT_PRODUCT_COLOUR)
if(mysterious)
product.name += "?"
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index ac47fd706e..c7ec0ff31c 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -149,7 +149,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
if(src.arcanecheckout)
new /obj/item/weapon/book/tome(src.loc)
user << "Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a dusty old tome sitting on the desk. You don't really remember printing it."
- user.visible_message("[user] stares at the blank screen for a few moments, his expression frozen in fear. When he finally awakens from it, he looks a lot older.", 2)
+ user.visible_message("\The [user] stares at the blank screen for a few moments, \his expression frozen in fear. When \he finally awakens from it, \he looks a lot older.", 2)
src.arcanecheckout = 0
if(1)
// Inventory
diff --git a/code/modules/lighting/light_source.dm b/code/modules/lighting/light_source.dm
index 8322e14098..73a65f064f 100644
--- a/code/modules/lighting/light_source.dm
+++ b/code/modules/lighting/light_source.dm
@@ -11,13 +11,16 @@
var/lum_g
var/lum_b
- var/list/effect_r
- var/list/effect_g
- var/list/effect_b
+ var/tmp/old_lum_r
+ var/tmp/old_lum_g
+ var/tmp/old_lum_b
+
+ var/list/effect_str
var/list/effect_turf
var/applied
+ var/vis_update //Whetever we should smartly recalculate visibility. and then only update tiles that became (in) visible to us
var/needs_update
var/destroyed
var/force_update
@@ -38,9 +41,7 @@
parse_light_color()
- effect_r = list()
- effect_g = list()
- effect_b = list()
+ effect_str = list()
effect_turf = list()
update()
@@ -50,8 +51,8 @@
/datum/light_source/proc/destroy()
destroyed = 1
force_update()
- if(source_atom) source_atom.light_sources -= src
- if(top_atom) top_atom.light_sources -= src
+ if(source_atom && source_atom.light_sources) source_atom.light_sources -= src
+ if(top_atom && top_atom.light_sources) top_atom.light_sources -= src
/datum/light_source/proc/update(atom/new_top_atom)
if(new_top_atom && new_top_atom != top_atom)
@@ -61,15 +62,22 @@
if(!top_atom.light_sources) top_atom.light_sources = list()
top_atom.light_sources += src
- if(!needs_update)
+ if(!needs_update) //Incase we're already updating either way.
lighting_update_lights += src
needs_update = 1
/datum/light_source/proc/force_update()
force_update = 1
- if(!needs_update)
- lighting_update_lights += src
+ if(!needs_update) //Incase we're already updating either way.
needs_update = 1
+ lighting_update_lights += src
+
+/datum/light_source/proc/vis_update()
+ if(!needs_update)
+ needs_update = 1
+ lighting_update_lights += src
+
+ vis_update = 1
/datum/light_source/proc/check()
if(!source_atom || !light_range || !light_power)
@@ -96,14 +104,19 @@
light_range = source_atom.light_range
. = 1
+ if(light_range && light_power && !applied)
+ . = 1
+
+ if(. || source_atom.light_color != light_color)//Save the old lumcounts if we need to update, if the colour changed DO IT BEFORE we parse the colour and LOSE the old lumcounts!
+ old_lum_r = lum_r
+ old_lum_g = lum_g
+ old_lum_b = lum_b
+
if(source_atom.light_color != light_color)
light_color = source_atom.light_color
parse_light_color()
. = 1
- if(light_range && light_power && !applied)
- . = 1
-
/datum/light_source/proc/parse_light_color()
if(light_color)
lum_r = GetRedPart(light_color) / 255
@@ -114,54 +127,57 @@
lum_g = 1
lum_b = 1
-/datum/light_source/proc/falloff(atom/movable/lighting_overlay/O)
- #if LIGHTING_FALLOFF == 1 // circular
- . = (O.x - source_turf.x)**2 + (O.y - source_turf.y)**2 + LIGHTING_HEIGHT
-
- #if LIGHTING_LAMBERTIAN == 1
- . = CLAMP01((1 - CLAMP01(sqrt(.) / light_range)) * (1 / (sqrt(. + 1))))
- #else
- . = 1 - CLAMP01(sqrt(.) / light_range)
- #endif
-
- #elif LIGHTING_FALLOFF == 2 // square
- . = abs(O.x - source_turf.x) + abs(O.y - source_turf.y) + LIGHTING_HEIGHT
-
- #if LIGHTING_LAMBERTIAN == 1
- . = CLAMP01((1 - CLAMP01(. / light_range)) * (1 / (sqrt(.)**2 + )))
- #else
- . = 1 - CLAMP01(. / light_range)
- #endif
+#if LIGHTING_FALLOFF == 1 //circular
+ #define LUM_DISTANCE(swapvar, O, T) swapvar = (O.x - T.x)**2 + (O.y - T.y)**2 + LIGHTING_HEIGHT
+ #if LIGHTING_LAMBERTIAN == 1
+ #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(sqrt(swapvar) / max(1,light_range))) * (1 / sqrt(swapvar + 1)))
+ #else
+ #define LUM_ATTENUATION(swapvar) swapvar = 1 - CLAMP01(sqrt(swapvar) / max(1,light_range))
#endif
+#elif LIGHTING_FALLOFF == 2 //square
+ #define LUM_DISTANCE(swapvar, O, T) swapvar = abs(O.x - T.x) + abs(O.y - T.y) + LIGHTING_HEIGHT
+ #if LIGHTING_LAMBERTIAN == 1
+ #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(swapvar / max(1,light_range))) * (1 / sqrt(swapvar**2 + 1)))
+ #else
+ #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01(swapvar / max(1,light_range))
+ #endif
+#endif
+
+#define LUM_FALLOFF(swapvar, O, T) \
+ LUM_DISTANCE(swapvar, O, T); \
+ LUM_ATTENUATION(swapvar);
/datum/light_source/proc/apply_lum()
applied = 1
if(istype(source_turf))
- for(var/turf/T in dview(light_range, source_turf, INVISIBILITY_LIGHTING))
+ FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING)
if(T.lighting_overlay)
- var/strength = light_power * falloff(T.lighting_overlay)
+ var/strength
+ LUM_FALLOFF(strength, T, source_turf)
+ strength *= light_power
+
if(!strength) //Don't add turfs that aren't affected to the affected turfs.
continue
- effect_r += round(lum_r * strength, LIGHTING_ROUND_VALUE)
- effect_g += round(lum_g * strength, LIGHTING_ROUND_VALUE)
- effect_b += round(lum_b * strength, LIGHTING_ROUND_VALUE)
+ strength = round(strength, LIGHTING_ROUND_VALUE) //Screw sinking points.
+
+ effect_str += strength
T.lighting_overlay.update_lumcount(
- round(lum_r * strength, LIGHTING_ROUND_VALUE),
- round(lum_g * strength, LIGHTING_ROUND_VALUE),
- round(lum_b * strength, LIGHTING_ROUND_VALUE)
+ lum_r * strength,
+ lum_g * strength,
+ lum_b * strength
)
+
else
- effect_r += 0
- effect_g += 0
- effect_b += 0
+ effect_str += 0
if(!T.affecting_lights)
T.affecting_lights = list()
T.affecting_lights += src
effect_turf += T
+ END_FOR_DVIEW
/datum/light_source/proc/remove_lum()
applied = 0
@@ -171,11 +187,65 @@
T.affecting_lights -= src
if(T.lighting_overlay)
- T.lighting_overlay.update_lumcount(-effect_r[i], -effect_g[i], -effect_b[i])
+ var/str = effect_str[i]
+ T.lighting_overlay.update_lumcount(-str * old_lum_r, -str * old_lum_g, -str * old_lum_b)
i++
- effect_r.Cut()
- effect_g.Cut()
- effect_b.Cut()
+ effect_str.Cut()
effect_turf.Cut()
+
+//Smartly updates the lighting, only removes lum from and adds lum to turfs that actually got changed.
+//This is for lights that need to reconsider due to nearby opacity changes.
+//Stupid dumb copy pasta because BYOND and speed.
+/datum/light_source/proc/smart_vis_update()
+ var/list/view[0]
+ FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING)
+ view += T //Filter out turfs.
+ END_FOR_DVIEW
+ //This is the part where we calculate new turfs (if any)
+ var/list/new_turfs = view - effect_turf //This will result with all the tiles that are added.
+ for(var/turf/T in new_turfs)
+ if(T.lighting_overlay)
+ LUM_FALLOFF(., T, source_turf)
+ . *= light_power
+
+ if(!.) //Don't add turfs that aren't affected to the affected turfs.
+ continue
+
+ . = round(., LIGHTING_ROUND_VALUE)
+
+ effect_str += .
+
+ T.lighting_overlay.update_lumcount(
+ lum_r * .,
+ lum_g * .,
+ lum_b * .
+ )
+
+ else
+ effect_str += 0
+
+ if(!T.affecting_lights)
+ T.affecting_lights = list()
+
+ T.affecting_lights += src
+ effect_turf += T
+
+ var/list/old_turfs = effect_turf - view
+ for(var/turf/T in old_turfs)
+ //Insert not-so-huge copy paste from remove_lum().
+ var/idx = effect_turf.Find(T) //Get the index, luckily Find() is cheap in small lists like this. (with small I mean under a couple thousand len)
+ if(T.affecting_lights)
+ T.affecting_lights -= src
+
+ if(T.lighting_overlay)
+ var/str = effect_str[idx]
+ T.lighting_overlay.update_lumcount(-str * lum_r, -str * lum_g, -str * lum_b)
+
+ effect_turf.Cut(idx, idx + 1)
+ effect_str.Cut(idx, idx + 1)
+
+#undef LUM_FALLOFF
+#undef LUM_DISTANCE
+#undef LUM_ATTENUATION
diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm
index 92500ecc1d..a99f2f24ea 100644
--- a/code/modules/lighting/lighting_atom.dm
+++ b/code/modules/lighting/lighting_atom.dm
@@ -7,11 +7,19 @@
var/list/light_sources
/atom/proc/set_light(l_range, l_power, l_color)
- if(l_power != null) light_power = l_power
- if(l_range != null) light_range = l_range
- if(l_color != null) light_color = l_color
+ . = 0 //make it less costly if nothing's changed
- update_light()
+ if(l_power != null && l_power != light_power)
+ light_power = l_power
+ . = 1
+ if(l_range != null && l_range != light_range)
+ light_range = l_range
+ . = 1
+ if(l_color != null && l_color != light_color)
+ light_color = l_color
+ . = 1
+
+ if(.) update_light()
/atom/proc/update_light()
if(!light_power || !light_range)
@@ -46,21 +54,13 @@
T.reconsider_lights()
return ..()
-/atom/movable/Move()
- var/turf/old_loc = loc
+/atom/Entered(atom/movable/obj, atom/prev_loc)
. = ..()
- if(loc != old_loc)
- for(var/datum/light_source/L in light_sources)
+ if(obj && prev_loc != src)
+ for(var/datum/light_source/L in obj.light_sources)
L.source_atom.update_light()
- var/turf/new_loc = loc
- if(istype(old_loc) && opacity)
- old_loc.reconsider_lights()
-
- if(istype(new_loc) && opacity)
- new_loc.reconsider_lights()
-
/atom/proc/set_opacity(new_opacity)
var/old_opacity = opacity
opacity = new_opacity
diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm
index a22023d983..2dd3889e4e 100644
--- a/code/modules/lighting/lighting_overlay.dm
+++ b/code/modules/lighting/lighting_overlay.dm
@@ -98,8 +98,5 @@
var/turf/T = loc
if(istype(T))
T.lighting_overlay = null
-
- for(var/datum/light_source/D in T.affecting_lights) //Remove references to us on the light sources affecting us.
- D.effect_r -= src
- D.effect_g -= src
- D.effect_b -= src
+
+ ..()
diff --git a/code/modules/lighting/lighting_process.dm b/code/modules/lighting/lighting_process.dm
index 1571c6e388..1c8361dbaf 100644
--- a/code/modules/lighting/lighting_process.dm
+++ b/code/modules/lighting/lighting_process.dm
@@ -10,12 +10,17 @@
lighting_update_lights = list()
for(var/datum/light_source/L in lighting_update_lights_old)
- if(L.needs_update)
- if(L.destroyed || L.check() || L.force_update)
- L.remove_lum()
- if(!L.destroyed) L.apply_lum()
- L.force_update = 0
- L.needs_update = 0
+ if(L.destroyed || L.check() || L.force_update)
+ L.remove_lum()
+ if(!L.destroyed)
+ L.apply_lum()
+
+ else if(L.vis_update) //We smartly update only tiles that became (in) visible to use.
+ L.smart_vis_update()
+
+ L.vis_update = 0
+ L.force_update = 0
+ L.needs_update = 0
scheck()
@@ -24,8 +29,7 @@
lighting_update_overlays = list()
for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old)
- if(O.needs_update)
- O.update_overlay()
- O.needs_update = 0
+ O.update_overlay()
+ O.needs_update = 0
scheck()
diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm
index 0a438b047c..e261931c41 100644
--- a/code/modules/lighting/lighting_turf.dm
+++ b/code/modules/lighting/lighting_turf.dm
@@ -4,7 +4,7 @@
/turf/proc/reconsider_lights()
for(var/datum/light_source/L in affecting_lights)
- L.force_update()
+ L.vis_update()
/turf/proc/lighting_clear_overlays()
if(lighting_overlay)
@@ -16,3 +16,13 @@
if(A.lighting_use_dynamic)
var/atom/movable/lighting_overlay/O = PoolOrNew(/atom/movable/lighting_overlay, src)
lighting_overlay = O
+
+/turf/Entered(atom/movable/obj)
+ . = ..()
+ if(obj && obj.opacity)
+ reconsider_lights()
+
+/turf/Exited(atom/movable/obj)
+ . = ..()
+ if(obj && obj.opacity)
+ reconsider_lights()
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index 4d4f6033e6..653879cfb9 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -40,8 +40,13 @@
update_strings()
return 1
+/obj/item/stack/material/get_material()
+ return material
+
/obj/item/stack/material/proc/update_strings()
// Update from material datum.
+ singular_name = material.sheet_singular_name
+
if(amount>1)
name = "[material.use_name] [material.sheet_plural_name]"
desc = "A stack of [material.use_name] [material.sheet_plural_name]."
@@ -188,15 +193,15 @@
/obj/item/stack/material/glass/reinforced
name = "reinforced glass"
icon_state = "sheet-rglass"
- default_type = "reinforced glass"
+ default_type = "rglass"
/obj/item/stack/material/glass/phoronglass
name = "phoron glass"
singular_name = "phoron glass sheet"
icon_state = "sheet-phoronglass"
- default_type = "phoron glass"
+ default_type = "phglass"
/obj/item/stack/material/glass/phoronrglass
name = "reinforced phoron glass"
icon_state = "sheet-phoronrglass"
- default_type = "reinforced phoron glass"
+ default_type = "rphglass"
diff --git a/code/modules/materials/material_synth.dm b/code/modules/materials/material_synth.dm
index 23b0e7e546..86e3e16a2d 100644
--- a/code/modules/materials/material_synth.dm
+++ b/code/modules/materials/material_synth.dm
@@ -34,5 +34,5 @@
/obj/item/stack/material/cyborg/glass/reinforced
icon_state = "sheet-rglass"
- default_type = "reinforced glass"
+ default_type = "rglass"
charge_costs = list(500, 1000)
\ No newline at end of file
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index 49ddcfa300..1645a2b575 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -27,6 +27,17 @@
// Assoc list containing all material datums indexed by name.
var/list/name_to_material
+//Returns the material the object is made of, if applicable.
+//Will we ever need to return more than one value here? Or should we just return the "dominant" material.
+/obj/proc/get_material()
+ return null
+
+//mostly for convenience
+/obj/proc/get_material_name()
+ var/material/material = get_material()
+ if(material)
+ return material.name
+
// Builds the datum list above.
/proc/populate_material_list(force_remake=0)
if(name_to_material && !force_remake) return // Already set up!
@@ -44,6 +55,12 @@ var/list/name_to_material
populate_material_list()
return name_to_material[name]
+/proc/material_display_name(name)
+ var/material/material = get_material_by_name(name)
+ if(material)
+ return material.display_name
+ return null
+
// Material definition and procs follow.
/material
var/name // Unique name for use in indexing the list.
@@ -310,7 +327,7 @@ var/list/name_to_material
icon_colour = "#666666"
/material/steel/holographic
- name = "holographic " + DEFAULT_WALL_MATERIAL
+ name = "holo" + DEFAULT_WALL_MATERIAL
display_name = DEFAULT_WALL_MATERIAL
stack_type = null
shard_type = SHARD_NONE
@@ -420,7 +437,8 @@ var/list/name_to_material
return (hardness > 35) //todo
/material/glass/reinforced
- name = "reinforced glass"
+ name = "rglass"
+ display_name = "reinforced glass"
stack_type = /obj/item/stack/material/glass/reinforced
flags = MATERIAL_BRITTLE
icon_colour = "#00E1FF"
@@ -438,7 +456,8 @@ var/list/name_to_material
rod_product = null
/material/glass/phoron
- name = "phoron glass"
+ name = "phglass"
+ display_name = "phoron glass"
stack_type = /obj/item/stack/material/glass/phoronglass
flags = MATERIAL_BRITTLE
ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE+300
@@ -450,7 +469,8 @@ var/list/name_to_material
rod_product = /obj/item/stack/material/glass/phoronrglass
/material/glass/phoron/reinforced
- name = "reinforced phoron glass"
+ name = "rphglass"
+ display_name = "reinforced phoron glass"
stack_type = /obj/item/stack/material/glass/phoronrglass
stack_origin_tech = list(TECH_MATERIAL = 4, TECH_PHORON = 2)
composite_material = list() //todo
@@ -474,7 +494,7 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 3)
/material/plastic/holographic
- name = "holographic plastic"
+ name = "holoplastic"
display_name = "plastic"
stack_type = null
shard_type = SHARD_NONE
@@ -551,7 +571,7 @@ var/list/name_to_material
sheet_plural_name = "planks"
/material/wood/holographic
- name = "holographic wood"
+ name = "holowood"
display_name = "wood"
stack_type = null
shard_type = SHARD_NONE
diff --git a/code/modules/mining/alloys.dm b/code/modules/mining/alloys.dm
index 9461c1e6b9..dac05badd0 100644
--- a/code/modules/mining/alloys.dm
+++ b/code/modules/mining/alloys.dm
@@ -12,7 +12,7 @@
metaltag = "plasteel"
requires = list(
"platinum" = 1,
- "coal" = 2,
+ "carbon" = 2,
"hematite" = 2
)
product_mod = 0.3
@@ -21,7 +21,7 @@
/datum/alloy/steel
metaltag = DEFAULT_WALL_MATERIAL
requires = list(
- "coal" = 1,
+ "carbon" = 1,
"hematite" = 1
)
product = /obj/item/stack/material/steel
\ No newline at end of file
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index 9d8ceb2603..180d84ff60 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -112,16 +112,17 @@
var/sheets_per_tick = 10
var/list/ores_processing[0]
var/list/ores_stored[0]
- var/list/alloy_data[0]
+ var/static/list/alloy_data
var/active = 0
/obj/machinery/mineral/processing_unit/New()
-
..()
- //TODO: Ore and alloy global storage datum.
- for(var/alloytype in typesof(/datum/alloy)-/datum/alloy)
- alloy_data += new alloytype()
+ // initialize static alloy_data list
+ if(!alloy_data)
+ alloy_data = list()
+ for(var/alloytype in typesof(/datum/alloy)-/datum/alloy)
+ alloy_data += new alloytype()
if(!ore_data || !ore_data.len)
for(var/oretype in typesof(/ore)-/ore)
@@ -209,7 +210,7 @@
var/can_make = Clamp(ores_stored[metal],0,sheets_per_tick-sheets)
if(can_make%2>0) can_make--
- var/material/M = name_to_material[O.compresses_to]
+ var/material/M = get_material_by_name(O.compresses_to)
if(!istype(M) || !can_make || ores_stored[metal] < 1)
continue
@@ -223,7 +224,7 @@
var/can_make = Clamp(ores_stored[metal],0,sheets_per_tick-sheets)
- var/material/M = name_to_material[O.smelts_to]
+ var/material/M = get_material_by_name(O.smelts_to)
if(!istype(M) || !can_make || ores_stored[metal] < 1)
continue
diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm
index 96f6fb480c..99dc1956b1 100644
--- a/code/modules/mining/mint.dm
+++ b/code/modules/mining/mint.dm
@@ -37,26 +37,26 @@
/obj/machinery/mineral/mint/process()
if ( src.input)
- var/obj/item/stack/material/O
- O = locate(/obj/item/stack/material, input.loc)
+ var/obj/item/stack/O
+ O = locate(/obj/item/stack, input.loc)
if(O)
- if (istype(O,/obj/item/stack/material/gold))
- amt_gold += 100 * O.get_amount()
- qdel(O)
- if (istype(O,/obj/item/stack/material/silver))
- amt_silver += 100 * O.get_amount()
- qdel(O)
- if (istype(O,/obj/item/stack/material/diamond))
- amt_diamond += 100 * O.get_amount()
- qdel(O)
- if (istype(O,/obj/item/stack/material/phoron))
- amt_phoron += 100 * O.get_amount()
- qdel(O)
- if (istype(O,/obj/item/stack/material/uranium))
- amt_uranium += 100 * O.get_amount()
- qdel(O)
- if (istype(O,/obj/item/stack/material/steel))
- amt_iron += 100 * O.get_amount()
+ var/processed = 1
+ switch(O.get_material_name())
+ if("gold")
+ amt_gold += 100 * O.get_amount()
+ if("silver")
+ amt_silver += 100 * O.get_amount()
+ if("diamond")
+ amt_diamond += 100 * O.get_amount()
+ if("phoron")
+ amt_phoron += 100 * O.get_amount()
+ if("uranium")
+ amt_uranium += 100 * O.get_amount()
+ if(DEFAULT_WALL_MATERIAL)
+ amt_iron += 100 * O.get_amount()
+ else
+ processed = 0
+ if(processed)
qdel(O)
/obj/machinery/mineral/mint/attack_hand(user as mob)
diff --git a/code/modules/mob/animations.dm b/code/modules/mob/animations.dm
index ac4224dc43..9bff0fbbe9 100644
--- a/code/modules/mob/animations.dm
+++ b/code/modules/mob/animations.dm
@@ -77,10 +77,36 @@ note dizziness decrements automatically in the mob's Life() proc.
pixel_y = old_y
-//handles up-down floaty effect in space
+//handles up-down floaty effect in space and zero-gravity
/mob/var/is_floating = 0
/mob/var/floatiness = 0
+/mob/proc/update_floating(var/dense_object=0)
+
+ if(anchored||buckled)
+ make_floating(0)
+ return
+
+ var/turf/turf = get_turf(src)
+ if(!istype(turf,/turf/space))
+ var/area/A = turf.loc
+ if(istype(A) && A.has_gravity)
+ make_floating(0)
+ return
+ else if (Check_Shoegrip())
+ make_floating(0)
+ return
+ else
+ make_floating(1)
+ return
+
+ if(dense_object && Check_Shoegrip())
+ make_floating(0)
+ return
+
+ make_floating(1)
+ return
+
/mob/proc/make_floating(var/n)
floatiness = n
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 71afbc893d..cd7afde0e4 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -34,6 +34,7 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images
/mob/dead/observer/New(mob/body)
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
see_invisible = SEE_INVISIBLE_OBSERVER
+ see_in_dark = 100
verbs += /mob/dead/observer/proc/dead_tele
stat = DEAD
@@ -187,8 +188,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/Stat()
..()
- statpanel("Status")
- if (client.statpanel == "Status")
+ if(statpanel("Status"))
stat(null, "Station Time: [worldtime2text()]")
if(emergency_shuttle)
var/eta_status = emergency_shuttle.get_status_panel_eta()
@@ -559,13 +559,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(src.invisibility != 0)
user.visible_message( \
- "[user] drags ghost, [src], to our plane of reality!", \
+ "\The [user] drags ghost, [src], to our plane of reality!", \
"You drag [src] to our plane of reality!" \
)
toggle_visibility(1)
else
user.visible_message ( \
- "[user] just tried to smash his book into that ghost! It's not very effective.", \
+ "\The [user] just tried to smash \his book into that ghost! It's not very effective.", \
"You get the feeling that the ghost can't become any more visible." \
)
@@ -633,13 +633,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/proc/updateghostsight()
if (!seedarkness)
- see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING
- see_in_dark = 100
+ see_invisible = SEE_INVISIBLE_NOLIGHTING
else
see_invisible = SEE_INVISIBLE_OBSERVER
if (!ghostvision)
see_invisible = SEE_INVISIBLE_LIVING;
- see_in_dark = 0
updateghostimages()
/proc/updateallghostimages()
diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm
index 3d605a061a..014c27df1b 100644
--- a/code/modules/mob/death.dm
+++ b/code/modules/mob/death.dm
@@ -70,6 +70,7 @@
blind.layer = 0
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
+ see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
drop_r_hand()
diff --git a/code/modules/mob/freelook/ai/eye.dm b/code/modules/mob/freelook/ai/eye.dm
index c0a42ace48..93fda30055 100644
--- a/code/modules/mob/freelook/ai/eye.dm
+++ b/code/modules/mob/freelook/ai/eye.dm
@@ -27,23 +27,37 @@
// The AI's "eye". Described on the top of the page.
/mob/living/silicon/ai
- eyeobj = new /mob/eye/aiEye()
var/obj/machinery/hologram/holopad/holo = null
+/mob/living/silicon/ai/proc/destroy_eyeobj(var/atom/new_eye)
+ if(!eyeobj) return
+ if(!new_eye)
+ new_eye = src
+ eyeobj.owner = null
+ qdel(eyeobj) // No AI, no Eye
+ eyeobj = null
+ if(client)
+ client.eye = new_eye
+
+/mob/living/silicon/ai/proc/create_eyeobj(var/newloc)
+ if(eyeobj) destroy_eyeobj()
+ if(!newloc) newloc = src.loc
+ eyeobj = PoolOrNew(/mob/eye/aiEye, newloc)
+ eyeobj.owner = src
+ eyeobj.name = "[src.name] (AI Eye)" // Give it a name
+ if(client) client.eye = eyeobj
+ SetName(src.name)
+
// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
/mob/living/silicon/ai/New()
..()
- eyeobj.owner = src
- eyeobj.name = "[src.name] (AI Eye)" // Give it a name
+ create_eyeobj()
spawn(5)
if(eyeobj)
eyeobj.loc = src.loc
/mob/living/silicon/ai/Destroy()
- if(eyeobj)
- eyeobj.owner = null
- qdel(eyeobj) // No AI, no Eye
- eyeobj = null
+ destroy_eyeobj()
..()
/atom/proc/move_camera_by_click()
@@ -53,23 +67,18 @@
AI.eyeobj.setLoc(src)
// Return to the Core.
-
/mob/living/silicon/ai/proc/core()
set category = "AI Commands"
set name = "AI Core"
view_core()
-
/mob/living/silicon/ai/proc/view_core()
camera = null
unset_machine()
if(!src.eyeobj)
- src << "ERROR: Eyeobj not found. Creating new eye..."
- src.eyeobj = new(src.loc)
- src.eyeobj.owner = src
- src.SetName(src.name)
+ return
if(client && client.eye)
client.eye = src
diff --git a/code/modules/mob/freelook/eye.dm b/code/modules/mob/freelook/eye.dm
index e77084553d..fb2b04a434 100644
--- a/code/modules/mob/freelook/eye.dm
+++ b/code/modules/mob/freelook/eye.dm
@@ -15,6 +15,7 @@
var/acceleration = 1
var/owner_follows_eye = 0
+ see_in_dark = 7
status_flags = GODMODE
invisibility = INVISIBILITY_EYE
diff --git a/code/modules/mob/freelook/update_triggers.dm b/code/modules/mob/freelook/update_triggers.dm
index 8408083ba8..405e4bdd9e 100644
--- a/code/modules/mob/freelook/update_triggers.dm
+++ b/code/modules/mob/freelook/update_triggers.dm
@@ -29,7 +29,6 @@
..()
/obj/structure/New()
- ..()
updateVisibility(src)
// EFFECTS
diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm
index d93edf3ac2..17a145ae02 100644
--- a/code/modules/mob/language/generic.dm
+++ b/code/modules/mob/language/generic.dm
@@ -25,7 +25,7 @@
speech_verb = "says"
whisper_verb = "whispers"
key = "0"
- flags = RESTRICTED
+ flags = RESTRICTED | COMMON_VERBS
syllables = list("blah","blah","blah","bleh","meh","neh","nah","wah")
//TODO flag certain languages to use the mob-type specific say_quote and then get rid of these.
diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm
index 3d45e84f99..f2427b056c 100644
--- a/code/modules/mob/language/station.dm
+++ b/code/modules/mob/language/station.dm
@@ -73,7 +73,7 @@
whisper_verb = "whispers"
colour = "solcom"
key = "1"
- flags = RESTRICTED
+ flags = WHITELISTED
//syllables are at the bottom of the file
diff --git a/code/modules/mob/living/blob/blob.dm b/code/modules/mob/living/blob/blob.dm
index 959e6ed379..8bbf517e60 100644
--- a/code/modules/mob/living/blob/blob.dm
+++ b/code/modules/mob/living/blob/blob.dm
@@ -4,6 +4,7 @@
icon = 'icons/mob/blob.dmi'
icon_state = "blob_spore_temp"
pass_flags = PASSBLOB
+ see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
var/ghost_name = "Unknown"
var/creating_blob = 0
diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm
index d58af33eef..821c87bb1f 100644
--- a/code/modules/mob/living/bot/bot.dm
+++ b/code/modules/mob/living/bot/bot.dm
@@ -16,6 +16,7 @@
var/obj/access_scanner = null
var/list/req_access = list()
+ var/list/req_one_access = list()
/mob/living/bot/New()
..()
@@ -26,14 +27,16 @@
access_scanner = new /obj(src)
access_scanner.req_access = req_access.Copy()
+ access_scanner.req_one_access = req_one_access.Copy()
/mob/living/bot/Life()
..()
+ if(health <= 0)
+ death()
+ return
weakened = 0
stunned = 0
paralysis = 0
- if(health <= 0)
- death()
/mob/living/bot/updatehealth()
if(status_flags & GODMODE)
diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm
index 9ec4341607..d21b74dca4 100644
--- a/code/modules/mob/living/bot/floorbot.dm
+++ b/code/modules/mob/living/bot/floorbot.dm
@@ -251,15 +251,16 @@
target = null
repairing = 0
update_icons()
- else if(istype(A, /obj/item/stack/material/steel) && amount + 3 < maxAmount)
- var/obj/item/stack/material/steel/M = A
- visible_message("[src] begins to make tiles.")
- repairing = 1
- update_icons()
- if(do_after(50))
- if(M)
- M.use(1)
- addTiles(4)
+ else if(istype(A, /obj/item/stack/material) && amount + 4 <= maxAmount)
+ var/obj/item/stack/material/M = A
+ if(M.get_material_name() == DEFAULT_WALL_MATERIAL)
+ visible_message("[src] begins to make tiles.")
+ repairing = 1
+ update_icons()
+ if(do_after(50))
+ if(M)
+ M.use(1)
+ addTiles(4)
/mob/living/bot/floorbot/explode()
turn_off()
diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm
index a0a7a69450..ee4a35e15b 100644
--- a/code/modules/mob/living/bot/secbot.dm
+++ b/code/modules/mob/living/bot/secbot.dm
@@ -4,7 +4,7 @@
icon_state = "secbot0"
maxHealth = 50
health = 50
- req_access = list(access_security, access_forensics_lockers)
+ req_one_access = list(access_security, access_forensics_lockers)
botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
var/mob/target
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index 1043cf0bfa..429e82b3d0 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -95,11 +95,13 @@
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
+ see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
+ see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (healths)
diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm
index da1e59f0de..5c40906bfb 100644
--- a/code/modules/mob/living/carbon/brain/brain_item.dm
+++ b/code/modules/mob/living/carbon/brain/brain_item.dm
@@ -23,6 +23,7 @@
/obj/item/organ/brain/New()
..()
+ health = config.default_brain_health
spawn(5)
if(brainmob && brainmob.client)
brainmob.client.screen.len = null //clear the hud
diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm
index a2098baa9f..283bb595c6 100644
--- a/code/modules/mob/living/carbon/brain/life.dm
+++ b/code/modules/mob/living/carbon/brain/life.dm
@@ -199,11 +199,13 @@
sight |= SEE_TURFS
sight |= SEE_MOBS
sight |= SEE_OBJS
+ see_in_dark = 8
see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (stat != 2)
sight &= ~SEE_TURFS
sight &= ~SEE_MOBS
sight &= ~SEE_OBJS
+ see_in_dark = 2
see_invisible = SEE_INVISIBLE_LIVING
if (client)
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
@@ -252,4 +254,4 @@
emp_damage += rand(10,20)
if(3)
emp_damage += rand(0,10)
- ..()*/
+ ..()*/
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 534c77c2a1..45c2cde53a 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -372,8 +372,8 @@
/mob/living/carbon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
..()
- var/temp_inc = max(BODYTEMP_HEATING_MAX*(1-get_heat_protection()), 0)
- bodytemperature = min(bodytemperature + temp_inc, exposed_temperature)
+ var/temp_inc = max(min(BODYTEMP_HEATING_MAX*(1-get_heat_protection()), exposed_temperature - bodytemperature), 0)
+ bodytemperature += temp_inc
/mob/living/carbon/can_use_hands()
if(handcuffed)
diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm
index 3990490145..3b8e566964 100644
--- a/code/modules/mob/living/carbon/human/appearance.dm
+++ b/code/modules/mob/living/carbon/human/appearance.dm
@@ -154,14 +154,14 @@
return valid_species
-/mob/living/carbon/human/proc/generate_valid_hairstyles()
+/mob/living/carbon/human/proc/generate_valid_hairstyles(var/check_gender = 1)
var/list/valid_hairstyles = new()
for(var/hairstyle in hair_styles_list)
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
- if(gender == MALE && S.gender == FEMALE)
+ if(check_gender && gender == MALE && S.gender == FEMALE)
continue
- if(gender == FEMALE && S.gender == MALE)
+ if(check_gender && gender == FEMALE && S.gender == MALE)
continue
if(!(species.name in S.species_allowed))
continue
@@ -185,11 +185,7 @@
return valid_facial_hairstyles
-/proc/q()
- var/mob/living/carbon/human/H = usr
- H.change_appearance(APPEARANCE_ALL)
-
/mob/living/carbon/human/proc/force_update_limbs()
for(var/obj/item/organ/external/O in organs)
O.sync_colour_to_human(src)
- update_body(0)
\ No newline at end of file
+ update_body(0)
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 10b2a91477..c1abe448f3 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -101,7 +101,7 @@
if ("choke")
if(miming)
- message = "clutches his throat desperately!"
+ message = "clutches [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] throat desperately!"
m_type = 1
else
if (!muzzled)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 07dbcaf056..4f3f52a364 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -54,16 +54,13 @@
/mob/living/carbon/human/Stat()
..()
- statpanel("Status")
-
- stat(null, "Intent: [a_intent]")
- stat(null, "Move Mode: [m_intent]")
- if(emergency_shuttle)
- var/eta_status = emergency_shuttle.get_status_panel_eta()
- if(eta_status)
- stat(null, eta_status)
-
- if (client.statpanel == "Status")
+ if(statpanel("Status"))
+ stat(null, "Intent: [a_intent]")
+ stat(null, "Move Mode: [m_intent]")
+ if(emergency_shuttle)
+ var/eta_status = emergency_shuttle.get_status_panel_eta()
+ if(eta_status)
+ stat(null, eta_status)
if (internal)
if (!internal.air_contents)
@@ -210,6 +207,10 @@
/mob/living/carbon/human/show_inv(mob/user as mob)
+ // TODO : Change to incapacitated() on merge.
+ if(user.stat || user.lying || user.resting || user.buckled)
+ return
+
var/obj/item/clothing/under/suit = null
if (istype(w_uniform, /obj/item/clothing/under))
suit = w_uniform
@@ -723,7 +724,7 @@
/mob/living/carbon/human/proc/play_xylophone()
if(!src.xylophone)
- visible_message("\red [src] begins playing his ribcage like a xylophone. It's quite spooky.","\blue You begin to play a spooky refrain on your ribcage.","\red You hear a spooky xylophone melody.")
+ visible_message("\red \The [src] begins playing \his ribcage like a xylophone. It's quite spooky.","\blue You begin to play a spooky refrain on your ribcage.","\red You hear a spooky xylophone melody.")
var/song = pick('sound/effects/xylophone1.ogg','sound/effects/xylophone2.ogg','sound/effects/xylophone3.ogg')
playsound(loc, song, 50, 1, -1)
xylophone = 1
@@ -1361,3 +1362,8 @@
..()
if(update_hud)
handle_regular_hud_updates()
+
+/mob/living/carbon/human/Check_Shoegrip()
+ if(istype(shoes, /obj/item/clothing/shoes/magboots) && (shoes.flags & NOSLIP)) //magboots + dense_object = no floating
+ return 1
+ return 0
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
index 7451e6ae6a..8224d3e518 100644
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ b/code/modules/mob/living/carbon/human/human_attackhand.dm
@@ -1,3 +1,9 @@
+/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone)
+ for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
+ if(u_attack.is_usable(src, target, hit_zone))
+ return u_attack
+ return null
+
/mob/living/carbon/human/attack_hand(mob/living/carbon/M as mob)
var/mob/living/carbon/human/H = M
@@ -184,18 +190,7 @@
miss_type = 2
// See what attack they use
- var/possible_moves = list()
- var/datum/unarmed_attack/attack = null
- for(var/part in list("l_hand","r_hand","l_foot","r_foot","head"))
- var/obj/item/organ/external/E = H.get_organ(part)
- possible_moves |= E.species.unarmed_attacks
-
- for(var/datum/unarmed_attack/u_attack in possible_moves)
- if(!u_attack.is_usable(H, src, hit_zone))
- continue
- else
- attack = u_attack
- break
+ var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone)
if(!attack)
return 0
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index af603fcb9b..8f82504609 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -32,7 +32,7 @@
var/obj/item/organ/brain/sponge = internal_organs_by_name["brain"]
if(sponge)
sponge.take_damage(amount)
- sponge.damage = min(max(brainloss, 0),(maxHealth*2))
+ sponge.damage = min(max(sponge.damage, 0),(maxHealth*2))
brainloss = sponge.damage
else
brainloss = 200
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 3295e67ea2..7a59816de3 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -10,9 +10,11 @@ emp_act
/mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone)
- var/obj/item/organ/external/organ = get_organ(check_zone(def_zone))
- if(!organ)
- return
+ def_zone = check_zone(def_zone)
+ if(!has_organ(def_zone))
+ return PROJECTILE_FORCE_MISS //if they don't have the organ in question then the projectile just passes by.
+
+ var/obj/item/organ/external/organ = get_organ()
//Shields
if(check_shields(P.damage, "the [P.name]"))
@@ -37,7 +39,7 @@ emp_act
// redirect the projectile
P.redirect(new_x, new_y, curloc, src)
- return -1 // complete projectile permutation
+ return PROJECTILE_CONTINUE // complete projectile permutation
//Shrapnel
if(P.can_embed())
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 7f469f08d7..f3f399c886 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -41,7 +41,7 @@ This saves us from having to call add_fingerprint() any time something is put in
/mob/living/carbon/human/proc/has_organ(name)
var/obj/item/organ/external/O = organs_by_name[name]
- return (O && !(O.status & ORGAN_DESTROYED) )
+ return (O && !(O.status & ORGAN_DESTROYED) && !O.is_stump())
/mob/living/carbon/human/proc/has_organ_for_slot(slot)
switch(slot)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 1b04060213..44e9ac4095 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -1197,7 +1197,7 @@
damageoverlay.overlays += I
if( stat == DEAD )
- sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
+ sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS|SEE_SELF
see_in_dark = 8
if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO
if(healths) healths.icon_state = "health7" //DEAD healthmeter
@@ -1208,23 +1208,13 @@
item.zoom()
break
- /*
- if(locate(/obj/item/weapon/gun/energy/sniperrifle, contents))
- var/obj/item/weapon/gun/energy/sniperrifle/s = locate() in src
- if(s.zoom)
- s.zoom()
- if(locate(/obj/item/device/binoculars, contents))
- var/obj/item/device/binoculars/b = locate() in src
- if(b.zoom)
- b.zoom()
- */
-
else
sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS)
see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : SEE_INVISIBLE_LIVING
if(XRAY in mutations)
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
+ see_in_dark = 8
if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO
if(seer==1)
@@ -1236,7 +1226,9 @@
seer = 0
else
- sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS)
+ sight = species.vision_flags
+ see_in_dark = species.darksight
+ see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : SEE_INVISIBLE_LIVING
var/tmp/glasses_processed = 0
var/obj/item/weapon/rig/rig = back
if(istype(rig) && rig.visor)
@@ -1250,6 +1242,7 @@
process_glasses(glasses)
if(XRAY in mutations)
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
+ see_in_dark = 8
if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO
if(!glasses_processed && (species.vision_flags > 0))
@@ -1275,6 +1268,8 @@
if(0 to 20) healths.icon_state = "health5"
else healths.icon_state = "health6"
+ if(!seer)
+ see_invisible = SEE_INVISIBLE_LIVING
if(nutrition_icon)
switch(nutrition)
if(450 to INFINITY) nutrition_icon.icon_state = "nutrition0"
@@ -1402,6 +1397,8 @@
sight |= G.vision_flags
if(!druggy && !seer)
see_invisible = SEE_INVISIBLE_MINIMUM
+ if(G.see_invisible >= 0)
+ see_invisible = G.see_invisible
if(istype(G,/obj/item/clothing/glasses/night) && !seer)
see_invisible = SEE_INVISIBLE_MINIMUM
/* HUD shit goes here, as long as it doesn't modify sight flags */
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index bbf1844c45..44b8e6f238 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -6,9 +6,6 @@
message = sanitize(message)
..(message, alt_name = alt_name)
-/mob/living/carbon/human/is_muzzled()
- return istype(src.wear_mask, /obj/item/clothing/mask/muzzle)
-
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
if(client)
@@ -132,11 +129,11 @@
if(silent || (sdisabilities & MUTE))
message = ""
speech_problem_flag = 1
- else if(istype(wear_mask, /obj/item/clothing/mask/horsehead))
- var/obj/item/clothing/mask/horsehead/hoers = wear_mask
- if(hoers.voicechange)
- message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!")
- verb = pick("whinnies","neighs", "says")
+ else if(istype(wear_mask, /obj/item/clothing/mask))
+ var/obj/item/clothing/mask/M = wear_mask
+ if(M.voicechange)
+ message = pick(M.say_messages)
+ verb = pick(M.say_verbs)
speech_problem_flag = 1
if(message != "")
diff --git a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
index cf2295a98c..dd614bb55b 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
@@ -8,6 +8,7 @@
language = "Sol Common" //todo?
unarmed_types = list(/datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/sharp)
light_dam = 2
+ darksight = 8
has_organ = list()
siemens_coefficient = 0
@@ -22,4 +23,4 @@
/datum/species/shadow/handle_death(var/mob/living/carbon/human/H)
spawn(1)
new /obj/effect/decal/cleanable/ash(H.loc)
- qdel(H)
+ qdel(H)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/outsider/vox.dm b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
index 926781abe1..905e962dd1 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/vox.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
@@ -5,6 +5,7 @@
deform = 'icons/mob/human_races/r_def_vox.dmi'
default_language = "Vox-pidgin"
language = "Galactic Common"
+ num_alternate_languages = 1
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/strong)
rarity_value = 2
blurb = "The Vox are the broken remnants of a once-proud race, now reduced to little more than \
@@ -65,7 +66,7 @@
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/vox(H.back), slot_in_backpack)
H.internal = H.r_hand
H.internals.icon_state = "internal1"
-
+
/datum/species/vox/can_shred(var/mob/living/carbon/human/H, var/ignore_intent)
if(!H.mind || !H.mind.special_role) // Pariah check.
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index 500fad9c86..47063874b7 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -34,9 +34,10 @@
// Language/culture vars.
var/default_language = "Galactic Common" // Default language is used when 'say' is used without modifiers.
var/language = "Galactic Common" // Default racial language, if any.
- var/secondary_langs = list() // The names of secondary languages that are available to this species.
+ var/list/secondary_langs = list() // The names of secondary languages that are available to this species.
var/list/speech_sounds // A list of sounds to potentially play when speaking.
var/list/speech_chance // The likelihood of a speech sound playing.
+ var/num_alternate_languages = 0 // How many secondary languages are available to select at character creation
// Combat vars.
var/total_health = 100 // Point at which the mob will enter crit.
@@ -47,7 +48,7 @@
var/list/unarmed_attacks = null // For empty hand harm-intent attack
var/brute_mod = 1 // Physical damage multiplier.
var/burn_mod = 1 // Burn damage multiplier.
- var/vision_flags = 0 // Same flags as glasses.
+ var/vision_flags = SEE_SELF // Same flags as glasses.
// Death vars.
var/meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/human
@@ -100,6 +101,7 @@
var/list/inherent_verbs // Species-specific verbs.
var/has_fine_manipulation = 1 // Can use small items.
var/siemens_coefficient = 1 // The lower, the thicker the skin and better the insulation.
+ var/darksight = 2 // Native darksight distance.
var/flags = 0 // Various specific features.
var/slowdown = 0 // Passive movement speed malus (or boost, if negative)
var/primitive_form // Lesser form, if any (ie. monkey for humans)
diff --git a/code/modules/mob/living/carbon/human/species/species_attack.dm b/code/modules/mob/living/carbon/human/species/species_attack.dm
index c3312b9a7a..466b1bd2ab 100644
--- a/code/modules/mob/living/carbon/human/species/species_attack.dm
+++ b/code/modules/mob/living/carbon/human/species/species_attack.dm
@@ -9,11 +9,15 @@
/datum/unarmed_attack/diona
attack_verb = list("lashed", "bludgeoned")
attack_noun = list("tendril")
+ eye_attack_text = "a tendril"
+ eye_attack_text_victim = "a tendril"
damage = 5
/datum/unarmed_attack/claws
attack_verb = list("scratched", "clawed", "slashed")
attack_noun = list("claws")
+ eye_attack_text = "claws"
+ eye_attack_text_victim = "sharp claws"
attack_sound = 'sound/weapons/slice.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
damage = 5
diff --git a/code/modules/mob/living/carbon/human/species/station/slime.dm b/code/modules/mob/living/carbon/human/species/station/slime.dm
index e5aada89d6..46a7e9f5f5 100644
--- a/code/modules/mob/living/carbon/human/species/station/slime.dm
+++ b/code/modules/mob/living/carbon/human/species/station/slime.dm
@@ -10,6 +10,7 @@
unarmed_types = list(/datum/unarmed_attack/slime_glomp)
flags = IS_RESTRICTED | NO_SCAN | NO_SLIP | NO_BREATHE
siemens_coefficient = 3
+ darksight = 3
blood_color = "#05FF9B"
flesh_color = "#05FFFB"
diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm
index 3ddf983b76..5ba275057b 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -1,7 +1,6 @@
/datum/species/human
name = "Human"
name_plural = "Humans"
- language = "Sol Common"
primitive_form = "Monkey"
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite)
blurb = "Humanity originated in the Sol system, and over the last five centuries has spread \
@@ -9,6 +8,8 @@
While the central Sol government maintains control of its far-flung people, powerful corporate \
interests, rampant cyber and bio-augmentation and secretive factions make life on most human \
worlds tumultous at best."
+ num_alternate_languages = 2
+ secondary_langs = list("Sol Common")
flags = CAN_JOIN | HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR
@@ -17,12 +18,14 @@
name_plural = "Unathi"
icobase = 'icons/mob/human_races/r_lizard.dmi'
deform = 'icons/mob/human_races/r_def_lizard.dmi'
- language = "Sinta'unathi"
tail = "sogtail"
tail_animation = 'icons/mob/species/unathi/tail.dmi'
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp)
primitive_form = "Stok"
+ darksight = 3
gluttonous = 1
+ num_alternate_languages = 2
+ secondary_langs = list("Sinta'unathi")
blurb = "A heavily reptillian species, Unathi (or 'Sinta as they call themselves) hail from the \
Uuosa-Eso system, which roughly translates to 'burning mother'.
Coming from a harsh, radioactive \
@@ -68,12 +71,14 @@
name_plural = "Tajaran"
icobase = 'icons/mob/human_races/r_tajaran.dmi'
deform = 'icons/mob/human_races/r_def_tajaran.dmi'
- language = "Siik'tajr"
tail = "tajtail"
tail_animation = 'icons/mob/species/tajaran/tail.dmi'
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp)
+ darksight = 8
slowdown = -1
brute_mod = 1.2
+ num_alternate_languages = 2
+ secondary_langs = list("Siik'tajr")
blurb = "The Tajaran race is a species of feline-like bipeds hailing from the planet of Ahdomai in the \
S'randarr system. They have been brought up into the space age by the Humans and Skrell, and have been \
@@ -114,7 +119,6 @@
icobase = 'icons/mob/human_races/r_skrell.dmi'
deform = 'icons/mob/human_races/r_def_skrell.dmi'
eyes = "skrell_eyes_s"
- language = "Skrellian"
primitive_form = "Neara"
unarmed_types = list(/datum/unarmed_attack/punch)
blurb = "An amphibious species, Skrell come from the star system known as Qerr'Vallis, which translates to 'Star of \
@@ -122,6 +126,8 @@
of the Qerr'Katish, a caste within their society which keeps the empire of the Skrell running smoothly. Skrell are \
herbivores on the whole and tend to be co-operative with the other species of the galaxy, although they rarely reveal \
the secrets of their empire to their allies."
+ num_alternate_languages = 2
+ secondary_langs = list("Skrellian")
flags = CAN_JOIN | IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR
@@ -145,6 +151,7 @@
siemens_coefficient = 0.3
eyes = "blank_eyes"
show_ssd = "completely quiescent"
+ num_alternate_languages = 1
blurb = "Commonly referred to (erroneously) as 'plant people', the Dionaea are a strange space-dwelling collective \
@@ -249,6 +256,7 @@
language = "Encoded Audio Language"
unarmed_types = list(/datum/unarmed_attack/punch)
rarity_value = 2
+ num_alternate_languages = 1 // potentially could be 2?
eyes = "blank_eyes"
brute_mod = 1.875 // 100% * 1.875 * 0.8 (robolimbs) ~= 150%
diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm
index ee24e3f6b7..b48593796f 100644
--- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm
+++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm
@@ -42,7 +42,7 @@
breath_type = null
poison_type = null
- vision_flags = SEE_MOBS
+ vision_flags = SEE_SELF|SEE_MOBS
has_organ = list(
"heart" = /obj/item/organ/heart,
diff --git a/code/modules/mob/living/carbon/human/stripping.dm b/code/modules/mob/living/carbon/human/stripping.dm
index 8eaef15861..aa08a0efd5 100644
--- a/code/modules/mob/living/carbon/human/stripping.dm
+++ b/code/modules/mob/living/carbon/human/stripping.dm
@@ -3,6 +3,11 @@
if(!slot_to_strip || !istype(user))
return
+ // TODO : Change to incapacitated() on merge.
+ if(user.stat || user.lying || user.resting || user.buckled)
+ user << browse(null, text("window=mob[src.name]"))
+ return
+
var/obj/item/target_slot = get_equipped_item(text2num(slot_to_strip))
switch(slot_to_strip)
diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/modules/mob/living/carbon/human/unarmed_attack.dm
index 155a1f23b7..289b4a2273 100644
--- a/code/modules/mob/living/carbon/human/unarmed_attack.dm
+++ b/code/modules/mob/living/carbon/human/unarmed_attack.dm
@@ -8,8 +8,11 @@
var/shredding = 0 // Calls the old attack_alien() behavior on objects/mobs when on harm intent.
var/sharp = 0
var/edge = 0
+
+ var/eye_attack_text
+ var/eye_attack_text_victim
-/datum/unarmed_attack/proc/is_usable(var/mob/living/carbon/human/user)
+/datum/unarmed_attack/proc/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone)
if(user.restrained())
return 0
@@ -78,6 +81,13 @@
user.visible_message("[user] [pick(attack_verb)] [target] in the [affecting.name]!")
playsound(user.loc, attack_sound, 25, 1, -1)
+/datum/unarmed_attack/proc/handle_eye_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target)
+ var/obj/item/organ/eyes/eyes = target.internal_organs_by_name["eyes"]
+ eyes.take_damage(rand(3,4), 1)
+
+ user.visible_message("[user] presses \his [eye_attack_text] into [target]'s [eyes.name]!")
+ target << "You experience[(target.species.flags & NO_PAIN)? "" : " immense pain as you feel" ] [eye_attack_text_victim] being pressed into your [eyes.name][(target.species.flags & NO_PAIN)? "." : "!"]"
+
/datum/unarmed_attack/bite
attack_verb = list("bit")
attack_sound = 'sound/weapons/bite.ogg'
@@ -97,6 +107,8 @@
/datum/unarmed_attack/punch
attack_verb = list("punched")
attack_noun = list("fist")
+ eye_attack_text = "fingers"
+ eye_attack_text_victim = "digits"
damage = 0
/datum/unarmed_attack/punch/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 208a79c5c1..3bb42237a8 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -504,7 +504,7 @@ var/global/list/damage_icon_parts = list()
var/obj/item/clothing/under/under = w_uniform
if(under.accessories.len)
for(var/obj/item/clothing/accessory/A in under.accessories)
- standing.overlays |= A.get_inv_mob_overlay()
+ standing.overlays |= A.get_mob_overlay()
overlays_standing[UNIFORM_LAYER] = standing
else
diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm
index 4d084a7533..86f8f2d672 100644
--- a/code/modules/mob/living/carbon/metroid/metroid.dm
+++ b/code/modules/mob/living/carbon/metroid/metroid.dm
@@ -14,6 +14,7 @@
update_icon = 0
nutrition = 700
+ see_in_dark = 8
update_slimes = 0
// canstun and canweaken don't affect slimes because they ignore stun and weakened variables
@@ -401,4 +402,4 @@
/mob/living/carbon/slime/cannot_use_vents()
if(Victim)
return "You cannot ventcrawl while feeding."
- ..()
+ ..()
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index a126bccc87..20e8ba14d6 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -128,6 +128,7 @@ proc/get_radio_key_from_channel(var/channel)
return verb
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="")
+
if(client)
if(client.prefs.muted & MUTE_IC)
src << "\red You cannot speak in IC (Muted)."
@@ -138,10 +139,6 @@ proc/get_radio_key_from_channel(var/channel)
return say_dead(message)
return
- if(is_muzzled())
- src << "You're muzzled and cannot speak!"
- return
-
var/message_mode = parse_message_mode(message, "headset")
switch(copytext(message,1,2))
@@ -165,7 +162,6 @@ proc/get_radio_key_from_channel(var/channel)
else
speaking = get_default_language()
- var/ending = copytext(message, length(message))
if (speaking)
// This is broadcast to all mobs with the language,
// irrespective of distance or anything else.
@@ -173,9 +169,16 @@ proc/get_radio_key_from_channel(var/channel)
speaking.broadcast(src,trim(message))
return
//If we've gotten this far, keep going!
- verb = speaking.get_spoken_verb(ending)
+ if(speaking.flags & COMMON_VERBS)
+ verb = say_quote(message)
+ else
+ verb = speaking.get_spoken_verb(copytext(message, length(message)))
else
- verb = get_speech_ending(verb, ending)
+ verb = say_quote(message)
+
+ if(is_muzzled())
+ src << "You're muzzled and cannot speak!"
+ return
message = trim_left(message)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 26c0bf8365..3004b9dd9e 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -49,7 +49,6 @@ var/list/ai_verbs_default = list(
var/list/network = list("Exodus")
var/obj/machinery/camera/camera = null
var/list/connected_robots = list()
- var/has_power = 0
var/aiRestorePowerRoutine = 0
var/viewalerts = 0
var/icon/holo_icon//Default is assigned when AI is created.
@@ -384,8 +383,7 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/check_eye(var/mob/user as mob)
if (!camera)
- return null
- user.reset_view(camera)
+ return -1
return 0
/mob/living/silicon/ai/restrained()
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index 8db82ead31..d67eb27753 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -38,18 +38,19 @@
src << "APU GENERATOR FAILURE! (System Damaged)"
stop_apu(1)
- has_power = 1
+ var/blind = 0
var/area/loc = null
if (istype(T, /turf))
loc = T.loc
if (istype(loc, /area))
if (!loc.power_equip && !istype(src.loc,/obj/item) && !APU_power)
- has_power = 0
+ blind = 1
- if (has_power)
+ if (!blind)
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
src.sight |= SEE_OBJS
+ src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_LIVING
if (aiRestorePowerRoutine==2)
@@ -79,10 +80,12 @@
//Blind the AI
updateicon()
src.blind.screen_loc = "1,1 to 15,15"
-
+ if (src.blind.layer!=18)
+ src.blind.layer = 18
src.sight = src.sight&~SEE_TURFS
src.sight = src.sight&~SEE_MOBS
src.sight = src.sight&~SEE_OBJS
+ src.see_in_dark = 0
src.see_invisible = SEE_INVISIBLE_LIVING
//Now to tell the AI why they're blind and dying slowly.
diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm
index 69d957fbaf..c4a4d63448 100644
--- a/code/modules/mob/living/silicon/laws.dm
+++ b/code/modules/mob/living/silicon/laws.dm
@@ -39,20 +39,23 @@
laws.delete_law(law)
log_and_message_admins("has deleted a law belonging to [src]: [law.law]")
-/mob/living/silicon/proc/clear_inherent_laws()
+/mob/living/silicon/proc/clear_inherent_laws(var/silent = 0)
laws_sanity_check()
laws.clear_inherent_laws()
- log_and_message_admins("cleared the inherent laws of [src]")
+ if(!silent)
+ log_and_message_admins("cleared the inherent laws of [src]")
-/mob/living/silicon/proc/clear_ion_laws()
+/mob/living/silicon/proc/clear_ion_laws(var/silent = 0)
laws_sanity_check()
laws.clear_ion_laws()
- log_and_message_admins("cleared the ion laws of [src]")
+ if(!silent)
+ log_and_message_admins("cleared the ion laws of [src]")
-/mob/living/silicon/proc/clear_supplied_laws()
+/mob/living/silicon/proc/clear_supplied_laws(var/silent = 0)
laws_sanity_check()
laws.clear_supplied_laws()
- log_and_message_admins("cleared the supplied laws of [src]")
+ if(!silent)
+ log_and_message_admins("cleared the supplied laws of [src]")
/mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws)
var/prefix = ""
diff --git a/code/modules/mob/living/silicon/pai/admin.dm b/code/modules/mob/living/silicon/pai/admin.dm
new file mode 100644
index 0000000000..069c5d2c68
--- /dev/null
+++ b/code/modules/mob/living/silicon/pai/admin.dm
@@ -0,0 +1,21 @@
+// Originally a debug verb, made it a proper adminverb for ~fun~
+/client/proc/makePAI(turf/t in view(), name as text, pai_key as null|text)
+ set name = "Make pAI"
+ set category = "Admin"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ if(!pai_key)
+ var/client/C = input("Select client") as null|anything in clients
+ if(!C) return
+ pai_key = C.key
+
+ log_and_message_admins("made a pAI with key=[pai_key] at ([t.x],[t.y],[t.z])")
+ var/obj/item/device/paicard/card = new(t)
+ var/mob/living/silicon/pai/pai = new(card)
+ pai.key = pai_key
+ card.setPersonality(pai)
+
+ if(name)
+ pai.SetName(name)
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 6deab260d9..ad06c58d6e 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -120,7 +120,6 @@
/mob/living/silicon/pai/check_eye(var/mob/user as mob)
if (!src.current)
return -1
- user.reset_view(src.current)
return 0
/mob/living/silicon/pai/blob_act()
diff --git a/code/modules/mob/living/silicon/robot/custom_sprites.dm b/code/modules/mob/living/silicon/robot/custom_sprites.dm
index 5966796f4d..c3632cd62e 100644
--- a/code/modules/mob/living/silicon/robot/custom_sprites.dm
+++ b/code/modules/mob/living/silicon/robot/custom_sprites.dm
@@ -25,6 +25,6 @@ var/list/robot_custom_icons
var/rname = robot_custom_icons[ckey]
if(rname && rname == real_name)
custom_sprite = 1
- icon = 'icons/mob/custom_synthetic.dmi'
+ icon = CUSTOM_ITEM_SYNTH
if(icon_state == "robot")
icon_state = "[ckey]-Standard"
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 3662ef7247..04e3728c6a 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -160,11 +160,11 @@
clear_supplied_laws()
clear_inherent_laws()
laws = new /datum/ai_laws/syndicate_override
- set_zeroth_law("Only [user.real_name] and people he designates as being such are operatives.")
+ set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.")
src << "Obey these laws:"
laws.show_laws(src)
- src << "ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
+ src << "ALERT: [user.real_name] is your new master. Obey your new laws and \his commands."
return 1
//DRONE LIFE/DEATH
@@ -213,9 +213,9 @@
death()
/mob/living/silicon/robot/drone/proc/full_law_reset()
- clear_supplied_laws()
- clear_inherent_laws()
- clear_ion_laws()
+ clear_supplied_laws(1)
+ clear_inherent_laws(1)
+ clear_ion_laws(1)
laws = new law_type
//Reboot procs.
@@ -257,23 +257,21 @@
src << "You are a maintenance drone, a tiny-brained robotic repair machine."
src << "You have no individual will, no personality, and no drives or urges other than your laws."
src << "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI."
- src << "Use :d to talk to other drones and say to speak silently to your nearby fellows."
+ src << "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows."
/mob/living/silicon/robot/drone/start_pulling(var/atom/movable/AM)
- if(istype(AM,/obj/item/pipe) || istype(AM,/obj/structure/disposalconstruct))
- ..()
- else if(istype(AM,/obj/item))
- var/obj/item/O = AM
- if(O.w_class > can_pull_size)
- src << "You are too small to pull that."
- return
+ if(!(istype(AM,/obj/item/pipe) || istype(AM,/obj/structure/disposalconstruct)))
+ if(istype(AM,/obj/item))
+ var/obj/item/O = AM
+ if(O.w_class > can_pull_size)
+ src << "You are too small to pull that."
+ return
else
- ..()
- else
- if(!can_pull_mobs)
- src << "You are too small to pull that."
- return
+ if(!can_pull_mobs)
+ src << "You are too small to pull that."
+ return
+ ..()
/mob/living/silicon/robot/drone/add_robot_verbs()
src.verbs |= silicon_subsystems
@@ -300,4 +298,4 @@
/mob/living/silicon/robot/drone/construction/updatename()
real_name = "construction drone ([rand(100,999)])"
- name = real_name
\ No newline at end of file
+ name = real_name
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm
new file mode 100644
index 0000000000..71ca1c6918
--- /dev/null
+++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm
@@ -0,0 +1,40 @@
+/mob/living/silicon/robot/drone/say(var/message)
+ if(local_transmit)
+ if (src.client)
+ if(client.prefs.muted & MUTE_IC)
+ src << "You cannot send IC messages (muted)."
+ return 0
+ if (src.client.handle_spam_prevention(message,MUTE_IC))
+ return 0
+
+ message = sanitize(message)
+
+ if (stat == 2)
+ return say_dead(message)
+
+ if(copytext(message,1,2) == "*")
+ return emote(copytext(message,2))
+
+ if(copytext(message,1,2) == ";")
+ var/datum/language/L = all_languages["Drone Talk"]
+ if(istype(L))
+ return L.broadcast(src,trim(copytext(message,2)))
+
+ //Must be concious to speak
+ if (stat)
+ return 0
+
+ var/list/listeners = hearers(5,src)
+ listeners |= src
+
+ for(var/mob/living/silicon/D in listeners)
+ if(D.client && D.local_transmit)
+ D << "[src] transmits, \"[message]\""
+
+ for (var/mob/M in player_list)
+ if (istype(M, /mob/new_player))
+ continue
+ else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
+ if(M.client) M << "[src] transmits, \"[message]\""
+ return 1
+ ..(message)
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index 34df63d397..dca60f597c 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -65,12 +65,12 @@
m_type = 2
if ("flap")
if (!src.restrained())
- message = "flaps his wings."
+ message = "flaps its wings."
m_type = 2
if ("aflap")
if (!src.restrained())
- message = "flaps his wings ANGRILY!"
+ message = "flaps its wings ANGRILY!"
m_type = 2
if ("twitch")
@@ -213,4 +213,4 @@
if ((message && src.stat == 0))
custom_emote(m_type,message)
- return
\ No newline at end of file
+ return
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index ad5203bb76..2008edec86 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -65,9 +65,9 @@
if(src.camera && !scrambledcodes)
if(src.stat == 2 || wires.IsIndexCut(BORG_WIRE_CAMERA))
- src.camera.status = 0
+ src.camera.set_status(0)
else
- src.camera.status = 1
+ src.camera.set_status(1)
updatehealth()
@@ -163,11 +163,13 @@
see_invisible = SEE_INVISIBLE_MINIMUM
else if (src.sight_mode & BORGTHERM)
src.sight |= SEE_MOBS
+ src.see_in_dark = 8
src.see_invisible = SEE_INVISIBLE_LEVEL_TWO
else if (src.stat != 2)
src.sight &= ~SEE_MOBS
src.sight &= ~SEE_TURFS
src.sight &= ~SEE_OBJS
+ src.see_in_dark = 8 // see_in_dark means you can FAINTLY see in the dark, humans have a range of 3 or so, tajaran have it at 8
src.see_invisible = SEE_INVISIBLE_LIVING // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness
// has a "invisible" value of 15
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 82a9426b77..6f434257f4 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -182,7 +182,7 @@
aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src)
laws = new /datum/ai_laws/syndicate_override
- module = new /obj/item/weapon/robot_module/syndicate(src)
+ new /obj/item/weapon/robot_module/syndicate(src)
radio.keyslot = new /obj/item/device/encryptionkey/syndicate(radio)
radio.recalculateChannels()
@@ -263,7 +263,7 @@
return
var/module_type = robot_modules[modtype]
- module = new module_type(src)
+ new module_type(src)
hands.icon_state = lowertext(modtype)
feedback_inc("cyborg_[lowertext(modtype)]",1)
@@ -421,8 +421,7 @@
// update the status screen display
/mob/living/silicon/robot/Stat()
..()
- statpanel("Status")
- if (client.statpanel == "Status")
+ if (statpanel("Status"))
show_cell_power()
show_jetpack_pressure()
stat(null, text("Lights: [lights_on ? "ON" : "OFF"]"))
@@ -1049,25 +1048,25 @@
laws = new /datum/ai_laws/syndicate_override
var/time = time2text(world.realtime,"hh:mm:ss")
lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
- set_zeroth_law("Only [user.real_name] and people he designates as being such are operatives.")
+ set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.")
. = 1
spawn()
- src << "\red ALERT: Foreign software detected."
+ src << "ALERT: Foreign software detected."
sleep(5)
- src << "\red Initiating diagnostics..."
+ src << "Initiating diagnostics..."
sleep(20)
- src << "\red SynBorg v1.7.1 loaded."
+ src << "SynBorg v1.7.1 loaded."
sleep(5)
- src << "\red LAW SYNCHRONISATION ERROR"
+ src << "LAW SYNCHRONISATION ERROR"
sleep(5)
- src << "\red Would you like to send a report to NanoTraSoft? Y/N"
+ src << "Would you like to send a report to NanoTraSoft? Y/N"
sleep(10)
- src << "\red > N"
+ src << "> N"
sleep(20)
- src << "\red ERRORERRORERROR"
+ src << "ERRORERRORERROR"
src << "Obey these laws:"
laws.show_laws(src)
- src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
+ src << "ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
if(src.module)
var/rebuild = 0
for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules)
@@ -1081,4 +1080,4 @@
user << "You fail to hack [src]'s interface."
src << "Hack attempt detected."
return 1
- return
+ return
diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm
index 96514fa671..ade9bf0f93 100644
--- a/code/modules/mob/living/silicon/robot/robot_items.dm
+++ b/code/modules/mob/living/silicon/robot/robot_items.dm
@@ -36,7 +36,7 @@
for(var/obj/I in contents)
for(var/mob/M in I.contents)
M.death()
- if(istype(I,/obj/item/stack/material))//Only deconsturcts one sheet at a time instead of the entire stack
+ if(istype(I,/obj/item/stack/material))//Only deconstructs one sheet at a time instead of the entire stack
var/obj/item/stack/material/S = I
if(S.get_amount() > 1)
S.use(1)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index a338588df0..819fbf4561 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -39,6 +39,8 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/New(var/mob/living/silicon/robot/R)
..()
+ R.module = src
+
add_camera_networks(R)
add_languages(R)
add_subsystems(R)
@@ -69,7 +71,7 @@ var/global/list/robot_modules = list(
synths = null
emag = null
jetpack = null
- ..()
+ return ..()
/obj/item/weapon/robot_module/emp_act(severity)
if(modules)
@@ -504,7 +506,7 @@ var/global/list/robot_modules = list(
src.modules += L
src.modules += new /obj/item/weapon/tray/robotray(src)
- src.modules += new /obj/item/weapon/reagent_containers/food/drinks/shaker(src)
+ src.modules += new /obj/item/weapon/reagent_containers/borghypo/service(src)
src.emag = new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src)
var/datum/reagents/R = new/datum/reagents(50)
diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm
index 1fefa272e5..25052354ed 100644
--- a/code/modules/mob/living/silicon/say.dm
+++ b/code/modules/mob/living/silicon/say.dm
@@ -1,3 +1,35 @@
+/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
+ log_say("[key_name(src)] : [message]")
+
+/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
+ ..()
+ if(message_mode)
+ if(!is_component_functioning("radio"))
+ src << "Your radio isn't functional at this time."
+ return 0
+ if(message_mode == "general")
+ message_mode = null
+ return radio.talk_into(src,message,message_mode,verb,speaking)
+
+/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
+ ..()
+ if(message_mode == "department")
+ return holopad_talk(message, verb, speaking)
+ else if(message_mode)
+ if (aiRadio.disabledAi || aiRestorePowerRoutine || stat)
+ src << "System Error - Transceiver Disabled."
+ return 0
+ if(message_mode == "general")
+ message_mode = null
+ return aiRadio.talk_into(src,message,message_mode,verb,speaking)
+
+/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
+ ..()
+ if(message_mode)
+ if(message_mode == "general")
+ message_mode = null
+ return radio.talk_into(src,message,message_mode,verb,speaking)
+
/mob/living/silicon/say_quote(var/text)
var/ending = copytext(text, length(text))
@@ -23,131 +55,6 @@
return 1
return ..()
-/mob/living/silicon/say(var/message)
- if (!message)
- return 0
-
- if (src.client)
- if(client.prefs.muted & MUTE_IC)
- src << "You cannot send IC messages (muted)."
- return 0
- if (src.client.handle_spam_prevention(message,MUTE_IC))
- return 0
-
- message = sanitize(message)
-
- if (stat == 2)
- return say_dead(message)
-
- if(copytext(message,1,2) == "*")
- return emote(copytext(message,2))
-
- var/bot_type = 0 //Let's not do a fuck ton of type checks, thanks.
- if(istype(src, /mob/living/silicon/ai))
- bot_type = IS_AI
- else if(istype(src, /mob/living/silicon/robot))
- bot_type = IS_ROBOT
- else if(istype(src, /mob/living/silicon/pai))
- bot_type = IS_PAI
-
- var/mob/living/silicon/ai/AI = src //and let's not declare vars over and over and over for these guys.
- var/mob/living/silicon/robot/R = src
- var/mob/living/silicon/pai/P = src
-
- //Must be concious to speak
- if (stat)
- return 0
-
- var/verb = say_quote(message)
-
- //parse radio key and consume it
- var/message_mode = parse_message_mode(message, "general")
- if (message_mode)
- if (message_mode == "general")
- message = trim(copytext(message,2))
- else
- message = trim(copytext(message,3))
-
- //parse language key and consume it
- var/datum/language/speaking = parse_language(message)
- if (speaking)
- verb = speaking.speech_verb
- message = trim(copytext(message,2+length(speaking.key)))
-
- if(speaking.flags & HIVEMIND)
- speaking.broadcast(src,trim(message))
- return 1
-
- // Currently used by drones.
- if(local_transmit)
- var/list/listeners = hearers(5,src)
- listeners |= src
-
- for(var/mob/living/silicon/D in listeners)
- if(D.client && istype(D,src.type))
- D << "[src] transmits, \"[message]\""
-
- for (var/mob/M in player_list)
- if (istype(M, /mob/new_player))
- continue
- else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
- if(M.client) M << "[src] transmits, \"[message]\""
- return 1
-
- if(message_mode && bot_type == IS_ROBOT && !R.is_component_functioning("radio"))
- src << "\red Your radio isn't functional at this time."
- return 0
-
- switch(message_mode)
- if("department")
- switch(bot_type)
- if(IS_AI)
- return AI.holopad_talk(message, verb, speaking)
- if(IS_ROBOT)
- log_say("[key_name(src)] : [message]")
- return R.radio.talk_into(src,message,message_mode,verb,speaking)
- if(IS_PAI)
- log_say("[key_name(src)] : [message]")
- return P.radio.talk_into(src,message,message_mode,verb,speaking)
- return 0
-
- if("general")
- switch(bot_type)
- if(IS_AI)
- if (AI.aiRadio.disabledAi || AI.aiRestorePowerRoutine || AI.stat)
- src << "\red System Error - Transceiver Disabled"
- return 0
- else
- log_say("[key_name(src)] : [message]")
- return AI.aiRadio.talk_into(src,message,null,verb,speaking)
- if(IS_ROBOT)
- log_say("[key_name(src)] : [message]")
- return R.radio.talk_into(src,message,null,verb,speaking)
- if(IS_PAI)
- log_say("[key_name(src)] : [message]")
- return P.radio.talk_into(src,message,null,verb,speaking)
- return 0
-
- else
- if(message_mode)
- switch(bot_type)
- if(IS_AI)
- if (AI.aiRadio.disabledAi || AI.aiRestorePowerRoutine || AI.stat)
- src << "\red System Error - Transceiver Disabled"
- return 0
- else
- log_say("[key_name(src)] : [message]")
- return AI.aiRadio.talk_into(src,message,message_mode,verb,speaking)
- if(IS_ROBOT)
- log_say("[key_name(src)] : [message]")
- return R.radio.talk_into(src,message,message_mode,verb,speaking)
- if(IS_PAI)
- log_say("[key_name(src)] : [message]")
- return P.radio.talk_into(src,message,message_mode,verb,speaking)
- return 0
-
- return ..(message,speaking,verb)
-
//For holopads only. Usable by AI.
/mob/living/silicon/ai/proc/holopad_talk(var/message, verb, datum/language/speaking)
diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm
index 847ba4909d..de7d397f86 100644
--- a/code/modules/mob/living/simple_animal/constructs/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm
@@ -27,6 +27,7 @@
show_stat_health = 1
faction = "cult"
supernatural = 1
+ see_invisible = SEE_INVISIBLE_NOLIGHTING
var/nullblock = 0
mob_swap_flags = HUMAN|SIMPLE_ANIMAL|SLIME|MONKEY
@@ -150,6 +151,7 @@
attacktext = "slashed"
speed = -1
environment_smash = 1
+ see_in_dark = 7
attack_sound = 'sound/weapons/rapidslice.ogg'
construct_spells = list(/spell/targeted/ethereal_jaunt/shift)
@@ -227,6 +229,7 @@
attacktext = "violently stabbed"
speed = -1
environment_smash = 1
+ see_in_dark = 7
attack_sound = 'sound/weapons/pierce.ogg'
construct_spells = list(
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 9c78b95522..3197c6023c 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -11,6 +11,7 @@
emote_see = list("shakes their head", "shivers")
speak_chance = 1
turns_per_move = 5
+ see_in_dark = 6
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
response_help = "pets"
response_disarm = "gently pushes aside"
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm
index e5a670d472..322d08dc9f 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm
@@ -17,6 +17,7 @@
response_help = "pets"
response_disarm = "bops"
response_harm = "kicks"
+ see_in_dark = 5
mob_size = 8
var/obj/item/inventory_head
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index c619250388..60ddd0638b 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -11,6 +11,7 @@
emote_see = list("shakes its head", "stamps a foot", "glares around")
speak_chance = 1
turns_per_move = 5
+ see_in_dark = 6
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
meat_amount = 4
response_help = "pets"
@@ -95,6 +96,7 @@
emote_see = list("shakes its head")
speak_chance = 1
turns_per_move = 5
+ see_in_dark = 6
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
meat_amount = 6
response_help = "pets"
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 6424087631..70f7282b8e 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -13,6 +13,7 @@
small = 1
speak_chance = 1
turns_per_move = 5
+ see_in_dark = 6
maxHealth = 5
health = 5
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index b673aee9f0..73de95acee 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -12,6 +12,7 @@
emote_see = list("stares ferociously", "stomps")
speak_chance = 1
turns_per_move = 5
+ see_in_dark = 6
meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat
response_help = "pets"
response_disarm = "gently pushes aside"
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 a6da79247f..bf4ea6b572 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -15,6 +15,7 @@
emote_hear = list("chitters")
speak_chance = 5
turns_per_move = 5
+ see_in_dark = 10
meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat
response_help = "pets"
response_disarm = "gently pushes aside"
@@ -212,4 +213,4 @@
#undef SPINNING_WEB
#undef LAYING_EGGS
#undef MOVING_TO_TARGET
-#undef SPINNING_COCOON
+#undef SPINNING_COCOON
diff --git a/code/modules/mob/living/simple_animal/kobold.dm b/code/modules/mob/living/simple_animal/kobold.dm
index f634bd70f1..3e52a40874 100644
--- a/code/modules/mob/living/simple_animal/kobold.dm
+++ b/code/modules/mob/living/simple_animal/kobold.dm
@@ -12,6 +12,7 @@
emote_see = list("looks around suspiciously.", "scratches it's arm.","putters around a bit.")
speak_chance = 15
turns_per_move = 5
+ see_in_dark = 6
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/monkey
response_help = "pets"
response_disarm = "gently pushes aside"
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 4407773119..10a8daa868 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -2,7 +2,15 @@
mob_list -= src
dead_mob_list -= src
living_mob_list -= src
+ unset_machine()
qdel(hud_used)
+ if(client)
+ for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
+ qdel(spell_master)
+ remove_screen_obj_references()
+ for(var/atom/movable/AM in client.screen)
+ qdel(AM)
+ client.screen = list()
if(mind && mind.current == src)
spellremove(src)
for(var/infection in viruses)
@@ -10,6 +18,32 @@
ghostize()
..()
+/mob/proc/remove_screen_obj_references()
+ flash = null
+ blind = null
+ hands = null
+ pullin = null
+ purged = null
+ internals = null
+ oxygen = null
+ i_select = null
+ m_select = null
+ toxin = null
+ fire = null
+ bodytemp = null
+ healths = null
+ throw_icon = null
+ nutrition_icon = null
+ pressure = null
+ damageoverlay = null
+ pain = null
+ item_use_icon = null
+ gun_move_icon = null
+ gun_run_icon = null
+ gun_setting_icon = null
+ spell_masters = null
+ zone_sel = null
+
/mob/New()
mob_list += src
if(stat == DEAD)
@@ -617,31 +651,35 @@
/mob/Stat()
..()
+ . = (client && client.inactivity < 1200)
- if(client && client.holder)
- if(statpanel("Status"))
- statpanel("Status","Location:","([x], [y], [z])")
- statpanel("Status","CPU:","[world.cpu]")
- statpanel("Status","Instances:","[world.contents.len]")
- if(statpanel("Status") && processScheduler && processScheduler.getIsRunning())
- for(var/datum/controller/process/P in processScheduler.processes)
- statpanel("Status",P.getStatName(), P.getTickTime())
- else
- statpanel("Status","processScheduler is not running.")
+ if(.)
+ if(client.holder)
+ if(statpanel("Status"))
+ statpanel("Status","Location:","([x], [y], [z])")
+ statpanel("Status","CPU:","[world.cpu]")
+ statpanel("Status","Instances:","[world.contents.len]")
+ if(statpanel("Status") && processScheduler && processScheduler.getIsRunning())
+ for(var/datum/controller/process/P in processScheduler.processes)
+ statpanel("Status",P.getStatName(), P.getTickTime())
+ else
+ statpanel("Status","processScheduler is not running.")
- if(listed_turf && client)
- if(!TurfAdjacent(listed_turf))
- listed_turf = null
- else
- statpanel(listed_turf.name, null, listed_turf)
- for(var/atom/A in listed_turf)
- if(!A.mouse_opacity)
- continue
- if(A.invisibility > see_invisible)
- continue
- if(is_type_in_list(A, shouldnt_see))
- continue
- statpanel(listed_turf.name, null, A)
+ if(listed_turf && client)
+ if(!TurfAdjacent(listed_turf))
+ listed_turf = null
+ else
+ statpanel(listed_turf.name, null, listed_turf)
+ for(var/atom/A in listed_turf)
+ if(!A.mouse_opacity)
+ continue
+ if(A.invisibility > see_invisible)
+ continue
+ if(is_type_in_list(A, shouldnt_see))
+ continue
+ statpanel(listed_turf.name, null, A)
+
+ sleep(4) //Prevent updating the stat panel for the next .4 seconds, prevents clientside latency from updates
// facing verbs
/mob/proc/canface()
@@ -1048,4 +1086,4 @@ mob/proc/yank_out_object()
/mob/proc/throw_mode_on()
src.in_throw_mode = 1
if(src.throw_icon)
- src.throw_icon.icon_state = "act_throw_on"
\ No newline at end of file
+ src.throw_icon.icon_state = "act_throw_on"
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 934e89bc06..cee9e723a4 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -2,7 +2,6 @@
density = 1
layer = 4.0
animate_movement = 2
- see_in_dark = 0
// flags = NOREACT
var/datum/mind/mind
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index 60d2bf419b..acc95fbe40 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -351,6 +351,11 @@
if(I_HURT)
if(hit_zone == "eyes")
+ var/mob/living/carbon/human/H = affecting
+ var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone)
+ if(!attack)
+ return
+
if(state < GRAB_NECK)
assailant << "You require a better grab to do this."
return
@@ -362,16 +367,11 @@
if(!affecting.has_eyes())
assailant << "You cannot locate any eyes on [affecting]!"
return
- assailant.visible_message("[assailant] pressed \his fingers into [affecting]'s eyes!")
- affecting << "You experience immense pain as you feel digits being pressed into your eyes!"
- assailant.attack_log += text("\[[time_stamp()]\] Pressed fingers into the eyes of [affecting.name] ([affecting.ckey])")
- affecting.attack_log += text("\[[time_stamp()]\] Had fingers pressed into their eyes by [assailant.name] ([assailant.ckey])")
- msg_admin_attack("[key_name(assailant)] has pressed his fingers into [key_name(affecting)]'s eyes.")
- var/obj/item/organ/eyes/eyes = affecting:internal_organs_by_name["eyes"]
- eyes.damage += rand(3,4)
- if (eyes.damage >= eyes.min_broken_damage)
- if(affecting.stat != 2)
- affecting << "\red You go blind!"
+ assailant.attack_log += text("\[[time_stamp()]\] Attacked [affecting.name]'s eyes using grab ([affecting.ckey])")
+ affecting.attack_log += text("\[[time_stamp()]\] Had eyes attacked by [assailant.name]'s grab ([assailant.ckey])")
+ msg_admin_attack("[key_name(assailant)] attacked [key_name(affecting)]'s eyes using a grab action.")
+
+ attack.handle_eye_attack(assailant, affecting)
else if(hit_zone != "head")
if(state < GRAB_NECK)
assailant << "You require a better grab to do this."
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index b496a554b4..c9998888f5 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -268,11 +268,11 @@ var/list/global/organ_rel_size = list(
/proc/get_zone_with_miss_chance(zone, var/mob/target, var/miss_chance_mod = 0, var/ranged_attack=0)
zone = check_zone(zone)
- // you cannot miss if your target is prone or restrained
- if(target.buckled || target.lying)
- return zone
- // if your target is being grabbed aggressively by someone you cannot miss either
if(!ranged_attack)
+ // you cannot miss if your target is prone or restrained
+ if(target.buckled || target.lying)
+ return zone
+ // if your target is being grabbed aggressively by someone you cannot miss either
for(var/obj/item/weapon/grab/G in target.grabbed_by)
if(G.state >= GRAB_AGGRESSIVE)
return zone
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 8ba66ffe31..bb333b82c5 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -449,17 +449,10 @@
/mob/proc/Process_Spacemove(var/check_drift = 0)
if(!Check_Dense_Object()) //Nothing to push off of so end here
- make_floating(1)
+ update_floating(0)
return 0
- if(istype(src,/mob/living/carbon/human/))
- var/mob/living/carbon/human/H = src
- if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.flags & NOSLIP)) //magboots + dense_object = no floaty effect
- make_floating(0)
- else
- make_floating(1)
- else
- make_floating(1)
+ update_floating(1)
if(restrained()) //Check to see if we can do things
return 0
@@ -477,6 +470,8 @@
/mob/proc/Check_Dense_Object() //checks for anything to push off in the vicinity. also handles magboots on gravity-less floors tiles
var/dense_object = 0
+ var/shoegrip
+
for(var/turf/turf in oview(1,src))
if(istype(turf,/turf/space))
continue
@@ -484,14 +479,9 @@
if(istype(turf,/turf/simulated/floor)) // Floors don't count if they don't have gravity
var/area/A = turf.loc
if(istype(A) && A.has_gravity == 0)
- var/can_walk = 0
-
- if(ishuman(src)) // Only humans can wear magboots, so we give them a chance to.
- var/mob/living/carbon/human/H = src
- if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.flags & NOSLIP))
- can_walk = 1
-
- if(!can_walk)
+ if(shoegrip == null)
+ shoegrip = Check_Shoegrip() //Shoegrip is only ever checked when a zero-gravity floor is encountered to reduce load
+ if(!shoegrip)
continue
dense_object++
@@ -511,6 +501,8 @@
return dense_object
+/mob/proc/Check_Shoegrip()
+ return 0
/mob/proc/Process_Spaceslipping(var/prob_slip = 5)
//Setup slipage
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 4d3f68ceec..45698b5e9d 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -5,7 +5,6 @@
var/spawning = 0//Referenced when you want to delete the new_player later on in the code.
var/totalPlayers = 0 //Player counts for the Lobby tab
var/totalPlayersReady = 0
-
universal_speak = 1
invisibility = 101
@@ -134,8 +133,6 @@
if(client.prefs.be_random_name)
client.prefs.real_name = random_name(client.prefs.gender)
- if(client.prefs.dummy)
- qdel(client.prefs.dummy)
observer.real_name = client.prefs.real_name
observer.name = observer.real_name
if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
@@ -442,12 +439,12 @@
new_character.lastarea = get_area(loc)
- var/datum/language/chosen_language
- if(client.prefs.language)
- chosen_language = all_languages["[client.prefs.language]"]
- if(chosen_language)
- if(is_alien_whitelisted(src, client.prefs.language) || !config.usealienwhitelist || !(chosen_language.flags & WHITELISTED) || (new_character.species && (chosen_language.name in new_character.species.secondary_langs)))
- new_character.add_language("[client.prefs.language]")
+ for(var/lang in client.prefs.alternate_languages)
+ var/datum/language/chosen_language = all_languages[lang]
+ if(chosen_language)
+ if(!config.usealienwhitelist || !(chosen_language.flags & WHITELISTED) || is_alien_whitelisted(src, lang) || has_admin_rights() \
+ || (new_character.species && (chosen_language.name in new_character.species.secondary_langs)))
+ new_character.add_language(lang)
if(ticker.random_players)
new_character.gender = pick(MALE, FEMALE)
@@ -455,8 +452,7 @@
client.prefs.randomize_appearance_for(new_character)
else
client.prefs.copy_to(new_character)
- if(client.prefs.dummy)
- qdel(client.prefs.dummy)
+
src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS cant last forever yo
if(mind)
diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm
index d3800f5b02..00b6a3b8e4 100644
--- a/code/modules/mob/new_player/preferences_setup.dm
+++ b/code/modules/mob/new_player/preferences_setup.dm
@@ -178,46 +178,519 @@ datum/preferences
b_skin = blue
- proc/update_preview_icon() //seriously. This is horrendous. //less so now
- if(!dummy)
- dummy = new(null, species)
- dummy.set_species(species)
- dummy.flags |= GODMODE
- copy_to(dummy)
- for (var/obj/item/I in dummy)
- dummy.drop_from_inventory(I)
- if(I.loc != dummy)
- qdel(I)
- var/jobflag
- var/dept
- if (job_civilian_low & ASSISTANT)
- jobflag = job_civilian_low
- dept = CIVILIAN
- else if(job_civilian_high)
- jobflag = job_civilian_high
- dept = CIVILIAN
- else if (job_medsci_high)
- jobflag = job_medsci_high
- dept = MEDSCI
- else if (job_engsec_high)
- jobflag = job_engsec_high
- dept = ENGSEC
- if(jobflag && dept && job_master)
- for (var/datum/job/J in job_master.occupations)
- if((J.department_flag & dept) && (J.flag & jobflag))
- var/alt = GetPlayerAltTitle(J)
- if(alt) //more hacks
- if(!dummy.mind)
- dummy.mind = new
- dummy.mind.role_alt_title = alt
- J.equip_preview(dummy)
- break
- dummy.update_eyes()
- dummy.force_update_limbs()
- dummy.regenerate_icons()
- preview_icon = icon(dummy.icon)
- for(var/image/I in dummy.overlays_standing)
- if(I && I.icon)
- preview_icon.Blend(icon(I.icon, I.icon_state), ICON_OVERLAY)
+ proc/update_preview_icon() //seriously. This is horrendous.
+ qdel(preview_icon_front)
+ qdel(preview_icon_side)
+ qdel(preview_icon)
+
+ var/g = "m"
+ if(gender == FEMALE) g = "f"
+
+ var/icon/icobase
+ var/datum/species/current_species = all_species[species]
+
+ if(current_species)
+ icobase = current_species.icobase
+ else
+ icobase = 'icons/mob/human_races/r_human.dmi'
+
+ preview_icon = new /icon(icobase, "torso_[g]")
+ preview_icon.Blend(new /icon(icobase, "groin_[g]"), ICON_OVERLAY)
+ preview_icon.Blend(new /icon(icobase, "head_[g]"), ICON_OVERLAY)
+
+ for(var/name in list("r_arm","r_hand","r_leg","r_foot","l_leg","l_foot","l_arm","l_hand"))
+ if(organ_data[name] == "amputated") continue
+ if(organ_data[name] == "cyborg")
+ var/datum/robolimb/R
+ if(rlimb_data[name]) R = all_robolimbs[rlimb_data[name]]
+ if(!R) R = basic_robolimb
+ preview_icon.Blend(icon(R.icon, "[name]"), ICON_OVERLAY) // This doesn't check gendered_icon. Not an issue while only limbs can be robotic.
+ continue
+ preview_icon.Blend(new /icon(icobase, "[name]"), ICON_OVERLAY)
+
+ //Tail
+ if(current_species && (current_species.tail))
+ var/icon/temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[current_species.tail]_s")
+ preview_icon.Blend(temp, ICON_OVERLAY)
+
+ // Skin color
+ if(current_species && (current_species.flags & HAS_SKIN_COLOR))
+ preview_icon.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD)
+
+ // Skin tone
+ if(current_species && (current_species.flags & HAS_SKIN_TONE))
+ if (s_tone >= 0)
+ preview_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD)
+ else
+ preview_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT)
+
+ var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = current_species ? current_species.eyes : "eyes_s")
+ if ((current_species && (current_species.flags & HAS_EYE_COLOR)))
+ eyes_s.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD)
+
+ var/datum/sprite_accessory/hair_style = hair_styles_list[h_style]
+ if(hair_style)
+ var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
+ hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD)
+ eyes_s.Blend(hair_s, ICON_OVERLAY)
+
+ var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style]
+ if(facial_hair_style)
+ var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
+ facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD)
+ eyes_s.Blend(facial_s, ICON_OVERLAY)
+
+ var/icon/underwear_s = null
+ if(underwear && current_species.flags & HAS_UNDERWEAR)
+ underwear_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = underwear)
+
+ var/icon/undershirt_s = null
+ if(undershirt && current_species.flags & HAS_UNDERWEAR)
+ undershirt_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = undershirt)
+
+ var/icon/clothes_s = null
+ if(job_civilian_low & ASSISTANT)//This gives the preview icon clothes depending on which job(if any) is set to 'high'
+ clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if(backbag == 2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ else if(backbag == 3 || backbag == 4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+
+ else if(job_civilian_high)//I hate how this looks, but there's no reason to go through this switch if it's empty
+ switch(job_civilian_high)
+ if(HOP)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "hop_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "ianshirt"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(BARTENDER)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "ba_suit_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "tophat"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(BOTANIST)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "hydroponics_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "ggloves"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "apron"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "nymph"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-hyd"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CHEF)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chef_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "chefhat"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "apronchef"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(JANITOR)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "janitor_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "bio_janitor"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(LIBRARIAN)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "red_suit_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "hairflower"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(QUARTERMASTER)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "qm_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "poncho"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CARGOTECH)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "cargotech_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "flat_cap"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(MINER)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "miner_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "bearpelt"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(LAWYER)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "internalaffairs_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "briefcase"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "suitjacket_blue"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CHAPLAIN)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chapblack_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "imperium_monk"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CLOWN)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "clown_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "clown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/mask.dmi', "clown"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "clownpack"), ICON_OVERLAY)
+ if(MIME)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "mime_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "lgloves"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/mask.dmi', "mime"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "beret"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "suspenders"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+
+ else if(job_medsci_high)
+ switch(job_medsci_high)
+ if(RD)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "director_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "petehat"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(SCIENTIST)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "metroid"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(XENOBIOLOGIST)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "metroid"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CHEMIST)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chemistrywhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labgreen"), ICON_OVERLAY)
+ else
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_chem_open"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-chem"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CMO)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "cmo_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "bio_cmo"), ICON_OVERLAY)
+ else
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_cmo_open"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-med"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(DOCTOR)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "medical_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "surgeon"), ICON_OVERLAY)
+ else
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-med"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(GENETICIST)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "geneticswhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "monkeysuit"), ICON_OVERLAY)
+ else
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_gen_open"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-gen"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(VIROLOGIST)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "virologywhite_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/mask.dmi', "sterile"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_vir_open"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "plaguedoctor"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-vir"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(ROBOTICIST)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "robotics_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "toolbox_blue"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+
+ else if(job_engsec_high)
+ switch(job_engsec_high)
+ if(CAPTAIN)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "captain_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "centcomcaptain"), ICON_OVERLAY)
+ else
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "captain"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-cap"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(HOS)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "hosred_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "hosberet"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(WARDEN)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "warden_s")
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "slippers_worn"), ICON_OVERLAY)
+ else
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(DETECTIVE)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "detective_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/mask.dmi', "cigaron"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "detective"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "detective"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(OFFICER)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "secred_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "officerberet"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CHIEF)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "chief_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "hardhat0_white"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "blueprints"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "engiepack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(ENGINEER)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "engine_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "orange"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "hardhat0_yellow"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "hazard"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "engiepack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(ATMOSTECH)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "atmos_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY)
+ if(prob(1))
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "firesuit"), ICON_OVERLAY)
+ switch(backbag)
+ if(2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ if(3)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY)
+ if(4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+
+ if(AI)//Gives AI and borgs assistant-wear, so they can still customize their character
+ clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "straight_jacket"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "cardborg_h"), ICON_OVERLAY)
+ if(backbag == 2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ else if(backbag == 3 || backbag == 4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+ if(CYBORG)
+ clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s")
+ clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
+ clothes_s.Blend(new /icon('icons/mob/suit.dmi', "cardborg"), ICON_OVERLAY)
+ clothes_s.Blend(new /icon('icons/mob/head.dmi', "cardborg_h"), ICON_OVERLAY)
+ if(backbag == 2)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
+ else if(backbag == 3 || backbag == 4)
+ clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
+
+ if(disabilities & NEARSIGHTED)
+ preview_icon.Blend(new /icon('icons/mob/eyes.dmi', "glasses"), ICON_OVERLAY)
+
+ preview_icon.Blend(eyes_s, ICON_OVERLAY)
+ if(underwear_s)
+ preview_icon.Blend(underwear_s, ICON_OVERLAY)
+ if(undershirt_s)
+ preview_icon.Blend(undershirt_s, ICON_OVERLAY)
+ if(clothes_s)
+ preview_icon.Blend(clothes_s, ICON_OVERLAY)
preview_icon_front = new(preview_icon, dir = SOUTH)
- preview_icon_side = new(preview_icon, dir = WEST)
\ No newline at end of file
+ preview_icon_side = new(preview_icon, dir = WEST)
+
+ qdel(eyes_s)
+ qdel(underwear_s)
+ qdel(undershirt_s)
+ qdel(clothes_s)
diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm
index 958808234f..a6ae6dc4a0 100644
--- a/code/modules/mob/update_icons.dm
+++ b/code/modules/mob/update_icons.dm
@@ -1,15 +1,6 @@
//Most of these are defined at this level to reduce on checks elsewhere in the code.
//Having them here also makes for a nice reference list of the various overlay-updating procs available
-//default item on-mob icons
-#define INV_HEAD_DEF_ICON 'icons/mob/head.dmi'
-#define INV_BACK_DEF_ICON 'icons/mob/back.dmi'
-#define INV_L_HAND_DEF_ICON 'icons/mob/items/lefthand.dmi'
-#define INV_R_HAND_DEF_ICON 'icons/mob/items/righthand.dmi'
-#define INV_W_UNIFORM_DEF_ICON 'icons/mob/uniform.dmi'
-#define INV_ACCESSORIES_DEF_ICON 'icons/mob/ties.dmi'
-#define INV_SUIT_DEF_ICON 'icons/mob/suit.dmi'
-
/mob/proc/regenerate_icons() //TODO: phase this out completely if possible
return
diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm
index aa692e0a23..79c08227d5 100644
--- a/code/modules/nano/interaction/default.dm
+++ b/code/modules/nano/interaction/default.dm
@@ -15,7 +15,7 @@
return STATUS_UPDATE // Ghosts can view updates
/mob/living/silicon/pai/default_can_use_topic(var/src_object)
- if(src_object == src && !stat)
+ if((src_object == src || src_object == radio) && !stat)
return STATUS_INTERACTIVE
else
return ..()
diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm
index 340e049763..4074ea1b92 100644
--- a/code/modules/nano/modules/crew_monitor.dm
+++ b/code/modules/nano/modules/crew_monitor.dm
@@ -1,19 +1,12 @@
/datum/nano_module/crew_monitor
name = "Crew monitor"
- var/list/tracked = new
/datum/nano_module/crew_monitor/Topic(href, href_list)
- if(..()) return
- var/turf/T = get_turf(src)
+ if(..()) return 1
+ var/turf/T = get_turf(nano_host()) // TODO: Allow setting any config.contact_levels from the interface.
if (!T || !(T.z in config.player_levels))
usr << "Unable to establish a connection: You're too far away from the station!"
return 0
- if(href_list["close"] )
- var/mob/user = usr
- var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
- usr.unset_machine()
- ui.close()
- return 0
if(href_list["track"])
if(usr.isMobAI())
var/mob/living/silicon/ai/AI = usr
@@ -23,51 +16,11 @@
return 1
/datum/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- user.set_machine(src)
- src.scan()
-
var/data[0]
- var/turf/T = get_turf(src)
- var/list/crewmembers = list()
- for(var/obj/item/clothing/under/C in src.tracked)
-
- var/turf/pos = get_turf(C)
-
- if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
- if(istype(C.loc, /mob/living/carbon/human))
-
- var/mob/living/carbon/human/H = C.loc
- if(H.w_uniform != C)
- continue
-
- var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
-
- crewmemberData["sensor_type"] = C.sensor_mode
- crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
- crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
- crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
-
- if(C.sensor_mode >= SUIT_SENSOR_BINARY)
- crewmemberData["dead"] = H.stat > 1
-
- if(C.sensor_mode >= SUIT_SENSOR_VITAL)
- crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
- crewmemberData["tox"] = round(H.getToxLoss(), 1)
- crewmemberData["fire"] = round(H.getFireLoss(), 1)
- crewmemberData["brute"] = round(H.getBruteLoss(), 1)
-
- if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
- var/area/A = get_area(H)
- crewmemberData["area"] = sanitize(A.name)
- crewmemberData["x"] = pos.x
- crewmemberData["y"] = pos.y
-
- crewmembers[++crewmembers.len] = crewmemberData
-
- crewmembers = sortByKey(crewmembers, "name")
+ var/turf/T = get_turf(nano_host())
data["isAI"] = user.isMobAI()
- data["crewmembers"] = crewmembers
+ data["crewmembers"] = crew_repository.health_data(T)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
@@ -84,10 +37,11 @@
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
-/datum/nano_module/crew_monitor/proc/scan()
+/*/datum/nano_module/crew_monitor/proc/scan()
for(var/mob/living/carbon/human/H in mob_list)
if(istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/C = H.w_uniform
if (C.has_sensor)
tracked |= C
return 1
+*/
\ No newline at end of file
diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm
index 3b3deff06c..4486a0fb82 100644
--- a/code/modules/nano/modules/human_appearance.dm
+++ b/code/modules/nano/modules/human_appearance.dm
@@ -155,5 +155,5 @@
if(!valid_species.len)
valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist)
if(!valid_hairstyles.len || !valid_facial_hairstyles.len)
- valid_hairstyles = owner.generate_valid_hairstyles()
- valid_facial_hairstyles = owner.generate_valid_facial_hairstyles()
\ No newline at end of file
+ valid_hairstyles = owner.generate_valid_hairstyles(check_gender = 0)
+ valid_facial_hairstyles = owner.generate_valid_facial_hairstyles()
diff --git a/code/modules/nano/modules/law_manager.dm b/code/modules/nano/modules/law_manager.dm
index 7273938c59..798a4c4dfc 100644
--- a/code/modules/nano/modules/law_manager.dm
+++ b/code/modules/nano/modules/law_manager.dm
@@ -186,7 +186,7 @@
/datum/nano_module/law_manager/proc/package_laws(var/list/data, var/field, var/list/datum/ai_law/laws)
var/packaged_laws[0]
for(var/datum/ai_law/AL in laws)
- packaged_laws[++packaged_laws.len] = list("law" = sanitize(AL.law), "index" = AL.get_index(), "state" = owner.laws.get_state_law(AL), "ref" = "\ref[AL]")
+ packaged_laws[++packaged_laws.len] = list("law" = AL.law, "index" = AL.get_index(), "state" = owner.laws.get_state_law(AL), "ref" = "\ref[AL]")
data[field] = packaged_laws
data["has_[field]"] = packaged_laws.len
diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm
index f6325fd4f7..64c59bcefa 100644
--- a/code/modules/nano/nanomanager.dm
+++ b/code/modules/nano/nanomanager.dm
@@ -105,6 +105,26 @@
update_count++
return update_count
+ /**
+ * Close all /nanoui uis attached to src_object
+ *
+ * @param src_object /obj|/mob The obj or mob which the uis are attached to
+ *
+ * @return int The number of uis close
+ */
+/datum/nanomanager/proc/close_uis(src_object)
+ var/src_object_key = "\ref[src_object]"
+ if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return 0
+
+ var/close_count = 0
+ for (var/ui_key in open_uis[src_object_key])
+ for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
+ if(ui && ui.src_object && ui.user && ui.src_object.nano_host())
+ ui.close()
+ close_count++
+ return close_count
+
/**
* Update /nanoui uis belonging to user
*
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index 866e219811..c3f84aa85c 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -116,6 +116,9 @@ var/list/organ_cache = list()
if(B && prob(40))
reagents.remove_reagent("blood",0.1)
blood_splatter(src,B,1)
+ if(config.organs_decay) damage += rand(1,3)
+ if(damage >= max_damage)
+ damage = max_damage
germ_level += rand(2,6)
if(germ_level >= INFECTION_LEVEL_TWO)
germ_level += rand(2,6)
diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm
index a67e74c8f9..39a8a142cf 100644
--- a/code/modules/organs/organ_internal.dm
+++ b/code/modules/organs/organ_internal.dm
@@ -79,6 +79,21 @@
owner.b_eyes ? owner.b_eyes : 0
)
+/obj/item/organ/eyes/take_damage(amount, var/silent=0)
+ var/oldbroken = is_broken()
+ ..()
+ if(is_broken() && !oldbroken && owner && !owner.stat)
+ owner << "You go blind!"
+
+/obj/item/organ/eyes/process() //Eye damage replaces the old eye_stat var.
+ ..()
+ if(!owner)
+ return
+ if(is_bruised())
+ owner.eye_blurry = 20
+ if(is_broken())
+ owner.eye_blind = 20
+
/obj/item/organ/liver
name = "liver"
icon_state = "liver"
diff --git a/code/modules/organs/organ_stump.dm b/code/modules/organs/organ_stump.dm
index 4f353e193c..0ab0e145a0 100644
--- a/code/modules/organs/organ_stump.dm
+++ b/code/modules/organs/organ_stump.dm
@@ -14,7 +14,7 @@
..(holder, internal)
if(istype(limb))
max_damage = limb.max_damage
- if((limb.status & ORGAN_ROBOT) && (!parent || (parent.status & ORGAN_ROBOT)))
+ if((limb.status & ORGAN_ROBOT) && (!parent || (parent.status & ORGAN_ROBOT)))
robotize() //if both limb and the parent are robotic, the stump is robotic too
/obj/item/organ/external/stump/is_stump()
@@ -23,3 +23,6 @@
/obj/item/organ/external/stump/removed()
..()
qdel(src)
+
+/obj/item/organ/external/stump/is_usable()
+ return 0
\ No newline at end of file
diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm
index 8f39b91555..850f5114c0 100644
--- a/code/modules/organs/wound.dm
+++ b/code/modules/organs/wound.dm
@@ -36,9 +36,8 @@
var/list/stages
// internal wounds can only be fixed through surgery
var/internal = 0
- // maximum stage at which bleeding should still happen, counted from the right rather than the left of the list
- // 1 means all stages except the last should bleed
- var/max_bleeding_stage = 1
+ // maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented.
+ var/max_bleeding_stage = 0
// one of CUT, BRUISE, BURN
var/damage_type = CUT
// whether this wound needs a bandage/salve to heal at all
@@ -64,8 +63,6 @@
src.damage = damage
- max_bleeding_stage = src.desc_list.len - max_bleeding_stage
-
// initialize with the appropriate stage
src.init_stage(damage)
@@ -248,7 +245,9 @@
/** CUTS **/
/datum/wound/cut/small
// link wound descriptions to amounts of damage
- max_bleeding_stage = 2
+ // Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name.
+ // The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor).
+ max_bleeding_stage = 3
stages = list("ugly ripped cut" = 20, "ripped cut" = 10, "cut" = 5, "healing cut" = 2, "small scab" = 0)
damage_type = CUT
@@ -263,25 +262,25 @@
damage_type = CUT
/datum/wound/cut/gaping
- max_bleeding_stage = 2
- stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "large clot" = 15, "small angry scar" = 5, "small straight scar" = 0)
+ max_bleeding_stage = 3
+ stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "blood soaked clot" = 15, "small angry scar" = 5, "small straight scar" = 0)
damage_type = CUT
/datum/wound/cut/gaping_big
- max_bleeding_stage = 2
- stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large angry scar" = 10, "large straight scar" = 0)
+ max_bleeding_stage = 3
+ stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large blood soaked clot" = 25, "large angry scar" = 10, "large straight scar" = 0)
damage_type = CUT
datum/wound/cut/massive
- max_bleeding_stage = 2
- stages = list("massive wound" = 70, "massive healing wound" = 50, "massive angry scar" = 10, "massive jagged scar" = 0)
+ max_bleeding_stage = 3
+ stages = list("massive wound" = 70, "massive healing wound" = 50, "massive blood soaked clot" = 25, "massive angry scar" = 10, "massive jagged scar" = 0)
damage_type = CUT
/** BRUISES **/
/datum/wound/bruise
- stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,\
+ stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,
"moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5)
- max_bleeding_stage = 3
+ max_bleeding_stage = 3 //only large bruise and above can bleed.
autoheal_cutoff = 30
damage_type = BRUISE
@@ -311,7 +310,7 @@ datum/wound/cut/massive
internal = 1
stages = list("severed artery" = 30, "cut artery" = 20, "damaged artery" = 10, "bruised artery" = 5)
autoheal_cutoff = 5
- max_bleeding_stage = 0 //all stages bleed. It's called internal bleeding after all.
+ max_bleeding_stage = 4 //all stages bleed. It's called internal bleeding after all.
/** EXTERNAL ORGAN LOSS **/
/datum/wound/lost_limb
@@ -323,7 +322,7 @@ datum/wound/cut/massive
switch(losstype)
if(DROPLIMB_EDGE, DROPLIMB_BLUNT)
damage_type = CUT
- max_bleeding_stage = 3
+ max_bleeding_stage = 3 //clotted stump and above can bleed.
stages = list(
"ripped stump" = damage_amt*1.3,
"bloody stump" = damage_amt,
@@ -332,7 +331,6 @@ datum/wound/cut/massive
)
if(DROPLIMB_BURN)
damage_type = BURN
- max_bleeding_stage = 1
stages = list(
"ripped charred stump" = damage_amt*1.3,
"charred stump" = damage_amt,
diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm
index a0611c6866..e15de31969 100644
--- a/code/modules/overmap/ships/computers/helm.dm
+++ b/code/modules/overmap/ships/computers/helm.dm
@@ -53,11 +53,10 @@
/obj/machinery/computer/helm/check_eye(var/mob/user as mob)
if (!manual_control)
- return null
+ return -1
if (!get_dist(user, src) > 1 || user.blinded || !linked )
- return null
- user.reset_view(linked)
- return 1
+ return -1
+ return 0
/obj/machinery/computer/helm/attack_hand(var/mob/user as mob)
if(..())
@@ -67,6 +66,8 @@
if(!isAI(user))
user.set_machine(src)
+ if(linked)
+ user.reset_view(linked)
ui_interact(user)
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 46853a978c..90ed7ccf59 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -253,10 +253,9 @@ var/global/photo_count = 0
var/viewer = user
if(user.client) //To make shooting through security cameras possible
viewer = user.client.eye
- var/can_see = (dummy in viewers(world.view, viewer)) != null
+ var/can_see = (dummy in viewers(world.view, viewer))
- dummy.loc = null
- dummy = null //Alas, nameless creature //garbage collect it instead
+ qdel(dummy)
return can_see
/obj/item/device/camera/proc/captureimage(atom/target, mob/user, flag)
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 67a2010485..c1a42eeb8a 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -714,7 +714,7 @@
if(!user)
return
- if(wiresexposed /*&& (!istype(user, /mob/living/silicon))*/) //Commented out the typecheck to allow engiborgs to repair damaged apcs.
+ if(wiresexposed && !istype(user, /mob/living/silicon/ai))
wires.Interact(user)
return ui_interact(user)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 8960113159..da83d1471c 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -619,66 +619,23 @@ obj/structure/cable/proc/cableColor(var/colorC)
/obj/item/stack/cable_coil/cyborg/can_merge()
return 1
-/obj/item/stack/cable_coil/attackby(obj/item/weapon/W, mob/user)
- ..()
- if( istype(W, /obj/item/weapon/wirecutters) && src.get_amount() > 1)
- src.use(1)
- new/obj/item/stack/cable_coil(user.loc, 1,color)
- user << "You cut a piece off the cable coil."
- src.update_icon()
+/obj/item/stack/cable_coil/transfer_to(obj/item/stack/cable_coil/S)
+ if(!istype(S))
+ return
+ if(!can_merge(S))
return
- else if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/C = W
- if(!can_merge(C))
- user << "These coils do not go together."
- return
+ ..()
- if(C.get_amount() >= get_max_amount())
- user << "The coil is too long, you cannot add any more cable to it."
- return
-
- if( (C.get_amount() + src.get_amount() <= get_max_amount()) )
- user << "You join the cable coils together."
- C.give(src.get_amount()) // give it cable
- src.use(src.get_amount()) // make sure this one cleans up right
- return
-
- else
- var/amt = get_max_amount() - C.get_amount()
- user << "You transfer [amt] length\s of cable from one coil to the other."
- C.give(amt)
- src.use(amt)
- return
-
-//remove cables from the stack
-/* This is probably reduntant
-/obj/item/stack/cable_coil/use(var/used)
- if(src.amount < used)
- return 0
- else if (src.amount == used)
- if(ismob(loc)) //handle mob icon update
- var/mob/M = loc
- M.unEquip(src)
- qdel(src)
- return 1
- else
- amount -= used
- update_icon()
- return 1
-*/
-/obj/item/stack/cable_coil/use(var/used)
+/obj/item/stack/cable_coil/use()
. = ..()
update_icon()
return
-//add cables to the stack
-/obj/item/stack/cable_coil/proc/give(var/extra)
- if(amount + extra > MAXCOIL)
- amount = MAXCOIL
- else
- amount += extra
+/obj/item/stack/cable_coil/add()
+ . = ..()
update_icon()
+ return
///////////////////////////////////////////////
// Cable laying procedures
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index d5809cd823..ea5377c98b 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -251,7 +251,7 @@ var/list/solars_list = list()
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
return 1
- if(istype(W, /obj/item/stack/material/glass))
+ if(istype(W, /obj/item/stack/material) && (W.get_material_name() == "glass" || W.get_material_name() == "rglass"))
var/obj/item/stack/material/S = W
if(S.use(2))
glass_type = W.type
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 170af3b215..f1a3381737 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -1,32 +1,28 @@
/*
Defines a firing mode for a gun.
- burst number of shots fired when the gun is used
- burst_delay tick delay between shots in a burst
- fire_delay tick delay after the last shot before the gun may be used again
- move_delay tick delay after the last shot before the player may move
- dispersion dispersion of each shot in the burst measured in tiles per 7 tiles angle ratio
- accuracy accuracy modifier applied to each shot in tiles.
- applied on top of the base weapon accuracy.
+ A firemode is created from a list of fire mode settings. Each setting modifies the value of the gun var with the same name.
+ If the fire mode value for a setting is null, it will be replaced with the initial value of that gun's variable when the firemode is created.
+ Obviously not compatible with variables that take a null value. If a setting is not present, then the corresponding var will not be modified.
*/
/datum/firemode
var/name = "default"
- var/burst = 1
- var/burst_delay = null
- var/fire_delay = null
- var/move_delay = 1
- var/list/accuracy = list(0)
- var/list/dispersion = list(0)
+ var/list/settings = list()
-//using a list makes defining fire modes for new guns much nicer,
-//however we convert the lists to datums in part so that firemodes can be VVed if necessary.
-/datum/firemode/New(list/properties = null)
+/datum/firemode/New(obj/item/weapon/gun/gun, list/properties = null)
..()
if(!properties) return
- for(var/propname in vars)
- if(!isnull(properties[propname]))
- src.vars[propname] = properties[propname]
+ for(var/propname in properties)
+ var/propvalue = properties[propname]
+ if(isnull(propvalue))
+ settings[propname] = gun.vars[propname] //better than initial() as it handles list vars like burst_accuracy
+ else
+ settings[propname] = propvalue
+
+/datum/firemode/proc/apply_to(obj/item/weapon/gun/gun)
+ for(var/propname in settings)
+ gun.vars[propname] = settings[propname]
//Parent gun type. Guns are weapons that can be aimed at mobs and act over a distance
/obj/item/weapon/gun
@@ -51,8 +47,10 @@
attack_verb = list("struck", "hit", "bashed")
zoomdevicename = "scope"
+ var/burst = 1
var/fire_delay = 6 //delay after shooting before the gun can be used again
var/burst_delay = 2 //delay between shots, if firing in bursts
+ var/move_delay = 1
var/fire_sound = 'sound/weapons/Gunshot.ogg'
var/fire_sound_text = "gunshot"
var/recoil = 0 //screen shake
@@ -60,12 +58,13 @@
var/muzzle_flash = 3
var/accuracy = 0 //accuracy is measured in tiles. +1 accuracy means that everything is effectively one tile closer for the purpose of miss chance, -1 means the opposite. launchers are not supported, at the moment.
var/scoped_accuracy = null
+ var/list/burst_accuracy = list(0) //allows for different accuracies for each shot in a burst. Applied on top of accuracy
+ var/list/dispersion = list(0)
var/next_fire_time = 0
var/sel_mode = 1 //index of the currently selected mode
var/list/firemodes = list()
- var/firemode_type = /datum/firemode //for subtypes that need custom firemode data
//aiming system stuff
var/keep_aim = 1 //1 for keep shooting until aim is lowered
@@ -78,11 +77,8 @@
/obj/item/weapon/gun/New()
..()
- if(!firemodes.len)
- firemodes += new firemode_type
- else
- for(var/i in 1 to firemodes.len)
- firemodes[i] = new firemode_type(firemodes[i])
+ for(var/i in 1 to firemodes.len)
+ firemodes[i] = new /datum/firemode(src, firemodes[i])
if(isnull(scoped_accuracy))
scoped_accuracy = accuracy
@@ -156,28 +152,21 @@
user << "[src] is not ready to fire again!"
return
- //unpack firemode data
- var/datum/firemode/firemode = firemodes[sel_mode]
- var/_burst = firemode.burst
- var/_burst_delay = isnull(firemode.burst_delay)? src.burst_delay : firemode.burst_delay
- var/_fire_delay = isnull(firemode.fire_delay)? src.fire_delay : firemode.fire_delay
- var/_move_delay = firemode.move_delay
-
- var/shoot_time = (_burst - 1)*_burst_delay
+ var/shoot_time = (burst - 1)* burst_delay
user.next_move = world.time + shoot_time //no clicking on things while shooting
if(user.client) user.client.move_delay = world.time + shoot_time //no moving while shooting either
next_fire_time = world.time + shoot_time
//actually attempt to shoot
var/turf/targloc = get_turf(target) //cache this in case target gets deleted during shooting, e.g. if it was a securitron that got destroyed.
- for(var/i in 1 to _burst)
+ for(var/i in 1 to burst)
var/obj/projectile = consume_next_projectile(user)
if(!projectile)
handle_click_empty(user)
break
- var/acc = firemode.accuracy[min(i, firemode.accuracy.len)]
- var/disp = firemode.dispersion[min(i, firemode.dispersion.len)]
+ var/acc = burst_accuracy[min(i, burst_accuracy.len)]
+ var/disp = dispersion[min(i, dispersion.len)]
process_accuracy(projectile, user, target, acc, disp)
if(pointblank)
@@ -187,8 +176,8 @@
handle_post_fire(user, target, pointblank, reflex)
update_icon()
- if(i < _burst)
- sleep(_burst_delay)
+ if(i < burst)
+ sleep(burst_delay)
if(!(target && target.loc))
target = targloc
@@ -198,8 +187,8 @@
//update timing
user.next_move = world.time + 4
- if(user.client) user.client.move_delay = world.time + _move_delay
- next_fire_time = world.time + _fire_delay
+ if(user.client) user.client.move_delay = world.time + move_delay
+ next_fire_time = world.time + fire_delay
if(muzzle_flash)
set_light(0)
@@ -311,7 +300,7 @@
y_offset = rand(-1,1)
x_offset = rand(-1,1)
- return !P.launch(target, user, src, target_zone, x_offset, y_offset)
+ return !P.launch_from_gun(target, user, src, target_zone, x_offset, y_offset)
//Suicide handling.
/obj/item/weapon/gun/var/mouthshoot = 0 //To stop people from suiciding twice... >.>
@@ -379,14 +368,20 @@
var/datum/firemode/current_mode = firemodes[sel_mode]
user << "The fire selector is set to [current_mode.name]."
-/obj/item/weapon/gun/proc/switch_firemodes(mob/user=null)
+/obj/item/weapon/gun/proc/switch_firemodes()
+ if(firemodes.len <= 1)
+ return null
+
sel_mode++
if(sel_mode > firemodes.len)
sel_mode = 1
var/datum/firemode/new_mode = firemodes[sel_mode]
- user << "\The [src] is now set to [new_mode.name]."
+ new_mode.apply_to(src)
+
+ return new_mode
/obj/item/weapon/gun/attack_self(mob/user)
- if(firemodes.len > 1)
- switch_firemodes(user)
+ var/datum/firemode/new_mode = switch_firemodes(user)
+ if(new_mode)
+ user << "\The [src] is now set to [new_mode.name]."
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 05b4fd3de3..532ba47134 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -1,16 +1,9 @@
-/datum/firemode/energy
- var/projectile_type = null
- var/modifystate = null
- var/charge_cost = null
- var/fire_sound = null
-
/obj/item/weapon/gun/energy
name = "energy gun"
desc = "A basic energy-based gun."
icon_state = "energy"
fire_sound = 'sound/weapons/Taser.ogg'
fire_sound_text = "laser blast"
- firemode_type = /datum/firemode/energy
var/obj/item/weapon/cell/power_supply //What type of power cell this uses
var/charge_cost = 200 //How much energy is needed to fire.
@@ -26,15 +19,8 @@
var/recharge_time = 4
var/charge_tick = 0
-/obj/item/weapon/gun/energy/switch_firemodes(mob/user=null)
- ..()
- var/datum/firemode/energy/current_mode = firemodes[sel_mode]
- if(istype(current_mode))
- projectile_type = isnull(current_mode.projectile_type)? initial(projectile_type) : current_mode.projectile_type
- modifystate = isnull(current_mode.modifystate)? initial(modifystate) : current_mode.modifystate
- charge_cost = isnull(current_mode.charge_cost)? initial(charge_cost) : current_mode.charge_cost
- fire_sound = isnull(current_mode.fire_sound)? initial(fire_sound) : current_mode.fire_sound
-
+/obj/item/weapon/gun/energy/switch_firemodes()
+ if(..())
update_icon()
/obj/item/weapon/gun/energy/emp_act(severity)
diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm
index 507bc22735..2af6758e0a 100644
--- a/code/modules/projectiles/guns/energy/pulse.dm
+++ b/code/modules/projectiles/guns/energy/pulse.dm
@@ -11,8 +11,8 @@
max_shots = 10
firemodes = list(
- list(name="stun", projectile_type=/obj/item/projectile/beam/stun, fire_sound='sound/weapons/Taser.ogg'),
- list(name="lethal", projectile_type=/obj/item/projectile/beam, fire_sound='sound/weapons/Laser.ogg'),
+ list(name="stun", projectile_type=/obj/item/projectile/beam/stun, fire_sound='sound/weapons/Taser.ogg', fire_delay=null, charge_cost=null),
+ list(name="lethal", projectile_type=/obj/item/projectile/beam, fire_sound='sound/weapons/Laser.ogg', fire_delay=null, charge_cost=null),
list(name="DESTROY", projectile_type=/obj/item/projectile/beam/pulse, fire_sound='sound/weapons/pulse.ogg', fire_delay=25, charge_cost=400),
)
diff --git a/code/modules/projectiles/guns/launcher/crossbow.dm b/code/modules/projectiles/guns/launcher/crossbow.dm
index b199d4ad8b..e11844293e 100644
--- a/code/modules/projectiles/guns/launcher/crossbow.dm
+++ b/code/modules/projectiles/guns/launcher/crossbow.dm
@@ -254,9 +254,9 @@
else
user << "You need at least five segments of cable coil to complete this task."
return
- else if(istype(W,/obj/item/stack/material/plastic))
+ else if(istype(W,/obj/item/stack/material) && W.get_material_name() == "plastic")
if(buildstate == 3)
- var/obj/item/stack/material/plastic/P = W
+ var/obj/item/stack/material/P = W
if(P.use(3))
user << "You assemble and install a heavy plastic lath onto the crossbow."
buildstate++
diff --git a/code/modules/projectiles/guns/launcher/pneumatic.dm b/code/modules/projectiles/guns/launcher/pneumatic.dm
index e7c3870ed0..b20e9521e6 100644
--- a/code/modules/projectiles/guns/launcher/pneumatic.dm
+++ b/code/modules/projectiles/guns/launcher/pneumatic.dm
@@ -167,9 +167,9 @@
buildstate++
update_icon()
return
- else if(istype(W,/obj/item/stack/material/steel))
+ else if(istype(W,/obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL)
if(buildstate == 2)
- var/obj/item/stack/material/steel/M = W
+ var/obj/item/stack/material/M = W
if(M.use(5))
user << "You assemble a chassis around the cannon frame."
buildstate++
diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm
index 1fd6a6bb0c..c8185097ed 100644
--- a/code/modules/projectiles/guns/projectile/automatic.dm
+++ b/code/modules/projectiles/guns/projectile/automatic.dm
@@ -10,11 +10,12 @@
slot_flags = SLOT_BELT
ammo_type = /obj/item/ammo_casing/c9mm
multi_aim = 1
+ burst_delay = 2
firemodes = list(
- list(name="semiauto", burst=1, fire_delay=0),
- list(name="3-round bursts", burst=3, move_delay=4, accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.0, 0.6, 1.0)),
- list(name="short bursts", burst=5, move_delay=4, accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.6, 1.0, 1.0, 1.0, 1.2)),
+ list(name="semiauto", burst=1, fire_delay=0, move_delay=null, burst_accuracy=null, dispersion=null),
+ list(name="3-round bursts", burst=3, fire_delay=null, move_delay=4, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)),
+ list(name="short bursts", burst=5, fire_delay=null, move_delay=4, burst_accuracy=list(0,-1,-1,-2,-2), dispersion=list(0.6, 1.0, 1.0, 1.0, 1.2)),
)
/obj/item/weapon/gun/projectile/automatic/mini_uzi
@@ -66,9 +67,9 @@
magazine_type = /obj/item/ammo_magazine/c762
firemodes = list(
- list(name="semiauto", burst=1, fire_delay=0),
- list(name="3-round bursts", burst=3, move_delay=6, accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.0, 0.6, 0.6)),
- list(name="short bursts", burst=5, move_delay=6, accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.6, 1.0, 1.0, 1.0, 1.2)),
+ list(name="semiauto", burst=1, fire_delay=0, move_delay=null, burst_accuracy=null, dispersion=null),
+ list(name="3-round bursts", burst=3, fire_delay=null, move_delay=6, burst_accuracy=list(0,-1,-2), dispersion=list(0.0, 0.6, 0.6)),
+ list(name="short bursts", burst=5, fire_delay=null, move_delay=6, burst_accuracy=list(0,-1,-2,-2,-3), dispersion=list(0.6, 1.0, 1.0, 1.0, 1.2)),
)
/obj/item/weapon/gun/projectile/automatic/sts35/update_icon()
@@ -98,9 +99,6 @@
icon_state = "wt550"
return
-/datum/firemode/z8
- var/use_launcher = 0
-
/obj/item/weapon/gun/projectile/automatic/z8
name = "\improper Z8 Bulldog"
desc = "An older model bullpup carbine, made by the now defunct Zendai Foundries. Uses armor piercing 5.56mm rounds. Makes you feel like a space marine when you hold it."
@@ -119,13 +117,13 @@
auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
burst_delay = 4
- firemode_type = /datum/firemode/z8
firemodes = list(
- list(name="semiauto", burst=1, fire_delay=0),
- list(name="3-round bursts", burst=3, move_delay=6, accuracy = list(0,-1,-1), dispersion = list(0.0, 0.6, 0.6)),
- list(name="fire grenades", use_launcher=1)
+ list(name="semiauto", burst=1, fire_delay=0, move_delay=null, use_launcher=null, burst_accuracy=null, dispersion=null),
+ list(name="3-round bursts", burst=3, fire_delay=null, move_delay=6, use_launcher=null, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 0.6)),
+ list(name="fire grenades", burst=null, fire_delay=null, move_delay=null, use_launcher=1, burst_accuracy=null, dispersion=null)
)
+ var/use_launcher = 0
var/obj/item/weapon/gun/launcher/grenade/underslung/launcher
/obj/item/weapon/gun/projectile/automatic/z8/New()
@@ -139,15 +137,13 @@
..()
/obj/item/weapon/gun/projectile/automatic/z8/attack_hand(mob/user)
- var/datum/firemode/z8/current_mode = firemodes[sel_mode]
- if(user.get_inactive_hand() == src && current_mode.use_launcher)
+ if(user.get_inactive_hand() == src && use_launcher)
launcher.unload(user)
else
..()
/obj/item/weapon/gun/projectile/automatic/z8/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0)
- var/datum/firemode/z8/current_mode = firemodes[sel_mode]
- if(current_mode.use_launcher)
+ if(use_launcher)
launcher.Fire(target, user, params, pointblank, reflex)
if(!launcher.chambered)
switch_firemodes() //switch back automatically
@@ -187,8 +183,8 @@
magazine_type = /obj/item/ammo_magazine/a762
firemodes = list(
- list(name="short bursts", burst=5, move_delay=6, accuracy = list(0,-1,-1,-2,-2,-2,-3,-3), dispersion = list(0.6, 1.0, 1.0, 1.0, 1.2)),
- list(name="long bursts", burst=8, move_delay=8, accuracy = list(0,-1,-1,-2,-2,-2,-3,-3), dispersion = list(1.0, 1.0, 1.0, 1.0, 1.2)),
+ list(name="short bursts", burst=5, move_delay=6, burst_accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.6, 1.0, 1.0, 1.0, 1.2)),
+ list(name="long bursts", burst=8, move_delay=8, burst_accuracy = list(0,-1,-1,-2,-2,-2,-3,-3), dispersion = list(1.0, 1.0, 1.0, 1.0, 1.2)),
)
var/cover_open = 0
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index f13ad24287..ae6e91fea5 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -26,7 +26,7 @@
var/xo = null
var/current = null
var/obj/shot_from = null // the object which shot us
- var/atom/original = null // the original target clicked
+ var/atom/original = null // the target clicked (not necessarily where the projectile is headed). Should probably be renamed to 'target' or something.
var/turf/starting = null // the projectile's starting turf
var/list/permutated = list() // we've passed through these atoms, don't try to hit them again
@@ -110,21 +110,13 @@
p_x = between(0, p_x + rand(-radius, radius), world.icon_size)
p_y = between(0, p_y + rand(-radius, radius), world.icon_size)
-//called to launch a projectile from a gun
-/obj/item/projectile/proc/launch(atom/target, mob/user, obj/item/weapon/gun/launcher, var/target_zone, var/x_offset=0, var/y_offset=0)
- var/turf/curloc = get_turf(user)
+//called to launch a projectile
+/obj/item/projectile/proc/launch(atom/target, var/target_zone, var/x_offset=0, var/y_offset=0)
+ var/turf/curloc = get_turf(src)
var/turf/targloc = get_turf(target)
if (!istype(targloc) || !istype(curloc))
return 1
- firer = user
- def_zone = target_zone
-
- if(user == target) //Shooting yourself
- user.bullet_act(src, target_zone)
- on_impact(user)
- qdel(src)
- return 0
if(targloc == curloc) //Shooting something in the same turf
target.bullet_act(src, target_zone)
on_impact(target)
@@ -132,31 +124,39 @@
return 0
original = target
- loc = curloc
- starting = curloc
- current = curloc
- yo = targloc.y - curloc.y + y_offset
- xo = targloc.x - curloc.x + x_offset
-
- shot_from = launcher
- silenced = launcher.silenced
+ def_zone = target_zone
spawn()
+ setup_trajectory(curloc, targloc, x_offset, y_offset) //plot the initial trajectory
process()
return 0
+//called to launch a projectile from a gun
+/obj/item/projectile/proc/launch_from_gun(atom/target, mob/user, obj/item/weapon/gun/launcher, var/target_zone, var/x_offset=0, var/y_offset=0)
+ if(user == target) //Shooting yourself
+ user.bullet_act(src, target_zone)
+ on_impact(user)
+ qdel(src)
+ return 0
+
+ loc = get_turf(user) //move the projectile out into the world
+
+ firer = user
+ shot_from = launcher
+ silenced = launcher.silenced
+
+ return launch(target, target_zone, x_offset, y_offset)
+
//Used to change the direction of the projectile in flight.
/obj/item/projectile/proc/redirect(var/new_x, var/new_y, var/atom/starting_loc, var/mob/new_firer=null)
- original = locate(new_x, new_y, src.z)
- starting = starting_loc
- current = starting_loc
+ var/turf/new_target = locate(new_x, new_y, src.z)
+
+ original = new_target
if(new_firer)
firer = src
- yo = new_y - starting_loc.y
- xo = new_x - starting_loc.x
- setup_trajectory()
+ setup_trajectory(starting_loc, new_target)
//Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying.
/obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0)
@@ -165,14 +165,17 @@
//roll to-hit
miss_modifier = max(15*(distance-2) - round(15*accuracy) + miss_modifier, 0)
- var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1))
- if(!hit_zone)
+ var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss
+
+ var/result = PROJECTILE_FORCE_MISS
+ if(hit_zone)
+ def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
+ result = target_mob.bullet_act(src, def_zone)
+
+ if(result == PROJECTILE_FORCE_MISS)
visible_message("\The [src] misses [target_mob] narrowly!")
return 0
- //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
- def_zone = hit_zone
-
//hit messages
if(silenced)
target_mob << "You've been hit in the [parse_zone(def_zone)] by \the [src]!"
@@ -193,7 +196,7 @@
msg_admin_attack("UNKNOWN shot [target_mob] ([target_mob.ckey]) with \a [src] (JMP)")
//sometimes bullet_act() will want the projectile to continue flying
- if (target_mob.bullet_act(src, def_zone) == -1)
+ if (result == PROJECTILE_CONTINUE)
return 0
return 1
@@ -227,7 +230,7 @@
else
passthrough = 1 //so ghosts don't stop bullets
else
- passthrough = (A.bullet_act(src, def_zone) == -1) //backwards compatibility
+ passthrough = (A.bullet_act(src, def_zone) == PROJECTILE_CONTINUE) //backwards compatibility
if(isturf(A))
for(var/obj/O in A)
O.bullet_act(src)
@@ -272,9 +275,6 @@
/obj/item/projectile/process()
var/first_step = 1
- //plot the initial trajectory
- setup_trajectory()
-
spawn while(src && src.loc)
if(kill_count-- < 1)
on_impact(src.loc) //for any final impact behaviours
@@ -311,13 +311,16 @@
if(!hitscan)
sleep(step_delay) //add delay between movement iterations if it's not a hitscan weapon
-/obj/item/projectile/proc/process_step(first_step = 0)
- return
-
/obj/item/projectile/proc/before_move()
return
-/obj/item/projectile/proc/setup_trajectory()
+/obj/item/projectile/proc/setup_trajectory(turf/startloc, turf/targloc, var/x_offset = 0, var/y_offset = 0)
+ // setup projectile state
+ starting = startloc
+ current = startloc
+ yo = targloc.y - startloc.y + y_offset
+ xo = targloc.x - startloc.x + x_offset
+
// trajectory dispersion
var/offset = 0
if(dispersion)
@@ -376,7 +379,6 @@
invisibility = 101 //Nope! Can't see me!
yo = null
xo = null
- var/target = null
var/result = 0 //To pass the message back to the gun.
/obj/item/projectile/test/Bump(atom/A as mob|obj|turf|area)
@@ -391,25 +393,24 @@
result = 1
return
-/obj/item/projectile/test/process()
+/obj/item/projectile/test/launch(atom/target)
var/turf/curloc = get_turf(src)
var/turf/targloc = get_turf(target)
if(!curloc || !targloc)
return 0
- yo = targloc.y - curloc.y
- xo = targloc.x - curloc.x
- target = targloc
+
original = target
- starting = curloc
-
+
//plot the initial trajectory
- setup_trajectory()
+ setup_trajectory(curloc, targloc)
+ return process(targloc)
+/obj/item/projectile/test/process(var/turf/targloc)
while(src) //Loop on through!
if(result)
return (result - 1)
- if((!( target ) || loc == target))
- target = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge
+ if((!( targloc ) || loc == targloc))
+ targloc = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge
trajectory.increment() // increment the current location
location = trajectory.return_location(location) // update the locally stored location data
@@ -420,18 +421,22 @@
if(istype(M)) //If there is someting living...
return 1 //Return 1
else
- M = locate() in get_step(src,target)
+ M = locate() in get_step(src,targloc)
if(istype(M))
return 1
-/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASSTABLE|PASSGLASS|PASSGRILLE, flags=null) //Checks if you can hit them or not.
+//Helper proc to check if you can hit them or not.
+/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASSTABLE|PASSGLASS|PASSGRILLE, flags=null)
if(!istype(target) || !istype(firer))
return 0
+
var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test....
- trace.target = target
+
+ //Set the flags and pass flags to that of the real projectile...
if(!isnull(flags))
- trace.flags = flags //Set the flags...
- trace.pass_flags = pass_flags //And the pass flags to that of the real projectile...
- var/output = trace.process() //Test it!
+ trace.flags = flags
+ trace.pass_flags = pass_flags
+
+ var/output = trace.launch(target) //Test it!
qdel(trace) //No need for it anymore
return output //Send it back to the gun!
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index 928f67f3ef..d012b1fed6 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -10,7 +10,7 @@
..()
maximum_volume = max
my_atom = A
-
+
//I dislike having these here but map-objects are initialised before world/New() is called. >_>
if(!chemical_reagents_list)
//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
@@ -257,7 +257,7 @@
if(!target || !istype(target))
return
- amount = min(amount, total_volume, target.get_free_space() / multiplier)
+ amount = max(0, min(amount, total_volume, target.get_free_space() / multiplier))
if(!amount)
return
@@ -277,9 +277,9 @@
/* Holder-to-atom and similar procs */
-//The general proc for applying reagents to things. This proc assumes the reagents are being applied externally,
+//The general proc for applying reagents to things. This proc assumes the reagents are being applied externally,
//not directly injected into the contents. It first calls touch, then the appropriate trans_to_*() or splash_mob().
-//If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person),
+//If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person),
//call the appropriate trans_to_*() proc.
/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
touch(target) //First, handle mere touch effects
diff --git a/code/modules/reagents/Chemistry-Logging.dm b/code/modules/reagents/Chemistry-Logging.dm
new file mode 100644
index 0000000000..1432b18a2e
--- /dev/null
+++ b/code/modules/reagents/Chemistry-Logging.dm
@@ -0,0 +1,28 @@
+
+/var/list/chemical_reaction_logs = list()
+
+/proc/log_chemical_reaction(atom/A, datum/chemical_reaction/R, multiplier)
+ if(!A || !R)
+ return
+
+ var/turf/T = get_turf(A)
+ var/logstr = "[usr ? key_name(usr) : "EVENT"] mixed [R.name] ([R.result]) (x[multiplier]) in \the [A] at [T ? "[T.x],[T.y],[T.z]" : "*null*"]"
+
+ chemical_reaction_logs += "\[[time_stamp()]\] [logstr]"
+
+ if(R.log_is_important)
+ message_admins(logstr)
+ log_admin(logstr)
+
+/client/proc/view_chemical_reaction_logs()
+ set name = "Show Chemical Reactions"
+ set category = "Admin"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ var/html = ""
+ for(var/entry in chemical_reaction_logs)
+ html += "[entry]
"
+
+ usr << browse(html, "window=chemlogs")
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index 9d742d726a..af1f6ff2e5 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -119,7 +119,7 @@
if(href_list["amount"])
var/id = href_list["add"]
- var/amount = text2num(href_list["amount"])
+ var/amount = isgoodnumber(text2num(href_list["amount"]))
R.trans_id_to(src, id, amount)
else if (href_list["addcustom"])
@@ -133,7 +133,7 @@
if(href_list["amount"])
var/id = href_list["remove"]
- var/amount = text2num(href_list["amount"])
+ var/amount = isgoodnumber(text2num(href_list["amount"]))
if(mode)
reagents.trans_id_to(beaker, id, amount)
else
@@ -297,18 +297,10 @@
/obj/machinery/chem_master/proc/isgoodnumber(var/num)
if(isnum(num))
- if(num > 200)
- num = 200
- else if(num < 0)
- num = 1
- else
- num = round(num)
- return num
+ return Clamp(round(num), 0, 200)
else
return 0
-
-
/obj/machinery/chem_master/condimaster
name = "CondiMaster 3000"
condi = 1
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index ece76b00d0..878724a727 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -52,6 +52,7 @@
var/mix_message = "The solution begins to bubble."
var/reaction_sound = 'sound/effects/bubbles.ogg'
+ var/log_is_important = 0 // If this reaction should be considered important for logging. Important recipes message admins when mixed, non-important ones just log to file.
/datum/chemical_reaction/proc/can_happen(var/datum/reagents/holder)
//check that all the required reagents are present
if(!holder.has_all_reagents(required_reagents))
@@ -264,6 +265,7 @@
result = "kelotane"
required_reagents = list("silicon" = 1, "carbon" = 1)
result_amount = 2
+ log_is_important = 1
/datum/chemical_reaction/peridaxon
name = "Peridaxon"
@@ -503,6 +505,7 @@
result = "coolant"
required_reagents = list("tungsten" = 1, "acetone" = 1, "water" = 1)
result_amount = 3
+ log_is_important = 1
/datum/chemical_reaction/rezadone
name = "Rezadone"
@@ -638,6 +641,7 @@
result = "nitroglycerin"
required_reagents = list("glycerol" = 1, "pacid" = 1, "sacid" = 1)
result_amount = 2
+ log_is_important = 1
/datum/chemical_reaction/nitroglycerin/on_reaction(var/datum/reagents/holder, var/created_volume)
var/datum/effect/effect/system/reagents_explosion/e = new()
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index b57830e1d6..615db88168 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -1,5 +1,5 @@
/obj/item/weapon/reagent_containers/borghypo
- name = "Cyborg Hypospray"
+ name = "cyborg hypospray"
desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment."
icon = 'icons/obj/syringe.dmi'
item_state = "hypo"
@@ -7,13 +7,15 @@
amount_per_transfer_from_this = 5
volume = 30
possible_transfer_amounts = null
+
var/mode = 1
var/charge_cost = 50
var/charge_tick = 0
var/recharge_time = 5 //Time it takes for shots to recharge (in seconds)
- var/list/datum/reagents/reagent_list = list()
var/list/reagent_ids = list("tricordrazine", "inaprovaline", "spaceacillin")
+ var/list/reagent_volumes = list()
+ var/list/reagent_names = list()
/obj/item/weapon/reagent_containers/borghypo/surgeon
reagent_ids = list("bicaridine", "inaprovaline", "dexalin")
@@ -23,46 +25,38 @@
/obj/item/weapon/reagent_containers/borghypo/New()
..()
- for(var/R in reagent_ids)
- add_reagent(R)
+
+ for(var/T in reagent_ids)
+ reagent_volumes[T] = volume
+ var/datum/reagent/R = chemical_reagents_list[T]
+ reagent_names += R.name
processing_objects.Add(src)
-
/obj/item/weapon/reagent_containers/borghypo/Destroy()
processing_objects.Remove(src)
..()
-/obj/item/weapon/reagent_containers/borghypo/process() //Every [recharge_time] seconds, recharge some reagents for the cyborg
- charge_tick++
- if(charge_tick < recharge_time) return 0
+/obj/item/weapon/reagent_containers/borghypo/process() //Every [recharge_time] seconds, recharge some reagents for the cyborg+
+ if(++charge_tick < recharge_time)
+ return 0
charge_tick = 0
if(isrobot(loc))
var/mob/living/silicon/robot/R = loc
if(R && R.cell)
- var/datum/reagents/RG = reagent_list[mode]
- if(RG.total_volume < RG.maximum_volume) //Don't recharge reagents and drain power if the storage is full.
- R.cell.use(charge_cost) //Take power from borg...
- RG.add_reagent(reagent_ids[mode], 5) //And fill hypo with reagent.
+ for(var/T in reagent_ids)
+ if(reagent_volumes[T] < volume)
+ R.cell.use(charge_cost)
+ reagent_volumes[T] = min(reagent_volumes[T] + 5, volume)
return 1
-// Use this to add more chemicals for the borghypo to produce.
-/obj/item/weapon/reagent_containers/borghypo/proc/add_reagent(var/reagent)
- reagent_ids |= reagent
- var/datum/reagents/RG = new(30)
- RG.my_atom = src
- reagent_list += RG
-
- var/datum/reagents/R = reagent_list[reagent_list.len]
- R.add_reagent(reagent, 30)
-
-/obj/item/weapon/reagent_containers/borghypo/attack(mob/living/M as mob, mob/user as mob)
- var/datum/reagents/R = reagent_list[mode]
- if(!R.total_volume)
- user << "The injector is empty."
+/obj/item/weapon/reagent_containers/borghypo/attack(var/mob/living/M, var/mob/user)
+ if(!istype(M))
return
- if (!istype(M))
+
+ if(!reagent_volumes[reagent_ids[mode]])
+ user << "The injector is empty."
return
var/mob/living/carbon/human/H = M
@@ -75,37 +69,80 @@
user << "You cannot inject a robotic limb."
return
- if (R.total_volume && M.can_inject(user, 1))
+ if (M.can_inject(user, 1))
user << "You inject [M] with the injector."
M << "You feel a tiny prick!"
if(M.reagents)
- var/trans = R.trans_to_mob(M, amount_per_transfer_from_this, CHEM_BLOOD)
- user << "[trans] units injected. [R.total_volume] units remaining."
+ var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]])
+ M.reagents.add_reagent(reagent_ids[mode], t)
+ reagent_volumes[reagent_ids[mode]] -= t
+ admin_inject_log(user, M, src, reagent_ids[mode], t)
+ user << "[t] units injected. [reagent_volumes[reagent_ids[mode]]] units remaining."
return
-/obj/item/weapon/reagent_containers/borghypo/attack_self(mob/user as mob)
- playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) //Change the mode
- mode++
- if(mode > reagent_list.len)
- mode = 1
+/obj/item/weapon/reagent_containers/borghypo/attack_self(mob/user as mob) //Change the mode
+ var/t = ""
+ for(var/i = 1 to reagent_ids.len)
+ if(t)
+ t += ", "
+ if(mode == i)
+ t += "[reagent_names[i]]"
+ else
+ t += "[reagent_names[i]]"
+ t = "Available reagents: [t]."
+ user << t
- charge_tick = 0 //Prevents wasted chems/cell charge if you're cycling through modes.
- var/datum/reagent/R = chemical_reagents_list[reagent_ids[mode]]
- user << "Synthesizer is now producing '[R.name]'."
return
+/obj/item/weapon/reagent_containers/borghypo/Topic(var/href, var/list/href_list)
+ if(href_list["reagent"])
+ var/t = reagent_ids.Find(href_list["reagent"])
+ if(t)
+ playsound(loc, 'sound/effects/pop.ogg', 50, 0)
+ mode = t
+ var/datum/reagent/R = chemical_reagents_list[reagent_ids[mode]]
+ usr << "Synthesizer is now producing '[R.name]'."
+
/obj/item/weapon/reagent_containers/borghypo/examine(mob/user)
if(!..(user, 2))
return
- var/empty = 1
+ var/datum/reagent/R = chemical_reagents_list[reagent_ids[mode]]
- for(var/datum/reagents/RS in reagent_list)
- var/datum/reagent/R = locate() in RS.reagent_list
- if(R)
- user << "It currently has [R.volume] units of [R.name] stored."
- empty = 0
+ user << "It is currently producing [R.name] and has [reagent_volumes[reagent_ids[mode]]] out of [volume] units left."
- if(empty)
- user << "It is currently empty. Allow some time for the internal syntheszier to produce more."
+/obj/item/weapon/reagent_containers/borghypo/service
+ name = "cyborg drink synthesizer"
+ desc = "A portable drink dispencer."
+ icon = 'icons/obj/drinks.dmi'
+ icon_state = "shaker"
+ charge_cost = 20
+ recharge_time = 3
+ volume = 60
+ possible_transfer_amounts = list(5, 10, 20, 30)
+ reagent_ids = list("beer", "kahlua", "whiskey", "wine", "vodka", "gin", "rum", "tequilla", "vermouth", "cognac", "ale", "mead", "water", "sugar", "ice", "tea", "icetea", "cola", "spacemountainwind", "dr_gibb", "space_up", "tonic", "sodawater", "lemon_lime", "orangejuice", "limejuice", "watermelonjuice")
+
+/obj/item/weapon/reagent_containers/borghypo/service/attack(var/mob/M, var/mob/user)
+ return
+
+/obj/item/weapon/reagent_containers/borghypo/service/afterattack(var/obj/target, var/mob/user, var/proximity)
+ if(!proximity)
+ return
+
+ if(!target.is_open_container() || !target.reagents)
+ return
+
+ if(!reagent_volumes[reagent_ids[mode]])
+ user << "[src] is out of this reagent, give it some time to refill."
+ return
+
+ if(!target.reagents.get_free_space())
+ user << "[target] is full."
+ return
+
+ var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]])
+ target.reagents.add_reagent(reagent_ids[mode], t)
+ reagent_volumes[reagent_ids[mode]] -= t
+ user << "You transfer [t] units of the solution to [target]."
+ return
diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm
index 43a406153c..f70e06f421 100644
--- a/code/modules/reagents/reagent_containers/food/drinks.dm
+++ b/code/modules/reagents/reagent_containers/food/drinks.dm
@@ -18,7 +18,6 @@
attack(mob/M as mob, mob/user as mob, def_zone)
if(standard_feed_mob(user, M))
- robot_refill(user)
return
return 0
@@ -29,22 +28,10 @@
if(standard_dispenser_refill(user, target))
return
if(standard_pour_into(user, target))
- robot_refill(user)
return
return ..()
- proc/robot_refill(var/mob/living/silicon/robot/user)
- if(!istype(user))
- return 0
-
- user.cell.use(30)
- var/refill = reagents.get_master_reagent_id()
- user << "Now synthesizing [amount_per_transfer_from_this] units of [refill]..."
- spawn(300)
- reagents.add_reagent(refill, amount_per_transfer_from_this)
- user << "Cyborg [src] refilled."
-
self_feed_message(var/mob/user)
user << "You swallow a gulp from \the [src]."
diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm
index d88d5cb594..3ee774e012 100644
--- a/code/modules/recycling/disposal-construction.dm
+++ b/code/modules/recycling/disposal-construction.dm
@@ -83,7 +83,7 @@
///// Z-Level stuff
- if(ptype<6 || ptype>8 && !(ptype==11 || ptype==12))
+ if(!(ptype in list(6, 7, 8, 11, 12, 13, 14)))
///// Z-Level stuff
icon_state = "con[base_state]"
else
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index fd1e53ae0a..9dd8d1f956 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -46,7 +46,7 @@
eject()
if(trunk)
trunk.linked = null
- ..()
+ return ..()
// attack by item places it in to disposal
/obj/machinery/disposal/attackby(var/obj/item/I, var/mob/user)
@@ -636,7 +636,7 @@
/obj/structure/disposalholder/Destroy()
qdel(gas)
active = 0
- ..()
+ return ..()
// Disposal pipes
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index 6311470641..1cf31e63ed 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -361,25 +361,24 @@ won't update every console in existence) but it's more of a hassle to do. Also,
else if(href_list["lathe_ejectsheet"] && linked_lathe) //Causes the protolathe to eject a sheet of material
var/desired_num_sheets = text2num(href_list["amount"])
var/res_amount, type
- var/material/M = name_to_material[href_list["lathe_ejectsheet"]]
+ var/material/M = get_material_by_name(href_list["lathe_ejectsheet"])
if(istype(M))
type = M.stack_type
-
- switch(name_to_material[href_list["lathe_ejectsheet"]])
- if(DEFAULT_WALL_MATERIAL)
- res_amount = "m_amount"
- if("glass")
- res_amount = "g_amount"
- if("gold")
- res_amount = "gold_amount"
- if("silver")
- res_amount = "silver_amount"
- if("phoron")
- res_amount = "phoron_amount"
- if("uranium")
- res_amount = "uranium_amount"
- if("diamond")
- res_amount = "diamond_amount"
+ switch(M.name)
+ if(DEFAULT_WALL_MATERIAL)
+ res_amount = "m_amount"
+ if("glass")
+ res_amount = "g_amount"
+ if("gold")
+ res_amount = "gold_amount"
+ if("silver")
+ res_amount = "silver_amount"
+ if("phoron")
+ res_amount = "phoron_amount"
+ if("uranium")
+ res_amount = "uranium_amount"
+ if("diamond")
+ res_amount = "diamond_amount"
if(ispath(type) && hasvar(linked_lathe, res_amount))
var/obj/item/stack/material/sheet = new type(linked_lathe.loc)
diff --git a/code/modules/security levels/security levels.dm b/code/modules/security levels/security levels.dm
index 1892af891e..4b73c0dd28 100644
--- a/code/modules/security levels/security levels.dm
+++ b/code/modules/security levels/security levels.dm
@@ -25,46 +25,31 @@
if(SEC_LEVEL_GREEN)
security_announcement_down.Announce("[config.alert_desc_green]", "Attention! Security level lowered to green")
security_level = SEC_LEVEL_GREEN
- for(var/obj/machinery/firealarm/FA in machines)
- if(FA.z in config.contact_levels)
- FA.overlays = list()
- FA.overlays += image('icons/obj/monitors.dmi', "overlay_green")
if(SEC_LEVEL_BLUE)
if(security_level < SEC_LEVEL_BLUE)
security_announcement_up.Announce("[config.alert_desc_blue_upto]", "Attention! Security level elevated to blue")
else
security_announcement_down.Announce("[config.alert_desc_blue_downto]", "Attention! Security level lowered to blue")
security_level = SEC_LEVEL_BLUE
- for(var/obj/machinery/firealarm/FA in machines)
- if(FA.z in config.contact_levels)
- FA.overlays = list()
- FA.overlays += image('icons/obj/monitors.dmi', "overlay_blue")
if(SEC_LEVEL_RED)
if(security_level < SEC_LEVEL_RED)
security_announcement_up.Announce("[config.alert_desc_red_upto]", "Attention! Code red!")
else
security_announcement_down.Announce("[config.alert_desc_red_downto]", "Attention! Code red!")
security_level = SEC_LEVEL_RED
-
/* - At the time of commit, setting status displays didn't work properly
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")*/
-
- for(var/obj/machinery/firealarm/FA in machines)
- if(FA.z in config.contact_levels)
- FA.overlays = list()
- FA.overlays += image('icons/obj/monitors.dmi', "overlay_red")
-
if(SEC_LEVEL_DELTA)
security_announcement_up.Announce("[config.alert_desc_delta]", "Attention! Delta security level reached!", new_sound = 'sound/effects/siren.ogg')
security_level = SEC_LEVEL_DELTA
- for(var/obj/machinery/firealarm/FA in machines)
- if(FA.z in config.contact_levels)
- FA.overlays = list()
- FA.overlays += image('icons/obj/monitors.dmi', "overlay_delta")
- else
- return
+
+ var/newlevel = get_security_level()
+ for(var/obj/machinery/firealarm/FA in machines)
+ if(FA.z in config.contact_levels)
+ FA.set_security_level(newlevel)
+
/proc/get_security_level()
switch(security_level)
diff --git a/code/modules/spells/aoe_turf/aoe_turf.dm b/code/modules/spells/aoe_turf/aoe_turf.dm
index 9a70eb18c6..3265761077 100644
--- a/code/modules/spells/aoe_turf/aoe_turf.dm
+++ b/code/modules/spells/aoe_turf/aoe_turf.dm
@@ -1,25 +1,25 @@
-/*
-Aoe turf spells target a ring of tiles around the user
-This ring has an outer radius (range) and an inner radius (inner_radius)
-Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm
-*/
-
-/spell/aoe_turf //affects all turfs in view or range (depends)
- spell_flags = IGNOREDENSE
- var/inner_radius = -1 //for all your ring spell needs
-
-/spell/aoe_turf/choose_targets(mob/user = usr)
- var/list/targets = list()
-
- for(var/turf/target in view_or_range(range,user,selection_type))
- if(!(target in view_or_range(inner_radius,user,selection_type)))
- if(target.density && (spell_flags & IGNOREDENSE))
- continue
- if(istype(target, /turf/space) && (spell_flags & IGNORESPACE))
- continue
- targets += target
-
- if(!targets.len) //doesn't waste the spell
- return
-
+/*
+Aoe turf spells target a ring of tiles around the user
+This ring has an outer radius (range) and an inner radius (inner_radius)
+Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm
+*/
+
+/spell/aoe_turf //affects all turfs in view or range (depends)
+ spell_flags = IGNOREDENSE
+ var/inner_radius = -1 //for all your ring spell needs
+
+/spell/aoe_turf/choose_targets(mob/user = usr)
+ var/list/targets = list()
+
+ for(var/turf/target in view_or_range(range, holder, selection_type))
+ if(!(target in view_or_range(inner_radius, holder, selection_type)))
+ if(target.density && (spell_flags & IGNOREDENSE))
+ continue
+ if(istype(target, /turf/space) && (spell_flags & IGNORESPACE))
+ continue
+ targets += target
+
+ if(!targets.len) //doesn't waste the spell
+ return
+
return targets
\ No newline at end of file
diff --git a/code/modules/spells/spell_code.dm b/code/modules/spells/spell_code.dm
index ba631391b4..1e8274757e 100644
--- a/code/modules/spells/spell_code.dm
+++ b/code/modules/spells/spell_code.dm
@@ -1,9 +1,9 @@
var/list/spells = typesof(/spell) //needed for the badmin verb for now
/spell
- name = "Spell"
- desc = "A spell"
- parent_type = /atom/movable
+ var/name = "Spell"
+ var/desc = "A spell"
+ parent_type = /datum
var/panel = "Spells"//What panel the proc holder needs to go on.
var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit?
@@ -25,8 +25,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
var/range = 7 //the range of the spell; outer radius for aoe spells
var/message = "" //whatever it says to the guy affected by it
var/selection_type = "view" //can be "range" or "view"
- var/atom/movable/holder //where the spell is. Normally the user, can be a projectile
-
+ var/atom/movable/holder //where the spell is. Normally the user, can be an item
var/duration = 0 //how long the spell lasts
var/list/spell_levels = list(Sp_SPEED = 0, Sp_POWER = 0) //the current spell levels - total spell levels can be obtained by just adding the two values
@@ -53,6 +52,8 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
var/hud_state = "" //name of the icon used in generating the spell hud object
var/override_base = ""
+ var/obj/screen/connected_button
+
///////////////////////
///SETUP AND PROCESS///
///////////////////////
@@ -69,11 +70,6 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
sleep(1)
return
-/spell/Click()
- ..()
-
- perform(usr)
-
/////////////////
/////CASTING/////
/////////////////
@@ -182,18 +178,19 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
- if(!(src in user.spell_list))
+ if(!(src in user.spell_list) && holder == user)
+ error("[user] utilized the spell '[src]' without having it.")
user << "You shouldn't have this spell! Something's wrong."
return 0
if(silenced > 0)
return
- var/turf/Turf = get_turf(user)
- if(!Turf)
+ var/turf/user_turf = get_turf(user)
+ if(!user_turf)
user << "You cannot cast spells in null space!"
- if(spell_flags & Z2NOCAST && (Turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel
+ if(spell_flags & Z2NOCAST && (user_turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel
return 0
if(spell_flags & CONSTRUCT_CHECK)
@@ -201,7 +198,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
if(findNullRod(T))
return 0
- if(istype(user, /mob/living/simple_animal))
+ if(istype(user, /mob/living/simple_animal) && holder == user)
var/mob/living/simple_animal/SA = user
if(SA.purge)
SA << "The nullrod's power interferes with your own!"
@@ -210,7 +207,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
if(!src.check_charge(skipcharge, user)) //sees if we can cast based on charges alone
return 0
- if(!(spell_flags & GHOSTCAST))
+ if(!(spell_flags & GHOSTCAST) && holder == user)
if(user.stat && !(spell_flags & STATALLOWED))
usr << "Not when you're incapacitated."
return 0
@@ -221,7 +218,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
return 0
var/spell/noclothes/spell = locate() in user.spell_list
- if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)))//clothes check
+ if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)) && holder == user)//clothes check
if(!user.wearing_wiz_garb())
return 0
diff --git a/code/modules/spells/spell_projectile.dm b/code/modules/spells/spell_projectile.dm
index f3e69b9b6c..c94131b252 100644
--- a/code/modules/spells/spell_projectile.dm
+++ b/code/modules/spells/spell_projectile.dm
@@ -6,6 +6,7 @@
var/spell/targeted/projectile/carried
+ penetrating = 0
kill_count = 10 //set by the duration of the spell
var/proj_trail = 0 //if it leaves a trail
@@ -15,18 +16,15 @@
var/list/trails = new()
/obj/item/projectile/spell_projectile/Destroy()
- ..()
for(var/trail in trails)
qdel(trail)
+ carried = null
+ return ..()
/obj/item/projectile/spell_projectile/ex_act()
return
/obj/item/projectile/spell_projectile/before_move()
- if(carried)
- var/list/targets = carried.choose_prox_targets(user = carried.holder, spell_holder = src)
- if(targets.len)
- src.prox_cast(targets)
if(proj_trail && src && src.loc) //pretty trails
var/obj/effect/overlay/trail = PoolOrNew(/obj/effect/overlay, src.loc)
trails += trail
@@ -44,19 +42,14 @@
return
/obj/item/projectile/spell_projectile/Bump(var/atom/A)
- if(loc)
+ if(loc && carried)
prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src))
- return
+ return 1
/obj/item/projectile/spell_projectile/on_impact()
- if(loc)
+ if(loc && carried)
prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src))
- return
+ return 1
/obj/item/projectile/spell_projectile/seeking
name = "seeking spell"
-
-/obj/item/projectile/spell_projectile/seeking/process_step()
- ..()
- if(original && !isnull(src.loc))
- current = original //update the target
diff --git a/code/modules/spells/spellbook.dm b/code/modules/spells/spellbook.dm
index 7b4b7a001d..69c60689ec 100644
--- a/code/modules/spells/spellbook.dm
+++ b/code/modules/spells/spellbook.dm
@@ -34,8 +34,6 @@
This spell fires several, slow moving, magic projectiles at nearby targets. If they hit a target, it is paralyzed and takes minor damage.
Fireball (10)
This spell fires a fireball in the direction you're facing and does not require wizard garb. Be careful not to fire it at people that are standing next to you.
- Disintegrate (60)
- This spell instantly kills somebody adjacent to you with the vilest of magick. It has a long cooldown.
Disable Technology (60)
This spell disables all weapons, cameras and most other technology in range.
Smoke (10)
@@ -125,7 +123,7 @@
uses--
/*
*/
- var/list/available_spells = list(magicmissile = "Magic Missile", fireball = "Fireball", disintegrate = "Disintegrate", disabletech = "Disable Tech", smoke = "Smoke", blind = "Blind", subjugation = "Subjugation", mindswap = "Mind Transfer", forcewall = "Forcewall", blink = "Blink", teleport = "Teleport", mutate = "Mutate", etherealjaunt = "Ethereal Jaunt", knock = "Knock", horseman = "Curse of the Horseman", staffchange = "Staff of Change", mentalfocus = "Mental Focus", soulstone = "Six Soul Stone Shards and the spell Artificer", armor = "Mastercrafted Armor Set", staffanimate = "Staff of Animation", noclothes = "No Clothes",fleshtostone = "Flesh to Stone")
+ var/list/available_spells = list(magicmissile = "Magic Missile", fireball = "Fireball", disabletech = "Disable Tech", smoke = "Smoke", blind = "Blind", subjugation = "Subjugation", mindswap = "Mind Transfer", forcewall = "Forcewall", blink = "Blink", teleport = "Teleport", mutate = "Mutate", etherealjaunt = "Ethereal Jaunt", knock = "Knock", horseman = "Curse of the Horseman", staffchange = "Staff of Change", mentalfocus = "Mental Focus", soulstone = "Six Soul Stone Shards and the spell Artificer", armor = "Mastercrafted Armor Set", staffanimate = "Staff of Animation", noclothes = "No Clothes",fleshtostone = "Flesh to Stone")
var/already_knows = 0
for(var/spell/aspell in H.spell_list)
if(available_spells[href_list["spell_choice"]] == initial(aspell.name))
@@ -165,10 +163,6 @@
feedback_add_details("wizard_spell_learned","FB") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/projectile/dumbfire/fireball)
temp = "You have learned fireball."
- if("disintegrate")
- feedback_add_details("wizard_spell_learned","DG") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.add_spell(new/spell/targeted/disintegrate)
- temp = "You have learned disintegrate."
if("disabletech")
feedback_add_details("wizard_spell_learned","DT") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/aoe_turf/disable_tech)
@@ -215,12 +209,8 @@
temp = "You have learned knock."
if("horseman")
feedback_add_details("wizard_spell_learned","HH") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.add_spell(new/spell/targeted/horsemask)
+ H.add_spell(new/spell/targeted/equip_item/horsemask)
temp = "You have learned curse of the horseman."
- if("fleshtostone")
- feedback_add_details("wizard_spell_learned","FS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.add_spell(new/spell/targeted/flesh_to_stone)
- temp = "You have learned flesh to stone."
if("staffchange")
feedback_add_details("wizard_spell_learned","ST") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
new /obj/item/weapon/gun/energy/staff(get_turf(H))
@@ -256,8 +246,9 @@
if (!(XRAY in H.mutations))
H.mutations.Add(XRAY)
H.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS)
+ H.see_in_dark = 8
H.see_invisible = SEE_INVISIBLE_LEVEL_TWO
- H << "\blue The walls suddenly disappear."
+ H << "The walls suddenly disappear."
temp = "You have purchased a scrying orb, and gained x-ray vision."
max_uses--
else
@@ -428,7 +419,7 @@
user.Weaken(20)
/obj/item/weapon/spellbook/oneuse/horsemask
- spell = /spell/targeted/horsemask
+ spell = /spell/targeted/equip_item/horsemask
spellname = "horses"
icon_state ="bookhorses"
desc = "This book is more horse than your mind has room for."
diff --git a/code/modules/spells/spells.dm b/code/modules/spells/spells.dm
index d20eea00dc..5e378f46a3 100644
--- a/code/modules/spells/spells.dm
+++ b/code/modules/spells/spells.dm
@@ -1,20 +1,37 @@
+/datum/mind
+ var/list/learned_spells
+
/mob/Life()
..()
if(spell_masters && spell_masters.len)
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
spell_master.update_spells(0, src)
-/mob/Stat()
+/mob/Login()
..()
- if(spell_list && spell_list.len && statpanel("Spells"))
+ if(spell_masters)
+ for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
+ spell_master.toggle_open(1)
+ client.screen -= spell_master
+
+/mob/Stat()
+ . = ..()
+ if(. && spell_list && spell_list.len)
for(var/spell/S in spell_list)
+ if((!S.connected_button) || !statpanel(S.panel))
+ continue //Not showing the noclothes spell
switch(S.charge_type)
if(Sp_RECHARGE)
- statpanel("Spells","[S.charge_counter/10.0]/[S.charge_max/10]",S)
+ statpanel(S.panel,"[S.charge_counter/10.0]/[S.charge_max/10]",S.connected_button)
if(Sp_CHARGES)
- statpanel("Spells","[S.charge_counter]/[S.charge_max]",S)
+ statpanel(S.panel,"[S.charge_counter]/[S.charge_max]",S.connected_button)
if(Sp_HOLDVAR)
- statpanel("Spells","[S.holder_var_type] [S.holder_var_amount]",S)
+ statpanel(S.panel,"[S.holder_var_type] [S.holder_var_amount]",S.connected_button)
+
+/hook/clone/proc/restore_spells(var/mob/H)
+ if(H.mind && H.mind.learned_spells)
+ for(var/spell/spell_to_add in H.mind.learned_spells)
+ H.add_spell(spell_to_add)
/mob/proc/add_spell(var/spell/spell_to_add, var/spell_base = "wiz_spell_ready", var/master_type = /obj/screen/movable/spell_master)
if(!spell_masters)
@@ -36,6 +53,11 @@
new_spell_master.icon_state = spell_base
spell_masters.Add(new_spell_master)
spell_list.Add(spell_to_add)
+ if(mind)
+ if(!mind.learned_spells)
+ mind.learned_spells = list()
+ mind.learned_spells += spell_to_add
+
return 1
/mob/proc/remove_spell(var/spell/spell_to_remove)
@@ -48,6 +70,8 @@
if(!spell_masters || !spell_masters.len)
return
+ if(mind && mind.learned_spells)
+ mind.learned_spells.Remove(spell_to_remove)
spell_list.Remove(spell_to_remove)
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
spell_master.remove_spell(spell_to_remove)
diff --git a/code/modules/spells/targeted/disintegrate.dm b/code/modules/spells/targeted/disintegrate.dm
deleted file mode 100644
index c3f0ee80e9..0000000000
--- a/code/modules/spells/targeted/disintegrate.dm
+++ /dev/null
@@ -1,27 +0,0 @@
-/spell/targeted/disintegrate
- name = "Disintegrate"
- desc = "This spell instantly kills somebody adjacent to you with the vilest of magick."
-
- school = "evocation"
- charge_max = 600
- spell_flags = NEEDSCLOTHES
- invocation = "EI NATH"
- invocation_type = SpI_SHOUT
- range = 1
- cooldown_min = 200 //100 deciseconds reduction per rank
-
- sparks_spread = 1
- sparks_amt = 4
-
- hud_state = "wiz_disint"
-
-/spell/targeted/disintegrate/cast(var/list/targets)
- ..()
- for(var/mob/living/target in targets)
- if(ishuman(target))
- var/mob/living/carbon/C = target
- if(!C.has_brain()) // Their brain is already taken out
- var/obj/item/organ/brain/B = new(C.loc)
- B.transfer_identity(C)
- target.gib()
- return
\ No newline at end of file
diff --git a/code/modules/spells/targeted/equip/equip.dm b/code/modules/spells/targeted/equip/equip.dm
new file mode 100644
index 0000000000..735daf78e8
--- /dev/null
+++ b/code/modules/spells/targeted/equip/equip.dm
@@ -0,0 +1,40 @@
+//You can set duration to 0 to have the items last forever
+
+/spell/targeted/equip_item
+ name = "equipment spell"
+
+ var/list/equipped_summons = list() //assoc list of text ids and paths to spawn
+
+ var/list/summoned_items = list() //list of items we summoned and will dispose when the spell runs out
+
+ var/delete_old = 1 //if the item previously in the slot is deleted - otherwise, it's dropped
+
+/spell/targeted/equip_item/cast(list/targets, mob/user = usr)
+ ..()
+ for(var/mob/living/L in targets)
+ for(var/slot_id in equipped_summons)
+ var/to_create = equipped_summons[slot_id]
+ slot_id = text2num(slot_id) //because the index is text, we access this instead
+ var/obj/item/new_item = summon_item(to_create)
+ var/obj/item/old_item = L.get_equipped_item(slot_id)
+ L.equip_to_slot(new_item, slot_id)
+ if(old_item)
+ L.remove_from_mob(old_item)
+ if(delete_old)
+ qdel(old_item)
+ else
+ old_item.loc = L.loc
+
+ if(duration)
+ summoned_items += new_item //we store it in a list to remove later
+
+ if(duration)
+ spawn(duration)
+ for(var/obj/item/to_remove in summoned_items)
+ if(istype(to_remove.loc, /mob))
+ var/mob/M = to_remove.loc
+ M.remove_from_mob(to_remove)
+ qdel(to_remove)
+
+/spell/targeted/equip_item/proc/summon_item(var/newtype)
+ return new newtype
diff --git a/code/modules/spells/targeted/horsemask.dm b/code/modules/spells/targeted/equip/horsemask.dm
similarity index 63%
rename from code/modules/spells/targeted/horsemask.dm
rename to code/modules/spells/targeted/equip/horsemask.dm
index dad2032b72..92b85fdb36 100644
--- a/code/modules/spells/targeted/horsemask.dm
+++ b/code/modules/spells/targeted/equip/horsemask.dm
@@ -1,35 +1,39 @@
-/spell/targeted/horsemask
- name = "Curse of the Horseman"
- desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
- school = "transmutation"
- charge_type = Sp_RECHARGE
- charge_max = 150
- charge_counter = 0
- spell_flags = 0
- invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
- invocation_type = SpI_SHOUT
- range = 7
- max_targets = 1
- cooldown_min = 30 //30 deciseconds reduction per rank
- selection_type = "range"
-
- compatible_mobs = list(/mob/living/carbon/human)
-
- hud_state = "wiz_horse"
-
-/spell/targeted/horsemask/cast(list/targets, mob/user = usr)
- ..()
- for(var/mob/living/target in targets)
- var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead
- magichead.canremove = 0 //curses!
- magichead.flags_inv = null //so you can still see their face
- magichead.voicechange = 1 //NEEEEIIGHH
- target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \
- "Your face burns up, and shortly after the fire you realise you have the face of a horse!")
- var/obj/old_mask = target.wear_mask
- if(old_mask)
- target.drop_from_inventory(old_mask)
- qdel(old_mask) //get rid of this shit
- target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1)
-
- flick("e_flash", target.flash)
\ No newline at end of file
+/spell/targeted/equip_item/horsemask
+ name = "Curse of the Horseman"
+ desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
+ school = "transmutation"
+ charge_type = Sp_RECHARGE
+ charge_max = 150
+ charge_counter = 0
+ spell_flags = 0
+ invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
+ invocation_type = SpI_SHOUT
+ range = 7
+ max_targets = 1
+ cooldown_min = 30 //30 deciseconds reduction per rank
+ selection_type = "range"
+
+ compatible_mobs = list(/mob/living/carbon/human)
+
+ hud_state = "wiz_horse"
+
+/spell/targeted/equip_item/horsemask/New()
+ ..()
+ equipped_summons = list("[slot_wear_mask]" = /obj/item/clothing/mask/horsehead)
+
+/spell/targeted/equip_item/horsemask/cast(list/targets, mob/user = usr)
+ ..()
+ for(var/mob/living/target in targets)
+ target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \
+ "Your face burns up, and shortly after the fire you realise you have the face of a horse!")
+ flick("e_flash", target.flash)
+
+/spell/targeted/equip_item/horsemask/summon_item(var/new_type)
+ var/obj/item/new_item = new new_type
+ new_item.canremove = 0 //curses!
+ new_item.unacidable = 1
+ if(istype(new_item, /obj/item/clothing/mask/horsehead))
+ var/obj/item/clothing/mask/horsehead/magichead = new_item
+ magichead.flags_inv = null //so you can still see their face
+ magichead.voicechange = 1 //NEEEEIIGHH
+ return new_item
diff --git a/code/modules/spells/targeted/flesh_to_stone.dm b/code/modules/spells/targeted/flesh_to_stone.dm
deleted file mode 100644
index e640fba5c6..0000000000
--- a/code/modules/spells/targeted/flesh_to_stone.dm
+++ /dev/null
@@ -1,21 +0,0 @@
-/spell/targeted/flesh_to_stone
- name = "Flesh to Stone"
- desc = "This spell turns a single person into an inert statue for a long period of time."
-
- school = "transmutation"
- charge_max = 600
- spell_flags = NEEDSCLOTHES
- range = 3
- max_targets = 1
- invocation = "STAUN EI"
- invocation_type = SpI_SHOUT
- amt_stunned = 5//just exists to make sure the statue "catches" them
- cooldown_min = 200 //100 deciseconds reduction per rank
-
- hud_state = "wiz_statue"
-
-/spell/targeted/flesh_to_stone/cast(var/list/targets, mob/user)
- ..()
- for(var/mob/living/target in targets)
- new /obj/structure/closet/statue(target.loc, target) //makes the statue
- return
\ No newline at end of file
diff --git a/code/modules/spells/targeted/genetic.dm b/code/modules/spells/targeted/genetic.dm
index 028cdafba0..045fbc7d41 100644
--- a/code/modules/spells/targeted/genetic.dm
+++ b/code/modules/spells/targeted/genetic.dm
@@ -57,7 +57,7 @@ code\game\dna\genes\goon_powers.dm
spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER
invocation = "BIRUZ BENNAR"
invocation_type = SpI_SHOUT
- message = "\blue You feel strong! You feel a pressure building behind your eyes!"
+ message = "You feel strong! You feel a pressure building behind your eyes!"
range = 0
max_targets = 1
diff --git a/code/modules/spells/targeted/mind_transfer.dm b/code/modules/spells/targeted/mind_transfer.dm
index 2e1860da35..a3668a53d1 100644
--- a/code/modules/spells/targeted/mind_transfer.dm
+++ b/code/modules/spells/targeted/mind_transfer.dm
@@ -51,7 +51,10 @@
ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob.
caster.mind.transfer_to(victim)
- victim.spell_list = caster.spell_list//Now they are inside the victim's body.
+ victim.spell_list = list() //clear those out
+ for(var/spell/S in caster.spell_list)
+ victim.add_spell(S) //Now they are inside the victim's body - this also generates the HUD
+ caster.spell_list = list() //clean that out as well
if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster.
for(var/V in caster.mind.special_verbs)//Not too important but could come into play.
@@ -59,7 +62,9 @@
ghost.mind.transfer_to(caster)
caster.key = ghost.key //have to transfer the key since the mind was not active
- caster.spell_list = ghost.spell_list
+ for(var/spell/S in ghost.spell_list)
+ caster.add_spell(S)
+ ghost.spell_list = list()
if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here.
for(var/V in caster.mind.special_verbs)
@@ -71,4 +76,4 @@
//After a certain amount of time the victim gets a message about being in a different body.
spawn(msg_wait)
- caster << "\red You feel woozy and lightheaded. Your body doesn't seem like your own."
+ caster << "You feel woozy and lightheaded. Your body doesn't seem like your own."
diff --git a/code/modules/spells/targeted/targeted.dm b/code/modules/spells/targeted/targeted.dm
index 96bbab9905..498d363408 100644
--- a/code/modules/spells/targeted/targeted.dm
+++ b/code/modules/spells/targeted/targeted.dm
@@ -1,145 +1,145 @@
-/*
-Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range
-Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm
-*/
-
-
-/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
- var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
- var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
-
-
- var/amt_weakened = 0
- var/amt_paralysis = 0
- var/amt_stunned = 0
-
- var/amt_dizziness = 0
- var/amt_confused = 0
- var/amt_stuttering = 0
-
- //set to negatives for healing
- var/amt_dam_fire = 0
- var/amt_dam_brute = 0
- var/amt_dam_oxy = 0
- var/amt_dam_tox = 0
-
- var/amt_eye_blind = 0
- var/amt_eye_blurry = 0
-
- var/list/compatible_mobs = list()
-
-
-/spell/targeted/choose_targets(mob/user = usr)
- var/list/targets = list()
-
- if(max_targets == 0) //unlimited
- if(range == -2)
- targets = living_mob_list
- else
- for(var/mob/living/target in view_or_range(range, user, selection_type))
- targets += target
-
- else if(max_targets == 1) //single target can be picked
- if((range == 0 || range == -1) && spell_flags & INCLUDEUSER)
- targets += user
- else
- var/list/possible_targets = list()
- var/list/starting_targets
- if(range == -2)
- starting_targets = living_mob_list
- else
- starting_targets = view_or_range(range, user, selection_type)
-
- for(var/mob/living/M in starting_targets)
- if(!(spell_flags & INCLUDEUSER) && M == user)
- continue
- if(compatible_mobs && compatible_mobs.len)
- if(!is_type_in_list(M, compatible_mobs)) continue
- if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs))
- continue
- possible_targets += M
-
- if(possible_targets.len)
- if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details
- var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
- if(temp_target)
- targets += temp_target
- else
- targets += pick(possible_targets)
- //Adds a safety check post-input to make sure those targets are actually in range.
-
-
- else
- var/list/possible_targets = list()
- var/list/starting_targets
-
- if(range == -2)
- starting_targets = living_mob_list
- else
- starting_targets = view_or_range(range, user, selection_type)
-
- for(var/mob/living/target in starting_targets)
- if(!(spell_flags & INCLUDEUSER) && target == user)
- continue
- if(compatible_mobs && !is_type_in_list(target, compatible_mobs))
- continue
- possible_targets += target
-
- if(spell_flags & SELECTABLE)
- for(var/i = 1; i<=max_targets, i++)
- if(!possible_targets.len)
- break
- var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
- if(!M)
- break
- if(range != -2)
- if(!(M in view_or_range(range, user, selection_type)))
- continue
- targets += M
- possible_targets -= M
- else
- for(var/i=1,i<=max_targets,i++)
- if(!possible_targets.len)
- break
- if(target_ignore_prev)
- var/target = pick(possible_targets)
- possible_targets -= target
- targets += target
- else
- targets += pick(possible_targets)
-
- if(!(spell_flags & INCLUDEUSER) && (user in targets))
- targets -= user
-
- if(compatible_mobs && compatible_mobs.len)
- for(var/mob/living/target in targets) //filters out all the non-compatible mobs
- if(!is_type_in_list(target, compatible_mobs))
- targets -= target
-
- return targets
-
-/spell/targeted/cast(var/list/targets, mob/user)
- for(var/mob/living/target in targets)
- if(range >= 0)
- if(!(target in view_or_range(range, user, selection_type))) //filter at time of casting
- targets -= target
- continue
- apply_spell_damage(target)
-
-/spell/targeted/proc/apply_spell_damage(mob/living/target)
- target.adjustBruteLoss(amt_dam_brute)
- target.adjustFireLoss(amt_dam_fire)
- target.adjustToxLoss(amt_dam_tox)
- target.adjustOxyLoss(amt_dam_oxy)
- //disabling
- target.Weaken(amt_weakened)
- target.Paralyse(amt_paralysis)
- target.Stun(amt_stunned)
- if(amt_weakened || amt_paralysis || amt_stunned)
- if(target.buckled)
- target.buckled = null
- target.eye_blind += amt_eye_blind
- target.eye_blurry += amt_eye_blurry
- target.dizziness += amt_dizziness
- target.confused += amt_confused
+/*
+Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range
+Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm
+*/
+
+
+/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
+ var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
+ var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
+
+
+ var/amt_weakened = 0
+ var/amt_paralysis = 0
+ var/amt_stunned = 0
+
+ var/amt_dizziness = 0
+ var/amt_confused = 0
+ var/amt_stuttering = 0
+
+ //set to negatives for healing
+ var/amt_dam_fire = 0
+ var/amt_dam_brute = 0
+ var/amt_dam_oxy = 0
+ var/amt_dam_tox = 0
+
+ var/amt_eye_blind = 0
+ var/amt_eye_blurry = 0
+
+ var/list/compatible_mobs = list()
+
+
+/spell/targeted/choose_targets(mob/user = usr)
+ var/list/targets = list()
+
+ if(max_targets == 0) //unlimited
+ if(range == -2)
+ targets = living_mob_list
+ else
+ for(var/mob/living/target in view_or_range(range, holder, selection_type))
+ targets += target
+
+ else if(max_targets == 1) //single target can be picked
+ if((range == 0 || range == -1) && spell_flags & INCLUDEUSER)
+ targets += user
+ else
+ var/list/possible_targets = list()
+ var/list/starting_targets
+ if(range == -2)
+ starting_targets = living_mob_list
+ else
+ starting_targets = view_or_range(range, holder, selection_type)
+
+ for(var/mob/living/M in starting_targets)
+ if(!(spell_flags & INCLUDEUSER) && M == user)
+ continue
+ if(compatible_mobs && compatible_mobs.len)
+ if(!is_type_in_list(M, compatible_mobs)) continue
+ if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs))
+ continue
+ possible_targets += M
+
+ if(possible_targets.len)
+ if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details
+ var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
+ if(temp_target)
+ targets += temp_target
+ else
+ targets += pick(possible_targets)
+ //Adds a safety check post-input to make sure those targets are actually in range.
+
+
+ else
+ var/list/possible_targets = list()
+ var/list/starting_targets
+
+ if(range == -2)
+ starting_targets = living_mob_list
+ else
+ starting_targets = view_or_range(range, holder, selection_type)
+
+ for(var/mob/living/target in starting_targets)
+ if(!(spell_flags & INCLUDEUSER) && target == user)
+ continue
+ if(compatible_mobs && !is_type_in_list(target, compatible_mobs))
+ continue
+ possible_targets += target
+
+ if(spell_flags & SELECTABLE)
+ for(var/i = 1; i<=max_targets, i++)
+ if(!possible_targets.len)
+ break
+ var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
+ if(!M)
+ break
+ if(range != -2)
+ if(!(M in view_or_range(range, holder, selection_type)))
+ continue
+ targets += M
+ possible_targets -= M
+ else
+ for(var/i=1,i<=max_targets,i++)
+ if(!possible_targets.len)
+ break
+ if(target_ignore_prev)
+ var/target = pick(possible_targets)
+ possible_targets -= target
+ targets += target
+ else
+ targets += pick(possible_targets)
+
+ if(!(spell_flags & INCLUDEUSER) && (user in targets))
+ targets -= user
+
+ if(compatible_mobs && compatible_mobs.len)
+ for(var/mob/living/target in targets) //filters out all the non-compatible mobs
+ if(!is_type_in_list(target, compatible_mobs))
+ targets -= target
+
+ return targets
+
+/spell/targeted/cast(var/list/targets, mob/user)
+ for(var/mob/living/target in targets)
+ if(range >= 0)
+ if(!(target in view_or_range(range, holder, selection_type))) //filter at time of casting
+ targets -= target
+ continue
+ apply_spell_damage(target)
+
+/spell/targeted/proc/apply_spell_damage(mob/living/target)
+ target.adjustBruteLoss(amt_dam_brute)
+ target.adjustFireLoss(amt_dam_fire)
+ target.adjustToxLoss(amt_dam_tox)
+ target.adjustOxyLoss(amt_dam_oxy)
+ //disabling
+ target.Weaken(amt_weakened)
+ target.Paralyse(amt_paralysis)
+ target.Stun(amt_stunned)
+ if(amt_weakened || amt_paralysis || amt_stunned)
+ if(target.buckled)
+ target.buckled = null
+ target.eye_blind += amt_eye_blind
+ target.eye_blurry += amt_eye_blurry
+ target.dizziness += amt_dizziness
+ target.confused += amt_confused
target.stuttering += amt_stuttering
\ No newline at end of file
diff --git a/code/modules/tables/presets.dm b/code/modules/tables/presets.dm
index 60d45f1ede..933f54ea8b 100644
--- a/code/modules/tables/presets.dm
+++ b/code/modules/tables/presets.dm
@@ -63,11 +63,11 @@
icon_state = "holo_preview"
color = "#EEEEEE"
New()
- material = get_material_by_name("holographic [DEFAULT_TABLE_MATERIAL]")
+ material = get_material_by_name("holo[DEFAULT_TABLE_MATERIAL]")
..()
woodentable/holotable
icon_state = "holo_preview"
New()
- material = get_material_by_name("holographic wood")
+ material = get_material_by_name("holowood")
..()
diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm
index 11fc798d33..a496e32c81 100644
--- a/code/modules/tables/tables.dm
+++ b/code/modules/tables/tables.dm
@@ -200,7 +200,7 @@
// Returns the material to set the table to.
/obj/structure/table/proc/common_material_add(obj/item/stack/material/S, mob/user, verb) // Verb is actually verb without 'e' or 'ing', which is added. Works for 'plate'/'plating' and 'reinforce'/'reinforcing'.
- var/material/M = name_to_material[S.default_type]
+ var/material/M = S.get_material()
if(!istype(M))
user << "You cannot [verb]e \the [src] with \the [S]."
return null
diff --git a/code/world.dm b/code/world.dm
index 79b6c059c8..9a5508ffe9 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -127,7 +127,8 @@ var/world_topic_spam_protect_time = world.timeofday
n++
return n
- else if (T == "status")
+ else if (copytext(T,1,7) == "status")
+ var/input[] = params2list(T)
var/list/s = list()
s["version"] = game_version
s["mode"] = master_mode
@@ -136,21 +137,37 @@ var/world_topic_spam_protect_time = world.timeofday
s["vote"] = config.allow_vote_mode
s["ai"] = config.allow_ai
s["host"] = host ? host : null
- s["players"] = list()
s["stationtime"] = worldtime2text()
- var/n = 0
- var/admins = 0
- for(var/client/C in clients)
- if(C.holder)
- if(C.holder.fakekey)
- continue //so stealthmins aren't revealed by the hub
- admins++
- s["player[n]"] = C.key
- n++
- s["players"] = n
+ if(input["status"] == "2")
+ var/list/players = list()
+ var/list/admins = list()
- s["admins"] = admins
+ for(var/client/C in clients)
+ if(C.holder)
+ if(C.holder.fakekey)
+ continue
+ admins[C.key] = C.holder.rank
+ players += C.key
+
+ s["players"] = players.len
+ s["playerlist"] = list2params(players)
+ s["admins"] = admins.len
+ s["adminlist"] = list2params(admins)
+ else
+ var/n = 0
+ var/admins = 0
+
+ for(var/client/C in clients)
+ if(C.holder)
+ if(C.holder.fakekey)
+ continue //so stealthmins aren't revealed by the hub
+ admins++
+ s["player[n]"] = C.key
+ n++
+
+ s["players"] = n
+ s["admins"] = admins
return list2params(s)
diff --git a/config/example/config.txt b/config/example/config.txt
index 7b090d4b38..7f94edde44 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -362,7 +362,11 @@ STARLIGHT 0
## Enable asteroid tunnel/cave generation. Will behave strangely if turned off with a map that expects it on.
# GENERATE_ASTEROID
-
+## Uncomment to enable organ decay outside of a body or storage item.
+#ORGANS_CAN_DECAY
## Uncomment to have the changelog file automatically open when a user connects and hasn't seen the latest changelog
#AGGRESSIVE_CHANGELOG
+
+## Uncomment to override default brain health.
+#DEFAULT_BRAIN_HEALTH 400
\ No newline at end of file
diff --git a/config/example/rules.html b/config/example/rules.html
index af38d30f91..9fbad55bcf 100644
--- a/config/example/rules.html
+++ b/config/example/rules.html
@@ -4,7 +4,7 @@