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 2e0db0b4a2..8400913d05 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -31,6 +31,7 @@
#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"
@@ -145,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"
@@ -606,6 +608,7 @@
#include "code\game\objects\items\devices\scanners.dm"
#include "code\game\objects\items\devices\spy_bug.dm"
#include "code\game\objects\items\devices\suit_cooling.dm"
+#include "code\game\objects\items\devices\t_scanner.dm"
#include "code\game\objects\items\devices\taperecorder.dm"
#include "code\game\objects\items\devices\traitordevices.dm"
#include "code\game\objects\items\devices\transfer_valve.dm"
@@ -773,6 +776,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"
@@ -1113,6 +1117,7 @@
#include "code\modules\mob\animations.dm"
#include "code\modules\mob\death.dm"
#include "code\modules\mob\emote.dm"
+#include "code\modules\mob\gender.dm"
#include "code\modules\mob\hear_say.dm"
#include "code\modules\mob\holder.dm"
#include "code\modules\mob\inventory.dm"
@@ -1278,6 +1283,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"
@@ -1309,6 +1315,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"
@@ -1506,6 +1513,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"
@@ -1674,16 +1682,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
index 048cd644d5..56c95535fe 100644
--- a/code/__defines/lighting.dm
+++ b/code/__defines/lighting.dm
@@ -2,3 +2,5 @@
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..919a67ec37 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,9 @@
#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 HUD_LAYER 20 //Above lighting, but below obfuscation. For in-game HUD effects (whereas SCREEN_LAYER is for abstract/OOC things like inventory slots)
+#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 +155,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 e4e406d219..724225a24c 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -94,3 +94,13 @@
#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'
+#define MAX_SUPPLIED_LAW_NUMBER 50
+
+// NT's alignment towards the character
+#define COMPANY_LOYAL "Loyal"
+#define COMPANY_SUPPORTATIVE "Supportive"
+#define COMPANY_NEUTRAL "Neutral"
+#define COMPANY_SKEPTICAL "Skeptical"
+#define COMPANY_OPPOSED "Opposed"
+
+#define COMPANY_ALIGNMENTS list(COMPANY_LOYAL,COMPANY_SUPPORTATIVE,COMPANY_NEUTRAL,COMPANY_SKEPTICAL,COMPANY_OPPOSED)
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/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 dd4039bbe8..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
@@ -1317,3 +1301,11 @@ var/mob/dview/dview_mob = new
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/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/datums/ai_laws.dm b/code/datums/ai_laws.dm
index edfffde816..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)
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 b7520acefc..55beb37262 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -126,12 +126,12 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager,
/obj/item/weapon/storage/fancy/cigarettes/dromedaryco,
/obj/item/weapon/lipstick/random,
- /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
- /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
- /obj/item/weapon/reagent_containers/food/drinks/cans/beer)
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer)
cost = 20
containertype = /obj/structure/closet/crate
containername = "Party equipment"
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_movable.dm b/code/game/atoms_movable.dm
index 5bc8cc9941..a859f81932 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -21,9 +21,14 @@
if(auto_init && ticker && ticker.current_state == GAME_STATE_PLAYING)
initialize()
+/proc/generate_debug_runtime() // Guaranteed to runtime and print a stack trace to the runtime log
+ var/t = 0 // BYOND won't let us do var/t = 1/0 directly, but it's fine with this.
+ t = 1 / t
+
/atom/movable/Del()
if(isnull(gcDestroyed) && loc)
testing("GC: -- [type] was deleted via del() rather than qdel() --")
+ generate_debug_runtime() // stick a stack trace in the runtime logs
// else if(isnull(gcDestroyed))
// testing("GC: [type] was deleted via GC without qdel()") //Not really a huge issue but from now on, please qdel()
// else
@@ -164,7 +169,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/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm
index 5048977789..45a7dc3896 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/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 9ae0320b67..c741bafb88 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
@@ -379,8 +395,8 @@ var/global/list/additional_antag_types = list()
if (special_role in disregard_roles)
continue
- else if(man.client.prefs.nanotrasen_relation == "Opposed" && prob(50) || \
- man.client.prefs.nanotrasen_relation == "Skeptical" && prob(20))
+ else if(man.client.prefs.nanotrasen_relation == COMPANY_OPPOSED && prob(50) || \
+ man.client.prefs.nanotrasen_relation == COMPANY_SKEPTICAL && prob(20))
suspects += man
// Antags
else if(special_role_data && prob(special_role_data.suspicion_chance))
@@ -546,9 +562,9 @@ proc/get_nt_opposed()
var/list/dudes = list()
for(var/mob/living/carbon/human/man in player_list)
if(man.client)
- if(man.client.prefs.nanotrasen_relation == "Opposed")
+ if(man.client.prefs.nanotrasen_relation == COMPANY_OPPOSED)
dudes += man
- else if(man.client.prefs.nanotrasen_relation == "Skeptical" && prob(50))
+ else if(man.client.prefs.nanotrasen_relation == COMPANY_SKEPTICAL && prob(50))
dudes += man
if(dudes.len == 0) return null
return pick(dudes)
diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm
index c0f8d57f08..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
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/intercept_report.dm b/code/game/gamemodes/intercept_report.dm
index bfe0e1d90d..4feba5d1d2 100644
--- a/code/game/gamemodes/intercept_report.dm
+++ b/code/game/gamemodes/intercept_report.dm
@@ -90,7 +90,7 @@
/datum/intercept_text/proc/get_suspect()
var/list/dudes = list()
- for(var/mob/living/carbon/human/man in player_list) if(man.client && man.client.prefs.nanotrasen_relation == "Opposed")
+ for(var/mob/living/carbon/human/man in player_list) if(man.client && man.client.prefs.nanotrasen_relation == COMPANY_OPPOSED)
dudes += man
for(var/i = 0, i < max(player_list.len/10,2), i++)
dudes += pick(player_list)
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/job/assistant.dm b/code/game/jobs/job/assistant.dm
index f390303452..df54a4ea57 100644
--- a/code/game/jobs/job/assistant.dm
+++ b/code/game/jobs/job/assistant.dm
@@ -8,6 +8,7 @@
spawn_positions = -1
supervisors = "absolutely everyone"
selection_color = "#dddddd"
+ economic_modifier = 1
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","Visitor")
diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm
index f76ef8edb4..665016a1cf 100644
--- a/code/game/jobs/job/captain.dm
+++ b/code/game/jobs/job/captain.dm
@@ -16,6 +16,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
access = list() //See get_access()
minimal_access = list() //See get_access()
minimal_player_age = 14
+ economic_modifier = 20
equip(var/mob/living/carbon/human/H)
if(!H) return 0
H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(H), slot_l_ear)
@@ -60,6 +61,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
idtype = /obj/item/weapon/card/id/silver
req_admin_notify = 1
minimal_player_age = 10
+ economic_modifier = 10
access = list(access_security, access_sec_doors, access_brig, access_court, access_forensics_lockers,
access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm
index 26f5c02020..f45af97286 100644
--- a/code/game/jobs/job/civilian.dm
+++ b/code/game/jobs/job/civilian.dm
@@ -97,6 +97,7 @@
spawn_positions = 1
supervisors = "the head of personnel"
selection_color = "#dddddd"
+ economic_modifier = 5
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)
@@ -149,6 +150,7 @@
spawn_positions = 3
supervisors = "the quartermaster and the head of personnel"
selection_color = "#dddddd"
+ economic_modifier = 5
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")
@@ -311,6 +313,7 @@
spawn_positions = 2
supervisors = "Nanotrasen officials and Corporate Regulations"
selection_color = "#dddddd"
+ economic_modifier = 7
access = list(access_lawyer, access_court, access_sec_doors, access_maint_tunnels, access_heads)
minimal_access = list(access_lawyer, access_court, access_sec_doors, access_heads)
diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm
index 5c86336cb6..27cd6a753e 100644
--- a/code/game/jobs/job/engineering.dm
+++ b/code/game/jobs/job/engineering.dm
@@ -11,6 +11,7 @@
selection_color = "#ffeeaa"
idtype = /obj/item/weapon/card/id/silver
req_admin_notify = 1
+ economic_modifier = 10
access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels,
access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
access_heads, access_construction, access_sec_doors,
@@ -53,6 +54,7 @@
spawn_positions = 5
supervisors = "the chief engineer"
selection_color = "#fff5cc"
+ economic_modifier = 5
access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics)
minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction)
alt_titles = list("Maintenance Technician","Engine Technician","Electrician")
@@ -89,6 +91,7 @@
spawn_positions = 2
supervisors = "the chief engineer"
selection_color = "#fff5cc"
+ economic_modifier = 5
access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_external_airlocks)
minimal_access = list(access_eva, access_engine, access_atmospherics, access_maint_tunnels, access_emergency_storage, access_construction, access_external_airlocks)
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index 33cc45b69f..b84b673a40 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -20,6 +20,9 @@
var/department = null // Does this position have a department tag?
var/head_position = 0 // Is this position Command?
+ var/account_allowed = 1 // Does this job type come with a station account?
+ var/economic_modifier = 2 // With how much does this job modify the initial account amount?
+
/datum/job/proc/equip(var/mob/living/carbon/human/H)
return 1
@@ -34,6 +37,37 @@
H.species.equip_survival_gear(H,0)
return 1
+/datum/job/proc/setup_account(var/mob/living/carbon/human/H)
+ if(!account_allowed || (H.mind && H.mind.initial_account))
+ return
+
+ var/loyalty = 1
+ if(H.client)
+ switch(H.client.prefs.nanotrasen_relation)
+ if(COMPANY_LOYAL) loyalty = 1.30
+ if(COMPANY_SUPPORTATIVE)loyalty = 1.15
+ if(COMPANY_NEUTRAL) loyalty = 1
+ if(COMPANY_SKEPTICAL) loyalty = 0.85
+ if(COMPANY_OPPOSED) loyalty = 0.70
+
+ //give them an account in the station database
+ var/money_amount = (rand(5,50) + rand(5, 50)) * loyalty * economic_modifier * (H.species ? economic_species_modifier[H.species.type] : 2)
+ var/datum/money_account/M = create_account(H.real_name, money_amount, null)
+ if(H.mind)
+ var/remembered_info = ""
+ remembered_info += "Your account number is: #[M.account_number]
"
+ remembered_info += "Your account pin is: [M.remote_access_pin]
"
+ remembered_info += "Your account funds are: $[M.money]
"
+
+ if(M.transaction_log.len)
+ var/datum/transaction/T = M.transaction_log[1]
+ remembered_info += "Your account was created: [T.time], [T.date] at [T.source_terminal]
"
+ H.mind.store_memory(remembered_info)
+
+ H.mind.initial_account = M
+
+ H << "Your account number is: [M.account_number], your account pin is: [M.remote_access_pin]"
+
// overrideable separately so AIs/borgs can have cardborg hats without unneccessary new()/del()
/datum/job/proc/equip_preview(mob/living/carbon/human/H)
return equip(H)
diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm
index 0e79223b18..72a71e9196 100644
--- a/code/game/jobs/job/medical.dm
+++ b/code/game/jobs/job/medical.dm
@@ -11,6 +11,7 @@
selection_color = "#ffddf0"
idtype = /obj/item/weapon/card/id/silver
req_admin_notify = 1
+ economic_modifier = 10
access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_external_airlocks)
@@ -44,6 +45,7 @@
spawn_positions = 3
supervisors = "the chief medical officer"
selection_color = "#ffeef0"
+ economic_modifier = 7
access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics)
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_virology)
alt_titles = list("Surgeon","Emergency Physician","Nurse","Virologist")
@@ -106,6 +108,7 @@
spawn_positions = 2
supervisors = "the chief medical officer"
selection_color = "#ffeef0"
+ economic_modifier = 5
access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics)
minimal_access = list(access_medical, access_chemistry)
alt_titles = list("Pharmacist")
@@ -136,6 +139,7 @@
spawn_positions = 0
supervisors = "the chief medical officer and research director"
selection_color = "#ffeef0"
+ economic_modifier = 7
access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_research)
minimal_access = list(access_medical, access_morgue, access_genetics, access_research)
@@ -162,6 +166,7 @@
faction = "Station"
total_positions = 1
spawn_positions = 1
+ economic_modifier = 5
supervisors = "the chief medical officer"
selection_color = "#ffeef0"
access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_psychiatrist)
@@ -198,6 +203,7 @@
spawn_positions = 2
supervisors = "the chief medical officer"
selection_color = "#ffeef0"
+ economic_modifier = 4
access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_eva, access_maint_tunnels, access_external_airlocks, access_psychiatrist)
minimal_access = list(access_medical, access_medical_equip, access_eva, access_maint_tunnels, access_external_airlocks)
alt_titles = list("Emergency Medical Technician")
diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm
index a7d54284bf..05690d4339 100644
--- a/code/game/jobs/job/science.dm
+++ b/code/game/jobs/job/science.dm
@@ -11,6 +11,7 @@
selection_color = "#ffddff"
idtype = /obj/item/weapon/card/id/silver
req_admin_notify = 1
+ economic_modifier = 15
access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
access_tox_storage, access_teleporter, access_sec_doors,
access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
@@ -47,6 +48,7 @@
spawn_positions = 3
supervisors = "the research director"
selection_color = "#ffeeff"
+ economic_modifier = 7
access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch)
minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch)
alt_titles = list("Xenoarcheologist", "Anomalist", "Phoron Researcher")
@@ -76,6 +78,7 @@
spawn_positions = 2
supervisors = "the research director"
selection_color = "#ffeeff"
+ economic_modifier = 7
access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_hydroponics)
minimal_access = list(access_research, access_xenobiology, access_hydroponics, access_tox_storage)
alt_titles = list("Xenobotanist")
@@ -105,6 +108,7 @@
spawn_positions = 2
supervisors = "research director"
selection_color = "#ffeeff"
+ economic_modifier = 5
access = list(access_robotics, access_tox, access_tox_storage, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access.
minimal_access = list(access_robotics, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access.
alt_titles = list("Biomechanical Engineer","Mechatronic Engineer")
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index cb7a7d23f4..8a9461302d 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -11,6 +11,7 @@
selection_color = "#ffdddd"
idtype = /obj/item/weapon/card/id/silver
req_admin_notify = 1
+ economic_modifier = 10
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_court,
access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting,
@@ -54,6 +55,7 @@
spawn_positions = 1
supervisors = "the head of security"
selection_color = "#ffeeee"
+ economic_modifier = 5
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_morgue, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_external_airlocks)
minimal_player_age = 5
@@ -91,7 +93,7 @@
supervisors = "the head of security"
selection_color = "#ffeeee"
alt_titles = list("Forensic Technician")
-
+ economic_modifier = 5
access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
alt_titles = list("Forensic Technician")
@@ -133,6 +135,7 @@
spawn_positions = 3
supervisors = "the head of security"
selection_color = "#ffeeee"
+ economic_modifier = 4
access = list(access_security, access_eva, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_external_airlocks)
minimal_player_age = 3
diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm
index a76317af03..6cec7149e9 100644
--- a/code/game/jobs/job/silicon.dm
+++ b/code/game/jobs/job/silicon.dm
@@ -9,7 +9,8 @@
supervisors = "your laws"
req_admin_notify = 1
minimal_player_age = 7
-
+ account_allowed = 0
+ economic_modifier = 0
equip(var/mob/living/carbon/human/H)
if(!H) return 0
return 1
@@ -40,6 +41,8 @@
selection_color = "#ddffdd"
minimal_player_age = 1
alt_titles = list("Android", "Robot")
+ account_allowed = 0
+ economic_modifier = 0
equip(var/mob/living/carbon/human/H)
if(!H) return 0
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 143a603ec1..1768ffe642 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -392,6 +392,7 @@ var/global/datum/controller/occupations/job_master
spawn_in_storage += thing
//Equip job items.
job.equip(H)
+ job.setup_account(H)
job.equip_backpack(H)
job.equip_survival(H)
job.apply_fingerprints(H)
@@ -428,21 +429,6 @@ var/global/datum/controller/occupations/job_master
H.buckled.loc = H.loc
H.buckled.set_dir(H.dir)
- //give them an account in the station database
- var/datum/money_account/M = create_account(H.real_name, rand(50,500)*10, null)
- if(H.mind)
- var/remembered_info = ""
- remembered_info += "Your account number is: #[M.account_number]
"
- remembered_info += "Your account pin is: [M.remote_access_pin]
"
- remembered_info += "Your account funds are: $[M.money]
"
-
- if(M.transaction_log.len)
- var/datum/transaction/T = M.transaction_log[1]
- remembered_info += "Your account was created: [T.time], [T.date] at [T.source_terminal]
"
- H.mind.store_memory(remembered_info)
-
- H.mind.initial_account = M
-
// If they're head, give them the account info for their department
if(H.mind && job.head_position)
var/remembered_info = ""
@@ -455,9 +441,6 @@ var/global/datum/controller/occupations/job_master
H.mind.store_memory(remembered_info)
- spawn(0)
- H << "Your account number is: [M.account_number], your account pin is: [M.remote_access_pin]"
-
var/alt_title = null
if(H.mind)
H.mind.assigned_role = rank
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 05b7173323..d5ccdacc3a 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -337,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/alarm.dm b/code/game/machinery/alarm.dm
index 95e043db28..64101d4433 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/autolathe_datums.dm b/code/game/machinery/autolathe_datums.dm
index ca56b4bf78..9aca7c994b 100644
--- a/code/game/machinery/autolathe_datums.dm
+++ b/code/game/machinery/autolathe_datums.dm
@@ -333,7 +333,7 @@
/datum/autolathe/recipe/magazine_c20r
name = "ammunition (12mm)"
- path = /obj/item/ammo_magazine/a12mm
+ path = /obj/item/ammo_magazine/a10mm
hidden = 1
category = "Arms and Ammunition"
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/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 0c038b6c87..416472a31a 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/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/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/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/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm
index 99c1847961..d1ac6df4c5 100644
--- a/code/game/machinery/telecomms/telecomunications.dm
+++ b/code/game/machinery/telecomms/telecomunications.dm
@@ -47,11 +47,13 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
signal.data["slow"] += rand(0, round((100-integrity))) // apply some lag based on integrity
+ /*
+ // Edit by Atlantis: Commented out as emergency fix due to causing extreme delays in communications.
// Apply some lag based on traffic rates
var/netlag = round(traffic / 50)
if(netlag > signal.data["slow"])
signal.data["slow"] = netlag
-
+ */
// Loop through all linked machines and send the signal or copy.
for(var/obj/machinery/telecomms/machine in links)
if(filter && !istype( machine, text2path(filter) ))
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/vending.dm b/code/game/machinery/vending.dm
index 9c79441f32..a665ba9a10 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -688,8 +688,8 @@
/obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/vodka = 5,
/obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/rum = 5,
/obj/item/weapon/reagent_containers/food/drinks/bottle/wine = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/cognac = 5,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua = 5,/obj/item/weapon/reagent_containers/food/drinks/cans/beer = 6,
- /obj/item/weapon/reagent_containers/food/drinks/cans/ale = 6,/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice = 4,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer = 6,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale = 6,/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice = 4,
/obj/item/weapon/reagent_containers/food/drinks/bottle/tomatojuice = 4,/obj/item/weapon/reagent_containers/food/drinks/bottle/limejuice = 4,
/obj/item/weapon/reagent_containers/food/drinks/bottle/cream = 4,/obj/item/weapon/reagent_containers/food/drinks/cans/tonic = 8,
/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 8, /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater = 15,
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 fbdb7667a1..a01dc224c3 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..2b2e696459 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -7,60 +7,6 @@ GAS ANALYZER
MASS SPECTROMETER
REAGENT SCANNER
*/
-/obj/item/device/t_scanner
- name = "\improper T-ray scanner"
- desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
- icon_state = "t-ray0"
- var/on = 0
- slot_flags = SLOT_BELT
- w_class = 2
- item_state = "electronic"
-
- matter = list(DEFAULT_WALL_MATERIAL = 150)
-
- origin_tech = list(TECH_MAGNET = 1, TECH_ENGINERING = 1)
-
-/obj/item/device/t_scanner/attack_self(mob/user)
-
- on = !on
- icon_state = "t-ray[on]"
-
- if(on)
- processing_objects.Add(src)
-
-
-/obj/item/device/t_scanner/process()
- if(!on)
- processing_objects.Remove(src)
- return null
-
- for(var/turf/T in range(1, src.loc) )
-
- if(!T.intact)
- continue
-
- for(var/obj/O in T.contents)
-
- if(O.level != 1)
- continue
-
- if(O.invisibility == 101)
- O.invisibility = 0
- O.alpha = 128
- spawn(10)
- if(O)
- var/turf/U = O.loc
- if(U.intact)
- O.invisibility = 101
- O.alpha = 255
-
- var/mob/living/M = locate() in T
- if(M && M.invisibility == 2)
- M.invisibility = 0
- spawn(2)
- if(M)
- M.invisibility = INVISIBILITY_LEVEL_TWO
-
/obj/item/device/healthanalyzer
name = "health analyzer"
@@ -256,6 +202,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 +217,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/devices/t_scanner.dm b/code/game/objects/items/devices/t_scanner.dm
new file mode 100644
index 0000000000..02ba952621
--- /dev/null
+++ b/code/game/objects/items/devices/t_scanner.dm
@@ -0,0 +1,135 @@
+#define OVERLAY_CACHE_LEN 50
+
+/obj/item/device/t_scanner
+ name = "\improper T-ray scanner"
+ desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
+ icon_state = "t-ray0"
+ slot_flags = SLOT_BELT
+ w_class = 2
+ item_state = "electronic"
+ matter = list(DEFAULT_WALL_MATERIAL = 150)
+ origin_tech = list(TECH_MAGNET = 1, TECH_ENGINERING = 1)
+
+ var/scan_range = 1
+
+ var/on = 0
+ var/list/active_scanned = list() //assoc list of objects being scanned, mapped to their overlay
+ var/client/user_client //since making sure overlays are properly added and removed is pretty important, so we track the current user explicitly
+ var/flicker = 0
+
+ var/global/list/overlay_cache = list() //cache recent overlays
+
+/obj/item/device/t_scanner/update_icon()
+ icon_state = "t-ray[on]"
+
+/obj/item/device/t_scanner/attack_self(mob/user)
+ set_active(!on)
+
+/obj/item/device/t_scanner/proc/set_active(var/active)
+ on = active
+ if(on)
+ processing_objects.Add(src)
+ flicker = 0
+ else
+ processing_objects.Remove(src)
+ set_user_client(null)
+ update_icon()
+
+//If reset is set, then assume the client has none of our overlays, otherwise we only send new overlays.
+/obj/item/device/t_scanner/process()
+ if(!on) return
+
+ //handle clients changing
+ var/client/loc_client = null
+ if(ismob(src.loc))
+ var/mob/M = src.loc
+ loc_client = M.client
+ set_user_client(loc_client)
+
+ //no sense processing if no-one is going to see it.
+ if(!user_client) return
+
+ //get all objects in scan range
+ var/list/scanned = get_scanned_objects(scan_range)
+ var/list/update_add = scanned - active_scanned
+ var/list/update_remove = active_scanned - scanned
+
+ //Add new overlays
+ for(var/obj/O in update_add)
+ var/image/overlay = get_overlay(O)
+ active_scanned[O] = overlay
+ user_client.images += overlay
+
+ //Remove stale overlays
+ for(var/obj/O in update_remove)
+ user_client.images -= active_scanned[O]
+ active_scanned -= O
+
+ //Flicker effect
+ for(var/obj/O in active_scanned)
+ var/image/overlay = active_scanned[O]
+ if(flicker)
+ overlay.alpha = 0
+ else
+ overlay.alpha = 128
+ flicker = !flicker
+
+//creates a new overlay for a scanned object
+/obj/item/device/t_scanner/proc/get_overlay(obj/scanned)
+ //Use a cache so we don't create a whole bunch of new images just because someone's walking back and forth in a room.
+ //Also means that images are reused if multiple people are using t-rays to look at the same objects.
+ if(scanned in overlay_cache)
+ . = overlay_cache[scanned]
+ else
+ var/image/I = image(loc = scanned, icon = scanned.icon, icon_state = scanned.icon_state, layer = HUD_LAYER)
+
+ //Pipes are special
+ if(istype(scanned, /obj/machinery/atmospherics/pipe))
+ var/obj/machinery/atmospherics/pipe/P = scanned
+ I.color = P.pipe_color
+ I.overlays += P.overlays
+
+ I.alpha = 128
+ I.mouse_opacity = 0
+ . = I
+
+ // Add it to cache, cutting old entries if the list is too long
+ overlay_cache[scanned] = .
+ if(overlay_cache.len > OVERLAY_CACHE_LEN)
+ overlay_cache.Cut(1, overlay_cache.len-OVERLAY_CACHE_LEN-1)
+
+/obj/item/device/t_scanner/proc/get_scanned_objects(var/scan_dist)
+ . = list()
+
+ var/turf/center = get_turf(src.loc)
+ if(!center) return
+
+ for(var/turf/T in range(scan_range, center))
+ if(!T.intact)
+ continue
+
+ for(var/obj/O in T.contents)
+ if(O.level != 1)
+ continue
+ if(!O.invisibility)
+ continue //if it's already visible don't need an overlay for it
+ . += O
+
+/obj/item/device/t_scanner/proc/set_user_client(var/client/new_client)
+ if(new_client == user_client)
+ return
+ if(user_client)
+ for(var/scanned in active_scanned)
+ user_client.images -= active_scanned[scanned]
+ if(new_client)
+ for(var/scanned in active_scanned)
+ new_client.images += active_scanned[scanned]
+ else
+ active_scanned.Cut()
+
+ user_client = new_client
+
+/obj/item/device/t_scanner/dropped(mob/user)
+ set_user_client(null)
+
+#undef OVERLAY_CACHE_LEN
\ No newline at end of file
diff --git a/code/game/objects/items/devices/uplink_items.dm b/code/game/objects/items/devices/uplink_items.dm
index 9765519622..e06bc3da16 100644
--- a/code/game/objects/items/devices/uplink_items.dm
+++ b/code/game/objects/items/devices/uplink_items.dm
@@ -131,7 +131,7 @@ datum/uplink_item/dd_SortValue()
path = /obj/item/ammo_magazine/a357
/datum/uplink_item/item/ammo/mc9mm
- name = ".9mm"
+ name = "9mm"
path = /obj/item/ammo_magazine/mc9mm
/datum/uplink_item/item/ammo/darts
@@ -142,6 +142,14 @@ datum/uplink_item/dd_SortValue()
name = "14.5mm"
path = /obj/item/weapon/storage/box/sniperammo
+/datum/uplink_item/item/ammo/a12mm
+ name = "12mm"
+ path = /obj/item/ammo_magazine/a12mm
+
+/datum/uplink_item/item/ammo/a762
+ name = "7.62mm"
+ path = /obj/item/ammo_magazine/a762
+
/***************************************
* Highly Visible and Dangerous Weapons *
***************************************/
@@ -188,6 +196,17 @@ datum/uplink_item/dd_SortValue()
item_cost = DEFAULT_TELECRYSTAL_AMOUNT
path = /obj/item/weapon/gun/projectile/heavysniper
+//These are for traitors (or other antags, perhaps) to have the option of purchasing some merc gear.
+/datum/uplink_item/item/visible_weapons/submachinegun
+ name = "Submachine Gun"
+ item_cost = 6
+ path = /obj/item/weapon/gun/projectile/automatic/c20r
+
+/datum/uplink_item/item/visible_weapons/assaultrifle
+ name = "Assault Rifle"
+ item_cost = 7
+ path = /obj/item/weapon/gun/projectile/automatic/sts35
+
/*************************************
* Stealthy and Inconspicuous Weapons *
*************************************/
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/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 0e6db03bd6..886fa4eac7 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -68,10 +68,7 @@
if (istype(E, /datum/stack_recipe_list))
var/datum/stack_recipe_list/srl = E
- if (src.get_amount() >= srl.req_amount)
- t1 += "[srl.title] ([srl.req_amount] [src.singular_name]\s)"
- else
- t1 += "[srl.title] ([srl.req_amount] [src.singular_name]\s)
"
+ t1 += "[srl.title]"
if (istype(E, /datum/stack_recipe))
var/datum/stack_recipe/R = E
@@ -360,8 +357,6 @@
/datum/stack_recipe_list
var/title = "ERROR"
var/list/recipes = null
- var/req_amount = 1
- New(title, recipes, req_amount = 1)
+ New(title, recipes)
src.title = title
src.recipes = recipes
- src.req_amount = req_amount
diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm
index 5f8403246f..84e4f80d4a 100755
--- a/code/game/objects/items/weapons/AI_modules.dm
+++ b/code/game/objects/items/weapons/AI_modules.dm
@@ -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/bible.dm b/code/game/objects/items/weapons/storage/bible.dm
index af39700dbc..8a29fdefa8 100644
--- a/code/game/objects/items/weapons/storage/bible.dm
+++ b/code/game/objects/items/weapons/storage/bible.dm
@@ -15,8 +15,8 @@
/obj/item/weapon/storage/bible/booze/New()
..()
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src)
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src)
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src)
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src)
new /obj/item/weapon/spacecash(src)
new /obj/item/weapon/spacecash(src)
new /obj/item/weapon/spacecash(src)
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/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index 64f1f9925b..23d819afa0 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -25,6 +25,16 @@ LINEN BINS
add_fingerprint(user)
return
+/obj/item/weapon/bedsheet/attackby(obj/item/I, mob/user)
+ if(is_sharp(I))
+ user.visible_message("\The [user] begins cutting up [src] with [I].", "You begin cutting up [src] with [I].")
+ if(do_after(user, 50))
+ user << "You cut [src] into pieces!"
+ for(var/i in 1 to rand(2,5))
+ new /obj/item/weapon/reagent_containers/glass/rag(src.loc)
+ qdel(src)
+ return
+ ..()
/obj/item/weapon/bedsheet/blue
icon_state = "sheetblue"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
index 96a7e8131a..5fd5cfd314 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
@@ -11,16 +11,16 @@
New()
..()
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
- new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer( src )
return
/obj/structure/closet/secure_closet/bar/update_icon()
diff --git a/code/game/objects/structures/crates_lockers/closets/syndicate.dm b/code/game/objects/structures/crates_lockers/closets/syndicate.dm
index 2214a17f8e..0422b46eb4 100644
--- a/code/game/objects/structures/crates_lockers/closets/syndicate.dm
+++ b/code/game/objects/structures/crates_lockers/closets/syndicate.dm
@@ -42,11 +42,11 @@
/obj/structure/closet/syndicate/nuclear/New()
..()
- new /obj/item/ammo_magazine/a12mm(src)
- new /obj/item/ammo_magazine/a12mm(src)
- new /obj/item/ammo_magazine/a12mm(src)
- new /obj/item/ammo_magazine/a12mm(src)
- new /obj/item/ammo_magazine/a12mm(src)
+ new /obj/item/ammo_magazine/a10mm(src)
+ new /obj/item/ammo_magazine/a10mm(src)
+ new /obj/item/ammo_magazine/a10mm(src)
+ new /obj/item/ammo_magazine/a10mm(src)
+ new /obj/item/ammo_magazine/a10mm(src)
new /obj/item/weapon/storage/box/handcuffs(src)
new /obj/item/weapon/storage/box/flashbangs(src)
new /obj/item/weapon/gun/energy/gun(src)
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/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/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 7ffe728030..b9dcb3047d 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -395,7 +395,7 @@
if (istype(RG) && RG.is_open_container())
RG.reagents.add_reagent("water", min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
user.visible_message("[user] fills \the [RG] using \the [src].","You fill \the [RG] using \the [src].")
- return
+ return 1
else if (istype(O, /obj/item/weapon/melee/baton))
var/obj/item/weapon/melee/baton/B = O
@@ -413,7 +413,7 @@
user.visible_message( \
"[user] was stunned by \his wet [O]!", \
"[user] was stunned by \his wet [O]!")
- return
+ return 1
// Short of a rewrite, this is necessary to stop monkeycubes being washed.
else if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/monkeycube))
return
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 1fec557b8d..ead5e79ecd 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -239,6 +239,7 @@
if(istype(W, /obj/item/weapon/screwdriver))
if(reinf && state >= 1)
state = 3 - state
+ update_nearby_icons()
playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1)
user << (state == 1 ? "You have unfastened the window from the frame." : "You have fastened the window to the frame.")
else if(reinf && state == 0)
@@ -337,7 +338,11 @@
/obj/structure/window/Destroy()
density = 0
update_nearby_tiles()
- update_nearby_icons()
+ var/turf/location = loc
+ loc = null
+ for(var/obj/structure/window/W in orange(location, 1))
+ W.update_icon()
+ loc = location
..()
@@ -357,35 +362,31 @@
//This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc!
/obj/structure/window/proc/update_nearby_icons()
update_icon()
- for(var/direction in cardinal)
- for(var/obj/structure/window/W in get_step(src,direction) )
- W.update_icon()
+ for(var/obj/structure/window/W in orange(src, 1))
+ W.update_icon()
//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm)
/obj/structure/window/update_icon()
//A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong.
//this way it will only update full-tile ones
- //This spawn is here so windows get properly updated when one gets deleted.
- spawn(2)
- if(!src) return
- if(!is_fulltile())
- icon_state = "[basestate]"
- return
- var/junction = 0 //will be used to determine from which side the window is connected to other windows
- if(anchored)
- for(var/obj/structure/window/W in orange(src,1))
- if(W.anchored && W.density && W.is_fulltile()) //Only counts anchored, not-destroyed fill-tile windows.
- if(abs(x-W.x)-abs(y-W.y) ) //doesn't count windows, placed diagonally to src
- junction |= get_dir(src,W)
- if(opacity)
- icon_state = "[basestate][junction]"
- else
- if(reinf)
- icon_state = "[basestate][junction]"
- else
- icon_state = "[basestate][junction]"
-
+ overlays.Cut()
+ if(!is_fulltile())
+ icon_state = "[basestate]"
return
+ var/list/dirs = list()
+ if(anchored)
+ for(var/obj/structure/window/W in orange(src,1))
+ if(W.anchored && W.density && W.type == src.type && W.is_fulltile()) //Only counts anchored, not-destroyed fill-tile windows.
+ dirs += get_dir(src, W)
+
+ var/list/connections = dirs_to_corner_states(dirs)
+
+ icon_state = ""
+ for(var/i = 1 to 4)
+ var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1))
+ overlays += I
+
+ return
/obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature > T0C + 800)
@@ -466,11 +467,9 @@
basestate = "window"
maxhealth = 40
reinf = 1
+ basestate = "w"
dir = 5
- update_icon() //icon_state has to be set manually
- return
-
/obj/structure/window/reinforced/polarized
name = "electrochromic window"
desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it."
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_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index 32668e4743..5cc6ee9289 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -6,16 +6,16 @@
if(density)
can_open = WALL_OPENING
- set_wall_state("[material.icon_base]fwall_open")
//flick("[material.icon_base]fwall_opening", src)
sleep(15)
density = 0
+ update_icon()
set_light(0)
else
can_open = WALL_OPENING
//flick("[material.icon_base]fwall_closing", src)
- set_wall_state("[material.icon_base]0")
density = 1
+ update_icon()
sleep(15)
set_light(1)
@@ -208,7 +208,7 @@
construction_stage = 5
new /obj/item/stack/rods( src )
user << "You cut the outer grille."
- set_wall_state()
+ update_icon()
return
if(5)
if (istype(W, /obj/item/weapon/screwdriver))
@@ -217,7 +217,7 @@
if(!do_after(user,40) || !istype(src, /turf/simulated/wall) || construction_stage != 5)
return
construction_stage = 4
- set_wall_state()
+ update_icon()
user << "You remove the support lines."
return
else if( istype(W, /obj/item/stack/rods) )
@@ -225,7 +225,7 @@
if(O.get_amount()>0)
O.use(1)
construction_stage = 6
- set_wall_state()
+ update_icon()
user << "You replace the outer grille."
return
if(4)
@@ -247,7 +247,7 @@
if(!do_after(user, 60) || !istype(src, /turf/simulated/wall) || construction_stage != 4)
return
construction_stage = 3
- set_wall_state()
+ update_icon()
user << "You press firmly on the cover, dislodging it."
return
if(3)
@@ -257,7 +257,7 @@
if(!do_after(user,100) || !istype(src, /turf/simulated/wall) || construction_stage != 3)
return
construction_stage = 2
- set_wall_state()
+ update_icon()
user << "You pry off the cover."
return
if(2)
@@ -267,7 +267,7 @@
if(!do_after(user,40) || !istype(src, /turf/simulated/wall) || construction_stage != 2)
return
construction_stage = 1
- set_wall_state()
+ update_icon()
user << "You remove the bolts anchoring the support rods."
return
if(1)
@@ -287,7 +287,7 @@
if(!do_after(user,70) || !istype(src, /turf/simulated/wall) || construction_stage != 1)
return
construction_stage = 0
- set_wall_state()
+ update_icon()
new /obj/item/stack/rods(src)
user << "The support rods drop out as you cut them loose from the frame."
return
diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm
index fa6ee92855..4fcc6da93b 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)
@@ -21,82 +21,68 @@
name = "[material.display_name] wall"
desc = "It seems to be a section of hull plated with [material.display_name]."
- set_wall_state("[material.icon_base]0")
-
if(material.opacity > 0.5 && !opacity)
set_light(1)
else if(material.opacity < 0.5 && opacity)
set_light(0)
+ update_connections(1)
update_icon()
- check_relatives()
-/turf/simulated/wall/proc/set_wall_state(var/new_state)
-
- if(!material)
- return
-
- if(new_state)
- last_state = new_state
- else if(last_state)
- new_state = last_state
- else
- return
-
- overlays.Cut()
-
- if(!wall_cache["[new_state]-[material.icon_colour]"])
- var/image/I = image(icon='icons/turf/wall_masks.dmi',icon_state="[new_state]")
- I.color = material.icon_colour
- wall_cache["[new_state]-[material.icon_colour]"] = I
- overlays |= wall_cache["[new_state]-[material.icon_colour]"]
- if(reinf_material)
-
- var/cache_key = "[material.icon_reinf]-[reinf_material.icon_colour]"
- if(!isnull(construction_stage) && construction_stage<6)
- cache_key = "reinf_construct-[reinf_material.icon_colour]-[construction_stage]"
-
- if(!wall_cache[cache_key])
- var/image/I
- if(!isnull(construction_stage) && construction_stage<6)
- I = image(icon='icons/turf/wall_masks.dmi',icon_state="reinf_construct-[construction_stage]")
- else
- I = image(icon='icons/turf/wall_masks.dmi',icon_state="[material.icon_reinf]")
- I.color = reinf_material.icon_colour
- wall_cache[cache_key] = I
- overlays |= wall_cache[cache_key]
/turf/simulated/wall/proc/set_material(var/material/newmaterial, var/material/newrmaterial)
material = newmaterial
reinf_material = newrmaterial
update_material()
- check_relatives()
- check_relatives(1)
/turf/simulated/wall/proc/update_icon()
-
if(!material)
return
if(!damage_overlays[1]) //list hasn't been populated
generate_overlays()
- if(density)
- check_relatives(1)
- else
- set_wall_state("[material.icon_base]fwall_open")
+ overlays.Cut()
+ var/image/I
+
+ if(!density)
+ I = image('icons/turf/wall_masks.dmi', "[material.icon_base]fwall_open")
+ I.color = material.icon_colour
+ overlays += I
+ return
+
+ for(var/i = 1 to 4)
+ I = image('icons/turf/wall_masks.dmi', "[material.icon_base][wall_connections[i]]", dir = 1<<(i-1))
+ I.color = material.icon_colour
+ overlays += I
- 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_overlay && overlay == damage_overlay) //No need to update.
- return
+ if(construction_stage != null && construction_stage < 6)
+ I = image('icons/turf/wall_masks.dmi', "reinf_construct-[construction_stage]")
+ I.color = reinf_material.icon_colour
+ overlays += I
+ else
+ if("[reinf_material.icon_reinf]0" in icon_states('icons/turf/wall_masks.dmi'))
+ // Directional icon
+ for(var/i = 1 to 4)
+ I = image('icons/turf/wall_masks.dmi', "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1))
+ I.color = reinf_material.icon_colour
+ overlays += I
+ else
+ I = image('icons/turf/wall_masks.dmi', reinf_material.icon_reinf)
+ I.color = reinf_material.icon_colour
+ overlays += I
+
+ if(damage != 0)
+ 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
+
overlays += damage_overlays[overlay]
- damage_overlay = overlay
return
/turf/simulated/wall/proc/generate_overlays()
@@ -108,27 +94,23 @@
img.alpha = (i * alpha_inc) - 1
damage_overlays[i] = img
-//Smoothwall code. update_self for relativewall(), not for relativewall_neighbors()
-/turf/simulated/wall/proc/check_relatives(var/update_self)
+
+/turf/simulated/wall/proc/update_connections(propagate = 0)
if(!material)
return
- var/junction
- if(update_self)
- junction = 0
- for(var/checkdir in cardinal)
- var/turf/simulated/wall/T = get_step(src, checkdir)
- if(!istype(T) || !T.material)
+ var/list/dirs = list()
+ for(var/turf/simulated/wall/W in orange(src, 1))
+ if(!W.material)
continue
- if(update_self)
- if(can_join_with(T))
- junction |= get_dir(src,T) //Not too sure why, but using checkdir just breaks walls.
- else
- T.check_relatives(1)
- if(!isnull(junction))
- set_wall_state("[material.icon_base][junction]")
- return
+ if(propagate)
+ W.update_connections()
+ W.update_icon()
+ if(can_join_with(W))
+ dirs += get_dir(src, W)
+
+ wall_connections = dirs_to_corner_states(dirs)
/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..9d5e571d3c 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -1,5 +1,3 @@
-var/list/global/wall_cache = list()
-
/turf/simulated/wall
name = "wall"
desc = "A huge chunk of metal used to seperate rooms."
@@ -12,8 +10,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
@@ -21,6 +19,8 @@ var/list/global/wall_cache = list()
var/last_state
var/construction_stage
+ var/list/wall_connections = list("0", "0", "0", "0")
+
/turf/simulated/wall/New(var/newloc, var/materialtype, var/rmaterialtype)
..(newloc)
icon_state = "blank"
@@ -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,9 +169,9 @@ 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()
+ update_connections(1)
ChangeTurf(/turf/simulated/floor/plating)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 447178ecb3..00bc01eda1 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 b415a317fc..94bbf16415 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("
| AUTHOR | TITLE | CATEGORY | |
| TITLE | Close " user << browse(dat, "window=library") onclose(user, "library") - + /obj/machinery/librarycomp/emag_act(var/remaining_charges, var/mob/user) if (src.density && !src.emagged) src.emagged = 1 @@ -389,6 +389,8 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f if(isnum(orderid)) var/nhref = "src=\ref[src];targetid=[orderid]" spawn() src.Topic(nhref, params2list(nhref), src) + if(href_list["sort"] in list("author", "title", "category")) + sortby = href_list["sort"] src.add_fingerprint(usr) src.updateUsrDialog() return diff --git a/code/modules/lighting/light_source.dm b/code/modules/lighting/light_source.dm index 1ee235fa6f..73a65f064f 100644 --- a/code/modules/lighting/light_source.dm +++ b/code/modules/lighting/light_source.dm @@ -51,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) @@ -62,7 +62,7 @@ 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 @@ -130,16 +130,16 @@ #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) / light_range)) * (1 / sqrt(swapvar + 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) / light_range) + #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 / light_range)) * (1 / sqrt(swapvar**2 + 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 / light_range) + #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01(swapvar / max(1,light_range)) #endif #endif @@ -177,6 +177,7 @@ T.affecting_lights += src effect_turf += T + END_FOR_DVIEW /datum/light_source/proc/remove_lum() applied = 0 @@ -201,11 +202,10 @@ 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) - //Big huge copy paste from apply_lum() incoming because screw unreadable defines and screw proc call overhead. if(T.lighting_overlay) LUM_FALLOFF(., T, source_turf) . *= light_power diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 92500ecc1d..c900f17bf8 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -7,11 +7,22 @@ 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/copy_light(atom/A) + set_light(A.light_range, A.light_power, A.light_color) /atom/proc/update_light() if(!light_power || !light_range) @@ -46,21 +57,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 ca9d9b391f..2dd3889e4e 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -98,3 +98,5 @@ var/turf/T = loc if(istype(T)) T.lighting_overlay = null + + ..() diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index a7a5990709..e261931c41 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -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_recipes.dm b/code/modules/materials/material_recipes.dm index 67e60fc4c4..1912faf65b 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -28,7 +28,7 @@ recipes += new/datum/stack_recipe_list("office chairs",list( \ new/datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("light office chair", /obj/structure/bed/chair/office/light, 5, one_per_turf = 1, on_floor = 1) \ - ), 5) + )) recipes += new/datum/stack_recipe_list("comfy chairs", list( \ new/datum/stack_recipe("beige comfy chair", /obj/structure/bed/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("black comfy chair", /obj/structure/bed/chair/comfy/black, 2, one_per_turf = 1, on_floor = 1), \ @@ -39,7 +39,7 @@ new/datum/stack_recipe("blue comfy chair", /obj/structure/bed/chair/comfy/blue, 2, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("purple comfy chair", /obj/structure/bed/chair/comfy/purp, 2, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1), \ - ), 2) + )) recipes += new/datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1) @@ -69,7 +69,7 @@ new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1), \ - ), 4) + )) recipes += new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade) recipes += new/datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2) @@ -86,7 +86,7 @@ /material/sandstone/generate_recipes() ..() - recipes += new/datum/stack_recipe("pile of dirt", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1) /material/plastic/generate_recipes() ..() @@ -104,6 +104,7 @@ recipes += new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0) recipes += new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1) /material/cardboard/generate_recipes() ..() @@ -122,4 +123,4 @@ new/datum/stack_recipe("red folder", /obj/item/weapon/folder/red), \ new/datum/stack_recipe("white folder", /obj/item/weapon/folder/white), \ new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow), \ - ), 3) \ No newline at end of file + )) 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..153b4313c4 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 @@ -342,7 +359,7 @@ var/list/name_to_material weight = 15 door_icon_base = "stone" destruction_desc = "shatters" - window_options = list("One Direction", "Full Window") + window_options = list("One Direction" = 1, "Full Window" = 4) created_window = /obj/structure/window/basic wire_product = /obj/item/stack/light_w rod_product = /obj/item/stack/material/glass/reinforced @@ -400,9 +417,8 @@ var/list/name_to_material return 1 var/build_path = /obj/structure/windoor_assembly - var/sheets_needed = 4 + var/sheets_needed = window_options[choice] if(choice == "Windoor") - sheets_needed = 5 build_dir = user.dir else build_path = created_window @@ -420,7 +436,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" @@ -432,13 +449,14 @@ var/list/name_to_material weight = 30 stack_origin_tech = "materials=2" composite_material = list(DEFAULT_WALL_MATERIAL = 1875,"glass" = 3750) - window_options = list("One Direction", "Full Window", "Windoor") + window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 5) created_window = /obj/structure/window/reinforced wire_product = null 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 +468,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 +493,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 +570,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 649dee1e1e..b2d4f0f6a5 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 ed71989e50..8c6d44dbca 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -188,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() @@ -319,16 +318,56 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(following && following == target) return following = target - src << "\blue Now following [target]" - spawn(0) - while(target && following == target && client) - var/turf/T = get_turf(target) - if(!T) - break - // To stop the ghost flickering. - if(loc != T) - loc = T - sleep(15) + src << "Now following [target]" + if(ismob(target)) + loc = get_turf(target) + var/mob/M = target + M.following_mobs += src + else + spawn(0) + while(target && following == target && client) + var/turf/T = get_turf(target) + if(!T) + break + // To stop the ghost flickering. + if(loc != T) + loc = T + sleep(15) + +/mob/proc/update_following() + . = get_turf(src) + for(var/mob/dead/observer/M in following_mobs) + if(M.following != src) + following_mobs -= M + else + if(M.loc != .) + M.loc = . + +/mob + var/list/following_mobs = list() + +/mob/Destroy() + for(var/mob/dead/observer/M in following_mobs) + M.following = null + following_mobs = null + return ..() + +/mob/dead/observer/Destroy() + if(ismob(following)) + var/mob/M = following + M.following_mobs -= src + following = null + return ..() + +/mob/Move() + . = ..() + if(.) + update_following() + +/mob/Life() + // to catch teleports etc which directly set loc + update_following() + return ..() /mob/proc/check_holy(var/turf/T) return 0 @@ -560,13 +599,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." \ ) @@ -634,7 +673,7 @@ 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_invisible = SEE_INVISIBLE_NOLIGHTING else see_invisible = SEE_INVISIBLE_OBSERVER if (!ghostvision) 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/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/gender.dm b/code/modules/mob/gender.dm new file mode 100644 index 0000000000..393e0fb6c2 --- /dev/null +++ b/code/modules/mob/gender.dm @@ -0,0 +1,56 @@ + +/var/list/gender_datums = list() + +/hook/startup/proc/populate_gender_datum_list() + for(var/type in typesof(/datum/gender)) + var/datum/gender/G = new type + gender_datums[G.key] = G + return 1 + +/datum/gender + var/key = "plural" + + var/He = "They" + var/he = "they" + var/His = "Their" + var/his = "their" + var/him = "them" + var/has = "have" + var/is = "are" + var/does = "do" + +/datum/gender/male + key = "male" + + He = "He" + he = "he" + His = "His" + his = "his" + him = "him" + has = "has" + is = "is" + does = "does" + +/datum/gender/female + key = "female" + + He = "She" + he = "she" + His = "Her" + his = "her" + him = "her" + has = "has" + is = "is" + does = "does" + +/datum/gender/neuter + key = "neuter" + + He = "It" + he = "it" + His = "Its" + his = "its" + him = "it" + has = "has" + is = "is" + does = "does" diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm index 26cbefc482..862602bd5c 100644 --- a/code/modules/mob/holder.dm +++ b/code/modules/mob/holder.dm @@ -5,10 +5,12 @@ icon = 'icons/obj/objects.dmi' slot_flags = SLOT_HEAD sprite_sheets = list("Vox" = 'icons/mob/species/vox/head.dmi') + origin_tech = null item_icons = list( slot_l_hand_str = 'icons/mob/items/lefthand_holder.dmi', slot_r_hand_str = 'icons/mob/items/righthand_holder.dmi', ) + pixel_y = 8 /obj/item/weapon/holder/New() ..() @@ -31,6 +33,38 @@ qdel(src) +/obj/item/weapon/holder/proc/sync(var/mob/living/M) + dir = 2 + overlays.Cut() + icon = M.icon + icon_state = M.icon_state + color = M.color + name = M.name + desc = M.desc + overlays |= M.overlays + var/mob/living/carbon/human/H = loc + if(istype(H)) + if(H.l_hand == src) + H.update_inv_l_hand() + else if(H.r_hand == src) + H.update_inv_r_hand() + else + H.regenerate_icons() + +//Mob specific holders. +/obj/item/weapon/holder/diona + origin_tech = list(TECH_MAGNET = 3, TECH_BIO = 5) + slot_flags = SLOT_HEAD | SLOT_OCLOTHING + +/obj/item/weapon/holder/drone + origin_tech = list(TECH_MAGNET = 3, TECH_ENGINERING = 5) + +/obj/item/weapon/holder/mouse + w_class = 1 + +/obj/item/weapon/holder/borer + origin_tech = list(TECH_BIO = 6) + /obj/item/weapon/holder/attackby(obj/item/weapon/W as obj, mob/user as mob) for(var/mob/M in src.contents) M.attackby(W,user) @@ -50,72 +84,5 @@ grabber << "You scoop up [src]." src << "[grabber] scoops you up." grabber.status_flags |= PASSEMOTES + H.sync(src) return H - -//Mob specific holders. - -/obj/item/weapon/holder/diona - name = "diona nymph" - desc = "It's a tiny plant critter." - icon_state = "nymph" - origin_tech = list(TECH_MAGNET = 3, TECH_BIO = 5) - slot_flags = SLOT_HEAD | SLOT_OCLOTHING - -/obj/item/weapon/holder/drone - name = "maintenance drone" - desc = "It's a small maintenance robot." - icon_state = "drone" - origin_tech = list(TECH_MAGNET = 3, TECH_ENGINERING = 5) - -/obj/item/weapon/holder/cat - name = "cat" - desc = "It's a cat. Meow." - icon_state = "cat" - origin_tech = null - -/obj/item/weapon/holder/mouse - name = "mouse" - desc = "It's a small rodent." - icon_state = "mouse_gray" - origin_tech = null - w_class = 1 - -/obj/item/weapon/holder/mouse/gray - icon_state = "mouse_gray" - -/obj/item/weapon/holder/mouse/white - icon_state = "mouse_white" - -/obj/item/weapon/holder/mouse/brown - icon_state = "mouse_brown" - -/obj/item/weapon/holder/borer - name = "cortical borer" - desc = "It's a slimy brain slug. Gross." - icon_state = "borer" - origin_tech = list(TECH_BIO = 6) - -/obj/item/weapon/holder/monkey - name = "monkey" - desc = "It's a monkey. Ook." - icon_state = "monkey" - -/obj/item/weapon/holder/monkey/farwa - name = "farwa" - desc = "It's a farwa." - icon_state = "farwa" - -/obj/item/weapon/holder/monkey/stok - name = "stok" - desc = "It's a stok. stok." - icon_state = "stok" - -/obj/item/weapon/holder/monkey/neaera - name = "neaera" - desc = "It's a neaera." - icon_state = "neara" - -/obj/item/weapon/holder/pai - name = "pAI" - desc = "It's a little robot." - icon_state = "pai" 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/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/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm index 86dc101eda..95f01a6dff 100644 --- a/code/modules/mob/living/carbon/alien/diona/diona.dm +++ b/code/modules/mob/living/carbon/alien/diona/diona.dm @@ -9,6 +9,7 @@ universal_understand = 1 universal_speak = 0 // Dionaea do not need to speak to people other than other dionaea. holder_type = /obj/item/weapon/holder/diona + var/obj/item/hat /mob/living/carbon/alien/diona/New() @@ -32,3 +33,10 @@ /mob/living/carbon/alien/diona/put_in_hands(var/obj/item/W) // No hands. W.loc = get_turf(src) return 1 + +/mob/living/carbon/alien/diona/proc/wear_hat(var/obj/item/new_hat) + if(hat) + return + hat = new_hat + new_hat.loc = src + update_icons() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm index 956171abf7..45d1f6fe46 100644 --- a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm +++ b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm @@ -6,5 +6,22 @@ return get_scooped(H) return + else if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand)) + hat.loc = get_turf(src) + H.put_in_hands(hat) + H.visible_message("\The [H] removes \the [src]'s [hat].") + hat = null + update_icons() else return ..() + +/mob/living/carbon/alien/diona/attackby(var/obj/item/weapon/W, var/mob/user) + if(user.a_intent == "help" && istype(W, /obj/item/clothing/head)) + if(hat) + user << "\The [src] is already wearing \the [hat]." + return + user.unEquip(W) + wear_hat(W) + user.visible_message("\The [user] puts \the [W] on \the [src].") + return + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/update_icons.dm b/code/modules/mob/living/carbon/alien/diona/update_icons.dm index b39972cdad..1d694cf624 100644 --- a/code/modules/mob/living/carbon/alien/diona/update_icons.dm +++ b/code/modules/mob/living/carbon/alien/diona/update_icons.dm @@ -6,3 +6,7 @@ icon_state = "[initial(icon_state)]_sleep" else icon_state = "[initial(icon_state)]" + + overlays.Cut() + if(hat) + overlays |= get_hat_icon(hat, 0, -8) \ No newline at end of file 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/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 0695ec4861..cc25a915cb 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -24,46 +24,18 @@ if(wear_mask) skipface |= wear_mask.flags_inv & HIDEFACE - // crappy hacks because you can't do \his[src] etc. I'm sorry this proc is so unreadable, blame the text macros :< - var/t_He = "They" //capitalised for use at the start of each line. - var/t_he = "they" - var/t_his = "their" - var/t_him = "them" - var/t_has = "have" - var/t_is = "are" - var/t_does = "do" - var/msg = "*---------*\nThis is " - //big suits/masks/helmets make it hard to tell their gender - if(!skipjumpsuit || !skipface) + var/datum/gender/T = gender_datums[gender] + if(skipjumpsuit && skipface) //big suits/masks/helmets make it hard to tell their gender + T = gender_datums[PLURAL] + else if(icon) msg += "\icon[icon] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated - switch(gender) - if(MALE) - t_He = "He" - t_he = "he" - t_his = "his" - t_him = "him" - t_has = "has" - t_is = "is" - t_does = "does" - if(FEMALE) - t_He = "She" - t_he = "she" - t_his = "her" - t_him = "her" - t_has = "has" - t_is = "is" - t_does = "does" - if(NEUTER) - t_He = "It" - t_he = "it" - t_his = "its" - t_him = "it" - t_has = "has" - t_is = "is" - t_does = "does" + + if(!T) + // Just in case someone VVs the gender to something strange. It'll runtime anyway when it hits usages, better to CRASH() now with a helpful message. + CRASH("Gender datum was null; key was '[(skipjumpsuit && skipface) ? PLURAL : gender]'") msg += "[src.name]" if(species.name != "Human") @@ -80,111 +52,111 @@ tie_msg += ". Attached to it is [lowertext(english_list(U.accessories))]" if(w_uniform.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained [w_uniform.name][tie_msg]!\n" + msg += "[T.He] [T.is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained [w_uniform.name][tie_msg]!\n" else - msg += "[t_He] [t_is] wearing \icon[w_uniform] \a [w_uniform][tie_msg].\n" + msg += "[T.He] [T.is] wearing \icon[w_uniform] \a [w_uniform][tie_msg].\n" //head if(head) if(head.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[head] [head.gender==PLURAL?"some":"a"] [(head.blood_color != "#030303") ? "blood" : "oil"]-stained [head.name] on [t_his] head!\n" + msg += "[T.He] [T.is] wearing \icon[head] [head.gender==PLURAL?"some":"a"] [(head.blood_color != "#030303") ? "blood" : "oil"]-stained [head.name] on [T.his] head!\n" else - msg += "[t_He] [t_is] wearing \icon[head] \a [head] on [t_his] head.\n" + msg += "[T.He] [T.is] wearing \icon[head] \a [head] on [T.his] head.\n" //suit/armour if(wear_suit) if(wear_suit.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[wear_suit] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != "#030303") ? "blood" : "oil"]-stained [wear_suit.name]!\n" + msg += "[T.He] [T.is] wearing \icon[wear_suit] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != "#030303") ? "blood" : "oil"]-stained [wear_suit.name]!\n" else - msg += "[t_He] [t_is] wearing \icon[wear_suit] \a [wear_suit].\n" + msg += "[T.He] [T.is] wearing \icon[wear_suit] \a [wear_suit].\n" //suit/armour storage if(s_store && !skipsuitstorage) if(s_store.blood_DNA) - msg += "[t_He] [t_is] carrying \icon[s_store] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != "#030303") ? "blood" : "oil"]-stained [s_store.name] on [t_his] [wear_suit.name]!\n" + msg += "[T.He] [T.is] carrying \icon[s_store] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != "#030303") ? "blood" : "oil"]-stained [s_store.name] on [T.his] [wear_suit.name]!\n" else - msg += "[t_He] [t_is] carrying \icon[s_store] \a [s_store] on [t_his] [wear_suit.name].\n" + msg += "[T.He] [T.is] carrying \icon[s_store] \a [s_store] on [T.his] [wear_suit.name].\n" //back if(back) if(back.blood_DNA) - msg += "[t_He] [t_has] \icon[back] [back.gender==PLURAL?"some":"a"] [(back.blood_color != "#030303") ? "blood" : "oil"]-stained [back] on [t_his] back.\n" + msg += "[T.He] [T.has] \icon[back] [back.gender==PLURAL?"some":"a"] [(back.blood_color != "#030303") ? "blood" : "oil"]-stained [back] on [T.his] back.\n" else - msg += "[t_He] [t_has] \icon[back] \a [back] on [t_his] back.\n" + msg += "[T.He] [T.has] \icon[back] \a [back] on [T.his] back.\n" //left hand if(l_hand) if(l_hand.blood_DNA) - msg += "[t_He] [t_is] holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != "#030303") ? "blood" : "oil"]-stained [l_hand.name] in [t_his] left hand!\n" + msg += "[T.He] [T.is] holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != "#030303") ? "blood" : "oil"]-stained [l_hand.name] in [T.his] left hand!\n" else - msg += "[t_He] [t_is] holding \icon[l_hand] \a [l_hand] in [t_his] left hand.\n" + msg += "[T.He] [T.is] holding \icon[l_hand] \a [l_hand] in [T.his] left hand.\n" //right hand if(r_hand) if(r_hand.blood_DNA) - msg += "[t_He] [t_is] holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != "#030303") ? "blood" : "oil"]-stained [r_hand.name] in [t_his] right hand!\n" + msg += "[T.He] [T.is] holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != "#030303") ? "blood" : "oil"]-stained [r_hand.name] in [T.his] right hand!\n" else - msg += "[t_He] [t_is] holding \icon[r_hand] \a [r_hand] in [t_his] right hand.\n" + msg += "[T.He] [T.is] holding \icon[r_hand] \a [r_hand] in [T.his] right hand.\n" //gloves if(gloves && !skipgloves) if(gloves.blood_DNA) - msg += "[t_He] [t_has] \icon[gloves] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != "#030303") ? "blood" : "oil"]-stained [gloves.name] on [t_his] hands!\n" + msg += "[T.He] [T.has] \icon[gloves] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != "#030303") ? "blood" : "oil"]-stained [gloves.name] on [T.his] hands!\n" else - msg += "[t_He] [t_has] \icon[gloves] \a [gloves] on [t_his] hands.\n" + msg += "[T.He] [T.has] \icon[gloves] \a [gloves] on [T.his] hands.\n" else if(blood_DNA) - msg += "[t_He] [t_has] [(hand_blood_color != "#030303") ? "blood" : "oil"]-stained hands!\n" + msg += "[T.He] [T.has] [(hand_blood_color != "#030303") ? "blood" : "oil"]-stained hands!\n" //handcuffed? //handcuffed? if(handcuffed) if(istype(handcuffed, /obj/item/weapon/handcuffs/cable)) - msg += "[t_He] [t_is] \icon[handcuffed] restrained with cable!\n" + msg += "[T.He] [T.is] \icon[handcuffed] restrained with cable!\n" else - msg += "[t_He] [t_is] \icon[handcuffed] handcuffed!\n" + msg += "[T.He] [T.is] \icon[handcuffed] handcuffed!\n" //buckled if(buckled) - msg += "[t_He] [t_is] \icon[buckled] buckled to [buckled]!\n" + msg += "[T.He] [T.is] \icon[buckled] buckled to [buckled]!\n" //belt if(belt) if(belt.blood_DNA) - msg += "[t_He] [t_has] \icon[belt] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != "#030303") ? "blood" : "oil"]-stained [belt.name] about [t_his] waist!\n" + msg += "[T.He] [T.has] \icon[belt] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != "#030303") ? "blood" : "oil"]-stained [belt.name] about [T.his] waist!\n" else - msg += "[t_He] [t_has] \icon[belt] \a [belt] about [t_his] waist.\n" + msg += "[T.He] [T.has] \icon[belt] \a [belt] about [T.his] waist.\n" //shoes if(shoes && !skipshoes) if(shoes.blood_DNA) - msg += "[t_He] [t_is] wearing \icon[shoes] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != "#030303") ? "blood" : "oil"]-stained [shoes.name] on [t_his] feet!\n" + msg += "[T.He] [T.is] wearing \icon[shoes] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != "#030303") ? "blood" : "oil"]-stained [shoes.name] on [T.his] feet!\n" else - msg += "[t_He] [t_is] wearing \icon[shoes] \a [shoes] on [t_his] feet.\n" + msg += "[T.He] [T.is] wearing \icon[shoes] \a [shoes] on [T.his] feet.\n" else if(feet_blood_DNA) - msg += "[t_He] [t_has] [(feet_blood_color != "#030303") ? "blood" : "oil"]-stained feet!\n" + msg += "[T.He] [T.has] [(feet_blood_color != "#030303") ? "blood" : "oil"]-stained feet!\n" //mask if(wear_mask && !skipmask) if(wear_mask.blood_DNA) - msg += "[t_He] [t_has] \icon[wear_mask] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != "#030303") ? "blood" : "oil"]-stained [wear_mask.name] on [t_his] face!\n" + msg += "[T.He] [T.has] \icon[wear_mask] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != "#030303") ? "blood" : "oil"]-stained [wear_mask.name] on [T.his] face!\n" else - msg += "[t_He] [t_has] \icon[wear_mask] \a [wear_mask] on [t_his] face.\n" + msg += "[T.He] [T.has] \icon[wear_mask] \a [wear_mask] on [T.his] face.\n" //eyes if(glasses && !skipeyes) if(glasses.blood_DNA) - msg += "[t_He] [t_has] \icon[glasses] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != "#030303") ? "blood" : "oil"]-stained [glasses] covering [t_his] eyes!\n" + msg += "[T.He] [T.has] \icon[glasses] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != "#030303") ? "blood" : "oil"]-stained [glasses] covering [T.his] eyes!\n" else - msg += "[t_He] [t_has] \icon[glasses] \a [glasses] covering [t_his] eyes.\n" + msg += "[T.He] [T.has] \icon[glasses] \a [glasses] covering [T.his] eyes.\n" //left ear if(l_ear && !skipears) - msg += "[t_He] [t_has] \icon[l_ear] \a [l_ear] on [t_his] left ear.\n" + msg += "[T.He] [T.has] \icon[l_ear] \a [l_ear] on [T.his] left ear.\n" //right ear if(r_ear && !skipears) - msg += "[t_He] [t_has] \icon[r_ear] \a [r_ear] on [t_his] right ear.\n" + msg += "[T.He] [T.has] \icon[r_ear] \a [r_ear] on [T.his] right ear.\n" //ID if(wear_id) @@ -196,70 +168,71 @@ var/obj/item/weapon/card/id/idcard = wear_id id = idcard.registered_name if(id && (id != real_name) && (get_dist(src, usr) <= 1) && prob(10)) - msg += "[t_He] [t_is] wearing \icon[wear_id] \a [wear_id] yet something doesn't seem right...\n" + msg += "[T.He] [T.is] wearing \icon[wear_id] \a [wear_id] yet something doesn't seem right...\n" else*/ - msg += "[t_He] [t_is] wearing \icon[wear_id] \a [wear_id].\n" + msg += "[T.He] [T.is] wearing \icon[wear_id] \a [wear_id].\n" //Jitters if(is_jittery) if(jitteriness >= 300) - msg += "[t_He] [t_is] convulsing violently!\n" + msg += "[T.He] [T.is] convulsing violently!\n" else if(jitteriness >= 200) - msg += "[t_He] [t_is] extremely jittery.\n" + msg += "[T.He] [T.is] extremely jittery.\n" else if(jitteriness >= 100) - msg += "[t_He] [t_is] twitching ever so slightly.\n" + msg += "[T.He] [T.is] twitching ever so slightly.\n" //splints for(var/organ in list("l_leg","r_leg","l_arm","r_arm")) var/obj/item/organ/external/o = get_organ(organ) if(o && o.status & ORGAN_SPLINTED) - msg += "[t_He] [t_has] a splint on [t_his] [o.name]!\n" + msg += "[T.He] [T.has] a splint on [T.his] [o.name]!\n" if(suiciding) - msg += "[t_He] appears to have commited suicide... there is no hope of recovery.\n" + msg += "[T.He] appears to have commited suicide... there is no hope of recovery.\n" if(mSmallsize in mutations) - msg += "[t_He] [t_is] small halfling!\n" + msg += "[T.He] [T.is] small halfling!\n" var/distance = get_dist(usr,src) if(istype(usr, /mob/dead/observer) || usr.stat == 2) // ghosts can see anything distance = 1 if (src.stat) - msg += "[t_He] [t_is]n't responding to anything around [t_him] and seems to be asleep.\n" + msg += "[T.He] [T.is]n't responding to anything around [T.him] and seems to be asleep.\n" if((stat == 2 || src.losebreath) && distance <= 3) - msg += "[t_He] [t_does] not appear to be breathing.\n" + msg += "[T.He] [T.does] not appear to be breathing.\n" if(istype(usr, /mob/living/carbon/human) && !usr.stat && Adjacent(usr)) usr.visible_message("[usr] checks [src]'s pulse.", "You check [src]'s pulse.") spawn(15) if(distance <= 1 && usr.stat != 1) if(pulse == PULSE_NONE) - usr << "[t_He] [t_has] no pulse[src.client ? "" : " and [t_his] soul has departed"]..." + usr << "[T.He] [T.has] no pulse[src.client ? "" : " and [T.his] soul has departed"]..." else - usr << "[t_He] [t_has] a pulse!" + usr << "[T.He] [T.has] a pulse!" + if(fire_stacks) - msg += "[t_He] [t_is] covered in some liquid.\n" + msg += "[T.He] [T.is] covered in some liquid.\n" if(on_fire) - msg += "[t_He] [t_is] on fire!.\n" + msg += "[T.He] [T.is] on fire!.\n" msg += "" if(nutrition < 100) - msg += "[t_He] [t_is] severely malnourished.\n" + msg += "[T.He] [T.is] severely malnourished.\n" else if(nutrition >= 500) /*if(usr.nutrition < 100) - msg += "[t_He] [t_is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n" + msg += "[T.He] [T.is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n" else*/ - msg += "[t_He] [t_is] quite chubby.\n" + msg += "[T.He] [T.is] quite chubby.\n" msg += "" if(getBrainLoss() >= 60) - msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n" + msg += "[T.He] [T.has] a stupid expression on [T.his] face.\n" if(species.show_ssd && (!species.has_organ["brain"] || has_brain()) && stat != DEAD) if(!key) - msg += "[t_He] [t_is] fast asleep. It doesn't look like [t_he] [t_is] waking up anytime soon.\n" + msg += "[T.He] [T.is] [species.show_ssd]. It doesn't look like [T.he] [T.is] waking up anytime soon.\n" else if(!client) - msg += "[t_He] [t_is] [species.show_ssd].\n" + msg += "[T.He] [T.is] [species.show_ssd].\n" var/list/wound_flavor_text = list() var/list/is_destroyed = list() @@ -273,9 +246,9 @@ var/obj/item/organ/external/E = organs_by_name[organ_tag] if(!E) - wound_flavor_text["[organ_descriptor]"] = "[t_He] is missing [t_his] [organ_descriptor].\n" + wound_flavor_text["[organ_descriptor]"] = "[T.He] [T.is] missing [T.his] [organ_descriptor].\n" else if(E.is_stump()) - wound_flavor_text["[organ_descriptor]"] = "[t_He] has a stump where [t_his] [organ_descriptor] should be.\n" + wound_flavor_text["[organ_descriptor]"] = "[T.He] [T.has] a stump where [T.his] [organ_descriptor] should be.\n" else is_destroyed["organ_descriptor"] = 0 continue @@ -284,24 +257,24 @@ if(temp) if(temp.status & ORGAN_DESTROYED) is_destroyed["[temp.name]"] = 1 - wound_flavor_text["[temp.name]"] = "[t_He] [t_is] missing [t_his] [temp.name].\n" + wound_flavor_text["[temp.name]"] = "[T.He] [T.is] missing [T.his] [temp.name].\n" continue if(temp.status & ORGAN_ROBOT) if(!(temp.brute_dam + temp.burn_dam)) - wound_flavor_text["[temp.name]"] = "[t_He] has a robot [temp.name]!\n" + wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a robot [temp.name]!\n" continue else - wound_flavor_text["[temp.name]"] = "[t_He] has a robot [temp.name]. It has[temp.get_wounds_desc()]!\n" + wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a robot [temp.name]. It has[temp.get_wounds_desc()]!\n" else if(temp.wounds.len > 0 || temp.open) - wound_flavor_text["[temp.name]"] = "[t_He] has [temp.get_wounds_desc()] on [t_his] [temp.name]. " + wound_flavor_text["[temp.name]"] = "[T.He] [T.has] [temp.get_wounds_desc()] on [T.his] [temp.name]. " if(temp.status & ORGAN_BLEEDING) - is_bleeding["[temp.name]"] = "[capitalize(t_his)] [temp.name] is bleeding! " + is_bleeding["[temp.name]"] = "[T.His] [temp.name] is bleeding! " else wound_flavor_text["[temp.name]"] = "" if(temp.dislocated == 2) - wound_flavor_text["[temp.name]"] += "[capitalize(t_his)] [temp.joint] is dislocated! " + wound_flavor_text["[temp.name]"] += "[T.His] [temp.joint] is dislocated! " if(((temp.status & ORGAN_BROKEN) && temp.brute_dam > temp.min_broken_damage) || (temp.status & ORGAN_MUTATED)) - wound_flavor_text["[temp.name]"] += "[capitalize(t_his)] [temp.name] is dented and swollen! " + wound_flavor_text["[temp.name]"] += "[T.His] [temp.name] is dented and swollen! " //Handles the text strings being added to the actual description. //If they have something that covers the limb, and it is not missing, put flavortext. If it is covered but bleeding, add other flavortext. @@ -318,7 +291,7 @@ if(wound_flavor_text["head"] && (is_destroyed["head"] || (!skipmask && !(wear_mask && istype(wear_mask, /obj/item/clothing/mask/gas))))) msg += wound_flavor_text["head"] else if(is_bleeding["head"]) - msg += "[src] [t_has] blood running down [t_his] face!\n" + msg += "[src] [T.has] blood running down [T.his] face!\n" if(wound_flavor_text["upper body"] && !w_uniform && !skipjumpsuit) //No need. A missing chest gibs you. msg += wound_flavor_text["upper body"] @@ -369,11 +342,11 @@ display_shoes = 1 if(display_chest) - msg += "[src] [t_has] blood soaking through from under [t_his] clothing!\n" + msg += "[src] [T.has] blood soaking through from under [T.his] clothing!\n" if(display_shoes) - msg += "[src] [t_has] blood running from [t_his] shoes!\n" + msg += "[src] [T.has] blood running from [T.his] shoes!\n" if(display_gloves) - msg += "[src] [t_has] blood running from under [t_his] gloves!\n" + msg += "[src] [T.has] blood running from under [T.his] gloves!\n" */ for(var/limb in wound_flavor_text) @@ -382,9 +355,9 @@ for(var/limb in is_bleeding) msg += is_bleeding[limb] for(var/implant in get_visible_implants(0)) - msg += "[src] [t_has] \a [implant] sticking out of [t_his] flesh!\n" + msg += "[src] [T.has] \a [implant] sticking out of [T.his] flesh!\n" if(digitalcamo) - msg += "[t_He] [t_is] repulsively uncanny!\n" + msg += "[T.He] [T.is] repulsively uncanny!\n" if(hasHUD(usr,"security")) var/perpname = "wot" @@ -438,7 +411,7 @@ if (pose) if( findtext(pose,".",lentext(pose)) == 0 && findtext(pose,"!",lentext(pose)) == 0 && findtext(pose,"?",lentext(pose)) == 0 ) pose = addtext(pose,".") //Makes sure all emotes end with a period. - msg += "\n[t_He] [t_is] [pose]" + msg += "\n[T.He] [T.is] [pose]" user << msg diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 07dbcaf056..dc34cfec3c 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 @@ -1022,23 +1023,29 @@ return(visible_implants) +/mob/living/carbon/human/embedded_needs_process() + for(var/obj/item/organ/external/organ in src.organs) + for(var/obj/item/O in organ.implants) + if(!istype(O, /obj/item/weapon/implant)) //implant type items do not cause embedding effects, see handle_embedded_objects() + return 1 + return 0 + /mob/living/carbon/human/proc/handle_embedded_objects() for(var/obj/item/organ/external/organ in src.organs) if(organ.status & ORGAN_SPLINTED) //Splints prevent movement. continue - for(var/obj/item/weapon/O in organ.implants) + for(var/obj/item/O in organ.implants) if(!istype(O,/obj/item/weapon/implant) && prob(5)) //Moving with things stuck in you could be bad. // All kinds of embedded objects cause bleeding. - var/msg = null - switch(rand(1,3)) - if(1) - msg ="A spike of pain jolts your [organ.name] as you bump [O] inside." - if(2) - msg ="Your movement jostles [O] in your [organ.name] painfully." - if(3) - msg ="[O] in your [organ.name] twists painfully as you move." - src << msg + if(species.flags & NO_PAIN) + src << "You feel [O] moving inside your [organ.name]." + else + var/msg = pick( \ + "A spike of pain jolts your [organ.name] as you bump [O] inside.", \ + "Your movement jostles [O] in your [organ.name] painfully.", \ + "Your movement jostles [O] in your [organ.name] painfully.") + src << msg organ.take_damage(rand(1,3), 0, 0) if(!(organ.status & ORGAN_ROBOT) && !(species.flags & NO_BLOOD)) //There is no blood in protheses. @@ -1361,3 +1368,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 1faf2f7e7a..cdaad1c42f 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/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index 2dec075afa..d69f6e57cc 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -134,28 +134,29 @@ continue if(E.is_broken() || E.is_dislocated()) - if(E.body_part == HAND_LEFT) - if(!l_hand) - continue - drop_from_inventory(l_hand) - else - if(!r_hand) - continue - drop_from_inventory(r_hand) + switch(E.body_part) + if(HAND_LEFT, ARM_LEFT) + if(!l_hand) + continue + drop_from_inventory(l_hand) + if(HAND_RIGHT, ARM_RIGHT) + if(!r_hand) + continue + drop_from_inventory(r_hand) var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ") emote("me", 1, "[(species.flags & NO_PAIN) ? "" : emote_scream ]drops what they were holding in their [E.name]!") else if(E.is_malfunctioning()) - - if(E.body_part == HAND_LEFT) - if(!l_hand) - continue - drop_from_inventory(l_hand) - else - if(!r_hand) - continue - drop_from_inventory(r_hand) + switch(E.body_part) + if(HAND_LEFT, ARM_LEFT) + if(!l_hand) + continue + drop_from_inventory(l_hand) + if(HAND_RIGHT, ARM_RIGHT) + if(!r_hand) + continue + drop_from_inventory(r_hand) emote("me", 1, "drops what they were holding, their [E.name] malfunctioning!") @@ -176,4 +177,4 @@ /mob/living/carbon/human/proc/sync_organ_dna() var/list/all_bits = internal_organs|organs for(var/obj/item/organ/O in all_bits) - O.set_dna(dna) \ No newline at end of file + O.set_dna(dna) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index a75a4b1630..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) && !O.is_stump()) + 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 bd913f33cb..282831641c 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1015,6 +1015,10 @@ // Check everything else. + //Periodically double-check embedded_flag + if(embedded_flag && !(life_tick % 10)) + if(!embedded_needs_process()) + embedded_flag = 0 //Vision var/obj/item/organ/vision if(species.vision_organ) @@ -1197,7 +1201,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,17 +1212,6 @@ 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 @@ -1237,7 +1230,7 @@ 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 @@ -1279,6 +1272,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" @@ -1406,6 +1401,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/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 107ad0fe72..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 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/monkey.dm b/code/modules/mob/living/carbon/human/species/station/monkey.dm index db6c69b409..6ae24db2f6 100644 --- a/code/modules/mob/living/carbon/human/species/station/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/station/monkey.dm @@ -37,7 +37,6 @@ bump_flag = MONKEY swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL push_flags = MONKEY|SLIME|SIMPLE_ANIMAL|ALIEN - var/holder_type = /obj/item/weapon/holder/monkey /datum/species/monkey/handle_npc(var/mob/living/carbon/human/H) if(H.stat != CONSCIOUS) @@ -47,10 +46,6 @@ if(prob(1)) H.emote(pick("scratch","jump","roll","tail")) -/datum/species/monkey/handle_post_spawn(var/mob/living/carbon/human/H) - ..() - H.holder_type = holder_type - /datum/species/monkey/get_random_name() return "[lowertext(name)] ([rand(100,999)])" @@ -66,7 +61,6 @@ flesh_color = "#AFA59E" base_color = "#333333" tail = "farwatail" - holder_type = /obj/item/weapon/holder/monkey/farwa /datum/species/monkey/skrell name = "Neara" @@ -81,7 +75,6 @@ blood_color = "#1D2CBF" reagent_tag = IS_SKRELL tail = null - holder_type = /obj/item/weapon/holder/monkey/neaera /datum/species/monkey/unathi name = "Stok" @@ -96,4 +89,3 @@ flesh_color = "#34AF10" base_color = "#066000" reagent_tag = IS_UNATHI - holder_type = /obj/item/weapon/holder/monkey/stok 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 8e0402b91a..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,13 +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 \ @@ -69,13 +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 \ @@ -116,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 \ @@ -124,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 @@ -147,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 \ @@ -251,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/life.dm b/code/modules/mob/living/life.dm index d7f475ec5b..5e7a6e2d90 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -2,6 +2,8 @@ set invisibility = 0 set background = BACKGROUND_ENABLED + ..() + if (transforming) return if(!loc) @@ -125,7 +127,8 @@ //this handles hud updates. Calls update_vision() and handle_hud_icons() /mob/living/handle_regular_hud_updates() - if(!client) return 0 + if(!client) + return 0 ..() handle_vision() 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 c48339842c..3004b9dd9e 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -383,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/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..4641c7d2de 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -6,7 +6,6 @@ emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) small = 1 pass_flags = 1 - holder_type = /obj/item/weapon/holder/pai var/network = "SS13" var/obj/machinery/camera/current = null @@ -120,7 +119,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() @@ -431,4 +429,4 @@ get_scooped(H) return else - return ..() + return ..() 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..37c40d7161 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -1,3 +1,23 @@ +var/list/mob_hat_cache = list() +/proc/get_hat_icon(var/obj/item/hat, var/offset_x = 0, var/offset_y = 0) + var/t_state = hat.icon_state + if(hat.item_state_slots && hat.item_state_slots[slot_head_str]) + t_state = hat.item_state_slots[slot_head_str] + else if(hat.item_state) + t_state = hat.item_state + var/key = "[t_state]_[offset_x]_[offset_y]" + if(!mob_hat_cache[key]) // Not ideal as there's no guarantee all hat icon_states + var/t_icon = INV_HEAD_DEF_ICON // are unique across multiple dmis, but whatever. + if(hat.icon_override) + t_icon = hat.icon_override + else if(hat.item_icons && (slot_head_str in hat.item_icons)) + t_icon = hat.item_icons[slot_head_str] + var/image/I = image(icon = t_icon, icon_state = t_state) + I.pixel_x = offset_x + I.pixel_y = offset_y + mob_hat_cache[key] = I + return mob_hat_cache[key] + /mob/living/silicon/robot/drone name = "drone" real_name = "drone" @@ -29,9 +49,26 @@ var/module_type = /obj/item/weapon/robot_module/drone var/can_pull_size = 2 var/can_pull_mobs + var/obj/item/hat + var/hat_x_offset = 0 + var/hat_y_offset = -13 holder_type = /obj/item/weapon/holder/drone +/mob/living/silicon/robot/drone/Destroy() + if(hat) + hat.loc = get_turf(src) + ..() + +/mob/living/silicon/robot/drone/construction + icon_state = "constructiondrone" + law_type = /datum/ai_laws/construction_drone + module_type = /obj/item/weapon/robot_module/drone/construction + can_pull_size = 5 + can_pull_mobs = 1 + hat_x_offset = 1 + hat_y_offset = -12 + /mob/living/silicon/robot/drone/New() ..() @@ -82,6 +119,8 @@ overlays += "eyes-[icon_state]" else overlays -= "eyes" + if(hat) // Let the drones wear hats. + overlays |= get_hat_icon(hat, hat_x_offset, hat_y_offset) /mob/living/silicon/robot/drone/choose_icon() return @@ -89,10 +128,25 @@ /mob/living/silicon/robot/drone/pick_module() return -//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..(). -/mob/living/silicon/robot/drone/attackby(obj/item/weapon/W as obj, mob/user as mob) +/mob/living/silicon/robot/drone/proc/wear_hat(var/obj/item/new_hat) + if(hat) + return + hat = new_hat + new_hat.loc = src + updateicon() - if(istype(W, /obj/item/borg/upgrade/)) +//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..(). +/mob/living/silicon/robot/drone/attackby(var/obj/item/weapon/W, var/mob/user) + + if(user.a_intent == "help" && istype(W, /obj/item/clothing/head)) + if(hat) + user << "\The [src] is already wearing \the [hat]." + return + user.unEquip(W) + wear_hat(W) + user.visible_message("\The [user] puts \the [W] on \the [src].") + return + else if(istype(W, /obj/item/borg/upgrade/)) user << "\The [src] is not compatible with \the [W]." return @@ -135,7 +189,7 @@ return ..() - + /mob/living/silicon/robot/drone/emag_act(var/remaining_charges, var/mob/user) if(!client || stat == 2) user << "There's not much point subverting this heap of junk." @@ -160,11 +214,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 +267,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 +311,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 @@ -281,13 +333,6 @@ /mob/living/silicon/robot/drone/remove_robot_verbs() src.verbs -= silicon_subsystems -/mob/living/silicon/robot/drone/construction - icon_state = "constructiondrone" - law_type = /datum/ai_laws/construction_drone - module_type = /obj/item/weapon/robot_module/drone/construction - can_pull_size = 5 - can_pull_mobs = 1 - /mob/living/silicon/robot/drone/construction/welcome_drone() src << "You are a construction drone, an autonomous engineering and fabrication system.." src << "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible." @@ -300,4 +345,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_abilities.dm b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm index 0eaf1c8779..e5aa936a08 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm @@ -10,13 +10,13 @@ mail_destination = "" return - src << "\blue You configure your internal beacon, tagging yourself for delivery to '[new_tag]'." + src << "You configure your internal beacon, tagging yourself for delivery to '[new_tag]'." mail_destination = new_tag //Auto flush if we use this verb inside a disposal chute. var/obj/machinery/disposal/D = src.loc if(istype(D)) - src << "\blue \The [D] acknowledges your signal." + src << "\The [D] acknowledges your signal." D.flush_count = D.flush_every_ticks return @@ -27,5 +27,11 @@ if(H.a_intent == "help") get_scooped(H) return + else if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand)) + hat.loc = get_turf(src) + H.put_in_hands(hat) + H.visible_message("\The [H] removes \the [src]'s [hat].") + hat = null + updateicon() else return ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 84611ecb95..0ec65be420 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -14,6 +14,7 @@ /obj/item/weapon/firealarm_electronics, /obj/item/weapon/airalarm_electronics, /obj/item/weapon/airlock_electronics, + /obj/item/weapon/tracker_electronics, /obj/item/weapon/module/power_control, /obj/item/weapon/stock_parts, /obj/item/frame, diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index a292ead1b1..171fc29933 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -78,7 +78,8 @@ flick("h_lathe_leave",src) time_last_drone = world.time - var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src)) + if(player.mob && player.mob.mind) player.mob.mind.reset() + var/mob/living/silicon/robot/drone/new_drone = PoolOrNew(drone_type, get_turf(src)) new_drone.transfer_personality(player) new_drone.master_fabricator = src @@ -90,7 +91,6 @@ set name = "Join As Drone" set desc = "If there is a powered, enabled fabricator in the game world with a prepared chassis, join as a maintenance drone." - if(ticker.current_state < GAME_STATE_PLAYING) src << "The game hasn't started yet!" return @@ -108,17 +108,11 @@ if(jobban_isbanned(src,"Cyborg")) usr << "You are banned from playing synthetics and cannot spawn as a drone." return - + if(!MayRespawn(1)) return var/deathtime = world.time - src.timeofdeath - if(istype(src,/mob/dead/observer)) - var/mob/dead/observer/G = src - if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted) - usr << "Upon using the antagHUD you forfeighted the ability to join the round." - return - var/deathtimeminutes = round(deathtime / 600) var/pluralcheck = "minute" if(deathtimeminutes == 0) 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 c9d08b2b49..8e8ab59ca6 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() 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 4d7179bbfc..a36cca1710 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) @@ -505,7 +507,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/tray/robotray(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) + src.emag = new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src) var/datum/reagents/R = new/datum/reagents(50) src.emag.reagents = R @@ -538,7 +540,7 @@ var/global/list/robot_modules = list( var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules E.reagents.add_reagent("enzyme", 2 * amount) if(src.emag) - var/obj/item/weapon/reagent_containers/food/drinks/cans/beer/B = src.emag + var/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/B = src.emag B.reagents.add_reagent("beer2", 2 * amount) /obj/item/weapon/robot_module/miner 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 7781a26744..0dcf7d71c1 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 diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 3197c6023c..daf7b3768e 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -59,8 +59,13 @@ var/mob/dead/observer/spook = locate() in range(src,5) if(spook) var/turf/T = spook.loc - var/obj/O = pick(T.contents) - visible_emote("suddenly stops and stares at something unseen[istype(O) ? " near [O]":""].") + var/list/visible = list() + for(var/obj/O in T.contents) + if(!O.invisibility && O.name) + visible += O + if(visible.len) + var/atom/A = pick(visible) + visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].") /mob/living/simple_animal/cat/proc/handle_movement_target() //if our target is neither inside a turf or inside a human(???), stop diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 70f7282b8e..e0ffc718ff 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -63,13 +63,6 @@ if(!body_color) body_color = pick( list("brown","gray","white") ) - switch(body_color) - if("brown") - holder_type = /obj/item/weapon/holder/mouse/brown - if("gray") - holder_type = /obj/item/weapon/holder/mouse/gray - if("white") - holder_type = /obj/item/weapon/holder/mouse/white icon_state = "mouse_[body_color]" icon_living = "mouse_[body_color]" icon_dead = "mouse_[body_color]_dead" @@ -125,17 +118,14 @@ /mob/living/simple_animal/mouse/white body_color = "white" icon_state = "mouse_white" - holder_type = /obj/item/weapon/holder/mouse/white /mob/living/simple_animal/mouse/gray body_color = "gray" icon_state = "mouse_gray" - holder_type = /obj/item/weapon/holder/mouse/gray /mob/living/simple_animal/mouse/brown body_color = "brown" icon_state = "mouse_brown" - holder_type = /obj/item/weapon/holder/mouse/brown //TOM IS ALIVE! SQUEEEEEEEE~K :) /mob/living/simple_animal/mouse/brown/Tom diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index fa742733a2..9156f24c7f 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -107,7 +107,7 @@ rapid = 1 icon_state = "syndicateranged" icon_living = "syndicateranged" - casingtype = /obj/item/ammo_casing/a12mm + casingtype = /obj/item/ammo_casing/a10mm projectilesound = 'sound/weapons/Gunshot_light.ogg' projectiletype = /obj/item/projectile/bullet/pistol/medium diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4407773119..9f24c4e1a1 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() @@ -834,6 +872,9 @@ visible_implants += O return visible_implants +/mob/proc/embedded_needs_process() + return (embedded.len > 0) + mob/proc/yank_out_object() set category = "Object" set name = "Yank out object" @@ -1048,4 +1089,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_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/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/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_external.dm b/code/modules/organs/organ_external.dm index ad4021adf3..1b6108c238 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -53,7 +53,7 @@ var/joint = "joint" // Descriptive string used in dislocation. var/amputation_point // Descriptive string used in amputation. var/dislocated = 0 // If you target a joint, you can dislocate the limb, causing temporary damage to the organ. - var/can_grasp + var/can_grasp //It would be more appropriate if these two were named "affects_grasp" and "affects_stand" at this point var/can_stand /obj/item/organ/external/Destroy() 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/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/paper.dm b/code/modules/paperwork/paper.dm index f72fa474fd..d7b41e80cb 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -107,6 +107,15 @@ return /obj/item/weapon/paper/attack_self(mob/living/user as mob) + if(user.a_intent == I_HURT) + if(icon_state == "scrap") + user.show_message("\The [src] is already crumpled.") + return + //crumple dat paper + info = stars(info,85) + user.visible_message("\The [user] crumples \the [src] into a ball!") + icon_state = "scrap" + return user.examinate(src) if(rigged && (Holiday == "April Fool's Day")) if(spam_flag == 0) @@ -442,6 +451,10 @@ B.update_icon() else if(istype(P, /obj/item/weapon/pen)) + if(icon_state == "scrap") + usr << "\The [src] is too crumpled to write on." + return + var/obj/item/weapon/pen/robopen/RP = P if ( istype(RP) && RP.mode == 2 ) RP.RenamePaper(user,src) diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 4ef6f1eef5..963243107f 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -17,7 +17,17 @@ if((user == usr && (!( usr.restrained() ) && (!( usr.stat ) && (usr.contents.Find(src) || in_range(src, usr)))))) if(!istype(usr, /mob/living/carbon/slime) && !istype(usr, /mob/living/simple_animal)) if( !usr.get_active_hand() ) //if active hand is empty - attack_hand(usr, 1, 1) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name["r_hand"] + + if (H.hand) + temp = H.organs_by_name["l_hand"] + if(temp && !temp.is_usable()) + user << "You try to move your [temp.name], but cannot!" + return + + user << "You pick up the [src]." + user.put_in_hands(src) return 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/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm index ac0dde64c0..e4e6b4b08a 100644 --- a/code/modules/projectiles/ammunition/boxes.dm +++ b/code/modules/projectiles/ammunition/boxes.dm @@ -110,18 +110,18 @@ /obj/item/ammo_magazine/c9mm/empty initial_ammo = 0 -/obj/item/ammo_magazine/a12mm - name = "magazine (12mm)" +/obj/item/ammo_magazine/a10mm + name = "magazine (10mm)" icon_state = "12mm" origin_tech = list(TECH_COMBAT = 2) mag_type = MAGAZINE - caliber = "12mm" + caliber = "10mm" matter = list(DEFAULT_WALL_MATERIAL = 1500) - ammo_type = "/obj/item/ammo_casing/a12mm" + ammo_type = /obj/item/ammo_casing/a10mm max_ammo = 20 multiple_sprites = 1 -/obj/item/ammo_magazine/a12mm/empty +/obj/item/ammo_magazine/a10mm/empty initial_ammo = 0 /obj/item/ammo_magazine/a556 diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm index ce22fd271f..345752835b 100644 --- a/code/modules/projectiles/ammunition/bullets.dm +++ b/code/modules/projectiles/ammunition/bullets.dm @@ -64,9 +64,9 @@ caliber = ".45" projectile_type = /obj/item/projectile/energy/flash -/obj/item/ammo_casing/a12mm - desc = "A 12mm bullet casing." - caliber = "12mm" +/obj/item/ammo_casing/a10mm + desc = "A 10mm bullet casing." + caliber = "10mm" projectile_type = /obj/item/projectile/bullet/pistol/medium diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 14e70bcfa4..1d1b905c45 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/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index ba1340ea96..b1c47fd605 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -1,14 +1,14 @@ /obj/item/weapon/gun/energy/laser name = "laser carbine" - desc = "A common laser weapon, designed to kill with concentrated energy blasts." + desc = "An Hesphaistos Industries G40E carbine, designed to kill with concentrated energy blasts." icon_state = "laser" item_state = "laser" fire_sound = 'sound/weapons/Laser.ogg' slot_flags = SLOT_BELT|SLOT_BACK w_class = 3 force = 10 - origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) - matter = list(DEFAULT_WALL_MATERIAL = 2000) + origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 2000) projectile_type = /obj/item/projectile/beam fire_delay = 1 //rapid fire @@ -17,15 +17,15 @@ use_external_power = 1 /obj/item/weapon/gun/energy/laser/practice - name = "practice laser gun" - desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice." + name = "practice laser carbine" + desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice." projectile_type = /obj/item/projectile/beam/practice obj/item/weapon/gun/energy/retro name = "retro laser" icon_state = "retro" item_state = "retro" - desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." + desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." fire_sound = 'sound/weapons/Laser.ogg' slot_flags = SLOT_BELT w_class = 3 @@ -36,7 +36,7 @@ obj/item/weapon/gun/energy/retro name = "antique laser gun" icon_state = "caplaser" item_state = "caplaser" - desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding." + desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well" force = 5 fire_sound = 'sound/weapons/Laser.ogg' slot_flags = SLOT_BELT @@ -78,8 +78,8 @@ obj/item/weapon/gun/energy/retro fire_delay = 1 /obj/item/weapon/gun/energy/sniperrifle - name = "\improper L.W.A.P. sniper rifle" - desc = "A high-power laser rifle fitted with a SMART aiming-system scope." + name = "marksman energy rifle" + desc = "The HI DMR 9E is an older design of Hesphaistos Industries. A designated marksman rifle capable of shooting powerful ionized beams, this is a weapon to kill from a distance." icon_state = "sniper" item_state = "laser" fire_sound = 'sound/weapons/marauder.ogg' diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index fe209aeadc..0c222a9c34 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/energy/gun name = "energy gun" - desc = "An energy-based gun with two settings: Stun and kill." + desc = "Another bestseller of Lawson Arms and the FTU, the LAEP90 Perun is a versatile energy based sidearm, capable of switching between low and high capacity projectile settings. In other words: Stun or Kill." icon_state = "energystun100" item_state = null //so the human update icon uses the icon_state instead. fire_sound = 'sound/weapons/Taser.ogg' @@ -24,9 +24,9 @@ name = "advanced energy gun" desc = "An energy gun with an experimental miniaturized reactor." icon_state = "nucgun" - origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 5, TECH_POWER = 3) + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 5, TECH_POWER = 3) slot_flags = SLOT_BELT - force = 8 //looks heavier than a pistol + force = 8 //looks heavier than a pistol self_recharge = 1 modifystate = null @@ -34,7 +34,7 @@ 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'), ) - + var/lightfail = 0 //override for failcheck behaviour 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/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 7f1457d638..738ab8fa7b 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/energy/ionrifle name = "ion rifle" - desc = "A man portable anti-armor weapon designed to disable mechanical threats" + desc = "The NT Mk60 EW Halicon is a man portable anti-armor weapon designed to disable mechanical threats, produced by NT. Not the best of its type." icon_state = "ionrifle" item_state = "ionrifle" fire_sound = 'sound/weapons/Laser.ogg' @@ -28,9 +28,9 @@ desc = "A gun that discharges high amounts of controlled radiation to slowly break a target into component elements." icon_state = "decloner" item_state = "decloner" - fire_sound = 'sound/weapons/pulse3.ogg' + fire_sound = 'sound/weapons/pulse3.ogg' origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 4, TECH_POWER = 3) - max_shots = 10 + max_shots = 10 projectile_type = /obj/item/projectile/energy/declone /obj/item/weapon/gun/energy/floragun diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 05a3c579e5..72392da29a 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/energy/taser name = "taser gun" - desc = "A small, low capacity gun used for non-lethal takedowns." + desc = "The NT Mk30 NL is a small, low capacity gun used for non-lethal takedowns. Produced by NT, it's actually a licensed version of a W-T design." icon_state = "taser" item_state = null //so the human update icon uses the icon_state instead. fire_sound = 'sound/weapons/Taser.ogg' @@ -20,11 +20,11 @@ /obj/item/weapon/gun/energy/stunrevolver name = "stun revolver" - desc = "A high-tech revolver that fires stun cartridges. The stun cartridges can be recharged using a conventional energy weapon recharger." + desc = "A LAEP20 Zeus. Designed by Lawson Arms and produced under the wing of the FTU, several TSCs have been trying to get a hold of the blueprints for half a decade." icon_state = "stunrevolver" item_state = "stunrevolver" - fire_sound = 'sound/weapons/Gunshot.ogg' - origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3, TECH_POWER = 2) + fire_sound = 'sound/weapons/Gunshot.ogg' + origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3, TECH_POWER = 2) projectile_type = /obj/item/projectile/energy/electrode max_shots = 8 @@ -35,8 +35,8 @@ icon_state = "crossbow" w_class = 2.0 item_state = "crossbow" - origin_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 2, TECH_ILLEGAL = 5) - matter = list(DEFAULT_WALL_MATERIAL = 2000) + origin_tech = list(TECH_COMBAT = 2, TECH_MAGNET = 2, TECH_ILLEGAL = 5) + matter = list(DEFAULT_WALL_MATERIAL = 2000) slot_flags = SLOT_BELT silenced = 1 fire_sound = 'sound/weapons/Genhit.ogg' 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..110b009c7e 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/projectile/automatic //Hopefully someone will find a way to make these fire in bursts or something. --Superxpdude - name = "submachine gun" - desc = "A lightweight, fast firing gun. Uses 9mm rounds." + name = "prototype SMG" + desc = "A protoype lightweight, fast firing gun. Uses 9mm rounds." icon_state = "saber" //ugly w_class = 3 load_method = SPEEDLOADER //yup. until someone sprites a magazine for it. @@ -10,16 +10,17 @@ 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 name = "\improper Uzi" - desc = "A lightweight, fast firing gun, for when you want someone dead. Uses .45 rounds." + desc = "The UZI is a lightweight, fast firing gun. For when you want someone dead. Uses .45 rounds." icon_state = "mini-uzi" w_class = 3 load_method = SPEEDLOADER //yup. until someone sprites a magazine for it. @@ -29,18 +30,18 @@ ammo_type = /obj/item/ammo_casing/c45 /obj/item/weapon/gun/projectile/automatic/c20r - name = "\improper C-20r SMG" - desc = "A lightweight, fast firing gun, for when you REALLY need someone dead. Uses 12mm pistol rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp" + name = "submachine gun" + desc = "The C-20r is a lightweight and rapid firing SMG, for when you REALLY need someone dead. Uses 10mm rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp." icon_state = "c20r" item_state = "c20r" w_class = 3 force = 10 - caliber = "12mm" + caliber = "10mm" origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2, TECH_ILLEGAL = 8) slot_flags = SLOT_BELT|SLOT_BACK fire_sound = 'sound/weapons/Gunshot_light.ogg' load_method = MAGAZINE - magazine_type = /obj/item/ammo_magazine/a12mm + magazine_type = /obj/item/ammo_magazine/a10mm auto_eject = 1 auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' @@ -53,8 +54,8 @@ return /obj/item/weapon/gun/projectile/automatic/sts35 - name = "\improper STS-35 automatic rifle" - desc = "A durable, rugged looking automatic weapon of a make popular on the frontier worlds. Uses 7.62mm rounds. It is unmarked." + name = "assault rifle" + desc = "The rugged STS-35 is a durable automatic weapon of a make popular on the frontier worlds. Uses 7.62mm rounds. This one is unmarked." icon_state = "arifle" item_state = null w_class = 4 @@ -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() @@ -77,8 +78,8 @@ update_held_icon() /obj/item/weapon/gun/projectile/automatic/wt550 - name = "\improper W-T 550 Saber" - desc = "A cheap, mass produced Ward-Takahashi PDW. Uses 9mm rounds." + name = "machine pistol" + desc = "The W-T 550 Saber is a cheap self-defense weapon, mass-produced by Ward-Takahashi for paramilitary and private use. Uses 9mm rounds." icon_state = "wt550" item_state = "wt550" w_class = 3 @@ -98,12 +99,9 @@ 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." + name = "bullpup assault rifle" + desc = "The Z8 Bulldog is 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." icon_state = "carbine" item_state = "z8carbine" w_class = 4 @@ -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 @@ -170,8 +166,8 @@ user << "\The [launcher] is empty." /obj/item/weapon/gun/projectile/automatic/l6_saw - name = "\improper L6 SAW" - desc = "A rather traditionally made light machine gun with a pleasantly lacquered wooden pistol grip. Has 'Aussec Armoury- 2531' engraved on the reciever" + name = "light machine gun" + desc = "A rather traditionally made L6 SAW with a pleasantly lacquered wooden pistol grip. Has 'Aussec Armoury- 2531' engraved on the reciever" icon_state = "l6closed100" item_state = "l6closedmag" w_class = 4 @@ -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/guns/projectile/dartgun.dm b/code/modules/projectiles/guns/projectile/dartgun.dm index e484d95d70..4f72eff500 100644 --- a/code/modules/projectiles/guns/projectile/dartgun.dm +++ b/code/modules/projectiles/guns/projectile/dartgun.dm @@ -43,7 +43,7 @@ /obj/item/weapon/gun/projectile/dartgun name = "dart gun" - desc = "A small gas-powered dartgun, capable of delivering chemical cocktails swiftly across short distances." + desc = "Zeng-Hu Pharmaceutical's entry into the arms market, the Z-H P Artemis is a gas-powered dart gun capable of delivering chemical cocktails swiftly across short distances." icon_state = "dartgun-empty" item_state = null @@ -203,4 +203,4 @@ starting_chems = list("kelotane","bicaridine","anti_toxin") /obj/item/weapon/gun/projectile/dartgun/vox/raider - starting_chems = list("space_drugs","stoxin","impedrezene") \ No newline at end of file + starting_chems = list("space_drugs","stoxin","impedrezene") diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index f3d37c84b6..05e2a08c6b 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/projectile/colt - name = "\improper Colt M1911" - desc = "A cheap Martian knock-off of a Colt M1911." + name = "vintage .45 pistol" + desc = "A cheap Martian knock-off of a Colt M1911. Uses .45 rounds." magazine_type = /obj/item/ammo_magazine/c45m icon_state = "colt" caliber = ".45" @@ -9,7 +9,6 @@ load_method = MAGAZINE /obj/item/weapon/gun/projectile/colt/detective - desc = "A cheap Martian knock-off of a Colt M1911. Uses .45 rounds." magazine_type = /obj/item/ammo_magazine/c45m/rubber /obj/item/weapon/gun/projectile/colt/detective/verb/rename_gun() @@ -31,8 +30,8 @@ return 1 /obj/item/weapon/gun/projectile/sec - desc = "A NanoTrasen designed sidearm, found pretty much everywhere humans are. Uses .45 rounds." - name = "\improper NT Mk58" + name = ".45 pistol" + desc = "The NT Mk58 is a cheap, ubiquitous sidearm, produced by a Nanotrasen subsidiary. Found pretty much everywhere humans are. Uses .45 rounds." icon_state = "secguncomp" magazine_type = /obj/item/ammo_magazine/c45m/rubber caliber = ".45" @@ -41,12 +40,12 @@ load_method = MAGAZINE /obj/item/weapon/gun/projectile/sec/flash - name = "\improper NT Mk58 signal pistol" + name = ".45 signal pistol" magazine_type = /obj/item/ammo_magazine/c45m/flash /obj/item/weapon/gun/projectile/sec/wood - desc = "A Nanotrasen designed sidearm, this one has a sweet wooden grip. Uses .45 rounds." - name = "\improper Custom NT Mk58" + desc = "The NT Mk58 is a cheap, ubiquitous sidearm, produced by a Nanotrasen subsidiary. This one has a sweet wooden grip. Uses .45 rounds." + name = "custom .45 Pistol" icon_state = "secgundark" /obj/item/weapon/gun/projectile/silenced @@ -106,8 +105,8 @@ icon_state = "gyropistol" /obj/item/weapon/gun/projectile/pistol - name = "\improper Stechtkin pistol" - desc = "A small, easily concealable gun. Uses 9mm rounds." + name = "holdout pistol" + desc = "The Lumoco Arms P3 Whisper. A small, easily concealable gun. Uses 9mm rounds." icon_state = "pistol" item_state = null w_class = 2 @@ -119,8 +118,7 @@ magazine_type = /obj/item/ammo_magazine/mc9mm /obj/item/weapon/gun/projectile/pistol/flash - name = "\improper Stechtkin signal pistol" - desc = "A small, easily concealable gun. Uses 9mm rounds." + name = "holdout signal pistol" magazine_type = /obj/item/ammo_magazine/mc9mm/flash /obj/item/weapon/gun/projectile/pistol/attack_hand(mob/user as mob) @@ -166,19 +164,19 @@ w_class = 2 /obj/item/weapon/gun/projectile/pirate - name = "zipgun" + name = "zip gun" desc = "Little more than a barrel, handle, and firing mechanism, cheap makeshift firearms like this one are not uncommon in frontier systems." icon_state = "sawnshotgun" item_state = "sawnshotgun" handle_casings = CYCLE_CASINGS //player has to take the old casing out manually before reloading load_method = SINGLE_CASING max_shells = 1 //literally just a barrel - + var/global/list/ammo_types = list( /obj/item/ammo_casing/a357 = ".357", /obj/item/ammo_casing/c9mmf = "9mm", /obj/item/ammo_casing/c45f = ".45", - /obj/item/ammo_casing/a12mm = "12mm", + /obj/item/ammo_casing/a10mm = "10mm", /obj/item/ammo_casing/shotgun = "12 gauge", /obj/item/ammo_casing/shotgun = "12 gauge", /obj/item/ammo_casing/shotgun/pellet = "12 gauge", @@ -194,7 +192,7 @@ /obj/item/weapon/gun/projectile/pirate/New() ammo_type = pick(ammo_types) desc += " Uses [ammo_types[ammo_type]] rounds." - + var/obj/item/ammo_casing/ammo = ammo_type caliber = initial(ammo.caliber) ..() diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index bf238167be..4375377ec0 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/projectile/revolver name = "revolver" - desc = "A classic revolver. Uses .357 ammo" + desc = "The Lumoco Arms HE Colt is a choice revolver for when you absolutely, positively need to put a hole in the other guy. Uses .357 ammo." icon_state = "revolver" item_state = "revolver" caliber = "357" @@ -34,7 +34,6 @@ /obj/item/weapon/gun/projectile/revolver/mateba name = "mateba" - desc = "When you absolutely, positively need a 10mm hole in the other guy. Uses .357 ammo." //>10mm hole >.357 icon_state = "mateba" origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm index 377b8c7742..85c4522d8d 100644 --- a/code/modules/projectiles/guns/projectile/shotgun.dm +++ b/code/modules/projectiles/guns/projectile/shotgun.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/projectile/shotgun/pump name = "shotgun" - desc = "Useful for sweeping alleys." + desc = "The mass-produced W-T Remmington 29x shotgun is a favourite of police and security forces on many worlds. Useful for sweeping alleys." icon_state = "shotgun" item_state = "shotgun" max_shells = 4 @@ -41,6 +41,7 @@ /obj/item/weapon/gun/projectile/shotgun/pump/combat name = "combat shotgun" + desc = "Built for close quarters combat, the Hesphaistos Industries KS-40 is widely regarded as a weapon of choice for repelling boarders." icon_state = "cshotgun" item_state = "cshotgun" origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2) diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm index b3a3c7580c..e38740e732 100644 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/projectile/heavysniper - name = "\improper PTR-7 rifle" - desc = "A portable anti-armour rifle fitted with a scope. Originally designed to used against armoured exosuits, it is capable of punching through windows and non-reinforced walls with ease. Fires armor piercing 14.5mm shells." + name = "anti-materiel rifle" + desc = "A portable anti-armour rifle fitted with a scope, the HI PTR-7 Rifle was originally designed to used against armoured exosuits. It is capable of punching through windows and non-reinforced walls with ease. Fires armor piercing 14.5mm shells." icon_state = "heavysniper" item_state = "l6closednomag" //placeholder w_class = 4 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 d012b1fed6..7eb95a1485 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -292,9 +292,15 @@ return trans_to_obj(target, amount, multiplier, copy) return 0 -//Using this in case we want to differentiate splashing an atom from transferring reagents to it later down the road. -//For now it just calls trans_to. -/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0) +//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well. +/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60) + var/spill = 0 + if(!isturf(target) && target.loc) + spill = amount*(rand(min_spill, max_spill)/100) + amount -= spill + if(spill) + splash(target.loc, spill, multiplier, copy, min_spill, max_spill) + trans_to(target, amount, multiplier, copy) /datum/reagents/proc/trans_id_to(var/atom/target, var/id, var/amount = 1) 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-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/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index f18a1457f9..bdb1754ca8 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -65,7 +65,7 @@ return else - trans = reagents.splash(target, amount_per_transfer_from_this) //sprinkling reagents on generic non-mobs + trans = reagents.trans_to(target, amount_per_transfer_from_this) //sprinkling reagents on generic non-mobs user << "You transfer [trans] units of the solution." else // Taking from something diff --git a/code/modules/reagents/reagent_containers/food/cans.dm b/code/modules/reagents/reagent_containers/food/cans.dm index 8155207b7e..7d72b8bf51 100644 --- a/code/modules/reagents/reagent_containers/food/cans.dm +++ b/code/modules/reagents/reagent_containers/food/cans.dm @@ -1,43 +1,12 @@ /obj/item/weapon/reagent_containers/food/drinks/cans + volume = 40 //just over one and a half cups amount_per_transfer_from_this = 5 - flags = 0 - - attack_self(mob/user as mob) - if (!is_open_container()) - playsound(loc,'sound/effects/canopen.ogg', rand(10,50), 1) - user << "You open the drink with an audible pop!" - flags |= OPENCONTAINER - else - return - - attack(mob/M as mob, mob/user as mob, def_zone) - if(!is_open_container()) - user << "You need to open the drink!" - return - - return ..() - - - afterattack(obj/target, mob/user, proximity) - if(!proximity) return - - if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. - if(!is_open_container()) - user << "You need to open the drink!" - return - - - else if(target.is_open_container()) //Something like a glass. Player probably wants to transfer TO it. - if(!is_open_container()) - user << "You need to open the drink!" - return - - return ..() + flags = 0 //starts closed //DRINKS /obj/item/weapon/reagent_containers/food/drinks/cans/cola - name = "Space Cola" + name = "\improper Space Cola" desc = "Cola. in space." icon_state = "cola" center_of_mass = list("x"=16, "y"=10) @@ -46,7 +15,7 @@ reagents.add_reagent("cola", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle - name = "Bottled Water" + name = "bottled water" desc = "Introduced to the vending machines by Skrellian request, this water comes straight from the Martian poles." icon_state = "waterbottle" center_of_mass = list("x"=15, "y"=8) @@ -54,28 +23,8 @@ ..() reagents.add_reagent("water", 30) -/obj/item/weapon/reagent_containers/food/drinks/cans/beer - name = "Space Beer" - desc = "Contains only water, malt and hops." - icon_state = "beer" - center_of_mass = list("x"=16, "y"=12) - New() - ..() - reagents.add_reagent("beer", 30) - -/obj/item/weapon/reagent_containers/food/drinks/cans/ale - name = "Magm-Ale" - desc = "A true dorf's drink of choice." - icon_state = "alebottle" - item_state = "beer" - center_of_mass = list("x"=16, "y"=10) - New() - ..() - reagents.add_reagent("ale", 30) - - /obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind - name = "Space Mountain Wind" + name = "\improper Space Mountain Wind" desc = "Blows right through you like a space wind." icon_state = "space_mountain_wind" center_of_mass = list("x"=16, "y"=10) @@ -84,7 +33,7 @@ reagents.add_reagent("spacemountainwind", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko - name = "Thirteen Loko" + name = "\improper Thirteen Loko" desc = "The CMO has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkeness, or even death. Please Drink Responsibly." icon_state = "thirteen_loko" center_of_mass = list("x"=16, "y"=8) @@ -93,7 +42,7 @@ reagents.add_reagent("thirteenloko", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb - name = "Dr. Gibb" + name = "\improper Dr. Gibb" desc = "A delicious mixture of 42 different flavors." icon_state = "dr_gibb" center_of_mass = list("x"=16, "y"=10) @@ -102,7 +51,7 @@ reagents.add_reagent("dr_gibb", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/starkist - name = "Star-kist" + name = "\improper Star-kist" desc = "The taste of a star in liquid form. And, a bit of tuna...?" icon_state = "starkist" center_of_mass = list("x"=16, "y"=10) @@ -111,7 +60,7 @@ reagents.add_reagent("brownstar", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/space_up - name = "Space-Up" + name = "\improper Space-Up" desc = "Tastes like a hull breach in your mouth." icon_state = "space-up" center_of_mass = list("x"=16, "y"=10) @@ -120,7 +69,7 @@ reagents.add_reagent("space_up", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime - name = "Lemon-Lime" + name = "\improper Lemon-Lime" desc = "You wanted ORANGE. It gave you Lemon Lime." icon_state = "lemon-lime" center_of_mass = list("x"=16, "y"=10) @@ -129,7 +78,7 @@ reagents.add_reagent("lemon_lime", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea - name = "Vrisk Serket Iced Tea" + name = "\improper Vrisk Serket Iced Tea" desc = "That sweet, refreshing southern earthy flavor. That's where it's from, right? South Earth?" icon_state = "ice_tea_can" center_of_mass = list("x"=16, "y"=10) @@ -138,7 +87,7 @@ reagents.add_reagent("icetea", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice - name = "Grapel Juice" + name = "\improper Grapel Juice" desc = "500 pages of rules of how to appropriately enter into a combat with this juice!" icon_state = "purple_can" center_of_mass = list("x"=16, "y"=10) @@ -147,7 +96,7 @@ reagents.add_reagent("grapejuice", 30) /obj/item/weapon/reagent_containers/food/drinks/cans/tonic - name = "T-Borg's Tonic Water" + name = "\improper T-Borg's Tonic Water" desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." icon_state = "tonic" center_of_mass = list("x"=16, "y"=10) @@ -156,7 +105,7 @@ reagents.add_reagent("tonic", 50) /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater - name = "Soda Water" + name = "soda water" desc = "A can of soda water. Still water's more refreshing cousin." icon_state = "sodawater" center_of_mass = list("x"=16, "y"=10) diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm index f70e06f421..7fd9bec3a2 100644 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -14,12 +14,18 @@ return attack_self(mob/user as mob) - return + if(!is_open_container()) + open(user) - attack(mob/M as mob, mob/user as mob, def_zone) - if(standard_feed_mob(user, M)) + proc/open(mob/user) + playsound(loc,'sound/effects/canopen.ogg', rand(10,50), 1) + user << "You open [src] with an audible pop!" + flags |= OPENCONTAINER + + attack(mob/M as mob, mob/user as mob, def_zone) + if(standard_feed_mob(user, M)) return - + return 0 afterattack(obj/target, mob/user, proximity) @@ -29,7 +35,24 @@ return if(standard_pour_into(user, target)) return + return ..() + standard_feed_mob(var/mob/user, var/mob/target) + if(!is_open_container()) + user << "You need to open [src]!" + return 1 + return ..() + + standard_dispenser_refill(var/mob/user, var/obj/structure/reagent_dispensers/target) + if(!is_open_container()) + user << "You need to open [src]!" + return 1 + return ..() + + standard_pour_into(var/mob/user, var/atom/target) + if(!is_open_container()) + user << "You need to open [src]!" + return 1 return ..() self_feed_message(var/mob/user) diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index 7e289a45f3..a73e73bc5a 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -4,19 +4,51 @@ /obj/item/weapon/reagent_containers/food/drinks/bottle amount_per_transfer_from_this = 10 - volume = 120 + volume = 100 item_state = "broken_beer" //Generic held-item sprite until unique ones are made. - var/const/duration = 13 //Directly relates to the 'weaken' duration. Lowered by armor (i.e. helmets) + force = 5 + var/smash_duration = 5 //Directly relates to the 'weaken' duration. Lowered by armor (i.e. helmets) var/isGlass = 1 //Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it + + var/obj/item/weapon/reagent_containers/glass/rag/rag = null + var/rag_underlay = "rag" -/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/smash(mob/living/target as mob, mob/living/user as mob) +/obj/item/weapon/reagent_containers/food/drinks/bottle/Destroy() + rag = null + ..() + +//when thrown on impact, bottles smash and spill their contents +/obj/item/weapon/reagent_containers/food/drinks/bottle/throw_impact(atom/hit_atom, var/speed) + ..() + + var/mob/M = thrower + if(isGlass && istype(M) && M.a_intent == I_HURT) + var/throw_dist = get_dist(throw_source, loc) + if(speed >= throw_speed && smash_check(throw_dist)) //not as reliable as smashing directly + if(reagents) + hit_atom.visible_message("The contents of the [src] splash all over [hit_atom]!") + reagents.splash(hit_atom, reagents.total_volume) + src.smash(loc, hit_atom) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/smash_check(var/distance) + if(!isGlass || !smash_duration) + return 0 + + var/list/chance_table = list(90, 90, 85, 85, 60, 35, 15) //starting from distance 0 + var/idx = max(distance + 1, 1) //since list indices start at 1 + if(idx > chance_table.len) + return 0 + return prob(chance_table[idx]) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/smash(var/newloc, atom/against = null) + if(ismob(loc)) + var/mob/M = loc + M.drop_from_inventory(src) //Creates a shattering noise and replaces the bottle with a broken_bottle - user.drop_item() - var/obj/item/weapon/broken_bottle/B = new /obj/item/weapon/broken_bottle(user.loc) - user.put_in_active_hand(B) + var/obj/item/weapon/broken_bottle/B = new /obj/item/weapon/broken_bottle(newloc) if(prob(33)) - new/obj/item/weapon/material/shard(target.loc) // Create a glass shard at the target's location! + new/obj/item/weapon/material/shard(newloc) // Create a glass shard at the target's location! B.icon_state = src.icon_state var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) @@ -24,23 +56,68 @@ I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) B.icon = I + if(rag && rag.on_fire && isliving(against)) + rag.forceMove(loc) + var/mob/living/L = against + L.IgniteMob() + playsound(src, "shatter", 70, 1) - user.put_in_active_hand(B) src.transfer_fingerprints_to(B) qdel(src) + return B + +/obj/item/weapon/reagent_containers/food/drinks/bottle/attackby(obj/item/W, mob/user) + if(!rag && istype(W, /obj/item/weapon/reagent_containers/glass/rag)) + insert_rag(W, user) + return + if(rag && istype(W, /obj/item/weapon/flame)) + rag.attackby(W, user) + return + ..() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/attack_self(mob/user) + if(rag) + remove_rag(user) + else + ..() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/insert_rag(obj/item/weapon/reagent_containers/glass/rag/R, mob/user) + if(!isGlass || rag) return + if(user.unEquip(R)) + user << "You stuff [R] into [src]." + rag = R + rag.forceMove(src) + flags &= ~OPENCONTAINER + update_icon() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/proc/remove_rag(mob/user) + if(!rag) return + user.put_in_hands(rag) + rag = null + flags |= (initial(flags) & OPENCONTAINER) + update_icon() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/open(mob/user) + if(rag) return + ..() + +/obj/item/weapon/reagent_containers/food/drinks/bottle/update_icon() + underlays.Cut() + if(rag) + var/underlay_image = image(icon='icons/obj/drinks.dmi', icon_state=rag.on_fire? "[rag_underlay]_lit" : rag_underlay) + underlays += underlay_image + copy_light(rag) + else + set_light(0) /obj/item/weapon/reagent_containers/food/drinks/bottle/attack(mob/living/target as mob, mob/living/user as mob) - if(!target) return if(user.a_intent != I_HURT || !isGlass) return ..() - - force = 15 //Smashing bottles over someoen's head hurts. - var/obj/item/organ/external/affecting = user.zone_sel.selecting //Find what the player is aiming at var/armor_block = 0 //Get the target's armour values for normal attack damage. @@ -48,13 +125,16 @@ //Calculating duration and calculating damage. armor_block = target.run_armor_check(affecting, "melee") - armor_duration = duration + force - target.getarmor(affecting, "melee") + + //force will counteract armour, but will never increase duration + armor_duration = smash_duration + min(0, force - target.getarmor(affecting, "melee") + 10) //Apply the damage! target.apply_damage(force, BRUTE, affecting, armor_block, sharp=0) // You are going to knock someone out for longer if they are not wearing a helmet. - if(affecting == "head" && istype(target, /mob/living/carbon/)) + var/do_smash = smash_check(1) //won't always break on the first hit + if(affecting == "head" && istype(target, /mob/living/carbon/) && do_smash) //Display an attack message. for(var/mob/O in viewers(user, null)) @@ -62,8 +142,7 @@ else O.show_message(text("\red [target] hit \himself with a bottle of [src.name] on the head!"), 1) //Weaken the target for the duration that we calculated and divide it by 5. if(armor_duration) - target.apply_effect(min(armor_duration, 10) , WEAKEN, armor_block) // Never weaken more than a flash! - + target.apply_effect(min(armor_duration, 5) , WEAKEN, armor_block) // Never weaken more than a flash! else //Default attack message and don't weaken the target. for(var/mob/O in viewers(user, null)) @@ -75,13 +154,15 @@ target.attack_log += text("\[[time_stamp()]\] Has been smashed with a bottle by [user.name] ([user.ckey])") msg_admin_attack("[user.name] ([user.ckey]) attacked [target.name] ([target.ckey]) with a bottle. (INTENT: [uppertext(user.a_intent)]) (JMP)") - //The reagents in the bottle splash all over the target, thanks for the idea Nodrak - if(reagents) - user.visible_message("The contents of the [src] splash all over [target]!") - reagents.splash(target, reagents.total_volume) + if(do_smash) + //The reagents in the bottle splash all over the target, thanks for the idea Nodrak + if(reagents) + user.visible_message("The contents of the [src] splash all over [target]!") + reagents.splash(target, reagents.total_volume) - //Finally, smash the bottle. This kills (qdel) the bottle. - src.smash(target, user) + //Finally, smash the bottle. This kills (qdel) the bottle. + var/obj/item/weapon/broken_bottle/B = src.smash(target.loc, target) + user.put_in_active_hand(B) return @@ -92,8 +173,8 @@ desc = "A bottle with a sharp broken bottom." icon = 'icons/obj/drinks.dmi' icon_state = "broken_bottle" - force = 9.0 - throwforce = 5.0 + force = 9 + throwforce = 5 throw_speed = 3 throw_range = 5 item_state = "beer" @@ -314,3 +395,31 @@ New() ..() reagents.add_reagent("limejuice", 100) + +//Small bottles +/obj/item/weapon/reagent_containers/food/drinks/bottle/small + volume = 50 + smash_duration = 1 + flags = 0 //starts closed + rag_underlay = "rag_small" + +/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer + name = "space beer" + desc = "Contains only water, malt and hops." + icon_state = "beer" + center_of_mass = list("x"=16, "y"=12) + New() + ..() + reagents.add_reagent("beer", 30) + +/obj/item/weapon/reagent_containers/food/drinks/bottle/small/ale + name = "\improper Magm-Ale" + desc = "A true dorf's drink of choice." + icon_state = "alebottle" + item_state = "beer" + center_of_mass = list("x"=16, "y"=10) + New() + ..() + reagents.add_reagent("ale", 30) + + diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index db5229b680..69d98f11d6 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -463,6 +463,7 @@ desc = "An egg!" icon_state = "egg" filling_color = "#FDFFD1" + volume = 10 /obj/item/weapon/reagent_containers/food/snacks/egg/New() ..() 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 ae71bf8249..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)) @@ -258,7 +248,7 @@ 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 @@ -429,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/debug.dm b/code/modules/tables/debug.dm new file mode 100644 index 0000000000..d1b7a968a9 --- /dev/null +++ b/code/modules/tables/debug.dm @@ -0,0 +1,22 @@ + +// Mostly for debugging table connections +// This file is not #included in the .dme. + +/obj/structure/table/debug + New() + material = get_material_by_name("debugium") + ..() + +/material/debug + name = "debugium" + stack_type = /obj/item/stack/material/debug + icon_base = "debug" + icon_reinf = "rdebug" + icon_colour = "#FFFFFF" + +/obj/item/stack/material/debug + name = "debugium" + icon = 'icons/obj/tables.dmi' + icon_state = "debugium" + default_type = "debugium" + 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..7ff4f8fe20 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 @@ -296,29 +296,33 @@ icon_state = "blank" overlays.Cut() + var/image/I + // Base frame shape. Mostly done for glass/diamond tables, where this is visible. - for(var/n in connections) - overlays += n + for(var/i = 1 to 4) + I = image(icon, dir = 1<<(i-1), icon_state = connections[i]) + overlays += I // Standard table image if(material) - for(var/n in connections) - var/image/I = image(icon, "[material.icon_base]_[n]") + for(var/i = 1 to 4) + I = image(icon, "[material.icon_base]_[connections[i]]", dir = 1<<(i-1)) I.color = material.icon_colour I.alpha = 255 * material.opacity overlays += I // Reinforcements if(reinforced) - for(var/n in connections) - var/image/I = image(icon, "[reinforced.icon_reinf]_[n]") + for(var/i = 1 to 4) + I = image(icon, "[reinforced.icon_reinf]_[connections[i]]", dir = 1<<(i-1)) I.color = reinforced.icon_colour I.alpha = 255 * reinforced.opacity overlays += I if(carpeted) - for(var/n in connections) - overlays += "carpet_[n]" + for(var/i = 1 to 4) + I = image(icon, "carpet_[connections[i]]", dir = 1<<(i-1)) + overlays += I else overlays.Cut() var/type = 0 @@ -353,13 +357,12 @@ overlays += I if(carpeted) - for(var/n in connections) - overlays += "carpet_flip[type]" + overlays += "carpet_flip[type]" // set propagate if you're updating a table that should update tables around it too, for example if it's a new table or something important has changed (like material). /obj/structure/table/proc/update_connections(propagate=0) if(!material) - connections = list("nw0", "ne0", "sw0", "se0") + connections = list("0", "0", "0", "0") if(propagate) for(var/obj/structure/table/T in oview(src, 1)) @@ -369,7 +372,7 @@ var/list/blocked_dirs = list() for(var/obj/structure/window/W in get_turf(src)) if(W.is_fulltile()) - connections = list("nw0", "ne0", "sw0", "se0") + connections = list("0", "0", "0", "0") return blocked_dirs |= W.dir @@ -412,40 +415,27 @@ connections = dirs_to_corner_states(connection_dirs) #define CORNER_NONE 0 -#define CORNER_EASTWEST 1 +#define CORNER_CLOCKWISE 1 #define CORNER_DIAGONAL 2 -#define CORNER_NORTHSOUTH 4 +#define CORNER_COUNTERCLOCKWISE 4 /proc/dirs_to_corner_states(list/dirs) if(!istype(dirs)) return - var/NE = CORNER_NONE - var/NW = CORNER_NONE - var/SE = CORNER_NONE - var/SW = CORNER_NONE + var/list/ret = list(NORTHWEST, SOUTHEAST, NORTHEAST, SOUTHWEST) - if(NORTH in dirs) - NE |= CORNER_NORTHSOUTH - NW |= CORNER_NORTHSOUTH - if(SOUTH in dirs) - SW |= CORNER_NORTHSOUTH - SE |= CORNER_NORTHSOUTH - if(EAST in dirs) - SE |= CORNER_EASTWEST - NE |= CORNER_EASTWEST - if(WEST in dirs) - NW |= CORNER_EASTWEST - SW |= CORNER_EASTWEST - if(NORTHWEST in dirs) - NW |= CORNER_DIAGONAL - if(NORTHEAST in dirs) - NE |= CORNER_DIAGONAL - if(SOUTHEAST in dirs) - SE |= CORNER_DIAGONAL - if(SOUTHWEST in dirs) - SW |= CORNER_DIAGONAL + for(var/i = 1 to ret.len) + var/dir = ret[i] + . = CORNER_NONE + if(dir in dirs) + . |= CORNER_DIAGONAL + if(turn(dir,45) in dirs) + . |= CORNER_CLOCKWISE + if(turn(dir,-45) in dirs) + . |= CORNER_COUNTERCLOCKWISE + ret[i] = "[.]" - return list("ne[NE]", "se[SE]", "sw[SW]", "nw[NW]") + return ret #undef CORNER_NONE #undef CORNER_EASTWEST 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/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 @@ |